From 4da6a5475d0ebb40a3cfbbb576a0532ae79fcfb5 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 14 Mar 2015 03:52:58 -0400 Subject: [PATCH 01/43] make elation play nice with node --- scripts/engine.js | 22 +- scripts/external/three/canvas/.dntrc | 19 + scripts/external/three/canvas/.gitmodules | 0 scripts/external/three/canvas/.npmignore | 6 + scripts/external/three/canvas/.travis.yml | 8 + scripts/external/three/canvas/History.md | 459 + scripts/external/three/canvas/Makefile | 24 + scripts/external/three/canvas/Readme.md | 336 + scripts/external/three/canvas/binding.gyp | 172 + scripts/external/three/canvas/build/Makefile | 337 + .../.deps/Release/canvas-postbuild.node.d | 1 + .../build/Release/.deps/Release/canvas.node.d | 1 + .../obj.target/canvas-postbuild.node.d | 1 + .../.deps/Release/obj.target/canvas.node.d | 1 + .../Release/obj.target/canvas/src/Canvas.o.d | 299 + .../obj.target/canvas/src/CanvasGradient.o.d | 266 + .../obj.target/canvas/src/CanvasPattern.o.d | 266 + .../canvas/src/CanvasRenderingContext2d.o.d | 299 + .../obj.target/canvas/src/FontFace.o.d | 288 + .../Release/obj.target/canvas/src/Image.o.d | 264 + .../obj.target/canvas/src/ImageData.o.d | 266 + .../obj.target/canvas/src/PixelArray.o.d | 265 + .../Release/obj.target/canvas/src/color.o.d | 4 + .../Release/obj.target/canvas/src/init.o.d | 297 + .../build/Release/canvas-postbuild.node | Bin 0 -> 7470 bytes .../three/canvas/build/Release/canvas.node | Bin 0 -> 208599 bytes .../three/canvas/build/Release/linker.lock | 0 .../Release/obj.target/canvas-postbuild.node | Bin 0 -> 7470 bytes .../build/Release/obj.target/canvas.node | Bin 0 -> 208599 bytes .../Release/obj.target/canvas/src/Canvas.o | Bin 0 -> 52960 bytes .../obj.target/canvas/src/CanvasGradient.o | Bin 0 -> 18256 bytes .../obj.target/canvas/src/CanvasPattern.o | Bin 0 -> 15968 bytes .../canvas/src/CanvasRenderingContext2d.o | Bin 0 -> 135424 bytes .../Release/obj.target/canvas/src/FontFace.o | Bin 0 -> 15536 bytes .../Release/obj.target/canvas/src/Image.o | Bin 0 -> 40216 bytes .../Release/obj.target/canvas/src/ImageData.o | Bin 0 -> 17832 bytes .../obj.target/canvas/src/PixelArray.o | Bin 0 -> 17832 bytes .../Release/obj.target/canvas/src/color.o | Bin 0 -> 18256 bytes .../Release/obj.target/canvas/src/init.o | Bin 0 -> 3968 bytes .../three/canvas/build/binding.Makefile | 6 + .../canvas/build/canvas-postbuild.target.mk | 42 + .../three/canvas/build/canvas.target.mk | 172 + .../external/three/canvas/build/config.gypi | 116 + scripts/external/three/canvas/index.js | 1 + scripts/external/three/canvas/install | 65 + scripts/external/three/canvas/lib/bindings.js | 2 + scripts/external/three/canvas/lib/canvas.js | 222 + .../external/three/canvas/lib/context2d.js | 386 + scripts/external/three/canvas/lib/image.js | 60 + .../external/three/canvas/lib/jpegstream.js | 61 + .../external/three/canvas/lib/pixelarray.js | 29 + .../external/three/canvas/lib/pngstream.js | 60 + .../three/canvas/node_modules/nan/.dntrc | 30 + .../canvas/node_modules/nan/CHANGELOG.md | 248 + .../three/canvas/node_modules/nan/LICENSE.md | 13 + .../three/canvas/node_modules/nan/README.md | 1228 + .../canvas/node_modules/nan/appveyor.yml | 35 + .../canvas/node_modules/nan/include_dirs.js | 1 + .../three/canvas/node_modules/nan/nan.h | 2038 + .../nan/nan_implementation_12_inl.h | 253 + .../nan/nan_implementation_pre_12_inl.h | 256 + .../three/canvas/node_modules/nan/nan_new.h | 320 + .../canvas/node_modules/nan/package.json | 69 + scripts/external/three/canvas/package.json | 67 + scripts/external/three/canvas/src/Canvas.cc | 575 + scripts/external/three/canvas/src/Canvas.h | 96 + .../three/canvas/src/CanvasGradient.cc | 121 + .../three/canvas/src/CanvasGradient.h | 28 + .../three/canvas/src/CanvasPattern.cc | 91 + .../external/three/canvas/src/CanvasPattern.h | 28 + .../canvas/src/CanvasRenderingContext2d.cc | 2403 + .../canvas/src/CanvasRenderingContext2d.h | 183 + scripts/external/three/canvas/src/FontFace.cc | 112 + scripts/external/three/canvas/src/FontFace.h | 33 + scripts/external/three/canvas/src/Image.cc | 971 + scripts/external/three/canvas/src/Image.h | 108 + .../external/three/canvas/src/ImageData.cc | 69 + scripts/external/three/canvas/src/ImageData.h | 28 + .../external/three/canvas/src/JPEGStream.h | 155 + scripts/external/three/canvas/src/PNG.h | 227 + .../external/three/canvas/src/PixelArray.cc | 154 + .../external/three/canvas/src/PixelArray.h | 33 + scripts/external/three/canvas/src/Point.h | 19 + scripts/external/three/canvas/src/closure.h | 65 + scripts/external/three/canvas/src/color.cc | 739 + scripts/external/three/canvas/src/color.h | 40 + scripts/external/three/canvas/src/init.cc | 74 + .../three/canvas/util/cairo_include.sh | 6 + .../three/canvas/util/has_cairo_freetype.sh | 13 + scripts/external/three/canvas/util/has_lib.sh | 27 + .../external/three/canvas/util/lib_lookup.sh | 6 + scripts/external/three/nodethree.js | 38346 ++++++++++++++++ scripts/materials.js | 10 +- scripts/systems/networking.js | 177 + scripts/systems/render.js | 30 +- scripts/systems/world.js | 15 +- scripts/things/generic.js | 14 +- scripts/things/menu.js | 24 +- scripts/things/player.js | 75 +- 99 files changed, 54709 insertions(+), 67 deletions(-) create mode 100644 scripts/external/three/canvas/.dntrc create mode 100644 scripts/external/three/canvas/.gitmodules create mode 100644 scripts/external/three/canvas/.npmignore create mode 100644 scripts/external/three/canvas/.travis.yml create mode 100644 scripts/external/three/canvas/History.md create mode 100644 scripts/external/three/canvas/Makefile create mode 100644 scripts/external/three/canvas/Readme.md create mode 100755 scripts/external/three/canvas/binding.gyp create mode 100644 scripts/external/three/canvas/build/Makefile create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d create mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d create mode 100755 scripts/external/three/canvas/build/Release/canvas-postbuild.node create mode 100755 scripts/external/three/canvas/build/Release/canvas.node create mode 100644 scripts/external/three/canvas/build/Release/linker.lock create mode 100755 scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node create mode 100755 scripts/external/three/canvas/build/Release/obj.target/canvas.node create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/color.o create mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/init.o create mode 100644 scripts/external/three/canvas/build/binding.Makefile create mode 100644 scripts/external/three/canvas/build/canvas-postbuild.target.mk create mode 100644 scripts/external/three/canvas/build/canvas.target.mk create mode 100644 scripts/external/three/canvas/build/config.gypi create mode 100644 scripts/external/three/canvas/index.js create mode 100755 scripts/external/three/canvas/install create mode 100644 scripts/external/three/canvas/lib/bindings.js create mode 100644 scripts/external/three/canvas/lib/canvas.js create mode 100644 scripts/external/three/canvas/lib/context2d.js create mode 100644 scripts/external/three/canvas/lib/image.js create mode 100644 scripts/external/three/canvas/lib/jpegstream.js create mode 100644 scripts/external/three/canvas/lib/pixelarray.js create mode 100644 scripts/external/three/canvas/lib/pngstream.js create mode 100644 scripts/external/three/canvas/node_modules/nan/.dntrc create mode 100644 scripts/external/three/canvas/node_modules/nan/CHANGELOG.md create mode 100644 scripts/external/three/canvas/node_modules/nan/LICENSE.md create mode 100644 scripts/external/three/canvas/node_modules/nan/README.md create mode 100644 scripts/external/three/canvas/node_modules/nan/appveyor.yml create mode 100644 scripts/external/three/canvas/node_modules/nan/include_dirs.js create mode 100644 scripts/external/three/canvas/node_modules/nan/nan.h create mode 100644 scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h create mode 100644 scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h create mode 100644 scripts/external/three/canvas/node_modules/nan/nan_new.h create mode 100644 scripts/external/three/canvas/node_modules/nan/package.json create mode 100644 scripts/external/three/canvas/package.json create mode 100644 scripts/external/three/canvas/src/Canvas.cc create mode 100644 scripts/external/three/canvas/src/Canvas.h create mode 100644 scripts/external/three/canvas/src/CanvasGradient.cc create mode 100644 scripts/external/three/canvas/src/CanvasGradient.h create mode 100644 scripts/external/three/canvas/src/CanvasPattern.cc create mode 100644 scripts/external/three/canvas/src/CanvasPattern.h create mode 100755 scripts/external/three/canvas/src/CanvasRenderingContext2d.cc create mode 100644 scripts/external/three/canvas/src/CanvasRenderingContext2d.h create mode 100755 scripts/external/three/canvas/src/FontFace.cc create mode 100644 scripts/external/three/canvas/src/FontFace.h create mode 100644 scripts/external/three/canvas/src/Image.cc create mode 100644 scripts/external/three/canvas/src/Image.h create mode 100644 scripts/external/three/canvas/src/ImageData.cc create mode 100644 scripts/external/three/canvas/src/ImageData.h create mode 100644 scripts/external/three/canvas/src/JPEGStream.h create mode 100644 scripts/external/three/canvas/src/PNG.h create mode 100644 scripts/external/three/canvas/src/PixelArray.cc create mode 100644 scripts/external/three/canvas/src/PixelArray.h create mode 100644 scripts/external/three/canvas/src/Point.h create mode 100644 scripts/external/three/canvas/src/closure.h create mode 100644 scripts/external/three/canvas/src/color.cc create mode 100644 scripts/external/three/canvas/src/color.h create mode 100755 scripts/external/three/canvas/src/init.cc create mode 100755 scripts/external/three/canvas/util/cairo_include.sh create mode 100755 scripts/external/three/canvas/util/has_cairo_freetype.sh create mode 100755 scripts/external/three/canvas/util/has_lib.sh create mode 100755 scripts/external/three/canvas/util/lib_lookup.sh create mode 100644 scripts/external/three/nodethree.js create mode 100644 scripts/systems/networking.js diff --git a/scripts/engine.js b/scripts/engine.js index 3131621..98cd45f 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -1,11 +1,20 @@ -elation.require([ - "engine.external.three.three", +var deps = [ "engine.parts", "engine.materials", "engine.geometries", "engine.things.generic", - "utils.math" -], function() { + "utils.math" ]; + +if (ENV_IS_BROWSER) { + deps.push("engine.external.three.three") +} + +else if (ENV_IS_NODE) { + deps.push("engine.external.three.nodethree") +} + + +elation.require(deps, function() { elation.requireCSS('engine.engine'); elation.extend("engine.instances", {}); @@ -24,7 +33,8 @@ elation.require([ this.init = function() { this.systems = new elation.engine.systems(this); // shutdown cleanly if the user leaves the page - elation.events.add(window, "unload", elation.bind(this, this.stop)); + // TODO + // elation.events.add(window, "unload", elation.bind(this, this.stop)); } this.start = function() { this.started = this.running = true; @@ -52,6 +62,7 @@ elation.require([ // fire engine_frame event, which kicks off processing in any active systems //console.log("=========="); elation.events.fire({type: "engine_frame", element: this, data: evdata}); + console.log('did a frame', this.systems.world.children.vrcade); this.lastupdate = ts; } @@ -75,6 +86,7 @@ elation.require([ } })(); this.frame = function(fn) { + var window = window || {}; this.requestAnimationFrame.call(window, fn); } diff --git a/scripts/external/three/canvas/.dntrc b/scripts/external/three/canvas/.dntrc new file mode 100644 index 0000000..41ef805 --- /dev/null +++ b/scripts/external/three/canvas/.dntrc @@ -0,0 +1,19 @@ +## DNT config file +## see https://github.com/rvagg/dnt + +NODE_VERSIONS="\ + master \ + v0.11.12 \ + v0.10.26 \ + v0.8.22 \ +" +OUTPUT_PREFIX="canvas-" +TEST_CMD="\ + sudo apt-get install -y libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev && \ + cd /dnt/ && \ + npm install node-gyp && \ + npm install && \ + node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild && \ + npm test; \ +" +LOG_OK_CMD="sed -r 's/^\s+[0-9]+ passing \([0-9]+ms\)$/ok/' | tail -2 | head -1" diff --git a/scripts/external/three/canvas/.gitmodules b/scripts/external/three/canvas/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/scripts/external/three/canvas/.npmignore b/scripts/external/three/canvas/.npmignore new file mode 100644 index 0000000..e91e149 --- /dev/null +++ b/scripts/external/three/canvas/.npmignore @@ -0,0 +1,6 @@ +testing +build +benchmarks +examples +support +test diff --git a/scripts/external/three/canvas/.travis.yml b/scripts/external/three/canvas/.travis.yml new file mode 100644 index 0000000..7049d0c --- /dev/null +++ b/scripts/external/three/canvas/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - '0.8' + - '0.10' + - '0.11' +before_install: + - sudo chown -R $USER /usr/local + - sh install diff --git a/scripts/external/three/canvas/History.md b/scripts/external/three/canvas/History.md new file mode 100644 index 0000000..3871d37 --- /dev/null +++ b/scripts/external/three/canvas/History.md @@ -0,0 +1,459 @@ +1.2.1 / 2015-02-10 +================== + + * Use non-cairo 1.12 API for shadow blur + +1.2.0 / 2015-01-31 +================== + + * travis: drop support for node v0.6 + * Merge pull request #507 from salzhrani/iojs + * io.js compatibility + * Merge pull request #505 from woodcoder/shadow-blur + * Fix issue with line width not being correct in stroked shadows. + * Add another shadow/transform test. + * Refactor setSourceRGBA to allow the context to be supplied. + * Simple image shadow (no blurring or handling current transforms) based on image's alpha channel. + * Test showing issue #133, that images don't have shadows. + * The +1 on the offset seems to match the browser's output better, but I can't work out why it would be needed (unless it's pixel alignment related). + * Make the shadow radius more accurately match the browser's, making use of sigma scale as used in SKIA: https://github.com/google/skia/blob/master/src/effects/SkBlurMask.cpp#L26. + * Create a new image surface to render blurred shadows to, this means that vector formats like PDF will now render blurs. + * Add recommended calls to flush and dirty buffer, as per http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-image-surface-get-data. + * Add PDF button to test page to easily generate PDF version of the test image. + * Fix to ensure shadowOffset is unaffected by the current transform. + * New test illustrating that canvas implementation doesn't translate the shadowOffset. + * Merge pull request #490 from AllYearbooks/master + * Merge pull request #501 from motiz88/hsl-color + * Code style + attribution. Also removed parseClipped() and commented out wrapInt (now wrap_int). + * Added visual tests for hsl() and hsla() color parsing. + * Fixed handling in hsl/hsla color parser. parseNumber() was erroring out on numbers with long fractional parts. + * hsl/hsla color parsing + rebeccapurple hsl() and hsla() color values are now supported, with corresponding unit tests. Also added rebeccapurple (from CSS Color Level 4) to the named color list. + * float rather than int for drawImage arguments + * with_pango to true and use fontconfig to load fonts + * Merge pull request #399 from nulltask/fix/lighten + * Merge pull request #465 from espadrine/master + * Merge pull request #470 from tonylukasavage/patch-1 + * Add one-liner MacPorts install to docs + * Offer SVG output. + * Readme update: node-gyp. + * Readme: fix subheading size + * Readme: remove Gemnasium badge, use SVG for npm badge + * Readme: add Travis-CI badge + * change operator lighter to lighten + +1.1.6 / 2014-08-01 +================== + + * export canvas.CanvasPixelArray instead of canvas.PixelArray which is undefined + * Glib version test into giflib exists test + * Giflib 5.1 + * install: use an even older version of giflib (v4.1.6) + * install: use an older version of giflib (v4.2.3) + * install: install `giflib` + * install: use more compatible sh syntax + * travis: attempt to run the ./install script before testintg + * travis: test node v0.6, v0.8, v0.10, and v0.11 + * Distinguish between 'add' and 'lighter' + +1.1.5 / 2014-06-26 +================== + + * Readme: remove Contributors section + * Readme: update copyright + * On Windows, copy required DLLs next to ".node" file (#442 @pandell) + * Duplicate "msvc_settings" for "Debug" configuration + * Remove unneeded #include + * Use float constants to prevent double->float conversion warning + * Ignore Visual C++ 2013 warnings (#441 @pandell) + * Add algorithm include to CanvasRenderingContext2d.cc for std::min (#435 @kkoopa) + * Updated NAN to 1.2.0 (#434 @kkoopa) + +1.1.4 / 2014-06-08 +================== + + * Fix compile error with Visual C++ + * Add support for the lineDash API + * Update NAN + * New V8 compatibility + * Correctly limit bounds in PutImageData to prevent segment fault + * Fix segfault when onload and onerror are not function + * Add support for Node 0.11.9 + +1.1.3 / 2014-01-08 +================== + + * Add CAIRO_FORMAT_INVALID + * Readjust the amount of allocated memory + * Fix argument index for filter parameter + * Make has_lib.sh work properly on Debian 64bit + +1.1.2 / 2013-10-31 +================== + + * NAN dep upgrade, full node@<=0.11.8 compatibility + * Use node::MakeCallback() instead of v8::Function::Call() + * Improve nan location discovery + * Fix enabling gif/jpeg options on Ubuntu 13.04 + +1.1.1 / 2013-10-09 +================== + + * add better support for outdated versions of Cairo + +1.1.0 / 2013-08-01 +================== + + * add png compression options + * add jpeg stream progressive mode option + * fix resource leaks on read errors + +1.0.4 / 2013-07-23 +================== + + * 0.11.4+ compatibility using NAN + * fix typo in context2d for imageSmoothingEnabled + +1.0.3 / 2013-06-04 +================== + + * add "nearest" and "bilinear" to patternQuality + * fix fread() retval check (items not bytes) + * removed unneeded private fields + +1.0.2 / 2013-03-22 +================== + + * add Context2d#imageSmoothingEnabled= + +1.0.1 / 2013-02-25 +================== + + * travis: test modern node versions + * change the node-gyp build to use pkg-config + +1.0.0 / 2013-01-16 +================== + + * add conditional pango font support [Julian Viereck] + * add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods + * add support for grayscale JPEGs + * fix: explicitly cast the after work callback function to "uv_after_work_cb" + * fix test server for express 3.x + * fix: call cairo_surface_finish in ~Canvas when pdf + * remove old 0.4.x binding support. Closes #197 + +0.13.1 / 2012-08-20 +================== + + * fix cases where GIF_LIB_VERSION is not defined + * fix auto-detection of optional libraries for OS X + * fix Context2d::SetFont for pango when setting normal weight/style + +0.13.0 / 2012-08-12 +================== + + * add pango support [c-spencer] + * add pango / png / jpeg gyp auto-detection [c-spencer] + * add `.gifVersion` [tootallnate] + * add `.jpegVersion` [tootallnate] + * add moar gyp stuff [tootallnate] + * remove wscript + * fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()` + +0.12.1 / 2012-06-29 +================== + + * fix jpeg malloc Image issue. Closes #160 [c-spencer] + * Improve Image mode API + * Add clearData method to handle reassignment of src, and clean up mime data memory handling. + * Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional. + * Add optional mime-data tracking to Image. + * Refactor JPEG decoding into decodeJPEGIntoSurface + +0.12.0 / 2012-05-02 +================== + + * Added `textDrawingMode` context property [c-spencer] + * Added additional TextMetrics properties [c-spencer] + +0.11.3 / 2012-04-25 +================== + + * Fixed `Image` memory leak. Closes #150 + * Fixed Context2d::hasShadow() + +0.11.2 / 2012-04-12 +================== + + * Fixed: pdf memory leak, free closure and surface in ~Canvas + +0.11.1 / 2012-04-10 +================== + + * Changed: renamed .nextPage() to .addPage() + +0.11.0 / 2012-04-10 +================== + + * Added quick PDF support + * Added `Canvas#type` getter + * Added ./examples/pdf-images.js + * Added ./examples/multiple-page-pdf.js + * Added ./examples/small-pdf.js + +0.10.3 / 2012-02-27 +================== + + * Fixed quadratic curve starting point for undefined path. Closes #155 + +0.10.2 / 2012-02-06 +================== + + * Fixed: Context2d setters with invalid values ignored + * Changed: replaced seek with `fstat()` + +0.10.1 / 2012-01-31 +================== + + * Added _/opt/local/lib_ to wscript [obarthel] + * Added bounds checking to `rgba_to_string()` [obarthel] + * Fixed cleanup in JPEG Image loading [obarthel] + * Fixed missing CSS color table values [obarthel] + +0.10.0 / 2012-01-18 +================== + + * Added `ctx.createPattern()` [slaskis] + +0.9.0 / 2012-01-13 +================== + + * Added `createJPEGStream()` [Elijah Hamovitz] + +0.8.3 / 2012-01-04 +================== + + * Added support for libjpeg62-dev or libjpeg8-dev [wwlinx] + +0.8.2 / 2011-12-14 +================== + + * Fixed two memory leaks in context2d [Tharit] + * Fixed `make test-server` + +0.8.1 / 2011-10-31 +================== + + * Added 0.5.x support [TooTallNate] + * Fixed `measureText().width`. Closes #126 + +0.8.0 / 2011-10-28 +================== + + * Added data uri support. Closes #49 + +0.7.3 / 2011-09-14 +================== + + * Added better lineTo() / moveTo() exception messages + +0.7.2 / 2011-08-30 +================== + + * Changed: prefix some private methods with _ + +0.7.1 / 2011-08-25 +================== + + * Added better image format detection + * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD + +0.7.0 / 2011-07-12 +================== + + * Added GIF support [Brian McKinney] + +0.6.0 / 2011-06-04 +================== + + * Added `Image#src=Buffer` support. Closes #91 + * Added `devDependencies` + * Added `source-atop` test + * Added _image-src.js_ example + * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()` + * Fixed v8 memory hint when resizing canvas [atomizer] + +0.5.4 / 2011-04-20 +================== + + * Added; special case of zero-width rectangle [atomizer] + * Fixed; do not clamp arguments to integer values [atomizer] + * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer] + * Fixed; `restorePath()`: clear current path before appending [atomizer] + +0.5.3 / 2011-04-11 +================== + + * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte] + +0.5.2 / 2011-04-09 +================== + + * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte] + +0.5.1 / 2011-03-16 +================== + + * Fixed (kinda) `img.src=` error handling + * Fixed; move closure.h down for malloc ref. Closes #80 + +0.5.0 / 2011-03-14 +================== + + * Added several more operators (color-dodge, color-burn, difference, etc) + * Performance; no longer re-allocating `closure->data` for each png write + * Fixed freeing of `Context2d` states + * Fixed text alignment / baseline [Olaf] + * Fixed HandleScopes [Olaf] + * Fixed small misc memory leaks + * Fixed `Buffer` usage for node 0.4.x + +0.4.3 / 2011-01-11 +================== + + * Fixed font family dereferencing. Closes #72 + * Fixed; stripping of quotes from font-family before applying + * Fixed duplicate textAlign getter + * Removed sans-serif default of _Arial_ + +0.4.2 / 2010-12-28 +================== + + * Fixed font size growing issue after successive calls. Closes #70 + +0.4.1 / 2010-12-18 +================== + + * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68 + +0.4.0 / 2010-12-12 +================== + + * Added `drawImage()` with `Canvas` instance support. Closes #67 + +0.3.3 / 2010-11-30 +================== + + * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_ + * Fixed; pre-multiply `putImageData()` components + * Fixed; `PixelArray` data is not premultiplied + +0.3.2 / 2010-11-26 +================== + + * Added --profile option to config + * Fixed `eio_custom` segfault(s). Closes #46 + * Fixed two named colors. Closes #62 [thanks noonat] + * Fixed a few warnings + * Fixed; freeing data in `Image::loadJPEG()` on failure + * Fixed; include _jpeglib_ only when __HAVE_JPEG__ + * Fixed; using `strstr()` instead of `strnstr()` + +0.3.1 / 2010-11-24 +================== + + * Fixed; `Image` loading is sync until race-condition is resolved + * Fixed; `Image::loadJPEG()` return status based on errno + +0.3.0 / 2010-11-24 +================== + + * Added arcTo(). Closes #11 + * Added c color parser, _./examples/ray.js_ is now twice as fast + * Fixed `putImageData()` bug messing up rgba channels + +0.2.1 / 2010-11-19 +================== + + * Added image _resize_ example + * Fixed canvas resizing via `{width,height}=`. Closes #57 + * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext + * Fixed async image loading (test server still messed) + +0.2.0 / 2010-11-18 +================== + + * Added jpeg `Image` support (when libjpeg is available) + * Added _hsl_ / _hsla_ color support. [Tom Carden] + +0.1.0 / 2010-11-17 +================== + + * Added `Image` + * Added `ImageData` + * Added `PixelArray` + * Added `CanvasRenderingContext2d#drawImage()` + * Added `CanvasRenderingContext2d#getImageData()` + * Added `CanvasRenderingContext2d#createImageData()` + * Added kraken blur benchmark example + * Added several new tests + * Fixed instanceof checks for many c++ methods + * Fixed test runner in firefox [Don Park] + +0.0.8 / 2010-11-12 +================== + + * Added `CanvasRenderingContext2d#drawImage()` + * Fixed `free()` call missing stdlib + * Fixed Image#{width,height} initialization to 0 + * Fixed; load image on non-LOADING state + +0.0.7 / 2010-11-12 +================== + + * Fixed _lighter_ for older versions of cairo + +0.0.6 / 2010-11-12 +================== + + * Added `Image` + * Added conditional support for cairo 1.10.0 operators + +0.0.5 / 2010-11-10 +================== + + * Added custom port support to _test/server.js_ + * Added more global composite operator support + * Added `Context2d#antialias=` + * Added _voronoi_ example + * Added -D__NDEBUG__ to default build + * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park] + * Fixed getter bug preventing patterns from being returned via `fillStyle` etc + + * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc() + * Fixed; free `Canvas::ToBuffer()` closure data + +0.0.4 / 2010-11-09 +================== + + * Bump to fix npm engine cache bug... + +0.0.3 / 2010-11-09 +================== + + * Added async `toDataURL()` support + * Added async `toBuffer()` support + * Removed buffer utils + +0.0.2 / 2010-11-08 +================== + + * Added shadow support (faster/better gaussian blur to come) + * Added node v0.3 support [Don Park] + * Added -O3 to build + * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()` + +0.0.1 / 2010-11-04 +================== + + * Initial release diff --git a/scripts/external/three/canvas/Makefile b/scripts/external/three/canvas/Makefile new file mode 100644 index 0000000..165474e --- /dev/null +++ b/scripts/external/three/canvas/Makefile @@ -0,0 +1,24 @@ + +ADDON = build/Release/canvas.node +REPORTER = dot + +$(ADDON): src/*.cc + npm install + +test: $(ADDON) + @./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + --ui exports \ + --require should \ + test/*.test.js + +test-server: $(ADDON) + @node test/server.js + +benchmark: + @node benchmarks/run.js + +clean: + rm -fr build + +.PHONY: test test-server benchmark clean diff --git a/scripts/external/three/canvas/Readme.md b/scripts/external/three/canvas/Readme.md new file mode 100644 index 0000000..28e694f --- /dev/null +++ b/scripts/external/three/canvas/Readme.md @@ -0,0 +1,336 @@ +node-canvas +=========== +### Canvas graphics API backed by Cairo +[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas) +[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas) + + node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org). + +## Authors + + - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia)) + - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate)) + - Rod Vagg ([rvagg](http://github.com/rvagg)) + - Juriy Zaytsev ([kangax](http://github.com/kangax)) + +## Installation + +```bash +$ npm install canvas +``` + +Unless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/LearnBoost/node-canvas/wiki/_pages). + +You can quickly install Cairo and its dependencies for OS X using the one liner below: + +```bash +$ wget https://raw.githubusercontent.com/LearnBoost/node-canvas/master/install -O - | sh +``` + +or if you use MacPorts + +```bash +sudo port install pkgconfig libpng giflib freetype libpixman cairo +``` + +## Screencasts + + - [Introduction](http://screenr.com/CTk) + +## Example + +```javascript +var Canvas = require('canvas') + , Image = Canvas.Image + , canvas = new Canvas(200,200) + , ctx = canvas.getContext('2d'); + +ctx.font = '30px Impact'; +ctx.rotate(.1); +ctx.fillText("Awesome!", 50, 100); + +var te = ctx.measureText('Awesome!'); +ctx.strokeStyle = 'rgba(0,0,0,0.5)'; +ctx.beginPath(); +ctx.lineTo(50, 102); +ctx.lineTo(50 + te.width, 102); +ctx.stroke(); + +console.log(''); +``` + +## Non-Standard API + + node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers. + +### Image#src=Buffer + + node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O. + +```javascript +fs.readFile(__dirname + '/images/squid.png', function(err, squid){ + if (err) throw err; + img = new Image; + img.src = squid; + ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4); +}); +``` + + Below is an example of a canvas drawing it-self as the source several time: + +```javascript +var img = new Image; +img.src = canvas.toBuffer(); +ctx.drawImage(img, 0, 0, 50, 50); +ctx.drawImage(img, 50, 0, 50, 50); +ctx.drawImage(img, 100, 0, 50, 50); +``` + +### Image#dataMode + +node-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs). + +When mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering. + +```javascript +var img = new Image; +img.dataMode = Image.MODE_IMAGE; // Only image data tracked +img.dataMode = Image.MODE_MIME; // Only mime data tracked +img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked +``` + +If image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF. + +### Canvas#pngStream() + + To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted. + +```javascript +var fs = require('fs') + , out = fs.createWriteStream(__dirname + '/text.png') + , stream = canvas.pngStream(); + +stream.on('data', function(chunk){ + out.write(chunk); +}); + +stream.on('end', function(){ + console.log('saved png'); +}); +``` + +Currently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`. + +### Canvas#jpegStream() and Canvas#syncJPEGStream() + +You can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with +some optional parameters; functionality is otherwise identical to +`pngStream()`. See `examples/crop.js` for an example. + +_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both +are synchronous_ + +```javascript +var stream = canvas.jpegStream({ + bufsize: 4096 // output buffer size in bytes, default: 4096 + , quality: 75 // JPEG quality (0-100) default: 75 + , progressive: false // true for progressive compression, default: false +}); +``` + +### Canvas#toBuffer() + +A call to `Canvas#toBuffer()` will return a node `Buffer` instance containing all of the PNG data. + +```javascript +canvas.toBuffer(); +``` + +### Canvas#toBuffer() async + +Optionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`. + +```javascript +canvas.toBuffer(function(err, buf){ + +}); +``` + +### Canvas#toDataURL() async + +Optionally we may pass a callback function to `Canvas#toDataURL()`, and this process will be performed asynchronously, and will `callback(err, str)`. + +```javascript +canvas.toDataURL(function(err, str){ + +}); +``` + +or specify the mime type: + +```javascript +canvas.toDataURL('image/png', function(err, str){ + +}); +``` + +### CanvasRenderingContext2d#patternQuality + +Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_. + + - fast + - good + - best + - nearest + - bilinear + +### CanvasRenderingContext2d#textDrawingMode + +Can be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill. + +Defaults to _path_. + +This property is tracked as part of the canvas state in save/restore. + +### CanvasRenderingContext2d#filter + +Like `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_. + + - fast + - good + - best + - nearest + - bilinear + +### Global Composite Operations + +In addition to those specified and commonly implemented by browsers, the following have been added: + + - multiply + - screen + - overlay + - hard-light + - soft-light + - hsl-hue + - hsl-saturation + - hsl-color + - hsl-luminosity + +## Anti-Aliasing + + Set anti-aliasing mode + + - default + - none + - gray + - subpixel + + For example: + +```javascript +ctx.antialias = 'none'; +``` + +## PDF Support + + Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating + a PDF on initialization, using the "pdf" string: + +```js +var canvas = new Canvas(200, 500, 'pdf'); +``` + + An additional method `.addPage()` is then available to create + multiple page PDFs: + +```js +ctx.font = '22px Helvetica'; +ctx.fillText('Hello World', 50, 80); +ctx.addPage(); + +ctx.font = '22px Helvetica'; +ctx.fillText('Hello World 2', 50, 80); +ctx.addPage(); + +ctx.font = '22px Helvetica'; +ctx.fillText('Hello World 3', 50, 80); +ctx.addPage(); +``` + +## SVG support + + Just like PDF support, make sure to install cairo with `--enable-svg=yes`. + You also need to tell node-canvas that it is working on SVG upon its initialization: + +```js +var canvas = new Canvas(200, 500, 'svg'); +// Use the normal primitives. +fs.writeFile('out.svg', canvas.toBuffer()); +``` + +## Benchmarks + + Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself. + +## Contribute + + Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/LearnBoost/node-canvas/issues) for existing issues. + +## Examples + + Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser. + +## Testing + +If you have not previously, init git submodules: + + $ git submodule update --init + +Build node-canvas: + + $ node-gyp rebuild + +Unit tests: + + $ make test + +Visual tests: + + $ make test-server + +## Versions + +Tested with and designed for: + + - node 0.4.2 + - cairo 1.8.6 + +For node 0.2.x `node-canvas` <= 0.4.3 may be used, +0.5.0 and above are designed for node 0.4.x only. + +## License + +(The MIT License) + +Copyright (c) 2010 LearnBoost, and contributors <dev@learnboost.com> + +Copyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/scripts/external/three/canvas/binding.gyp b/scripts/external/three/canvas/binding.gyp new file mode 100755 index 0000000..afb7323 --- /dev/null +++ b/scripts/external/three/canvas/binding.gyp @@ -0,0 +1,172 @@ +{ + 'conditions': [ + ['OS=="win"', { + 'variables': { + 'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle + 'with_jpeg%': 'false', + 'with_gif%': 'false', + 'with_pango%': 'false', + 'with_freetype%': 'false' + } + }, { # 'OS!="win"' + 'variables': { + 'with_jpeg%': '> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") + +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) + +# We support two kinds of shared objects (.so): +# 1) shared_library, which is just bundling together many dependent libraries +# into a link line. +# 2) loadable_module, which is generating a module intended for dlopen(). +# +# They differ only slightly: +# In the former case, we want to package all dependent code into the .so. +# In the latter case, we want to package just the API exposed by the +# outermost module. +# This means shared_library uses --whole-archive, while loadable_module doesn't. +# (Note that --whole-archive is incompatible with the --start-group used in +# normal linking.) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 1,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,canvas-postbuild.target.mk)))),) + include canvas-postbuild.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,canvas.target.mk)))),) + include canvas.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/root/dev/elation/components/vrcade/node_modules/canvas/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dmodule_root_dir=/root/dev/elation/components/vrcade/node_modules/canvas" binding.gyp +Makefile: $(srcdir)/../../../../../../../usr/share/node-gyp/addon.gypi $(srcdir)/../../../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d new file mode 100644 index 0000000..70941d7 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d @@ -0,0 +1 @@ +cmd_Release/canvas-postbuild.node := ln -f "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node" 2>/dev/null || (rm -rf "Release/canvas-postbuild.node" && cp -af "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node") diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d new file mode 100644 index 0000000..d2e1ae3 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d @@ -0,0 +1 @@ +cmd_Release/canvas.node := ln -f "Release/obj.target/canvas.node" "Release/canvas.node" 2>/dev/null || (rm -rf "Release/canvas.node" && cp -af "Release/obj.target/canvas.node" "Release/canvas.node") diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d new file mode 100644 index 0000000..5b77407 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d @@ -0,0 +1 @@ +cmd_Release/obj.target/canvas-postbuild.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas-postbuild.node -o Release/obj.target/canvas-postbuild.node -Wl,--start-group -Wl,--end-group diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d new file mode 100644 index 0000000..e233682 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d @@ -0,0 +1 @@ +cmd_Release/obj.target/canvas.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas.node -o Release/obj.target/canvas.node -Wl,--start-group Release/obj.target/canvas/src/Canvas.o Release/obj.target/canvas/src/CanvasGradient.o Release/obj.target/canvas/src/CanvasPattern.o Release/obj.target/canvas/src/CanvasRenderingContext2d.o Release/obj.target/canvas/src/color.o Release/obj.target/canvas/src/Image.o Release/obj.target/canvas/src/ImageData.o Release/obj.target/canvas/src/init.o Release/obj.target/canvas/src/PixelArray.o Release/obj.target/canvas/src/FontFace.o -Wl,--end-group -lpixman-1 -lcairo -lpng12 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -ljpeg -lgif diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d new file mode 100644 index 0000000..b6763b1 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d @@ -0,0 +1,299 @@ +cmd_Release/obj.target/canvas/src/Canvas.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Canvas.o.d.raw -c -o Release/obj.target/canvas/src/Canvas.o ../src/Canvas.cc +Release/obj.target/canvas/src/Canvas.o: ../src/Canvas.cc ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/PNG.h \ + /usr/include/libpng12/png.h /usr/include/libpng12/pngconf.h \ + /usr/include/libpng12/pngconf.h ../src/closure.h \ + ../src/CanvasRenderingContext2d.h ../src/color.h ../src/CanvasGradient.h \ + /usr/include/freetype2/ft2build.h \ + /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ + /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ + /usr/include/freetype2/config/ftconfig.h \ + /usr/include/freetype2/config/ftoption.h \ + /usr/include/freetype2/config/ftstdlib.h \ + /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ + /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ + /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ + ../src/JPEGStream.h +../src/Canvas.cc: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/PNG.h: +/usr/include/libpng12/png.h: +/usr/include/libpng12/pngconf.h: +/usr/include/libpng12/pngconf.h: +../src/closure.h: +../src/CanvasRenderingContext2d.h: +../src/color.h: +../src/CanvasGradient.h: +/usr/include/freetype2/ft2build.h: +/usr/include/freetype2/config/ftheader.h: +/usr/include/cairo/cairo-ft.h: +/usr/include/cairo/cairo.h: +/usr/include/freetype2/freetype.h: +/usr/include/freetype2/config/ftconfig.h: +/usr/include/freetype2/config/ftoption.h: +/usr/include/freetype2/config/ftstdlib.h: +/usr/include/freetype2/fttypes.h: +/usr/include/freetype2/ftsystem.h: +/usr/include/freetype2/ftimage.h: +/usr/include/freetype2/fterrors.h: +/usr/include/freetype2/ftmoderr.h: +/usr/include/freetype2/fterrdef.h: +../src/JPEGStream.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d new file mode 100644 index 0000000..0728fe6 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d @@ -0,0 +1,266 @@ +cmd_Release/obj.target/canvas/src/CanvasGradient.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d.raw -c -o Release/obj.target/canvas/src/CanvasGradient.o ../src/CanvasGradient.cc +Release/obj.target/canvas/src/CanvasGradient.o: ../src/CanvasGradient.cc \ + ../src/color.h ../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h \ + ../src/CanvasGradient.h +../src/CanvasGradient.cc: +../src/color.h: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/CanvasGradient.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d new file mode 100644 index 0000000..b0823a7 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d @@ -0,0 +1,266 @@ +cmd_Release/obj.target/canvas/src/CanvasPattern.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d.raw -c -o Release/obj.target/canvas/src/CanvasPattern.o ../src/CanvasPattern.cc +Release/obj.target/canvas/src/CanvasPattern.o: ../src/CanvasPattern.cc \ + ../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h \ + ../src/CanvasPattern.h +../src/CanvasPattern.cc: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/Image.h: +../src/CanvasPattern.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d new file mode 100644 index 0000000..807f274 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d @@ -0,0 +1,299 @@ +cmd_Release/obj.target/canvas/src/CanvasRenderingContext2d.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d.raw -c -o Release/obj.target/canvas/src/CanvasRenderingContext2d.o ../src/CanvasRenderingContext2d.cc +Release/obj.target/canvas/src/CanvasRenderingContext2d.o: \ + ../src/CanvasRenderingContext2d.cc ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Point.h \ + ../src/Image.h ../src/ImageData.h ../src/PixelArray.h \ + ../src/CanvasRenderingContext2d.h ../src/color.h ../src/CanvasGradient.h \ + /usr/include/freetype2/ft2build.h \ + /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ + /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ + /usr/include/freetype2/config/ftconfig.h \ + /usr/include/freetype2/config/ftoption.h \ + /usr/include/freetype2/config/ftstdlib.h \ + /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ + /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ + /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ + ../src/CanvasPattern.h ../src/FontFace.h +../src/CanvasRenderingContext2d.cc: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/Point.h: +../src/Image.h: +../src/ImageData.h: +../src/PixelArray.h: +../src/CanvasRenderingContext2d.h: +../src/color.h: +../src/CanvasGradient.h: +/usr/include/freetype2/ft2build.h: +/usr/include/freetype2/config/ftheader.h: +/usr/include/cairo/cairo-ft.h: +/usr/include/cairo/cairo.h: +/usr/include/freetype2/freetype.h: +/usr/include/freetype2/config/ftconfig.h: +/usr/include/freetype2/config/ftoption.h: +/usr/include/freetype2/config/ftstdlib.h: +/usr/include/freetype2/fttypes.h: +/usr/include/freetype2/ftsystem.h: +/usr/include/freetype2/ftimage.h: +/usr/include/freetype2/fterrors.h: +/usr/include/freetype2/ftmoderr.h: +/usr/include/freetype2/fterrdef.h: +../src/CanvasPattern.h: +../src/FontFace.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d new file mode 100644 index 0000000..b8c9275 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d @@ -0,0 +1,288 @@ +cmd_Release/obj.target/canvas/src/FontFace.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/FontFace.o.d.raw -c -o Release/obj.target/canvas/src/FontFace.o ../src/FontFace.cc +Release/obj.target/canvas/src/FontFace.o: ../src/FontFace.cc \ + ../src/FontFace.h ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h \ + /usr/include/freetype2/ft2build.h \ + /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ + /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ + /usr/include/freetype2/config/ftconfig.h \ + /usr/include/freetype2/config/ftoption.h \ + /usr/include/freetype2/config/ftstdlib.h \ + /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ + /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ + /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h +../src/FontFace.cc: +../src/FontFace.h: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +/usr/include/freetype2/ft2build.h: +/usr/include/freetype2/config/ftheader.h: +/usr/include/cairo/cairo-ft.h: +/usr/include/cairo/cairo.h: +/usr/include/freetype2/freetype.h: +/usr/include/freetype2/config/ftconfig.h: +/usr/include/freetype2/config/ftoption.h: +/usr/include/freetype2/config/ftstdlib.h: +/usr/include/freetype2/fttypes.h: +/usr/include/freetype2/ftsystem.h: +/usr/include/freetype2/ftimage.h: +/usr/include/freetype2/fterrors.h: +/usr/include/freetype2/ftmoderr.h: +/usr/include/freetype2/fterrdef.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d new file mode 100644 index 0000000..9b27358 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d @@ -0,0 +1,264 @@ +cmd_Release/obj.target/canvas/src/Image.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Image.o.d.raw -c -o Release/obj.target/canvas/src/Image.o ../src/Image.cc +Release/obj.target/canvas/src/Image.o: ../src/Image.cc ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h +../src/Image.cc: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/Image.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d new file mode 100644 index 0000000..6d4bc0f --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d @@ -0,0 +1,266 @@ +cmd_Release/obj.target/canvas/src/ImageData.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/ImageData.o.d.raw -c -o Release/obj.target/canvas/src/ImageData.o ../src/ImageData.cc +Release/obj.target/canvas/src/ImageData.o: ../src/ImageData.cc \ + ../src/ImageData.h ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/PixelArray.h +../src/ImageData.cc: +../src/ImageData.h: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/PixelArray.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d new file mode 100644 index 0000000..c6e0713 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d @@ -0,0 +1,265 @@ +cmd_Release/obj.target/canvas/src/PixelArray.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d.raw -c -o Release/obj.target/canvas/src/PixelArray.o ../src/PixelArray.cc +Release/obj.target/canvas/src/PixelArray.o: ../src/PixelArray.cc \ + ../src/PixelArray.h ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h +../src/PixelArray.cc: +../src/PixelArray.h: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d new file mode 100644 index 0000000..932f09d --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d @@ -0,0 +1,4 @@ +cmd_Release/obj.target/canvas/src/color.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/color.o.d.raw -c -o Release/obj.target/canvas/src/color.o ../src/color.cc +Release/obj.target/canvas/src/color.o: ../src/color.cc ../src/color.h +../src/color.cc: +../src/color.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d new file mode 100644 index 0000000..3c6fca7 --- /dev/null +++ b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d @@ -0,0 +1,297 @@ +cmd_Release/obj.target/canvas/src/init.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/init.o.d.raw -c -o Release/obj.target/canvas/src/init.o ../src/init.cc +Release/obj.target/canvas/src/init.o: ../src/init.cc ../src/Canvas.h \ + /usr/include/nodejs/deps/v8/include/v8.h \ + /usr/include/nodejs/deps/v8/include/v8stdint.h \ + /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ + /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ + /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node.h \ + /usr/include/nodejs/src/node_object_wrap.h \ + /usr/include/nodejs/src/node_version.h \ + /usr/include/pango-1.0/pango/pangocairo.h \ + /usr/include/pango-1.0/pango/pango.h \ + /usr/include/pango-1.0/pango/pango-attributes.h \ + /usr/include/pango-1.0/pango/pango-font.h \ + /usr/include/pango-1.0/pango/pango-coverage.h \ + /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ + /usr/include/glib-2.0/glib/gtypes.h \ + /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ + /usr/include/glib-2.0/glib/gmacros.h \ + /usr/include/glib-2.0/glib/gversionmacros.h \ + /usr/include/glib-2.0/glib/garray.h \ + /usr/include/glib-2.0/glib/gasyncqueue.h \ + /usr/include/glib-2.0/glib/gthread.h \ + /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ + /usr/include/glib-2.0/glib/gquark.h \ + /usr/include/glib-2.0/glib/gbacktrace.h \ + /usr/include/glib-2.0/glib/gbase64.h \ + /usr/include/glib-2.0/glib/gbitlock.h \ + /usr/include/glib-2.0/glib/gbookmarkfile.h \ + /usr/include/glib-2.0/glib/gbytes.h \ + /usr/include/glib-2.0/glib/gcharset.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/gconvert.h \ + /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ + /usr/include/glib-2.0/glib/gdatetime.h \ + /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ + /usr/include/glib-2.0/glib/genviron.h \ + /usr/include/glib-2.0/glib/gfileutils.h \ + /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ + /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ + /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ + /usr/include/glib-2.0/glib/gchecksum.h \ + /usr/include/glib-2.0/glib/ghook.h \ + /usr/include/glib-2.0/glib/ghostutils.h \ + /usr/include/glib-2.0/glib/giochannel.h \ + /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ + /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ + /usr/include/glib-2.0/glib/gunicode.h \ + /usr/include/glib-2.0/glib/gutils.h \ + /usr/include/glib-2.0/glib/gkeyfile.h \ + /usr/include/glib-2.0/glib/gmappedfile.h \ + /usr/include/glib-2.0/glib/gmarkup.h \ + /usr/include/glib-2.0/glib/gmessages.h \ + /usr/include/glib-2.0/glib/goption.h \ + /usr/include/glib-2.0/glib/gpattern.h \ + /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ + /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ + /usr/include/glib-2.0/glib/gregex.h \ + /usr/include/glib-2.0/glib/gscanner.h \ + /usr/include/glib-2.0/glib/gsequence.h \ + /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ + /usr/include/glib-2.0/glib/gspawn.h \ + /usr/include/glib-2.0/glib/gstrfuncs.h \ + /usr/include/glib-2.0/glib/gstringchunk.h \ + /usr/include/glib-2.0/glib/gtestutils.h \ + /usr/include/glib-2.0/glib/gthreadpool.h \ + /usr/include/glib-2.0/glib/gtimer.h \ + /usr/include/glib-2.0/glib/gtrashstack.h \ + /usr/include/glib-2.0/glib/gtree.h \ + /usr/include/glib-2.0/glib/gurifuncs.h \ + /usr/include/glib-2.0/glib/gvarianttype.h \ + /usr/include/glib-2.0/glib/gvariant.h \ + /usr/include/glib-2.0/glib/gversion.h \ + /usr/include/glib-2.0/glib/deprecated/gallocator.h \ + /usr/include/glib-2.0/glib/deprecated/gcache.h \ + /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ + /usr/include/glib-2.0/glib/deprecated/gmain.h \ + /usr/include/glib-2.0/glib/deprecated/grel.h \ + /usr/include/glib-2.0/glib/deprecated/gthread.h \ + /usr/include/pango-1.0/pango/pango-types.h \ + /usr/include/glib-2.0/glib-object.h \ + /usr/include/glib-2.0/gobject/gbinding.h \ + /usr/include/glib-2.0/gobject/gobject.h \ + /usr/include/glib-2.0/gobject/gtype.h \ + /usr/include/glib-2.0/gobject/gvalue.h \ + /usr/include/glib-2.0/gobject/gparam.h \ + /usr/include/glib-2.0/gobject/gclosure.h \ + /usr/include/glib-2.0/gobject/gsignal.h \ + /usr/include/glib-2.0/gobject/gmarshal.h \ + /usr/include/glib-2.0/gobject/gboxed.h \ + /usr/include/glib-2.0/gobject/glib-types.h \ + /usr/include/glib-2.0/gobject/genums.h \ + /usr/include/glib-2.0/gobject/gparamspecs.h \ + /usr/include/glib-2.0/gobject/gsourceclosure.h \ + /usr/include/glib-2.0/gobject/gtypemodule.h \ + /usr/include/glib-2.0/gobject/gtypeplugin.h \ + /usr/include/glib-2.0/gobject/gvaluearray.h \ + /usr/include/glib-2.0/gobject/gvaluetypes.h \ + /usr/include/pango-1.0/pango/pango-gravity.h \ + /usr/include/pango-1.0/pango/pango-matrix.h \ + /usr/include/pango-1.0/pango/pango-script.h \ + /usr/include/pango-1.0/pango/pango-language.h \ + /usr/include/pango-1.0/pango/pango-bidi-type.h \ + /usr/include/pango-1.0/pango/pango-break.h \ + /usr/include/pango-1.0/pango/pango-item.h \ + /usr/include/pango-1.0/pango/pango-context.h \ + /usr/include/pango-1.0/pango/pango-fontmap.h \ + /usr/include/pango-1.0/pango/pango-fontset.h \ + /usr/include/pango-1.0/pango/pango-engine.h \ + /usr/include/pango-1.0/pango/pango-glyph.h \ + /usr/include/pango-1.0/pango/pango-enum-types.h \ + /usr/include/pango-1.0/pango/pango-features.h \ + /usr/include/pango-1.0/pango/pango-glyph-item.h \ + /usr/include/pango-1.0/pango/pango-layout.h \ + /usr/include/pango-1.0/pango/pango-tabs.h \ + /usr/include/pango-1.0/pango/pango-renderer.h \ + /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ + /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ + /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ + /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ + ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h \ + ../src/ImageData.h ../src/PixelArray.h ../src/CanvasGradient.h \ + ../src/CanvasPattern.h ../src/CanvasRenderingContext2d.h ../src/color.h \ + /usr/include/freetype2/ft2build.h \ + /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ + /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ + /usr/include/freetype2/config/ftconfig.h \ + /usr/include/freetype2/config/ftoption.h \ + /usr/include/freetype2/config/ftstdlib.h \ + /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ + /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ + /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ + ../src/FontFace.h +../src/init.cc: +../src/Canvas.h: +/usr/include/nodejs/deps/v8/include/v8.h: +/usr/include/nodejs/deps/v8/include/v8stdint.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/deps/uv/include/uv.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: +/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: +/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node.h: +/usr/include/nodejs/src/node_object_wrap.h: +/usr/include/nodejs/src/node_version.h: +/usr/include/pango-1.0/pango/pangocairo.h: +/usr/include/pango-1.0/pango/pango.h: +/usr/include/pango-1.0/pango/pango-attributes.h: +/usr/include/pango-1.0/pango/pango-font.h: +/usr/include/pango-1.0/pango/pango-coverage.h: +/usr/include/glib-2.0/glib.h: +/usr/include/glib-2.0/glib/galloca.h: +/usr/include/glib-2.0/glib/gtypes.h: +/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: +/usr/include/glib-2.0/glib/gmacros.h: +/usr/include/glib-2.0/glib/gversionmacros.h: +/usr/include/glib-2.0/glib/garray.h: +/usr/include/glib-2.0/glib/gasyncqueue.h: +/usr/include/glib-2.0/glib/gthread.h: +/usr/include/glib-2.0/glib/gatomic.h: +/usr/include/glib-2.0/glib/gerror.h: +/usr/include/glib-2.0/glib/gquark.h: +/usr/include/glib-2.0/glib/gbacktrace.h: +/usr/include/glib-2.0/glib/gbase64.h: +/usr/include/glib-2.0/glib/gbitlock.h: +/usr/include/glib-2.0/glib/gbookmarkfile.h: +/usr/include/glib-2.0/glib/gbytes.h: +/usr/include/glib-2.0/glib/gcharset.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/gconvert.h: +/usr/include/glib-2.0/glib/gdataset.h: +/usr/include/glib-2.0/glib/gdate.h: +/usr/include/glib-2.0/glib/gdatetime.h: +/usr/include/glib-2.0/glib/gtimezone.h: +/usr/include/glib-2.0/glib/gdir.h: +/usr/include/glib-2.0/glib/genviron.h: +/usr/include/glib-2.0/glib/gfileutils.h: +/usr/include/glib-2.0/glib/ggettext.h: +/usr/include/glib-2.0/glib/ghash.h: +/usr/include/glib-2.0/glib/glist.h: +/usr/include/glib-2.0/glib/gmem.h: +/usr/include/glib-2.0/glib/gnode.h: +/usr/include/glib-2.0/glib/ghmac.h: +/usr/include/glib-2.0/glib/gchecksum.h: +/usr/include/glib-2.0/glib/ghook.h: +/usr/include/glib-2.0/glib/ghostutils.h: +/usr/include/glib-2.0/glib/giochannel.h: +/usr/include/glib-2.0/glib/gmain.h: +/usr/include/glib-2.0/glib/gpoll.h: +/usr/include/glib-2.0/glib/gslist.h: +/usr/include/glib-2.0/glib/gstring.h: +/usr/include/glib-2.0/glib/gunicode.h: +/usr/include/glib-2.0/glib/gutils.h: +/usr/include/glib-2.0/glib/gkeyfile.h: +/usr/include/glib-2.0/glib/gmappedfile.h: +/usr/include/glib-2.0/glib/gmarkup.h: +/usr/include/glib-2.0/glib/gmessages.h: +/usr/include/glib-2.0/glib/goption.h: +/usr/include/glib-2.0/glib/gpattern.h: +/usr/include/glib-2.0/glib/gprimes.h: +/usr/include/glib-2.0/glib/gqsort.h: +/usr/include/glib-2.0/glib/gqueue.h: +/usr/include/glib-2.0/glib/grand.h: +/usr/include/glib-2.0/glib/gregex.h: +/usr/include/glib-2.0/glib/gscanner.h: +/usr/include/glib-2.0/glib/gsequence.h: +/usr/include/glib-2.0/glib/gshell.h: +/usr/include/glib-2.0/glib/gslice.h: +/usr/include/glib-2.0/glib/gspawn.h: +/usr/include/glib-2.0/glib/gstrfuncs.h: +/usr/include/glib-2.0/glib/gstringchunk.h: +/usr/include/glib-2.0/glib/gtestutils.h: +/usr/include/glib-2.0/glib/gthreadpool.h: +/usr/include/glib-2.0/glib/gtimer.h: +/usr/include/glib-2.0/glib/gtrashstack.h: +/usr/include/glib-2.0/glib/gtree.h: +/usr/include/glib-2.0/glib/gurifuncs.h: +/usr/include/glib-2.0/glib/gvarianttype.h: +/usr/include/glib-2.0/glib/gvariant.h: +/usr/include/glib-2.0/glib/gversion.h: +/usr/include/glib-2.0/glib/deprecated/gallocator.h: +/usr/include/glib-2.0/glib/deprecated/gcache.h: +/usr/include/glib-2.0/glib/deprecated/gcompletion.h: +/usr/include/glib-2.0/glib/deprecated/gmain.h: +/usr/include/glib-2.0/glib/deprecated/grel.h: +/usr/include/glib-2.0/glib/deprecated/gthread.h: +/usr/include/pango-1.0/pango/pango-types.h: +/usr/include/glib-2.0/glib-object.h: +/usr/include/glib-2.0/gobject/gbinding.h: +/usr/include/glib-2.0/gobject/gobject.h: +/usr/include/glib-2.0/gobject/gtype.h: +/usr/include/glib-2.0/gobject/gvalue.h: +/usr/include/glib-2.0/gobject/gparam.h: +/usr/include/glib-2.0/gobject/gclosure.h: +/usr/include/glib-2.0/gobject/gsignal.h: +/usr/include/glib-2.0/gobject/gmarshal.h: +/usr/include/glib-2.0/gobject/gboxed.h: +/usr/include/glib-2.0/gobject/glib-types.h: +/usr/include/glib-2.0/gobject/genums.h: +/usr/include/glib-2.0/gobject/gparamspecs.h: +/usr/include/glib-2.0/gobject/gsourceclosure.h: +/usr/include/glib-2.0/gobject/gtypemodule.h: +/usr/include/glib-2.0/gobject/gtypeplugin.h: +/usr/include/glib-2.0/gobject/gvaluearray.h: +/usr/include/glib-2.0/gobject/gvaluetypes.h: +/usr/include/pango-1.0/pango/pango-gravity.h: +/usr/include/pango-1.0/pango/pango-matrix.h: +/usr/include/pango-1.0/pango/pango-script.h: +/usr/include/pango-1.0/pango/pango-language.h: +/usr/include/pango-1.0/pango/pango-bidi-type.h: +/usr/include/pango-1.0/pango/pango-break.h: +/usr/include/pango-1.0/pango/pango-item.h: +/usr/include/pango-1.0/pango/pango-context.h: +/usr/include/pango-1.0/pango/pango-fontmap.h: +/usr/include/pango-1.0/pango/pango-fontset.h: +/usr/include/pango-1.0/pango/pango-engine.h: +/usr/include/pango-1.0/pango/pango-glyph.h: +/usr/include/pango-1.0/pango/pango-enum-types.h: +/usr/include/pango-1.0/pango/pango-features.h: +/usr/include/pango-1.0/pango/pango-glyph-item.h: +/usr/include/pango-1.0/pango/pango-layout.h: +/usr/include/pango-1.0/pango/pango-tabs.h: +/usr/include/pango-1.0/pango/pango-renderer.h: +/usr/include/pango-1.0/pango/pango-utils.h: +/usr/include/cairo/cairo.h: +/usr/include/cairo/cairo-version.h: +/usr/include/cairo/cairo-features.h: +/usr/include/cairo/cairo-deprecated.h: +../node_modules/nan/nan.h: +/usr/include/nodejs/src/node_buffer.h: +../node_modules/nan/nan_new.h: +../node_modules/nan/nan_implementation_pre_12_inl.h: +../src/Image.h: +../src/ImageData.h: +../src/PixelArray.h: +../src/CanvasGradient.h: +../src/CanvasPattern.h: +../src/CanvasRenderingContext2d.h: +../src/color.h: +/usr/include/freetype2/ft2build.h: +/usr/include/freetype2/config/ftheader.h: +/usr/include/cairo/cairo-ft.h: +/usr/include/cairo/cairo.h: +/usr/include/freetype2/freetype.h: +/usr/include/freetype2/config/ftconfig.h: +/usr/include/freetype2/config/ftoption.h: +/usr/include/freetype2/config/ftstdlib.h: +/usr/include/freetype2/fttypes.h: +/usr/include/freetype2/ftsystem.h: +/usr/include/freetype2/ftimage.h: +/usr/include/freetype2/fterrors.h: +/usr/include/freetype2/ftmoderr.h: +/usr/include/freetype2/fterrdef.h: +../src/FontFace.h: diff --git a/scripts/external/three/canvas/build/Release/canvas-postbuild.node b/scripts/external/three/canvas/build/Release/canvas-postbuild.node new file mode 100755 index 0000000000000000000000000000000000000000..d826d22576e464358a537f4e48a94eaaa22eb693 GIT binary patch literal 7470 zcmeHMU2IfE6rOflEG@JJL<^F1qku)jwIFISskYRX3$_qT8ziy0x!t|}G5b^Y-o@6C zKvIkl(xjSb#0Ot^@xce4$!~c<11O zQ=e5m%1yBT9(s_+uaBW|K{PDsT;N59DH%z&li7HStDfu z3Q>*kqvJ~7OFUe_wxtNZt_W@y!8!ggJvyZcs23|mbA32RbzI`BM2m)V-d7fg|FE*x z>$y+bSBrUl@LJYzJejau&rW%kC9KiJs3)u;V#3XMc6NhYf^H|dL z2GgUlsF6rU9SWQX^91AjL)DKKH6MVFDZEML3pnIUbzxZ_kMZnOqw?hd&SMQUAHah{ z<$3@QrgR~I2j@|PiigK*u-$L~589iP*Q(5um7O(VVZJu&Rn9+7j^^aKsFB6bw5>5*LaleuRc#@;xd2v>0*--l`>GuKq&*I z43siZ%0MXt|Cj;nGqJCPajhy$DZWf`d`~P_GWOeRl#G4s14_pJbgh!HpXKigCg}h8 zE0bh-hIevA*mKsa%_{be*Ok87Hxs87uTi`~@$4Q~?LV<6ZB}~zCS&6LD%1Tw6XR+V z417jagg9rF9erj3BK?Ip>T zehgWk{PHsB!%G;EWIXO9JUtcvN#^k!{I)4}-hj$gnjs2stcgY)+{6UGn5 zn~w@Qq4CcE;E#C#PNxNuxLvk^KgMSpVO%%-F|WW+lP*ZAx-4W;33W4wc>zAlAdwzF z+UIkJpg-mrIOZk$bL@KjFA>HuVI9Ca1djEEOeE>~-%n`Je@+>IqkZL0XB9qy4{H9| z1xhVcSKz4m0Upu(v2KE6J%PO*e?s}={Vk|=!F7A&5A}^xf!B1rAFR_j&(iI6`55`u z1^ls&x2Qh~-Cmcc$(Qqw_S@9CM%!KbzeT?M?%|Jh4(EoLkH`bs$NPIvYaiz%m$*|z zO+L&1!XNxJX@ct4l80&K`9uio0bMXp+^)wf+%&wQY_>$~?BNxvqfww>R*;Uhs?#73(WUiyjEZy=i+sAo*xcEvK*qxf_WEI zh6If+%%^}NL?^(QCjpq^T$Oi@%=(bPu5Qtq$3ca-!AE8}#QWJYS`qd5c^_NOC+=E4 z4TU#rc)P;&{j>jnvlu7F^l3y=^i%80Iy)>QtM(AE(cSo<)y=z||T}Uk6KUiMeitr7D zD{%1;fGjJTw1#8JK|5wey=2O@?DV*xE$&#%@tmmfkPOc;O{=~nK;j0+*I{zYOF-f_);023+rK4_M__n3s J%}nlX(BIB@EUW+k literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/canvas.node b/scripts/external/three/canvas/build/Release/canvas.node new file mode 100755 index 0000000000000000000000000000000000000000..3f16b28e2a8dcab9530305f576986ef5d1928cc5 GIT binary patch literal 208599 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 #FJ7hR8XJl{oP&th=O!3UHqR#(I)mB`}axR}RN_ IMp&l*AM%-9)Bpeg literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/linker.lock b/scripts/external/three/canvas/build/Release/linker.lock new file mode 100644 index 0000000..e69de29 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node b/scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node new file mode 100755 index 0000000000000000000000000000000000000000..d826d22576e464358a537f4e48a94eaaa22eb693 GIT binary patch literal 7470 zcmeHMU2IfE6rOflEG@JJL<^F1qku)jwIFISskYRX3$_qT8ziy0x!t|}G5b^Y-o@6C zKvIkl(xjSb#0Ot^@xce4$!~c<11O zQ=e5m%1yBT9(s_+uaBW|K{PDsT;N59DH%z&li7HStDfu z3Q>*kqvJ~7OFUe_wxtNZt_W@y!8!ggJvyZcs23|mbA32RbzI`BM2m)V-d7fg|FE*x z>$y+bSBrUl@LJYzJejau&rW%kC9KiJs3)u;V#3XMc6NhYf^H|dL z2GgUlsF6rU9SWQX^91AjL)DKKH6MVFDZEML3pnIUbzxZ_kMZnOqw?hd&SMQUAHah{ z<$3@QrgR~I2j@|PiigK*u-$L~589iP*Q(5um7O(VVZJu&Rn9+7j^^aKsFB6bw5>5*LaleuRc#@;xd2v>0*--l`>GuKq&*I z43siZ%0MXt|Cj;nGqJCPajhy$DZWf`d`~P_GWOeRl#G4s14_pJbgh!HpXKigCg}h8 zE0bh-hIevA*mKsa%_{be*Ok87Hxs87uTi`~@$4Q~?LV<6ZB}~zCS&6LD%1Tw6XR+V z417jagg9rF9erj3BK?Ip>T zehgWk{PHsB!%G;EWIXO9JUtcvN#^k!{I)4}-hj$gnjs2stcgY)+{6UGn5 zn~w@Qq4CcE;E#C#PNxNuxLvk^KgMSpVO%%-F|WW+lP*ZAx-4W;33W4wc>zAlAdwzF z+UIkJpg-mrIOZk$bL@KjFA>HuVI9Ca1djEEOeE>~-%n`Je@+>IqkZL0XB9qy4{H9| z1xhVcSKz4m0Upu(v2KE6J%PO*e?s}={Vk|=!F7A&5A}^xf!B1rAFR_j&(iI6`55`u z1^ls&x2Qh~-Cmcc$(Qqw_S@9CM%!KbzeT?M?%|Jh4(EoLkH`bs$NPIvYaiz%m$*|z zO+L&1!XNxJX@ct4l80&K`9uio0bMXp+^)wf+%&wQY_>$~?BNxvqfww>R*;Uhs?#73(WUiyjEZy=i+sAo*xcEvK*qxf_WEI zh6If+%%^}NL?^(QCjpq^T$Oi@%=(bPu5Qtq$3ca-!AE8}#QWJYS`qd5c^_NOC+=E4 z4TU#rc)P;&{j>jnvlu7F^l3y=^i%80Iy)>QtM(AE(cSo<)y=z||T}Uk6KUiMeitr7D zD{%1;fGjJTw1#8JK|5wey=2O@?DV*xE$&#%@tmmfkPOc;O{=~nK;j0+*I{zYOF-f_);023+rK4_M__n3s J%}nlX(BIB@EUW+k literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas.node b/scripts/external/three/canvas/build/Release/obj.target/canvas.node new file mode 100755 index 0000000000000000000000000000000000000000..3f16b28e2a8dcab9530305f576986ef5d1928cc5 GIT binary patch literal 208599 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 #FJ7hR8XJl{oP&th=O!3UHqR#(I)mB`}axR}RN_ IMp&l*AM%-9)Bpeg literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o new file mode 100644 index 0000000000000000000000000000000000000000..4724529e8e1ba88a177354b2c32b40291a0c3807 GIT binary patch literal 52960 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 J6m~4h{~s4fnT7xW literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o new file mode 100644 index 0000000000000000000000000000000000000000..9537a84e66e034db6757f5e77e44cef75302178c GIT binary patch literal 18256 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 D_6yZQ literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o new file mode 100644 index 0000000000000000000000000000000000000000..f0eecca94a6bc5ab68311ba0d86e4b2d94052b0e GIT binary patch literal 15968 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 GzyAY>hUSL= literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o new file mode 100644 index 0000000000000000000000000000000000000000..0212cebe4b9123bcac452b2ee81c5f846fb18ea2 GIT binary patch literal 135424 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 Neup?bIwZk={ucu&Q!oGk literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o new file mode 100644 index 0000000000000000000000000000000000000000..e47afbcaad80c18045bb39290207be805b7c025d GIT binary patch literal 15536 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 literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o new file mode 100644 index 0000000000000000000000000000000000000000..8ec55dd7a533ebcf11f58a5b751901e2a5f5aa64 GIT binary patch literal 40216 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 literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o new file mode 100644 index 0000000000000000000000000000000000000000..b5952e2fd0a24fbeb1e5c94ebfb60e14cf93b253 GIT binary patch literal 17832 zcmd5@4RBP~b$()nkxj4!(-=~_VG&9U*erSi35gi0Wwp|-S;PiOfDL%PT0NnK)vmJp zB>rMYj!=^AB0>@;bz{$jOxnid+L_jAr>@%}av)GA9gk~|GmPEX)U6Y!J=4~n(xml- zo^$U#yJzpdCs68+dxm}YzVDuU&bjBFd+vMhiq8cjopY+H45BJylTo@O)G)>umFn%H z+HN!&s|7DMVV~bpI>!H^6&8XMW%*N`Fq3p_apg# z?Fmi1(|!p#{Dt0zy2+PnPrL&9!iCQ^)Cf3~KNrfM2^HodPpHr;z+=<3$L<5R(Bx~i z$7<(5CI5zKn4GRXaS;u54<2tNl;0VasTCf{xLQ@-&`}9>HDJFj|3|uwl^O5|!p{Ya4^ogT2 zFcQEcQzJFClatUtlK;=5p-a%Nt6L|p*z*Yv<GEJOq59KfH_V4lU_20MmOzqNka7z2)$E#|OJ&Yp-?*z>&;GoIc z$#;Hz^=hOrGVk&~L1oZayYv|9Ga^&gwE0>j{|hOxa?s~xLtd4W)AoFtA@C%1ygUSM zLjA;jc{!-5T`KQkIxasc??caB`W?L83%8-E1!zKOs#zAo;m>x#jWWim8JT8izH8>@ zPHLv{i+Jq?FTB_j%D)H0fmroQ`Gs3W=%Jq|t|q4+e1L_W?JtEKIDW~ywX512L}wI~ zKUb=rks>F~dgX-SWQ~JhoTJ58epoeH8_K_kzIppE2WyvhAb$5%b9(&n{K?Tj3Kcfb zd;42bf}_idJ{dgufsaQzWpwykVBp6X0m zsewRdG;Oa~>D}aQG?qyYUpN;W95XL6QfNZY!Scu;TU*FpkAjqn3B$Mla}H zy-D#H%fwyQ8qCEcht^9eL}5Fv_yLe3c!e>6czP_JizW|QDStK_KkT&*jlhVk0b?L; z$JJoCVd3HUKC1)U4kiceA!Eo&?i;d=KIhbg$p!W|;aON|j%(3mJfix`P~mem7>YMe zwAWQ#2Fy+TuJW$P39R|IAT#|pq$SuRrs#1J z^n$v#zwFF6MtsiA2dNoKMdkh#6IFZci_j?49h)AFiD5n1HgTzHaylQVvll4WQJ!|( zyCsj9Y-dxFq{6v*Xy)d9)cm2u$92ZzhS|m=1jp{Z!e_$yFveNM{|BN^tuYLX(0O6O z-ZP?bx#aA)olJOpS9vj+ZrHF*q|lv^K{ssZOJgQoG1j_aLrA32yRa%bHm&sTKA5zJ zyuIFy-eMNoTcKqvlN@jmjSAcZm&y1*>?`zOm>adSxn$0^ z(zfu$4%`7Y-RZ^dt5%j7u5QMXS$i~|5*!YG=u1QLhb_RBuF-${%)JeR`d7~GgQcmS z$pBZ&{*M~E0)Y+Q6@C4%Lyvmb`C5HVtIf7iaci!W0BXi}J*285+l{J2byc^1WM0il zcof2SK77wZT8*?wkSS49_M;`P&(gD1XPV~A)HH?laOdO3}5c>upRG*($30qh-z6Y75CZJA=~hY$0}ccE@$|% z8N5Mu)7M&lYr-w{@r|Za$pcpEFvnu|cCW(~W;T`<)mm7a!Le&`bu?X@$85p}Mao0L z?xwL;v$2$k!reV)tXZU@U@#cHrpjiKbSl)g6|?yD*woQDlK`y|k}PDw5#@_yI%&t^ z_;?F|aJp&`{s%_`>WkgmyQ9*lK^M-F?S?Or86JlGZ1~a{+wygF_pJu?i36&qH541n z#)mD#w=bIklm54~3}SGhgOGNGL8uDy!F3b-s^x95bn72de7t|-Ec!(#%@ zp?`Q5{qJ|^kFOTjtAEI$fB!7{)68=JVg9;a{f8X%`)ARA+@U}2FS>p&V3_J~f8umf z-8?23>D*PyMLGIl;O<+#T~|$1bhE z+H#8MHmEuI{{p^i15Jx7Y)4Sy+>!m{{~^GHeogQxrN346r$V3q1T;A5e?)v(G7O4i z)Q{iEb^Rv*bJBlN=^uc0PP+a)G&S_O}p$g&h+D)>-tx^=ogC> z_^;*v2I%jk|4V+UpZg!rL3I6{F8W6>SpbRWIaw7~ef)kG{Yy5>PLHd;=zn}J*Y)pr z(SPwe^;<6brycZv+(G{rNx!m_iYPpLBVo*P(#QXK7yUy4*^AaWj^7JEef-~q{x<`z z=g%RfpZI}AkbeJl7yaW7`s+ag^(VXj82ZCMLrXu#IO*3Kyuymo<@>6?N8>vs&OQt{ zqbnzG`K|Fi7yBPk_TR7g(SLYer`!KC7yTEnQ$N0MIIW*wI_SUMLI1Cmetn#EIH^Er zGbdmdMCBat8`U{qv+B<=tn0jsRe#O>Myu-Y)f&iuBzF2>k6rA!OD&WYntt7Wyw_N;yD^T76)39mz#6FIma6N=H0`AS#TC#1bX3K$ysPvd z;d+U7RU7|)Rmbt(L&;fd^cWw}5P9n{R4{6-9!uj*0$G{!2 zl03yPNabxFLj`3y4F2?Lh+&L^-Z>2C`-sP=ui!_(Q}l9qv!^19$aarGqu2RYl>_R| zBUW&E(^tget2Mq`4jaF(@F@*{OyHHt>Dvm|^Wb-t98HYzq{5%n8lG18X$^ly;eV^) zrxpH!hM!e9#W6KMuW)=8=JbNX^$)}^EBsTO8R{1l&f^JLex~pVjsH!Be@4T9A#iai zZxKmtZaJpzJjO~FTrCQ%)#I39G2Vm{jT>>N9RYDSd-S&_Dbi!itB{R=r~hl z=w|RDFtIZ0!8cSFyan)jmfu>HtWUe}e^&69R_B1?|2p8y*t(;*e#%A8Kf2&IgDaiv z-voF)%af#cr@-+|MH0RLJnACn`!4uTgdEzXOYbq4T=*Bm)H>NY=z>22_#(Csif_|k z^53}dzv6TI8{6xb)2$KHB%j@T-1{JZ6Ot`pvNxd6EEM^nD}n_1xDC z!W>Q+W-Tpfw#8!6?ZMvOdt#k^-GSclw(eNWS-3pHaP3j~eI8E^q`79Jv&arJIOZzQ zVSKYZ`lK0x9_0D?AAc zMx)(5vDT#elP+2*j#9)~mfK-cQMS20oa;(u`s1nM-*?TR1XrqDolVU>mL1IqOTy{0 zzcC9Y;Uuo4U~NY-HZCQp zM%F~GyT;VWS!~@JKVZ$k86Asuj=}6|2b`tzO-PMFroDMIwZd>TlTo@SR>4X)8F_ltAX*g;qDxS>NvKSJ7rzmG1>{2{y&7M@|U{^8j zIB=wKl7P$Zxso5$6JbA=|<8Lc#;n3ZeD~zfv?pn9U4+c`OOlI!W7Ce-&M$p%7 zy@yAvU^WZ$Q10LsIZW6-)d0`U_A9f z7!D@W)_|T2+hEE<;?Fb1{?Q!CB;qO9>KkJvTOlUl-fZ$G5>_sk$%fN|85%%K_vmoH zl@${=fL4~KwiQJ0#J~Ui4J4POs8q@1x~2hf`X9S@ASH7glYuAyWwx1(VL0zk##0ay z+QtbZFFxdu+bdR)4Ajo@*)7f%IxNQ4a8LxP83Vt@+Io`v(s6qICF<&YklphqAD+h8~RJ%SdFrI2uSj97?v#)btzMz~sM zqIDEhuBxKoW$C)2f5D9^P4UVI>&ZlY<}goGM22ZX*i+Jlp$nofdiYw=1;6+4Pt1W#*(|aD1)vGW@3sM|=7h z{tm-;FuX>63POHv=Te66Wc-Z`4=^0R&my6n=o1=mfbnl(IK9WA-U!3@GX7l*r}J6l z4>9~%#?R;RIfbKtmNEXHFn;czml=K!y&D<6oZ(#xN4O&lILg1B;qNkjF8@~wN5A1-Npfz3@4QIZoPr41u z-$W2dmqX8Wh~pTEAD>B(5buB=;rBxw3GJT;KQH`{aO_CP-vvM7$7e+(#JN35fl8dm z!-T?7zK92P|9cFthdRms3d8SU_@fF(y*wWNgzj@IyQIsJO+PfP^@= zGbd1q`=Cy89#FV$=P}05<32yf{!G#PCPwxgiaw nbK4Pye-t|^dYIw25D4Wn3}4J}dR`#CbPijijKhNF0=xYWVk%{3 literal 0 HcmV?d00001 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o new file mode 100644 index 0000000000000000000000000000000000000000..54a735d2e9a5eb869ffd7015cb1be18a864fea77 GIT binary patch literal 17832 zcmc&)4{#jSd0**dTVR}%6H*)?_+%7f8!WW4B}n!{Huv^2|@k7 z_vh}ryH*{+XGstt-P#Ek*Q4CpcHBnRh01O3gs47Y*DUN zmNVMVKplBLEAmT4{wE?|BJ!mouZCQvZr%D1e^=1@pi`gfc}dUy)~8#qy@jp8-1-_; z_)qW38CHN6-Fi+IgVs@A%pUcHtW!JvxAe>o97cJay7haIRH^6Yp&&gwQ>9xAatD0g z$M)A8d9(b(*YwyN=gsY3A_|-|x4)8+Pt56-$82D2<1^-J9U3G@rFv35o3H2-bLKo= zI~J(q`i@ra?3ra)kv*I$d$bZdva{zj(z15{wxIQizuVsxnlffOL)M#Md>tpw-GEei zg`wOktn1cnF!v3mpjw^LCtfvCE@!h|3tF1O%1`6S=+-gbFva9OJqJlr5|@_H1g(GM zSnl(vS5r@D>Wq2qExQXrQN@HhZ)VhR@&Q zzqM!f@BpS-@6vIUsqp!MBU%{0Q0&cTuva1L4Jk*r0&*Y&OW0I6Jm6j0D)_ettvPh^ zS%0@?{mkE`Sw}m;$4le{Io4i@x{kG1VPG~ZW{qZTsnM)}-2u~+k1Q{1 zGrR|}?&Df+i!ZnNg^82iLuWwB#0l@AbCCOUcU;;wb?GvHZgh#?I_F>UlE3*Q>qE`E z>N-`K?xo2eeB2?ZxtJc&9NE% zd-_zxVcnz6c$XeT3iTxKZ|;)A){95pS#rj^^0}5n<~<&)Rke7ZIt$2)XS}yQ3)k^8 z-s|3PIke^;?^D0?K6OI0FciuskgrUToj4S_r(DlITjpQyF<5LA)OcF082y8D#1NI;~k%0t|*&f zT*v$NVP7=NTiEVWr^kiMwII^8lzXlk(1JJHDf#hTEg3!tvffwRqp($P%v zfy$8eQ9f?7brj4Y_z9N^W!|S;20#eG&xyJf11G z6W)n#pb6y$7n}}3p)lXMOzYU`d9WtDOBFf~pT;n(^T~KR^9R- zBmKtp$yC3wJ9B*|9b?5vs&BUuGb3Z^=y2^Ia6lT2Ci@e{stv)UX{3|UL|fcQ^aoNS zNptxM-v(cuQq3tMwZV)wG;Ho$zC!RI(qTl?twz)w1avf-7%_Y|+~5N(t2PKOrJB{! z#y}>*DQsLs{B|R{2jnnXraBN!jz%-#_+BI7Pp6~%l!TGoWezGF_ZfSKp*KdqG?7>s z2gXFa-xp2q8W}Q@W`@`-d%^oJ@49tPhpC8<_KUJDRb?y=b~}&c4q$@7$^7j?q7o9O z!hL@v)&9>nJ+d#Dv*&j=%=#JJ<$VlG5+e8+c=#@7W^bN&9T&Q}SBHSRU(YGQ=878c zcV=MEHN->v#GN1o$jk;Ad!cOwZg(!ya~|07%!OgSiol*dx}1gNo>{qnaQ56@kjeBP z2ECx}H+MVJjY>M_<}uj}xk$zSWdrFQ|0Xmtb>lN55!S6cnzL_}P0Uzz9m)L5zk?24_>^QiXH#;Q5<($!0cQ&im(*`LQk^=dqCAqcU?HH^qf* zFY6cR#HRw=c%$3&V+`q;Wtq5*reOJC{8+bc3yT`tA!w{yhxg^9P3zX_EN-mFB5&WY zg0d?aGit_TzOI!HLb{U}f!xISc8DX>%l+U=)sBfG`EY$~BFipMUH5xfMn7mkz-l zh4DC_0j`$)Uo{*EDD8p3I^Xi{K6rYJ_}0`m)z+_4n@3nxUBLmV9p6mZ~o6z-Blh~G=Jlyr!`wq9soLguWi9LNKJU#hBQ5k=0g$N zZb1yv)p%q4yv+wyj6j(B@g`;av!3#sE(Xc|h06iH7uz7cfj3FBamv#+S<#-ISKg15 z!G#LEg)7Q&q=EDd-Xtx^Gm)r$VGm{+(E6bH1Ehhp2XBP7{1#5-19%De0Mp%gqcr14 z<6nrrSubety`Iu^0|nZ2i)derxs zd{CCsMj~2k8hcHpwm)h{mD;{cMyXAwu!7`jZBubog{tJKjojR^23Mh4S6FzfVf|{O zlxifIi0?5H`zYqb*;-%B=R~8{<5ozaFH2K;u^Y> z5Uf63ZEIaI4TM;Tfy1Il@nqbLMAxK1=MFM_)O1z&Y-EA^JN~gfW|AllG=IdeyIV}Ri^@0gQ zK5n)vumVZuZu~kYQz$>K3CSmOH~z2#KfWqRKAF4m?{MJ9HxbDvb2t882mVbLz(44~ z@4oV%A!q=ui>?aF5)?kKiVSg z!RHO8Yv4lt7|v+gAqgo6Wu&DEV-fTfGV9@@N$S6mf>4(H(vB9uocJFW zguk%yOFo%*34Z+ILepX4wfI0bp#|F+QpWEnv{O&F7m;S#UFto)!{>O!W zwikeQnQUe%BhcWa|0SWnS1_V}wB4?M8Zf5cCip#}zhCgn%-(+s8l3dkeU)<@7L2GL zzxUhqKLMDN{@#l@;~PB7-|hPU7FwM2&j|g4VxUn!K7;N0@hHPde;6O&kl6l+7unse z|6@R%^e^{wrh`O3o^ROouW->{bqVKZdoEsNcf0-?;CIsh&_>Smkl@Asn{4k0nQ}nIqJV0F1!9-;Ky}gk00L?`XxP=R^XTQoi6$Z9rWY= zPRf&ZB}D&i(_gt?=zj>>Y4Xtul=lgKk4-=?b_!A*&+>O)zQhZri~R?M{k?)7{fGNz zyZsNk=)eDu)c+SQ`cFCNuXfOXMCix0P18$4zkP1Xy3Ah`{B}RREcm}fg+dv~S(5qB z1;2pv*?$TCJRk~^PvXB7{I=m!6fdU;+Zv?*CI6eiFZ&`f%v)M{jm95*)=GXk|8VbS zpZmxe7Mr?1*bKH+nLlhMBD+#`70Z<4B95+vY9m~B{TBh|r2m!Wod2YVgS=MozpT6E zXlI4;{+v_0CvQb@t49&W7Q+uqU4&B$@Ce0oe@d*IMYM^8E0v6ju1rNlS9|T^k7bACZItKLRETVIqJ|{f+FCoP|9<Qr9F1Jv}((7QqqAXJOV@A?xflm?)i|;U8j&`B( z13~{}0b-?(1b&YV=id)X=j}YUh%YI5UMytzB87kJEC^dH@COSJD_tgV8?0O@aPnIQ zBdHenCL6;w0>|eLP1g!sY_IZ7{5!`Y<+eP+3k`xkV#C)loZW0KIKDL{7y=$S$!)D3 z?o=C!^iGitai@rl_`DJs2zW|%=bX%=*j~;6?u0IVmc+LXPO97sxP9-0O;5Ps&%5Ar zF8Jr5t4{LUUGNCt%Sb$I5_aD1LjTt;_>Y;K!qdNB$aw+qYO=27^Zj)fIZI$job1@LPBXj^jpX~oNro5V=QG02cL8_OdlgItCw#~SzYp+bB;Lw>`%hfxp8*`_ zNm$syzMDe%UjVNraj#CazwRREGI()xvhzy7o#fXE{FIQpROGD!mrIO&gN3&J0{4NR zFtP8RkpCs%PI}8=Nh~JMYq{T83b+$}mkWNU3;rV){J0BV2?jXneboi`z=p_)z8!G% zrw`U2CidMK@`wxlfS~Uc^z0in&`-F~Kj4BNaglRM;P1hD!nBHK%I{q8i(zZ!)UT^u z@a-=6T`u_3F8I$~@Xy1R&dHu;7ksx1ewPbA>4M+qf-8kjy0x*G61my+>$#>jMzzfms@kZlKnIBz_=){OM9a_Z7s9g! z&sEun{ziVV%D(Y8@&gC>$bTWS8u{^Ru#umh!U;iF1dk93k{cqQF1bClWure7iDX9l zBEd-Upw@;0a9|P&G~-RJV|Vyw4`nzw2?aQ?ngI>$UeE4$VKcADvUau>L3>n5zL_5N7Q$YfIKU~(X(DG|}B zEp2U`T34jYzcHk-35N$PDtCNmEH!KdU^byz^co+7)eWFEnCv(98vWrkkfhDH!GBF@ zg;OM9PoAk`WT?+bukJ9$w0WkB1@es%edV_1kgk><|$u4L34NgEJ(>{h61ER}>a=8>40N=xl9 z0n{cwrJ+x7mTaVrWbD&|L5ay~V-Q3~fm3!OAGXvr+%K}BUWFA`w9wc;ep*}%rU;$f z37cXPE_IVy4}t;-h#wtr0ILIG)cWwTZ8}x`k-&r5w@!cNY zHCQp7YhhFxBf-u!K-B4vXs}FxRb9<>22x2gol2l$b*%{F`}`(6HTp(O>Ks07Vb{S@b{r%w92$MA4U$RKyQCK9}wuV77=(B^W05^fZcyF7! zQevUX=-#aDjTytZ0-L+`4I5fI4eR4mr&HHpIyIK(w9)4sD`y{lrmOXVH2kS*@W;I7 z`q&kIbX>PiW3NXuaut4xIbuerO%Cf&dPU9}wKI_#gJ~rml5OeKP!ShjxCQ@Wj5Jr* z^PfUcSaNJgc%iu)o(Kc+q|sk8H+fL7ZECtwY`2Ho8ZA5+7w<#zjUQiM@f*j-_zyKC z`QD2-zRO8mez!$@9l=*a8581PflJbhV^)T*C%F9H1+Qc5e=tdp=e?Lv4xSxLJc}SC z#KUk&{96b@LOFi8Bz_-)kdS^OToQj2K}d+BZ4&<}f{+joz$Nix2tq=<6)uUtiXbF> zeMQ|8$M4OUkRH$GC4M>k-pO(5=W2nYj4ndIlF)Y(TqX3|2)>cfQ#)@Y_;y0yL+~90 z-%aqF2!5NuvAMlNcpt%^C3uYBbsnfd!e(6KQqBhgx9eSxhC{-P&f74-cR`z!GfZ$wKPGV0 z>m&4c5_;t_t z)92m46P)_<9Kq?jsDSUXm~dTG!zKN&Sm5X%DyP~7S6y(w3my?T>b;EU9U%BJf)5e= zYJ!gu`CldY9fY3BpCCAuKS}T!BImm<@_#_+Q9iD1On*giD*q9Je+lTMpPzJ*{||(o z%AX}TmH#}!sefK}k^g&UEua4(V$T9tg;Ha05*CPVA%YTC4RKDEbBK-=ur2JVyZx;|2Dy|gR+z_$KNjhK|)XE|B&ER{*MSw*Y)2E+%6yY zsF)D{8eGzz|F3no3ypz<?dd}h652`Qp@*TImcH)@m>tI!PO}SVW*DY4Nd);4 zQAT_d!F>eB|Nmu@@3}}X=OnhtGdaX>L_j1ef2#x`_lYvn|1t6}%@ zyjPSFM}Nxnbx}b45(z?nzbGTVNR%;qL6i}fa|5As1Ya!5m|ck-f`s&V;X65|78`zw upS?nq{DoM)N%vq!55?(A}GuVl&{kl{|Q8Iq~ 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 Y8ouA;(< + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var canvas = require('./bindings') + , Canvas = canvas.Canvas + , Image = canvas.Image + , cairoVersion = canvas.cairoVersion + , PixelArray = canvas.CanvasPixelArray + , Context2d = require('./context2d') + , PNGStream = require('./pngstream') + , JPEGStream = require('./jpegstream') + , FontFace = canvas.FontFace + , fs = require('fs') + , package = require("../package.json"); + +/** + * Export `Canvas` as the module. + */ + +var Canvas = exports = module.exports = Canvas; + +/** + * Library version. + */ + +exports.version = package.version; + +/** + * Cairo version. + */ + +exports.cairoVersion = cairoVersion; + +/** + * jpeglib version. + */ + +if (canvas.jpegVersion) { + exports.jpegVersion = canvas.jpegVersion; +} + +/** + * gif_lib version. + */ + +if (canvas.gifVersion) { + exports.gifVersion = canvas.gifVersion.replace(/[^.\d]/g, ''); +} + +/** + * Expose constructors. + */ + +exports.Context2d = Context2d; +exports.PNGStream = PNGStream; +exports.JPEGStream = JPEGStream; +exports.PixelArray = PixelArray; +exports.Image = Image; + +if (FontFace) { + function Font(name, path, idx) { + this.name = name; + this._faces = {}; + + this.addFace(path, 'normal', 'normal', idx); + }; + + Font.prototype.addFace = function(path, weight, style, idx) { + style = style || 'normal'; + weight = weight || 'normal'; + + var face = new FontFace(path, idx || 0); + this._faces[weight + '-' + style] = face; + }; + + Font.prototype.getFace = function(weightStyle) { + return this._faces[weightStyle] || this._faces['normal-normal']; + }; + + exports.Font = Font; +} + +/** + * Context2d implementation. + */ + +require('./context2d'); + +/** + * Image implementation. + */ + +require('./image'); + +/** + * PixelArray implementation. + */ + +require('./pixelarray'); + +/** + * Inspect canvas. + * + * @return {String} + * @api public + */ + +Canvas.prototype.inspect = function(){ + return '[Canvas ' + this.width + 'x' + this.height + ']'; +}; + +/** + * Get a context object. + * + * @param {String} contextId + * @return {Context2d} + * @api public + */ + +Canvas.prototype.getContext = function(contextId){ + if ('2d' == contextId) { + var ctx = this._context2d || (this._context2d = new Context2d(this)); + this.context = ctx; + ctx.canvas = this; + return ctx; + } +}; + +/** + * Create a `PNGStream` for `this` canvas. + * + * @return {PNGStream} + * @api public + */ + +Canvas.prototype.pngStream = +Canvas.prototype.createPNGStream = function(){ + return new PNGStream(this); +}; + +/** + * Create a synchronous `PNGStream` for `this` canvas. + * + * @return {PNGStream} + * @api public + */ + +Canvas.prototype.syncPNGStream = +Canvas.prototype.createSyncPNGStream = function(){ + return new PNGStream(this, true); +}; + +/** + * Create a `JPEGStream` for `this` canvas. + * + * @param {Object} options + * @return {JPEGStream} + * @api public + */ + +Canvas.prototype.jpegStream = +Canvas.prototype.createJPEGStream = function(options){ + return this.createSyncJPEGStream(options); +}; + +/** + * Create a synchronous `JPEGStream` for `this` canvas. + * + * @param {Object} options + * @return {JPEGStream} + * @api public + */ + +Canvas.prototype.syncJPEGStream = +Canvas.prototype.createSyncJPEGStream = function(options){ + options = options || {}; + return new JPEGStream(this, { + bufsize: options.bufsize || 4096 + , quality: options.quality || 75 + , progressive: options.progressive || false + }); +}; + +/** + * Return a data url. Pass a function for async support. + * + * @param {String|Function} type + * @param {Function} fn + * @return {String} + * @api public + */ + +Canvas.prototype.toDataURL = function(type, fn){ + // Default to png + type = type || 'image/png'; + + // Allow callback as first arg + if ('function' == typeof type) fn = type, type = 'image/png'; + + // Throw on non-png + if ('image/png' != type) throw new Error('currently only image/png is supported'); + + var prefix = 'data:' + type + ';base64,'; + + if (fn) { + this.toBuffer(function(err, buf){ + if (err) return fn(err); + var str = 'data:' + type + fn(null, prefix + buf.toString('base64')); + }); + } else { + return prefix + this.toBuffer().toString('base64'); + } +}; diff --git a/scripts/external/three/canvas/lib/context2d.js b/scripts/external/three/canvas/lib/context2d.js new file mode 100644 index 0000000..7dfbea0 --- /dev/null +++ b/scripts/external/three/canvas/lib/context2d.js @@ -0,0 +1,386 @@ +/*! + * Canvas - Context2d + * Copyright (c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var canvas = require('./bindings') + , Context2d = canvas.CanvasRenderingContext2d + , CanvasGradient = canvas.CanvasGradient + , CanvasPattern = canvas.CanvasPattern + , ImageData = canvas.ImageData + , PixelArray = canvas.CanvasPixelArray; + +/** + * Export `Context2d` as the module. + */ + +var Context2d = exports = module.exports = Context2d; + +/** + * Cache color string RGBA values. + */ + +var cache = {}; + +/** + * Text baselines. + */ + +var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging']; + +/** + * Font RegExp helpers. + */ + +var weights = 'normal|bold|bolder|lighter|[1-9]00' + , styles = 'normal|italic|oblique' + , units = 'px|pt|pc|in|cm|mm|%' + , string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+'; + +/** + * Font parser RegExp; + */ + +var fontre = new RegExp('^ *' + + '(?:(' + weights + ') *)?' + + '(?:(' + styles + ') *)?' + + '([\\d\\.]+)(' + units + ') *' + + '((?:' + string + ')( *, *(?:' + string + '))*)' + ); + +/** + * Parse font `str`. + * + * @param {String} str + * @return {Object} + * @api private + */ + +var parseFont = exports.parseFont = function(str){ + var font = {} + , captures = fontre.exec(str); + + // Invalid + if (!captures) return; + + // Cached + if (cache[str]) return cache[str]; + + // Populate font object + font.weight = captures[1] || 'normal'; + font.style = captures[2] || 'normal'; + font.size = parseFloat(captures[3]); + font.unit = captures[4]; + font.family = captures[5].replace(/["']/g, '').split(',')[0]; + + // TODO: dpi + // TODO: remaining unit conversion + switch (font.unit) { + case 'pt': + font.size /= .75; + break; + case 'in': + font.size *= 96; + break; + case 'mm': + font.size *= 96.0 / 25.4; + break; + case 'cm': + font.size *= 96.0 / 2.54; + break; + } + + return cache[str] = font; +}; + +/** + * Enable or disable image smoothing. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('imageSmoothingEnabled', function(val){ + this._imageSmoothing = !! val; + this.patternQuality = val ? 'best' : 'fast'; +}); + +/** + * Get image smoothing value. + * + * @api public + */ + +Context2d.prototype.__defineGetter__('imageSmoothingEnabled', function(val){ + return !! this._imageSmoothing; +}); + +/** + * Create a pattern from `Image` or `Canvas`. + * + * @param {Image|Canvas} image + * @param {String} repetition + * @return {CanvasPattern} + * @api public + */ + +Context2d.prototype.createPattern = function(image, repetition){ + // TODO Use repetition (currently always 'repeat') + return new CanvasPattern(image); +}; + +/** + * Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`. + * + * @param {Number} x0 + * @param {Number} y0 + * @param {Number} x1 + * @param {Number} y1 + * @return {CanvasGradient} + * @api public + */ + +Context2d.prototype.createLinearGradient = function(x0, y0, x1, y1){ + return new CanvasGradient(x0, y0, x1, y1); +}; + +/** + * Create a radial gradient at the given point `(x0, y0)` and `(x1, y1)` + * and radius `r0` and `r1`. + * + * @param {Number} x0 + * @param {Number} y0 + * @param {Number} r0 + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} r1 + * @return {CanvasGradient} + * @api public + */ + +Context2d.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){ + return new CanvasGradient(x0, y0, r0, x1, y1, r1); +}; + +/** + * Reset transform matrix to identity, then apply the given args. + * + * @param {...} + * @api public + */ + +Context2d.prototype.setTransform = function(){ + this.resetTransform(); + this.transform.apply(this, arguments); +}; + +/** + * Set the fill style with the given css color string. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('fillStyle', function(val){ + if (!val) return; + if ('CanvasGradient' == val.constructor.name + || 'CanvasPattern' == val.constructor.name) { + this.lastFillStyle = val; + this._setFillPattern(val); + } else if ('string' == typeof val) { + this._setFillColor(val); + } +}); + +/** + * Get previous fill style. + * + * @return {CanvasGradient|String} + * @api public + */ + +Context2d.prototype.__defineGetter__('fillStyle', function(){ + return this.lastFillStyle || this.fillColor; +}); + +/** + * Set the stroke style with the given css color string. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('strokeStyle', function(val){ + if (!val) return; + if ('CanvasGradient' == val.constructor.name + || 'CanvasPattern' == val.constructor.name) { + this.lastStrokeStyle = val; + this._setStrokePattern(val); + } else if ('string' == typeof val) { + this._setStrokeColor(val); + } +}); + +/** + * Get previous stroke style. + * + * @return {CanvasGradient|String} + * @api public + */ + +Context2d.prototype.__defineGetter__('strokeStyle', function(){ + return this.lastStrokeStyle || this.strokeColor; +}); + +/** + * Register `font` for usage. + * + * @param {Font} font + * @api public + */ + +Context2d.prototype.addFont = function(font) { + this._fonts = this._fonts || {}; + if (this._fonts[font.name]) return; + this._fonts[font.name] = font; +}; + +/** + * Set font. + * + * @see exports.parseFont() + * @api public + */ + +Context2d.prototype.__defineSetter__('font', function(val){ + if (!val) return; + if ('string' == typeof val) { + var font; + if (font = parseFont(val)) { + this.lastFontString = val; + + var fonts = this._fonts; + if (fonts && fonts[font.family]) { + var fontObj = fonts[font.family]; + var type = font.weight + '-' + font.style; + + var fontFace = fontObj.getFace(type); + this._setFontFace(fontFace, font.size); + } else { + this._setFont( + font.weight + , font.style + , font.size + , font.unit + , font.family); + } + } + } +}); + +/** + * Get the current font. + * + * @api public + */ + +Context2d.prototype.__defineGetter__('font', function(){ + return this.lastFontString || '10px sans-serif'; +}); + +/** + * Set text baseline. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('textBaseline', function(val){ + if (!val) return; + var n = baselines.indexOf(val); + if (~n) { + this.lastBaseline = val; + this._setTextBaseline(n); + } +}); + +/** + * Get the current baseline setting. + * + * @api public + */ + +Context2d.prototype.__defineGetter__('textBaseline', function(){ + return this.lastBaseline || 'alphabetic'; +}); + +/** + * Set text alignment. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('textAlign', function(val){ + switch (val) { + case 'center': + this._setTextAlignment(0); + this.lastTextAlignment = val; + break; + case 'left': + case 'start': + this._setTextAlignment(-1); + this.lastTextAlignment = val; + break; + case 'right': + case 'end': + this._setTextAlignment(1); + this.lastTextAlignment = val; + break; + } +}); + +/** + * Get the current font. + * + * @see exports.parseFont() + * @api public + */ + +Context2d.prototype.__defineGetter__('textAlign', function(){ + return this.lastTextAlignment || 'start'; +}); + +/** + * Get `ImageData` with the given rect. + * + * @param {Number} x + * @param {Number} y + * @param {Number} width + * @param {Number} height + * @return {ImageData} + * @api public + */ + +Context2d.prototype.getImageData = function(x, y, width, height){ + var arr = new PixelArray(this.canvas, x, y, width, height); + return new ImageData(arr); +}; + +/** + * Create `ImageData` with the given dimensions or + * `ImageData` instance for dimensions. + * + * @param {Number|ImageData} width + * @param {Number} height + * @return {ImageData} + * @api public + */ + +Context2d.prototype.createImageData = function(width, height){ + if ('ImageData' == width.constructor.name) { + height = width.height; + width = width.width; + } + return new ImageData(new PixelArray(width, height)); +}; diff --git a/scripts/external/three/canvas/lib/image.js b/scripts/external/three/canvas/lib/image.js new file mode 100644 index 0000000..558472b --- /dev/null +++ b/scripts/external/three/canvas/lib/image.js @@ -0,0 +1,60 @@ + +/*! + * Canvas - Image + * Copyright (c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Canvas = require('./bindings') + , Image = Canvas.Image; + +/** + * Src setter. + * + * - convert data uri to `Buffer` + * + * @param {String|Buffer} val filename, buffer, data uri + * @api public + */ + +Image.prototype.__defineSetter__('src', function(val){ + if ('string' == typeof val && 0 == val.indexOf('data:')) { + val = val.slice(val.indexOf(',') + 1); + this.source = new Buffer(val, 'base64'); + } else { + this.source = val; + } +}); + +/** + * Src getter. + * + * TODO: return buffer + * + * @api public + */ + +Image.prototype.__defineGetter__('src', function(){ + return this.source; +}); + +/** + * Inspect image. + * + * TODO: indicate that the .src was a buffer, data uri etc + * + * @return {String} + * @api public + */ + +Image.prototype.inspect = function(){ + return '[Image' + + (this.complete ? ':' + this.width + 'x' + this.height : '') + + (this.src ? ' ' + this.src : '') + + (this.complete ? ' complete' : '') + + ']'; +}; diff --git a/scripts/external/three/canvas/lib/jpegstream.js b/scripts/external/three/canvas/lib/jpegstream.js new file mode 100644 index 0000000..1db8670 --- /dev/null +++ b/scripts/external/three/canvas/lib/jpegstream.js @@ -0,0 +1,61 @@ + +/*! + * Canvas - JPEGStream + * Copyright (c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Stream = require('stream').Stream; + +/** + * Initialize a `JPEGStream` with the given `canvas`. + * + * "data" events are emitted with `Buffer` chunks, once complete the + * "end" event is emitted. The following example will stream to a file + * named "./my.jpeg". + * + * var out = fs.createWriteStream(__dirname + '/my.jpeg') + * , stream = canvas.createJPEGStream(); + * + * stream.pipe(out); + * + * @param {Canvas} canvas + * @param {Boolean} sync + * @api public + */ + +var JPEGStream = module.exports = function JPEGStream(canvas, options, sync) { + var self = this + , method = sync + ? 'streamJPEGSync' + : 'streamJPEG'; + this.options = options; + this.sync = sync; + this.canvas = canvas; + this.readable = true; + // TODO: implement async + if ('streamJPEG' == method) method = 'streamJPEGSync'; + process.nextTick(function(){ + canvas[method](options.bufsize, options.quality, options.progressive, function(err, chunk, len){ + if (err) { + self.emit('error', err); + self.readable = false; + } else if (len) { + self.emit('data', chunk, len); + } else { + self.emit('end'); + self.readable = false; + } + }); + }); +}; + +/** + * Inherit from `EventEmitter`. + */ + +JPEGStream.prototype.__proto__ = Stream.prototype; diff --git a/scripts/external/three/canvas/lib/pixelarray.js b/scripts/external/three/canvas/lib/pixelarray.js new file mode 100644 index 0000000..ff10cee --- /dev/null +++ b/scripts/external/three/canvas/lib/pixelarray.js @@ -0,0 +1,29 @@ + +/*! + * Canvas - PixelArray + * Copyright (c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Canvas = require('./bindings') + , PixelArray = Canvas.CanvasPixelArray; + +/** + * Custom inspect. + */ + +PixelArray.prototype.inspect = function(){ + var buf = '[PixelArray '; + for (var i = 0, len = this.length; i < len; i += 4) { + buf += '\n ' + i + ': rgba(' + + this[i + 0] + ',' + + this[i + 1] + ',' + + this[i + 2] + ',' + + this[i + 3] + ')'; + } + return buf + '\n]'; +}; diff --git a/scripts/external/three/canvas/lib/pngstream.js b/scripts/external/three/canvas/lib/pngstream.js new file mode 100644 index 0000000..38e08cd --- /dev/null +++ b/scripts/external/three/canvas/lib/pngstream.js @@ -0,0 +1,60 @@ + +/*! + * Canvas - PNGStream + * Copyright (c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Stream = require('stream').Stream; + +/** + * Initialize a `PNGStream` with the given `canvas`. + * + * "data" events are emitted with `Buffer` chunks, once complete the + * "end" event is emitted. The following example will stream to a file + * named "./my.png". + * + * var out = fs.createWriteStream(__dirname + '/my.png') + * , stream = canvas.createPNGStream(); + * + * stream.pipe(out); + * + * @param {Canvas} canvas + * @param {Boolean} sync + * @api public + */ + +var PNGStream = module.exports = function PNGStream(canvas, sync) { + var self = this + , method = sync + ? 'streamPNGSync' + : 'streamPNG'; + this.sync = sync; + this.canvas = canvas; + this.readable = true; + // TODO: implement async + if ('streamPNG' == method) method = 'streamPNGSync'; + process.nextTick(function(){ + canvas[method](function(err, chunk, len){ + if (err) { + self.emit('error', err); + self.readable = false; + } else if (len) { + self.emit('data', chunk, len); + } else { + self.emit('end'); + self.readable = false; + } + }); + }); +}; + +/** + * Inherit from `EventEmitter`. + */ + +PNGStream.prototype.__proto__ = Stream.prototype; \ No newline at end of file diff --git a/scripts/external/three/canvas/node_modules/nan/.dntrc b/scripts/external/three/canvas/node_modules/nan/.dntrc new file mode 100644 index 0000000..47971da --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/.dntrc @@ -0,0 +1,30 @@ +## DNT config file +## see https://github.com/rvagg/dnt + +NODE_VERSIONS="\ + master \ + v0.11.13 \ + v0.10.30 \ + v0.10.29 \ + v0.10.28 \ + v0.10.26 \ + v0.10.25 \ + v0.10.24 \ + v0.10.23 \ + v0.10.22 \ + v0.10.21 \ + v0.10.20 \ + v0.10.19 \ + v0.8.28 \ + v0.8.27 \ + v0.8.26 \ + v0.8.24 \ +" +OUTPUT_PREFIX="nan-" +TEST_CMD=" \ + cd /dnt/ && \ + npm install && \ + node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild --directory test && \ + node_modules/.bin/tap --gc test/js/*-test.js \ +" + diff --git a/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md b/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md new file mode 100644 index 0000000..6a0fdbe --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md @@ -0,0 +1,248 @@ +# NAN ChangeLog + +**Version 1.5.2: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3** + +### 1.5.2 Jan 23 2015 + + - Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4 + - Bugfix: Readded missing String constructors 18d828f + - Bugfix: Add overload handling NanNew(..) 5ef813b + - Bugfix: Fix uv_work_cb versioning 997e4ae + - Bugfix: Add function factory and test 4eca89c + - Bugfix: Add object template factory and test cdcb951 + - Correctness: Lifted an io.js related typedef c9490be + - Correctness: Make explicit downcasts of String lengths 00074e6 + - Windows: Limit the scope of disabled warning C4530 83d7deb + + +### 1.5.1 Jan 15 2015 + + - Build: version bump + +### 1.4.3 Jan 15 2015 + + - Build: version bump + +### 1.4.2 Jan 15 2015 + + - Feature: Support io.js 0dbc5e8 + +### 1.5.0 Jan 14 2015 + + - Feature: Support io.js b003843 + - Correctness: Improved NanNew internals 9cd4f6a + - Feature: Implement progress to NanAsyncWorker 8d6a160 + +### 1.4.1 Nov 8 2014 + + - Bugfix: Handle DEBUG definition correctly + - Bugfix: Accept int as Boolean + +### 1.4.0 Nov 1 2014 + + - Feature: Added NAN_GC_CALLBACK 6a5c245 + - Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8 + - Correctness: Added constness to references in NanHasInstance 02c61cd + - Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6 + - Windoze: Shut Visual Studio up when compiling 8d558c1 + - License: Switch to plain MIT from custom hacked MIT license 11de983 + - Build: Added test target to Makefile e232e46 + - Performance: Removed superfluous scope in NanAsyncWorker f4b7821 + - Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208 + - Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450 + +### 1.3.0 Aug 2 2014 + + - Added NanNew(std::string) + - Added NanNew(std::string&) + - Added NanAsciiString helper class + - Added NanUtf8String helper class + - Added NanUcs2String helper class + - Deprecated NanRawString() + - Deprecated NanCString() + - Added NanGetIsolateData(v8::Isolate *isolate) + - Added NanMakeCallback(v8::Handle target, v8::Handle func, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, v8::Handle symbol, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, const char* method, int argc, v8::Handle* argv) + - Added NanSetTemplate(v8::Handle templ, v8::Handle name , v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetPrototypeTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetInstanceTemplate(v8::Local templ, const char *name, v8::Handle value) + - Added NanSetInstanceTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + +### 1.2.0 Jun 5 2014 + + - Add NanSetPrototypeTemplate + - Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class, + introduced _NanWeakCallbackDispatcher + - Removed -Wno-unused-local-typedefs from test builds + - Made test builds Windows compatible ('Sleep()') + +### 1.1.2 May 28 2014 + + - Release to fix more stuff-ups in 1.1.1 + +### 1.1.1 May 28 2014 + + - Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0 + +### 1.1.0 May 25 2014 + + - Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead + - Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]), + (uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*, + v8::String::ExternalAsciiStringResource* + - Deprecate NanSymbol() + - Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker + +### 1.0.0 May 4 2014 + + - Heavy API changes for V8 3.25 / Node 0.11.13 + - Use cpplint.py + - Removed NanInitPersistent + - Removed NanPersistentToLocal + - Removed NanFromV8String + - Removed NanMakeWeak + - Removed NanNewLocal + - Removed NAN_WEAK_CALLBACK_OBJECT + - Removed NAN_WEAK_CALLBACK_DATA + - Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions + - Introduce NanUndefined, NanNull, NanTrue and NanFalse + - Introduce NanEscapableScope and NanEscapeScope + - Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node) + - Introduce NanMakeCallback for node::MakeCallback + - Introduce NanSetTemplate + - Introduce NanGetCurrentContext + - Introduce NanCompileScript and NanRunScript + - Introduce NanAdjustExternalMemory + - Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback + - Introduce NanGetHeapStatistics + - Rename NanAsyncWorker#SavePersistent() to SaveToPersistent() + +### 0.8.0 Jan 9 2014 + + - NanDispose -> NanDisposePersistent, deprecate NanDispose + - Extract _NAN_*_RETURN_TYPE, pull up NAN_*() + +### 0.7.1 Jan 9 2014 + + - Fixes to work against debug builds of Node + - Safer NanPersistentToLocal (avoid reinterpret_cast) + - Speed up common NanRawString case by only extracting flattened string when necessary + +### 0.7.0 Dec 17 2013 + + - New no-arg form of NanCallback() constructor. + - NanCallback#Call takes Handle rather than Local + - Removed deprecated NanCallback#Run method, use NanCallback#Call instead + - Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS + - Restore (unofficial) Node 0.6 compatibility at NanCallback#Call() + - Introduce NanRawString() for char* (or appropriate void*) from v8::String + (replacement for NanFromV8String) + - Introduce NanCString() for null-terminated char* from v8::String + +### 0.6.0 Nov 21 2013 + + - Introduce NanNewLocal(v8::Handle value) for use in place of + v8::Local::New(...) since v8 started requiring isolate in Node 0.11.9 + +### 0.5.2 Nov 16 2013 + + - Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public + +### 0.5.1 Nov 12 2013 + + - Use node::MakeCallback() instead of direct v8::Function::Call() + +### 0.5.0 Nov 11 2013 + + - Added @TooTallNate as collaborator + - New, much simpler, "include_dirs" for binding.gyp + - Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros + +### 0.4.4 Nov 2 2013 + + - Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+ + +### 0.4.3 Nov 2 2013 + + - Include node_object_wrap.h, removed from node.h for Node 0.11.8. + +### 0.4.2 Nov 2 2013 + + - Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for + Node 0.11.8 release. + +### 0.4.1 Sep 16 2013 + + - Added explicit `#include ` as it was removed from node.h for v0.11.8 + +### 0.4.0 Sep 2 2013 + + - Added NAN_INLINE and NAN_DEPRECATED and made use of them + - Added NanError, NanTypeError and NanRangeError + - Cleaned up code + +### 0.3.2 Aug 30 2013 + + - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent + in NanAsyncWorker + +### 0.3.1 Aug 20 2013 + + - fix "not all control paths return a value" compile warning on some platforms + +### 0.3.0 Aug 19 2013 + + - Made NAN work with NPM + - Lots of fixes to NanFromV8String, pulling in features from new Node core + - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API + - Added optional error number argument for NanThrowError() + - Added NanInitPersistent() + - Added NanReturnNull() and NanReturnEmptyString() + - Added NanLocker and NanUnlocker + - Added missing scopes + - Made sure to clear disposed Persistent handles + - Changed NanAsyncWorker to allocate error messages on the heap + - Changed NanThrowError(Local) to NanThrowError(Handle) + - Fixed leak in NanAsyncWorker when errmsg is used + +### 0.2.2 Aug 5 2013 + + - Fixed usage of undefined variable with node::BASE64 in NanFromV8String() + +### 0.2.1 Aug 5 2013 + + - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for + NanFromV8String() + +### 0.2.0 Aug 5 2013 + + - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR, + NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY + - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS, + _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS, + _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS, + _NAN_PROPERTY_QUERY_ARGS + - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer + - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT, + NAN_WEAK_CALLBACK_DATA, NanMakeWeak + - Renamed THROW_ERROR to _NAN_THROW_ERROR + - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*) + - Added NanBufferUse(char*, uint32_t) + - Added NanNewContextHandle(v8::ExtensionConfiguration*, + v8::Handle, v8::Handle) + - Fixed broken NanCallback#GetFunction() + - Added optional encoding and size arguments to NanFromV8String() + - Added NanGetPointerSafe() and NanSetPointerSafe() + - Added initial test suite (to be expanded) + - Allow NanUInt32OptionValue to convert any Number object + +### 0.1.0 Jul 21 2013 + + - Added `NAN_GETTER`, `NAN_SETTER` + - Added `NanThrowError` with single Local argument + - Added `NanNewBufferHandle` with single uint32_t argument + - Added `NanHasInstance(Persistent&, Handle)` + - Added `Local NanCallback#GetFunction()` + - Added `NanCallback#Call(int, Local[])` + - Deprecated `NanCallback#Run(int, Local[])` in favour of Call diff --git a/scripts/external/three/canvas/node_modules/nan/LICENSE.md b/scripts/external/three/canvas/node_modules/nan/LICENSE.md new file mode 100644 index 0000000..95c2eb5 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/LICENSE.md @@ -0,0 +1,13 @@ +The MIT License (MIT) +===================== + +Copyright (c) 2015 NAN contributors +----------------------------------- + +*NAN contributors listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/scripts/external/three/canvas/node_modules/nan/README.md b/scripts/external/three/canvas/node_modules/nan/README.md new file mode 100644 index 0000000..f91d08b --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/README.md @@ -0,0 +1,1228 @@ +Native Abstractions for Node.js +=============================== + +**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.** + +***Current version: 1.5.2*** + +*(See [CHANGELOG.md](https://github.com/rvagg/nan/blob/master/CHANGELOG.md) for complete ChangeLog)* + +[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/) + +[![Build Status](https://secure.travis-ci.org/rvagg/nan.png)](http://travis-ci.org/rvagg/nan) +[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan) + +Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle. + +This project also contains some helper utilities that make addon development a bit more pleasant. + + * **[News & Updates](#news)** + * **[Usage](#usage)** + * **[Example](#example)** + * **[API](#api)** + * **[Tests](#tests)** + + +## News & Updates + +### Jan-2015: 1.5.0 release + +* Support [io.js](https://github.com/iojs/io.js) thanks to [Ben Noordhuis](bnoordhuis) +* Rewritten NanNew internals thanks to [David Siegel](agnat) +* NanAsyncWorker now supports progress reporting thanks to [Brett Lawson](brett19) + +### Aug-2014: 1.3.0 release + +* `NanCString()` and `NanRawString()` have been deprecated in favour of new NanAsciiString, NanUtf8String and NanUcs2String. These classes manage the underlying memory for you in a safer way than just handing off an allocated array. You should now `*NanAsciiString(handle)` to access the raw `char` data, you can also allocate on the heap if you need to keep a reference. +* Two more NanMakeCallback overloads have been added to for parity with Node core. +* You can now `NanNew(std::string)` (use `NanNew(std::string&)` to pass by reference) +* NanSetTemplate, NanSetPrototypeTemplate and NanSetInstanceTemplate have been added. + +### May-2014: 1.1.0 release + +* We've deprecated `NanSymbol()`, you should just use `NanNew()` now. +* `NanNull()`, `NanUndefined()`, `NanTrue()`, `NanFalse()` all return `Local`s now. +* `nan_isolate` is gone, it was intended to be internal-only but if you were using it then you should switch to `v8::Isolate::GetCurrent()`. +* `NanNew()` has received some additional overload-love so you should be able to give it many kinds of values without specifying the ``. +* Lots of small fixes and additions to expand the V8 API coverage, *use the source, Luke*. + + +### May-2014: Major changes for V8 3.25 / Node 0.11.13 + +Node 0.11.11 and 0.11.12 were both broken releases for native add-ons, you simply can't properly compile against either of them for different reasons. But we now have a 0.11.13 release that jumps a couple of versions of V8 ahead and includes some more, major (traumatic) API changes. + +Because we are now nearing Node 0.12 and estimate that the version of V8 we are using in Node 0.11.13 will be close to the API we get for 0.12, we have taken the opportunity to not only *fix* NAN for 0.11.13 but make some major changes to improve the NAN API. + +We have **removed support for Node 0.11 versions prior to 0.11.13**. As usual, our tests are run against (and pass) the last 5 versions of Node 0.8 and Node 0.10. We also include Node 0.11.13 obviously. + +The major change is something that [Benjamin Byholm](kkoopa) has put many hours in to. We now have a fantastic new `NanNew(args)` interface for creating new `Local`s, this replaces `NanNewLocal()` and much more. If you look in [./nan.h](nan.h) you'll see a large number of overloaded versions of this method. In general you should be able to `NanNew(arguments)` for any type you want to make a `Local` from. This includes `Persistent` types, so we now have a `Local NanNew(const Persistent arg)` to replace `NanPersistentToLocal()`. + +We also now have `NanUndefined()`, `NanNull()`, `NanTrue()` and `NanFalse()`. Mainly because of the new requirement for an `Isolate` argument for each of the native V8 versions of this. + +V8 has now introduced an `EscapableHandleScope` from which you `scope.Escape(Local value)` to *return* a value from a one scope to another. This replaces the standard `HandleScope` and `scope.Close(Local value)`, although `HandleScope` still exists for when you don't need to return a handle to the caller. For NAN we are exposing it as `NanEscapableScope()` and `NanEscapeScope()`, while `NanScope()` is still how you create a new scope that doesn't need to return handles. For older versions of Node/V8, it'll still map to the older `HandleScope` functionality. + +`NanFromV8String()` was deprecated and has now been removed. You should use `NanCString()` or `NanRawString()` instead. + +Because `node::MakeCallback()` now takes an `Isolate`, and because it doesn't exist in older versions of Node, we've introduced `NanMakeCallback()`. You should *always* use this when calling a JavaScript function from C++. + +There's lots more, check out the Changelog in nan.h or look through [#86](https://github.com/rvagg/nan/pull/86) for all the gory details. + +### Dec-2013: NanCString and NanRawString + +Two new functions have been introduced to replace the functionality that's been provided by `NanFromV8String` until now. NanCString has sensible defaults so it's super easy to fetch a null-terminated c-style string out of a `v8::String`. `NanFromV8String` is still around and has defaults that allow you to pass a single handle to fetch a `char*` while `NanRawString` requires a little more attention to arguments. + +### Nov-2013: Node 0.11.9+ breaking V8 change + +The version of V8 that's shipping with Node 0.11.9+ has changed the signature for new `Local`s to: `v8::Local::New(isolate, value)`, i.e. introducing the `isolate` argument and therefore breaking all new `Local` declarations for previous versions. NAN 0.6+ now includes a `NanNewLocal(value)` that can be used in place to work around this incompatibility and maintain compatibility with 0.8->0.11.9+ (minus a few early 0.11 releases). + +For example, if you wanted to return a `null` on a callback you will have to change the argument from `v8::Local::New(v8::Null())` to `NanNewLocal(v8::Null())`. + +### Nov-2013: Change to binding.gyp `"include_dirs"` for NAN + +Inclusion of NAN in a project's binding.gyp is now greatly simplified. You can now just use `" +## Usage + +Simply add **NAN** as a dependency in the *package.json* of your Node addon: + +``` bash +$ npm install --save nan +``` + +Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files: + +``` python +"include_dirs" : [ + "` when compiling your addon. + + +## Example + +See **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use. + +For a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**. + +For another example, see **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon. + +Compare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work). + +Note that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class. + +```c++ +// addon.cc +#include +#include +// ... + +using v8::FunctionTemplate; +using v8::Handle; +using v8::Object; +using v8::String; + +void InitAll(Handle exports) { + exports->Set(NanNew("calculateSync"), + NanNew(CalculateSync)->GetFunction()); + + exports->Set(NanNew("calculateAsync"), + NanNew(CalculateAsync)->GetFunction()); +} + +NODE_MODULE(addon, InitAll) +``` + +```c++ +// sync.h +#include +#include + +NAN_METHOD(CalculateSync); +``` + +```c++ +// sync.cc +#include +#include +#include "./sync.h" +// ... + +using v8::Number; + +// Simple synchronous access to the `Estimate()` function +NAN_METHOD(CalculateSync) { + NanScope(); + + // expect a number as the first argument + int points = args[0]->Uint32Value(); + double est = Estimate(points); + + NanReturnValue(NanNew(est)); +} +``` + +```c++ +// async.h +#include +#include + +NAN_METHOD(CalculateAsync); +``` + +```c++ +// async.cc +#include +#include +#include "./async.h" + +// ... + +using v8::Function; +using v8::Local; +using v8::Null; +using v8::Number; +using v8::Value; + +class PiWorker : public NanAsyncWorker { + public: + PiWorker(NanCallback *callback, int points) + : NanAsyncWorker(callback), points(points) {} + ~PiWorker() {} + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute () { + estimate = Estimate(points); + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void HandleOKCallback () { + NanScope(); + + Local argv[] = { + NanNull() + , NanNew(estimate) + }; + + callback->Call(2, argv); + }; + + private: + int points; + double estimate; +}; + +// Asynchronous access to the `Estimate()` function +NAN_METHOD(CalculateAsync) { + NanScope(); + + int points = args[0]->Uint32Value(); + NanCallback *callback = new NanCallback(args[1].As()); + + NanAsyncQueueWorker(new PiWorker(callback, points)); + NanReturnUndefined(); +} +``` + + +## API + + * NAN_METHOD + * NAN_GETTER + * NAN_SETTER + * NAN_PROPERTY_GETTER + * NAN_PROPERTY_SETTER + * NAN_PROPERTY_ENUMERATOR + * NAN_PROPERTY_DELETER + * NAN_PROPERTY_QUERY + * NAN_INDEX_GETTER + * NAN_INDEX_SETTER + * NAN_INDEX_ENUMERATOR + * NAN_INDEX_DELETER + * NAN_INDEX_QUERY + * NAN_GC_CALLBACK + * NAN_WEAK_CALLBACK + * NAN_DEPRECATED + * NAN_INLINE + * NanNew + * NanUndefined + * NanNull + * NanTrue + * NanFalse + * NanReturnValue + * NanReturnUndefined + * NanReturnNull + * NanReturnEmptyString + * NanReturnThis + * NanReturnHolder + * NanScope + * NanEscapableScope + * NanEscapeScope + * NanLocker + * NanUnlocker + * NanGetInternalFieldPointer + * NanSetInternalFieldPointer + * NanObjectWrapHandle + * NanSymbol + * NanGetPointerSafe + * NanSetPointerSafe + * NanRawString + * NanCString + * NanAsciiString + * NanUtf8String + * NanUcs2String + * NanBooleanOptionValue + * NanUInt32OptionValue + * NanError, NanTypeError, NanRangeError + * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int) + * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t) + * NanBufferUse(char *, uint32_t) + * NanNewContextHandle + * NanGetCurrentContext + * NanHasInstance + * NanDisposePersistent + * NanAssignPersistent + * NanMakeWeakPersistent + * NanSetTemplate + * NanSetPrototypeTemplate + * NanSetInstanceTemplate + * NanMakeCallback + * NanCompileScript + * NanRunScript + * NanAdjustExternalMemory + * NanAddGCEpilogueCallback + * NanAddGCPrologueCallback + * NanRemoveGCEpilogueCallback + * NanRemoveGCPrologueCallback + * NanGetHeapStatistics + * NanCallback + * NanAsyncWorker + * NanAsyncQueueWorker + + +### NAN_METHOD(methodname) + +Use `NAN_METHOD` to define your V8 accessible methods: + +```c++ +// .h: +class Foo : public node::ObjectWrap { + ... + + static NAN_METHOD(Bar); + static NAN_METHOD(Baz); +} + + +// .cc: +NAN_METHOD(Foo::Bar) { + ... +} + +NAN_METHOD(Foo::Baz) { + ... +} +``` + +The reason for this macro is because of the method signature change in 0.11: + +```c++ +// 0.10 and below: +Handle name(const Arguments& args) + +// 0.11 and above +void name(const FunctionCallbackInfo& args) +``` + +The introduction of `FunctionCallbackInfo` brings additional complications: + + +### NAN_GETTER(methodname) + +Use `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`. + + +### NAN_SETTER(methodname) + +Use `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with. + + +### NAN_PROPERTY_GETTER(cbname) +Use `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`. + + +### NAN_PROPERTY_SETTER(cbname) +Use `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with. + + +### NAN_PROPERTY_ENUMERATOR(cbname) +Use `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`. + + +### NAN_PROPERTY_DELETER(cbname) +Use `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`. + + +### NAN_PROPERTY_QUERY(cbname) +Use `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`. + + +### NAN_INDEX_GETTER(cbname) +Use `NAN_INDEX_GETTER` to declare your V8 accessible index getters. You get a `uint32_t` `index` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_GETTER`. + + +### NAN_INDEX_SETTER(cbname) +Use `NAN_INDEX_SETTER` to declare your V8 accessible index setters. Same as `NAN_INDEX_GETTER` but you also get a `Local` `value` object to work with. + + +### NAN_INDEX_ENUMERATOR(cbname) +Use `NAN_INDEX_ENUMERATOR` to declare your V8 accessible index enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_INDEX_GETTER` call. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_ENUMERATOR`. + + +### NAN_INDEX_DELETER(cbname) +Use `NAN_INDEX_DELETER` to declare your V8 accessible index deleters. Same as `NAN_INDEX_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_DELETER`. + + +### NAN_INDEX_QUERY(cbname) +Use `NAN_INDEX_QUERY` to declare your V8 accessible index queries. Same as `NAN_INDEX_GETTER`. + +You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_QUERY`. + + +### NAN_GC_CALLBACK(cbname) +Use `NAN_GC_CALLBACK` to declare your callbacks for `NanAddGCEpilogueCallback` and `NanAddGCPrologueCallback`. You get arguments `GCType type` and `GCCallbackFlags flags`. + +```c++ +static Persistent callback; + +NAN_GC_CALLBACK(gcPrologueCallback) { + Local argv[] = {NanNew("prologue")}; + NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(callback), 1, argv); +} + +NAN_METHOD(Hook) { + NanScope(); + NanAssignPersistent(callback, args[0].As()); + NanAddGCPrologueCallback(gcPrologueCallback); + NanReturnValue(args.Holder()); +} +``` + + +### NAN_WEAK_CALLBACK(cbname) + +Use `NAN_WEAK_CALLBACK` to define your V8 WeakReference callbacks. There is an argument object `const _NanWeakCallbackData &data` allowing access to the weak object and the supplied parameter through its `GetValue` and `GetParameter` methods. You can even access the weak callback info object through the `GetCallbackInfo()`method, but you probably should not. `Revive()` keeps the weak object alive until the next GC round. + +```c++ +NAN_WEAK_CALLBACK(weakCallback) { + int *parameter = data.GetParameter(); + NanMakeCallback(NanGetCurrentContext()->Global(), data.GetValue(), 0, NULL); + if ((*parameter)++ == 0) { + data.Revive(); + } else { + delete parameter; + } +} +``` + + +### NAN_DEPRECATED +Declares a function as deprecated. + +```c++ +static NAN_DEPRECATED NAN_METHOD(foo) { + ... +} +``` + + +### NAN_INLINE +Inlines a function. + +```c++ +NAN_INLINE int foo(int bar) { + ... +} +``` + + +### Local<T> NanNew<T>( ... ) + +Use `NanNew` to construct almost all v8 objects (bound `Script`s are constructed with `NanCompileScript(Handle)`) and make new local handles. + +```c++ +Local s = NanNew("value"); + +... + +Persistent o; + +... + +Local lo = NanNew(o); + +``` + + +### Local<Primitive> NanUndefined() + +Use instead of `Undefined()` + + +### Local<Primitive> NanNull() + +Use instead of `Null()` + + +### Local<Boolean> NanTrue() + +Use instead of `True()` + + +### Local<Boolean> NanFalse() + +Use instead of `False()` + + +### NanReturnValue(Handle<Value>) + +Use `NanReturnValue` when you want to return a value from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Bar) { + ... + + NanReturnValue(NanNew("FooBar!")); +} +``` + +No `return` statement required. + + +### NanReturnUndefined() + +Use `NanReturnUndefined` when you don't want to return anything from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnUndefined(); +} +``` + + +### NanReturnNull() + +Use `NanReturnNull` when you want to return `Null` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnNull(); +} +``` + + +### NanReturnEmptyString() + +Use `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnEmptyString(); +} +``` + + +### NanReturnThis() + +Use `NanReturnThis` when you want to return `This` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnThis(); +} +``` + + +### NanReturnHolder() + +Use `NanReturnHolder` when you want to return `Holder` from your V8 accessible method: + +```c++ +NAN_METHOD(Foo::Baz) { + ... + + NanReturnHolder(); +} +``` + + +### NanScope() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope` when you do not wish to return handles (`Handle` or `Local`) to the surrounding scope (or in functions directly exposed to V8, as they do not return values in the normal sense): + +```c++ +NAN_METHOD(Foo::Bar) { + NanScope(); + + NanReturnValue(NanNew("FooBar!")); +} +``` + +This method is not directly exposed to V8, nor does it return a handle, so it uses an unescapable scope: + +```c++ +bool Foo::Bar() { + NanScope(); + + Local val = NanFalse(); + ... + return val->Value(); +} +``` + + +### NanEscapableScope() + +The separation of handle scopes into escapable and inescapable scopes makes `NanEscapableScope()` necessary, use it in place of `HandleScope scope` when you later wish to return a handle (`Handle` or `Local`) from the scope, this is for internal functions not directly exposed to V8: + +```c++ +Handle Foo::Bar() { + NanEscapableScope(); + + return NanEscapeScope(NanNew("FooBar!")); +} +``` + + +### Local<T> NanEscapeScope(Handle<T> value); +Use together with `NanEscapableScope` to escape the scope. Corresponds to `HandleScope::Close` or `EscapableHandleScope::Escape`. + + +### NanLocker() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`: + +```c++ +NAN_METHOD(Foo::Bar) { + NanLocker(); + ... + NanUnlocker(); +} +``` + + +### NanUnlocker() + +The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`: + +```c++ +NAN_METHOD(Foo::Bar) { + NanLocker(); + ... + NanUnlocker(); +} +``` + + +### void * NanGetInternalFieldPointer(Handle<Object>, int) + +Gets a pointer to the internal field with at `index` from a V8 `Object` handle. + +```c++ +Local obj; +... +NanGetInternalFieldPointer(obj, 0); +``` + +### void NanSetInternalFieldPointer(Handle<Object>, int, void *) + +Sets the value of the internal field at `index` on a V8 `Object` handle. + +```c++ +static Persistent dataWrapperCtor; +... +Local wrapper = NanNew(dataWrapperCtor)->NewInstance(); +NanSetInternalFieldPointer(wrapper, 0, this); +``` + + +### Local<Object> NanObjectWrapHandle(Object) + +When you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`: + +```c++ +NanObjectWrapHandle(iterator)->Get(NanNew("end")) +``` + + +### ~~Local<String> NanSymbol(const char *)~~ + +Deprecated. Use `NanNew` instead. +~~Use to create string symbol objects (i.e. `v8::String::NewSymbol(x)`), for getting and setting object properties, or names of objects.~~ + +```c++ +bool foo = false; +if (obj->Has(NanNew("foo"))) + foo = optionsObj->Get(NanNew("foo"))->BooleanValue() +``` + + +### Type NanGetPointerSafe(Type *[, Type]) + +A helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to. + +```c++ +char *plugh(uint32_t *optional) { + char res[] = "xyzzy"; + uint32_t param = NanGetPointerSafe(optional, 0x1337); + switch (param) { + ... + } + NanSetPointerSafe(optional, 0xDEADBEEF); +} +``` + + +### bool NanSetPointerSafe(Type *, Type) + +A helper for setting optional argument pointers. If the pointer is `NULL`, the function simply returns `false`. Otherwise, the value is assigned to the variable the pointer points to. + +```c++ +const char *plugh(size_t *outputsize) { + char res[] = "xyzzy"; + if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) { + ... + } + + ... +} +``` + + +### ~~void* NanRawString(Handle<Value>, enum Nan::Encoding, size_t *, void *, size_t, int)~~ + +Deprecated. Use something else. + +~~When you want to convert a V8 `String` to a `char*` buffer, use `NanRawString`. You have to supply an encoding as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows setting `String::WriteOptions`. +Just remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~ + +```c++ +size_t count; +void* decoded = NanRawString(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED); +... +delete[] reinterpret_cast(decoded); +``` + + +### ~~char* NanCString(Handle<Value>, size_t *[, char *, size_t, int])~~ + +Deprecated. Use `String::Utf8Value` or `NanUtf8String` instead. + +~~When you want to convert a V8 `String` to a null-terminated C `char*` use `NanCString`. The resulting `char*` will be UTF-8-encoded, and you need to supply a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `v8::String::NO_OPTIONS`. +Just remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~ + +```c++ +size_t count; +char* name = NanCString(args[0], &count); +... +delete[] name; +``` + + +### NanAsciiString + +Contrary to the name, this is not actually an ASCII string, it is a one-byte string with no particular encoding. Do not use unless you actually need this incorrect legacy behavior. Consider fixing your broken code instead. If you actually have a proper ASCII-string, use UTF-8, which is a proper superset of ASCII. +Convert a `String` to zero-terminated, sort-of Ascii-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. + +```c++ +NAN_METHOD(foo) { + NanScope(); + NanReturnValue(NanNew(*NanAsciiString(arg[0]))); +} +``` + +####*WRONG*: +the buffer `str` points to has been freed when `baz` was destroyed: +```c++ +static char *str; + +NAN_METHOD(bar) { + NanScope(); + NanAsciiString baz(arg[0]); + + str = *baz; + NanReturnUndefined(); // baz goes out of scope, freeing str +} + +... + +printf(str); // use-after-free error +``` + +####*RIGHT*: +```c++ +static NanAsciiString *str; + +NAN_METHOD(bar) { + NanScope(); + str = new NanAsciiString(arg[0]); + NanReturnUndefined(); +} + +... + +printf(**str); +``` + + +### NanUtf8String + +Equivalent to `String::Utf8Value`, it only exists for the sake of completeness. +Convert a `String` to zero-terminated, Utf8-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. + +```c++ +NAN_METHOD(foo) { + NanScope(); + NanReturnValue(NanNew(*NanUtf8String(arg[0]))); +} +``` + +####*WRONG*: +the buffer `str` points to has been freed when `baz` was destroyed: +```c++ +static char *str; + +NAN_METHOD(bar) { + NanScope(); + NanUtf8String baz(arg[0]); + + str = *baz; + NanReturnUndefined(); // baz goes out of scope, freeing str +} + +... + +printf(str); // use-after-free error +``` + +####*RIGHT*: +```c++ +static NanUtf8String *str; + +NAN_METHOD(bar) { + NanScope(); + str = new NanUtf8String(arg[0]); + NanReturnUndefined(); +} + +... + +printf(**str); +``` + + + +### NanUcs2String + +Equivalent to `String::Value`, it only exists for the sake of completeness. +Convert a `String` to zero-terminated, Ucs2-encoded `uint16_t *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. + +```c++ +NAN_METHOD(foo) { + NanScope(); + NanReturnValue(NanNew(*NanUcs2String(arg[0]))); +} +``` + +####*WRONG*: +the buffer `str` points to has been freed when `baz` was destroyed: +```c++ +static char *str; + +NAN_METHOD(bar) { + NanScope(); + NanUcs2String baz(arg[0]); + + str = *baz; + NanReturnUndefined(); // baz goes out of scope, freeing str +} + +... + +printf(str); // use-after-free error +``` + +####*RIGHT*: +```c++ +static NanUcs2String *str; + +NAN_METHOD(bar) { + NanScope(); + str = new NanUcs2String(arg[0]); + NanReturnUndefined(); +} + +... + +printf(**str); +``` + + +### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool]) + +When you have an "options" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`. + +The optional last parameter is the *default* value, which is `false` if left off: + +```c++ +// `foo` is false unless the user supplies a truthy value for it +bool foo = NanBooleanOptionValue(optionsObj, NanNew("foo")); +// `bar` is true unless the user supplies a falsy value for it +bool bar = NanBooleanOptionValueDefTrue(optionsObj, NanNew("bar"), true); +``` + + +### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t) + +Similar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer. + +Requires all 3 arguments as a default is not optional: + +```c++ +uint32_t count = NanUInt32OptionValue(optionsObj, NanNew("count"), 1024); +``` + + +### NanError(message), NanTypeError(message), NanRangeError(message) + +For making `Error`, `TypeError` and `RangeError` objects. + +```c++ +Local res = NanError("you must supply a callback argument"); +``` + + +### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int) + +For throwing `Error`, `TypeError` and `RangeError` objects. + +```c++ +NanThrowError("you must supply a callback argument"); +``` + +Can also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`. + + +### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t) + +The `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation: + +```c++ +NanNewBufferHandle((char*)value.data(), value.size()); +``` + +Can also be used to initialize a `Buffer` with just a `size` argument. + +Can also be supplied with a `NanFreeCallback` and a hint for the garbage collector. + + +### Local<Object> NanBufferUse(char*, uint32_t) + +`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data. +While it was possible to get around this, it required a shim by passing a +callback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove +needing to use this shim. + +`NanBufferUse` uses the `char*` passed as the backing data, and will free the +memory automatically when the weak callback is called. Keep this in mind, as +careless use can lead to "double free or corruption" and other cryptic failures. + + +### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>) + +Can be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for. + + +### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>]) +Creates a new `Local` handle. + +```c++ +Local ftmpl = NanNew(); +Local otmpl = ftmpl->InstanceTemplate(); +Local ctx = NanNewContextHandle(NULL, otmpl); +``` + + +### Local<Context> NanGetCurrentContext() + +Gets the current context. + +```c++ +Local ctx = NanGetCurrentContext(); +``` + + +### void NanDisposePersistent(Persistent<T> &) + +Use `NanDisposePersistent` to dispose a `Persistent` handle. + +```c++ +NanDisposePersistent(persistentHandle); +``` + + +### NanAssignPersistent(handle, object) + +Use `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier. + +In general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`: + +```c++ +Persistent persistentHandle; + +... + +Local obj = NanNew(); +obj->Set(NanNew("key"), keyHandle); // where keyHandle might be a Local +NanAssignPersistent(persistentHandle, obj) +``` + + +### _NanWeakCallbackInfo<T, P>* NanMakeWeakPersistent(Handle<T>, P*, _NanWeakCallbackInfo<T, P>::Callback) + +Creates a weak persistent handle with the supplied parameter and `NAN_WEAK_CALLBACK`. + +```c++ +NAN_WEAK_CALLBACK(weakCallback) { + +... + +} + +Local func; + +... + +int *parameter = new int(0); +NanMakeWeakPersistent(func, parameter, &weakCallback); +``` + + +### NanSetTemplate(templ, name, value [, attributes]) + +Use to add properties on object and function templates. + + +### NanSetPrototypeTemplate(templ, name, value [, attributes]) + +Use to add prototype properties on function templates. + + +### NanSetInstanceTemplate(templ, name, value [, attributes]) + +Use to add instance properties on function templates. + + +### NanMakeCallback(target, func, argc, argv) + +Use instead of `node::MakeCallback` to call javascript functions. This (or `NanCallback`) is the only proper way of calling functions. You must _*never, ever*_ directly use `Function::Call`, it will lead to run-time failures. + + +### NanCompileScript(Handle s [, const ScriptOrigin& origin]) + +Use to create new scripts bound to the current context. + + +### NanRunScript(script) + +Use to run both bound and unbound scripts. + + +### NanAdjustExternalMemory(int change_in_bytes) + +Simply does `AdjustAmountOfExternalAllocatedMemory`, note that the argument and returned value have type `int`. + + +### NanAddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll) + +Simply does `AddGCEpilogueCallback` + + +### NanAddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll) + +Simply does `AddGCPrologueCallback` + + +### NanRemoveGCEpilogueCallback(GCEpilogueCallback callback) + +Simply does `RemoveGCEpilogueCallback` + + +### NanRemoveGCPrologueCallback(GCPrologueCallback callback) + +Simply does `RemoveGCPrologueCallback` + + +### NanGetHeapStatistics(HeapStatistics *heap_statistics) + +Simply does `GetHeapStatistics` + + +### NanCallback + +Because of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Handle` is annoyingly tricky. `NanCallback` makes it easier by taking your handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`. + +```c++ +Local callbackHandle = args[0].As(); +NanCallback *callback = new NanCallback(callbackHandle); +// pass `callback` around and it's safe from GC until you: +delete callback; +``` + +You can execute the callback like so: + +```c++ +// no arguments: +callback->Call(0, NULL); + +// an error argument: +Handle argv[] = { + NanError(NanNew("fail!")) +}; +callback->Call(1, argv); + +// a success argument: +Handle argv[] = { + NanNull(), + NanNew("w00t!") +}; +callback->Call(2, argv); +``` + +`NanCallback` also has a `Local GetFunction()` method that you can use +to fetch a local handle to the underlying callback function, as well as a +`void SetFunction(Handle)` for setting the callback on the +`NanCallback`. You can check if a `NanCallback` is empty with the `bool IsEmpty()` method. Additionally a generic constructor is available for using +`NanCallback` without performing heap allocations. + + +### NanAsyncWorker + +`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress. + +See a rough outline of the implementation: + +```c++ +class NanAsyncWorker { +public: + NanAsyncWorker (NanCallback *callback); + + // Clean up persistent handles and delete the *callback + virtual ~NanAsyncWorker (); + + // Check the `ErrorMessage()` and call HandleOKCallback() + // or HandleErrorCallback depending on whether it has been set or not + virtual void WorkComplete (); + + // You must implement this to do some async work. If there is an + // error then use `SetErrorMessage()` to set an error message and the callback will + // be passed that string in an Error object + virtual void Execute (); + + // Save a V8 object in a Persistent handle to protect it from GC + void SaveToPersistent(const char *key, Local &obj); + + // Fetch a stored V8 object (don't call from within `Execute()`) + Local GetFromPersistent(const char *key); + + // Get the error message (or NULL) + const char *ErrorMessage(); + + // Set an error message + void SetErrorMessage(const char *msg); + +protected: + // Default implementation calls the callback function with no arguments. + // Override this to return meaningful data + virtual void HandleOKCallback (); + + // Default implementation calls the callback function with an Error object + // wrapping the `errmsg` string + virtual void HandleErrorCallback (); +}; +``` + + +### NanAsyncQueueWorker(NanAsyncWorker *) + +`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`. + + +### Tests + +To run the NAN tests do: + +``` sh +npm install +npm run-script rebuild-tests +npm test +``` + +Or just: + +``` sh +npm install +make test +``` + +### Contributors + +NAN is only possible due to the excellent work of the following contributors: + + + + + + + + + +
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnat-
+ +Licence & copyright +----------------------- + +Copyright (c) 2015 NAN contributors (listed above). + +Native Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/scripts/external/three/canvas/node_modules/nan/appveyor.yml b/scripts/external/three/canvas/node_modules/nan/appveyor.yml new file mode 100644 index 0000000..8a331b4 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/appveyor.yml @@ -0,0 +1,35 @@ +# http://www.appveyor.com/docs/appveyor-yml + +# Test against these versions of Node.js. +environment: + matrix: + # node.js + - nodejs_version: "0.8" + - nodejs_version: "0.10" + - nodejs_version: "0.11" + # io.js + - nodejs_version: "1.0" + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node 0.STABLE.latest + - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) + - IF NOT %nodejs_version% == 1.0 npm -g install npm + - IF NOT %nodejs_version% == 1.0 set PATH=%APPDATA%\npm;%PATH% + # Typical npm stuff. + - npm install + - npm run rebuild-tests + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - npm test + +# Don't actually build. +build: off + +# Set build version format here instead of in the admin panel. +version: "{build}" diff --git a/scripts/external/three/canvas/node_modules/nan/include_dirs.js b/scripts/external/three/canvas/node_modules/nan/include_dirs.js new file mode 100644 index 0000000..4f1dfb4 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/include_dirs.js @@ -0,0 +1 @@ +console.log(require('path').relative('.', __dirname)); diff --git a/scripts/external/three/canvas/node_modules/nan/nan.h b/scripts/external/three/canvas/node_modules/nan/nan.h new file mode 100644 index 0000000..531b3ac --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/nan.h @@ -0,0 +1,2038 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2015 NAN contributors: + * - Rod Vagg + * - Benjamin Byholm + * - Trevor Norris + * - Nathan Rajlich + * - Brett Lawson + * - Ben Noordhuis + * - David Siegel + * + * MIT License + * + * Version 1.5.2: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3 + * + * See https://github.com/rvagg/nan for the latest update to this file + **********************************************************************************/ + +#ifndef NAN_H_ +#define NAN_H_ + +#include +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +# pragma warning( disable : 4530 ) +# include +# pragma warning( default : 4530 ) +#else +# include +#endif + +#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) +# define NAN_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) +# define NAN_INLINE __forceinline +#else +# define NAN_INLINE inline +#endif + +#if defined(__GNUC__) && \ + !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) +# define NAN_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) && \ + !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) +# define NAN_DEPRECATED __declspec(deprecated) +#else +# define NAN_DEPRECATED +#endif + +#if (NODE_MODULE_VERSION < 12) +typedef v8::InvocationCallback NanFunctionCallback; +typedef v8::Script NanUnboundScript; +typedef v8::Script NanBoundScript; +#else +typedef v8::FunctionCallback NanFunctionCallback; +typedef v8::UnboundScript NanUnboundScript; +typedef v8::Script NanBoundScript; +#endif + +#if (NODE_MODULE_VERSION < 42) +typedef v8::String::ExternalAsciiStringResource + NanExternalOneByteStringResource; +#else // io.js v1.0.0 +typedef v8::String::ExternalOneByteStringResource + NanExternalOneByteStringResource; +#endif + +#include "nan_new.h" // NOLINT(build/include) + +// uv helpers +#ifdef UV_VERSION_MAJOR +#ifndef UV_VERSION_PATCH +#define UV_VERSION_PATCH 0 +#endif +#define NAUV_UVVERSION ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) +#else +#define NAUV_UVVERSION 0x000b00 +#endif + + +#if NAUV_UVVERSION < 0x000b17 +#define NAUV_WORK_CB(func) \ + void func(uv_async_t *async, int) +#else +#define NAUV_WORK_CB(func) \ + void func(uv_async_t *async) +#endif + +// some generic helpers + +template NAN_INLINE bool NanSetPointerSafe( + T *var + , T val +) { + if (var) { + *var = val; + return true; + } else { + return false; + } +} + +template NAN_INLINE T NanGetPointerSafe( + T *var + , T fallback = reinterpret_cast(0) +) { + if (var) { + return *var; + } else { + return fallback; + } +} + +NAN_INLINE bool NanBooleanOptionValue( + v8::Local optionsObj + , v8::Handle opt, bool def +) { + if (def) { + return optionsObj.IsEmpty() + || !optionsObj->Has(opt) + || optionsObj->Get(opt)->BooleanValue(); + } else { + return !optionsObj.IsEmpty() + && optionsObj->Has(opt) + && optionsObj->Get(opt)->BooleanValue(); + } +} + +NAN_INLINE bool NanBooleanOptionValue( + v8::Local optionsObj + , v8::Handle opt +) { + return NanBooleanOptionValue(optionsObj, opt, false); +} + +NAN_INLINE uint32_t NanUInt32OptionValue( + v8::Local optionsObj + , v8::Handle opt + , uint32_t def +) { + return !optionsObj.IsEmpty() + && optionsObj->Has(opt) + && optionsObj->Get(opt)->IsNumber() + ? optionsObj->Get(opt)->Uint32Value() + : def; +} + +template +v8::Local NanNew(v8::Handle); + +template +NAN_INLINE v8::Local _NanEnsureLocal(v8::Handle val) { + return NanNew(val); +} + +template +NAN_INLINE v8::Local _NanEnsureLocal(v8::Local val) { + return val; +} + +#if (NODE_MODULE_VERSION > 0x000B) +// Node 0.11+ (0.11.12 and below won't compile with these) + +# define _NAN_METHOD_ARGS_TYPE const v8::FunctionCallbackInfo& +# define _NAN_METHOD_ARGS _NAN_METHOD_ARGS_TYPE args +# define _NAN_METHOD_RETURN_TYPE void + +# define _NAN_GETTER_ARGS_TYPE const v8::PropertyCallbackInfo& +# define _NAN_GETTER_ARGS _NAN_GETTER_ARGS_TYPE args +# define _NAN_GETTER_RETURN_TYPE void + +# define _NAN_SETTER_ARGS_TYPE const v8::PropertyCallbackInfo& +# define _NAN_SETTER_ARGS _NAN_SETTER_ARGS_TYPE args +# define _NAN_SETTER_RETURN_TYPE void + +# define _NAN_PROPERTY_GETTER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_PROPERTY_GETTER_ARGS _NAN_PROPERTY_GETTER_ARGS_TYPE args +# define _NAN_PROPERTY_GETTER_RETURN_TYPE void + +# define _NAN_PROPERTY_SETTER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_PROPERTY_SETTER_ARGS _NAN_PROPERTY_SETTER_ARGS_TYPE args +# define _NAN_PROPERTY_SETTER_RETURN_TYPE void + +# define _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_PROPERTY_ENUMERATOR_ARGS _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE args +# define _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE void + +# define _NAN_PROPERTY_DELETER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_PROPERTY_DELETER_ARGS \ + _NAN_PROPERTY_DELETER_ARGS_TYPE args +# define _NAN_PROPERTY_DELETER_RETURN_TYPE void + +# define _NAN_PROPERTY_QUERY_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_PROPERTY_QUERY_ARGS _NAN_PROPERTY_QUERY_ARGS_TYPE args +# define _NAN_PROPERTY_QUERY_RETURN_TYPE void + +# define _NAN_INDEX_GETTER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_INDEX_GETTER_ARGS _NAN_INDEX_GETTER_ARGS_TYPE args +# define _NAN_INDEX_GETTER_RETURN_TYPE void + +# define _NAN_INDEX_SETTER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_INDEX_SETTER_ARGS _NAN_INDEX_SETTER_ARGS_TYPE args +# define _NAN_INDEX_SETTER_RETURN_TYPE void + +# define _NAN_INDEX_ENUMERATOR_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_INDEX_ENUMERATOR_ARGS _NAN_INDEX_ENUMERATOR_ARGS_TYPE args +# define _NAN_INDEX_ENUMERATOR_RETURN_TYPE void + +# define _NAN_INDEX_DELETER_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_INDEX_DELETER_ARGS _NAN_INDEX_DELETER_ARGS_TYPE args +# define _NAN_INDEX_DELETER_RETURN_TYPE void + +# define _NAN_INDEX_QUERY_ARGS_TYPE \ + const v8::PropertyCallbackInfo& +# define _NAN_INDEX_QUERY_ARGS _NAN_INDEX_QUERY_ARGS_TYPE args +# define _NAN_INDEX_QUERY_RETURN_TYPE void + +# define NanScope() v8::HandleScope scope(v8::Isolate::GetCurrent()) +# define NanEscapableScope() \ + v8::EscapableHandleScope scope(v8::Isolate::GetCurrent()) + +# define NanEscapeScope(val) scope.Escape(_NanEnsureLocal(val)) +# define NanLocker() v8::Locker locker(v8::Isolate::GetCurrent()) +# define NanUnlocker() v8::Unlocker unlocker(v8::Isolate::GetCurrent()) +# define NanReturnValue(value) return args.GetReturnValue().Set(value) +# define NanReturnUndefined() return +# define NanReturnHolder() NanReturnValue(args.Holder()) +# define NanReturnThis() NanReturnValue(args.This()) +# define NanReturnNull() return args.GetReturnValue().SetNull() +# define NanReturnEmptyString() return args.GetReturnValue().SetEmptyString() + +# define NanObjectWrapHandle(obj) obj->handle() + + NAN_INLINE v8::Local NanUndefined() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::Undefined(v8::Isolate::GetCurrent()))); + } + + NAN_INLINE v8::Local NanNull() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::Null(v8::Isolate::GetCurrent()))); + } + + NAN_INLINE v8::Local NanTrue() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::True(v8::Isolate::GetCurrent()))); + } + + NAN_INLINE v8::Local NanFalse() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::False(v8::Isolate::GetCurrent()))); + } + + NAN_INLINE int NanAdjustExternalMemory(int bc) { + return static_cast( + v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(bc)); + } + + NAN_INLINE void NanSetTemplate( + v8::Handle templ + , const char *name + , v8::Handle value) { + templ->Set(v8::Isolate::GetCurrent(), name, value); + } + + NAN_INLINE void NanSetTemplate( + v8::Handle templ + , v8::Handle name + , v8::Handle value + , v8::PropertyAttribute attributes) { + templ->Set(name, value, attributes); + } + + NAN_INLINE v8::Local NanGetCurrentContext() { + return v8::Isolate::GetCurrent()->GetCurrentContext(); + } + + NAN_INLINE void* NanGetInternalFieldPointer( + v8::Handle object + , int index) { + return object->GetAlignedPointerFromInternalField(index); + } + + NAN_INLINE void NanSetInternalFieldPointer( + v8::Handle object + , int index + , void* value) { + object->SetAlignedPointerInInternalField(index, value); + } + +# define NAN_GC_CALLBACK(name) \ + void name(v8::Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags) + + NAN_INLINE void NanAddGCEpilogueCallback( + v8::Isolate::GCEpilogueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::Isolate::GetCurrent()->AddGCEpilogueCallback(callback, gc_type_filter); + } + + NAN_INLINE void NanRemoveGCEpilogueCallback( + v8::Isolate::GCEpilogueCallback callback) { + v8::Isolate::GetCurrent()->RemoveGCEpilogueCallback(callback); + } + + NAN_INLINE void NanAddGCPrologueCallback( + v8::Isolate::GCPrologueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::Isolate::GetCurrent()->AddGCPrologueCallback(callback, gc_type_filter); + } + + NAN_INLINE void NanRemoveGCPrologueCallback( + v8::Isolate::GCPrologueCallback callback) { + v8::Isolate::GetCurrent()->RemoveGCPrologueCallback(callback); + } + + NAN_INLINE void NanGetHeapStatistics( + v8::HeapStatistics *heap_statistics) { + v8::Isolate::GetCurrent()->GetHeapStatistics(heap_statistics); + } + + NAN_DEPRECATED NAN_INLINE v8::Local NanSymbol( + const char* data, int length = -1) { + return NanNew(data, length); + } + + template + NAN_INLINE void NanAssignPersistent( + v8::Persistent& handle + , v8::Handle obj) { + handle.Reset(v8::Isolate::GetCurrent(), obj); + } + + template + NAN_INLINE void NanAssignPersistent( + v8::Persistent& handle + , const v8::Persistent& obj) { + handle.Reset(v8::Isolate::GetCurrent(), obj); + } + + template + class _NanWeakCallbackData; + + template + struct _NanWeakCallbackInfo { + typedef void (*Callback)(const _NanWeakCallbackData& data); + NAN_INLINE _NanWeakCallbackInfo(v8::Handle handle, P* param, Callback cb) + : parameter(param), callback(cb) { + NanAssignPersistent(persistent, handle); + } + + NAN_INLINE ~_NanWeakCallbackInfo() { + persistent.Reset(); + } + + P* const parameter; + Callback const callback; + v8::Persistent persistent; + }; + + template + class _NanWeakCallbackData { + public: + NAN_INLINE _NanWeakCallbackData(_NanWeakCallbackInfo *info) + : info_(info) { } + + NAN_INLINE v8::Local GetValue() const { + return NanNew(info_->persistent); + } + + NAN_INLINE P* GetParameter() const { return info_->parameter; } + + NAN_INLINE bool IsNearDeath() const { + return info_->persistent.IsNearDeath(); + } + + NAN_INLINE void Revive() const; + + NAN_INLINE _NanWeakCallbackInfo* GetCallbackInfo() const { + return info_; + } + + NAN_DEPRECATED NAN_INLINE void Dispose() const { + } + + private: + _NanWeakCallbackInfo* info_; + }; + + template + static void _NanWeakCallbackDispatcher( + const v8::WeakCallbackData > &data) { + _NanWeakCallbackInfo *info = data.GetParameter(); + _NanWeakCallbackData wcbd(info); + info->callback(wcbd); + if (wcbd.IsNearDeath()) { + delete wcbd.GetCallbackInfo(); + } + } + + template + NAN_INLINE void _NanWeakCallbackData::Revive() const { + info_->persistent.SetWeak(info_, &_NanWeakCallbackDispatcher); + } + +template +NAN_INLINE _NanWeakCallbackInfo* NanMakeWeakPersistent( + v8::Handle handle + , P* parameter + , typename _NanWeakCallbackInfo::Callback callback) { + _NanWeakCallbackInfo *cbinfo = + new _NanWeakCallbackInfo(handle, parameter, callback); + cbinfo->persistent.SetWeak(cbinfo, &_NanWeakCallbackDispatcher); + return cbinfo; +} + +# define NAN_WEAK_CALLBACK(name) \ + template \ + static void name(const _NanWeakCallbackData &data) + +# define _NAN_ERROR(fun, errmsg) fun(NanNew(errmsg)) + +# define _NAN_THROW_ERROR(fun, errmsg) \ + do { \ + NanScope(); \ + v8::Isolate::GetCurrent()->ThrowException(_NAN_ERROR(fun, errmsg)); \ + } while (0); + + NAN_INLINE v8::Local NanError(const char* errmsg) { + return _NAN_ERROR(v8::Exception::Error, errmsg); + } + + NAN_INLINE void NanThrowError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::Error, errmsg); + } + + NAN_INLINE void NanThrowError(v8::Handle error) { + NanScope(); + v8::Isolate::GetCurrent()->ThrowException(error); + } + + NAN_INLINE v8::Local NanError( + const char *msg + , const int errorNumber + ) { + v8::Local err = v8::Exception::Error(NanNew(msg)); + v8::Local obj = err.As(); + obj->Set(NanNew("code"), NanNew(errorNumber)); + return err; + } + + NAN_INLINE void NanThrowError( + const char *msg + , const int errorNumber + ) { + NanThrowError(NanError(msg, errorNumber)); + } + + NAN_INLINE v8::Local NanTypeError(const char* errmsg) { + return _NAN_ERROR(v8::Exception::TypeError, errmsg); + } + + NAN_INLINE void NanThrowTypeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); + } + + NAN_INLINE v8::Local NanRangeError(const char* errmsg) { + return _NAN_ERROR(v8::Exception::RangeError, errmsg); + } + + NAN_INLINE void NanThrowRangeError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); + } + + template NAN_INLINE void NanDisposePersistent( + v8::Persistent &handle + ) { + handle.Reset(); + } + + NAN_INLINE v8::Local NanNewBufferHandle ( + char *data + , size_t length + , node::smalloc::FreeCallback callback + , void *hint + ) { + return node::Buffer::New( + v8::Isolate::GetCurrent(), data, length, callback, hint); + } + + NAN_INLINE v8::Local NanNewBufferHandle ( + const char *data + , uint32_t size + ) { + return node::Buffer::New(v8::Isolate::GetCurrent(), data, size); + } + + NAN_INLINE v8::Local NanNewBufferHandle (uint32_t size) { + return node::Buffer::New(v8::Isolate::GetCurrent(), size); + } + + NAN_INLINE v8::Local NanBufferUse( + char* data + , uint32_t size + ) { + return node::Buffer::Use(v8::Isolate::GetCurrent(), data, size); + } + + NAN_INLINE bool NanHasInstance( + const v8::Persistent& function_template + , v8::Handle value + ) { + return NanNew(function_template)->HasInstance(value); + } + + NAN_INLINE v8::Local NanNewContextHandle( + v8::ExtensionConfiguration* extensions = NULL + , v8::Handle tmpl = v8::Handle() + , v8::Handle obj = v8::Handle() + ) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + return v8::Local::New( + isolate + , v8::Context::New(isolate, extensions, tmpl, obj) + ); + } + + NAN_INLINE v8::Local NanCompileScript( + v8::Local s + , const v8::ScriptOrigin& origin + ) { + v8::ScriptCompiler::Source source(s, origin); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); + } + + NAN_INLINE v8::Local NanCompileScript( + v8::Local s + ) { + v8::ScriptCompiler::Source source(s); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); + } + + NAN_INLINE v8::Local NanRunScript( + v8::Handle script + ) { + return script->BindToCurrentContext()->Run(); + } + + NAN_INLINE v8::Local NanRunScript( + v8::Handle script + ) { + return script->Run(); + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , v8::Handle func + , int argc + , v8::Handle* argv) { + return NanNew(node::MakeCallback( + v8::Isolate::GetCurrent(), target, func, argc, argv)); + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , v8::Handle symbol + , int argc + , v8::Handle* argv) { + return NanNew(node::MakeCallback( + v8::Isolate::GetCurrent(), target, symbol, argc, argv)); + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , const char* method + , int argc + , v8::Handle* argv) { + return NanNew(node::MakeCallback( + v8::Isolate::GetCurrent(), target, method, argc, argv)); + } + + template + NAN_INLINE void NanSetIsolateData( + v8::Isolate *isolate + , T *data + ) { + isolate->SetData(0, data); + } + + template + NAN_INLINE T *NanGetIsolateData( + v8::Isolate *isolate + ) { + return static_cast(isolate->GetData(0)); + } + + class NanAsciiString { + public: + NAN_INLINE explicit NanAsciiString(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Length(); + buf = new char[size + 1]; + size = toStr->WriteOneByte(reinterpret_cast(buf)); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + + NAN_INLINE char* operator*() { return buf; } + NAN_INLINE const char* operator*() const { return buf; } + + NAN_INLINE ~NanAsciiString() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanAsciiString(const NanAsciiString&); + void operator=(const NanAsciiString&); + + char *buf; + int size; + }; + + class NanUtf8String { + public: + NAN_INLINE explicit NanUtf8String(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Utf8Length(); + buf = new char[size + 1]; + toStr->WriteUtf8(buf); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + NAN_INLINE char* operator*() { return buf; } + NAN_INLINE const char* operator*() const { return buf; } + + NAN_INLINE ~NanUtf8String() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanUtf8String(const NanUtf8String&); + void operator=(const NanUtf8String&); + + char *buf; + int size; + }; + + class NanUcs2String { + public: + NAN_INLINE explicit NanUcs2String(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Length(); + buf = new uint16_t[size + 1]; + toStr->Write(buf); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + NAN_INLINE uint16_t* operator*() { return buf; } + NAN_INLINE const uint16_t* operator*() const { return buf; } + + NAN_INLINE ~NanUcs2String() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanUcs2String(const NanUcs2String&); + void operator=(const NanUcs2String&); + + uint16_t *buf; + int size; + }; + +#else +// Node 0.8 and 0.10 + +# define _NAN_METHOD_ARGS_TYPE const v8::Arguments& +# define _NAN_METHOD_ARGS _NAN_METHOD_ARGS_TYPE args +# define _NAN_METHOD_RETURN_TYPE v8::Handle + +# define _NAN_GETTER_ARGS_TYPE const v8::AccessorInfo & +# define _NAN_GETTER_ARGS _NAN_GETTER_ARGS_TYPE args +# define _NAN_GETTER_RETURN_TYPE v8::Handle + +# define _NAN_SETTER_ARGS_TYPE const v8::AccessorInfo & +# define _NAN_SETTER_ARGS _NAN_SETTER_ARGS_TYPE args +# define _NAN_SETTER_RETURN_TYPE void + +# define _NAN_PROPERTY_GETTER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_PROPERTY_GETTER_ARGS _NAN_PROPERTY_GETTER_ARGS_TYPE args +# define _NAN_PROPERTY_GETTER_RETURN_TYPE v8::Handle + +# define _NAN_PROPERTY_SETTER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_PROPERTY_SETTER_ARGS _NAN_PROPERTY_SETTER_ARGS_TYPE args +# define _NAN_PROPERTY_SETTER_RETURN_TYPE v8::Handle + +# define _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_PROPERTY_ENUMERATOR_ARGS _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE args +# define _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE v8::Handle + +# define _NAN_PROPERTY_DELETER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_PROPERTY_DELETER_ARGS _NAN_PROPERTY_DELETER_ARGS_TYPE args +# define _NAN_PROPERTY_DELETER_RETURN_TYPE v8::Handle + +# define _NAN_PROPERTY_QUERY_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_PROPERTY_QUERY_ARGS _NAN_PROPERTY_QUERY_ARGS_TYPE args +# define _NAN_PROPERTY_QUERY_RETURN_TYPE v8::Handle + +# define _NAN_INDEX_GETTER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_INDEX_GETTER_ARGS _NAN_INDEX_GETTER_ARGS_TYPE args +# define _NAN_INDEX_GETTER_RETURN_TYPE v8::Handle + +# define _NAN_INDEX_SETTER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_INDEX_SETTER_ARGS _NAN_INDEX_SETTER_ARGS_TYPE args +# define _NAN_INDEX_SETTER_RETURN_TYPE v8::Handle + +# define _NAN_INDEX_ENUMERATOR_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_INDEX_ENUMERATOR_ARGS _NAN_INDEX_ENUMERATOR_ARGS_TYPE args +# define _NAN_INDEX_ENUMERATOR_RETURN_TYPE v8::Handle + +# define _NAN_INDEX_DELETER_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_INDEX_DELETER_ARGS _NAN_INDEX_DELETER_ARGS_TYPE args +# define _NAN_INDEX_DELETER_RETURN_TYPE v8::Handle + +# define _NAN_INDEX_QUERY_ARGS_TYPE const v8::AccessorInfo& +# define _NAN_INDEX_QUERY_ARGS _NAN_INDEX_QUERY_ARGS_TYPE args +# define _NAN_INDEX_QUERY_RETURN_TYPE v8::Handle + + NAN_DEPRECATED NAN_INLINE v8::Local NanSymbol( + const char* data, int length = -1) { + return v8::String::NewSymbol(data, length); + } + +# define NanScope() v8::HandleScope scope +# define NanEscapableScope() v8::HandleScope scope +# define NanEscapeScope(val) scope.Close(val) +# define NanLocker() v8::Locker locker +# define NanUnlocker() v8::Unlocker unlocker +# define NanReturnValue(value) return scope.Close(value) +# define NanReturnHolder() NanReturnValue(args.Holder()) +# define NanReturnThis() NanReturnValue(args.This()) +# define NanReturnUndefined() return v8::Undefined() +# define NanReturnNull() return v8::Null() +# define NanReturnEmptyString() return v8::String::Empty() +# define NanObjectWrapHandle(obj) v8::Local::New(obj->handle_) + + NAN_INLINE v8::Local NanUndefined() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::Undefined())); + } + + NAN_INLINE v8::Local NanNull() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::Null())); + } + + NAN_INLINE v8::Local NanTrue() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::True())); + } + + NAN_INLINE v8::Local NanFalse() { + NanEscapableScope(); + return NanEscapeScope(NanNew(v8::False())); + } + + NAN_INLINE int NanAdjustExternalMemory(int bc) { + return static_cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(bc)); + } + + NAN_INLINE void NanSetTemplate( + v8::Handle templ + , const char *name + , v8::Handle value) { + templ->Set(name, value); + } + + NAN_INLINE void NanSetTemplate( + v8::Handle templ + , v8::Handle name + , v8::Handle value + , v8::PropertyAttribute attributes) { + templ->Set(name, value, attributes); + } + + NAN_INLINE v8::Local NanGetCurrentContext() { + return v8::Context::GetCurrent(); + } + + NAN_INLINE void* NanGetInternalFieldPointer( + v8::Handle object + , int index) { + return object->GetPointerFromInternalField(index); + } + + NAN_INLINE void NanSetInternalFieldPointer( + v8::Handle object + , int index + , void* value) { + object->SetPointerInInternalField(index, value); + } + +# define NAN_GC_CALLBACK(name) \ + void name(v8::GCType type, v8::GCCallbackFlags flags) + + NAN_INLINE void NanAddGCEpilogueCallback( + v8::GCEpilogueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::V8::AddGCEpilogueCallback(callback, gc_type_filter); + } + NAN_INLINE void NanRemoveGCEpilogueCallback( + v8::GCEpilogueCallback callback) { + v8::V8::RemoveGCEpilogueCallback(callback); + } + NAN_INLINE void NanAddGCPrologueCallback( + v8::GCPrologueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::V8::AddGCPrologueCallback(callback, gc_type_filter); + } + NAN_INLINE void NanRemoveGCPrologueCallback( + v8::GCPrologueCallback callback) { + v8::V8::RemoveGCPrologueCallback(callback); + } + NAN_INLINE void NanGetHeapStatistics( + v8::HeapStatistics *heap_statistics) { + v8::V8::GetHeapStatistics(heap_statistics); + } + + template + NAN_INLINE void NanAssignPersistent( + v8::Persistent& handle + , v8::Handle obj) { + handle.Dispose(); + handle = v8::Persistent::New(obj); + } + + template + class _NanWeakCallbackData; + + template + struct _NanWeakCallbackInfo { + typedef void (*Callback)(const _NanWeakCallbackData &data); + NAN_INLINE _NanWeakCallbackInfo(v8::Handle handle, P* param, Callback cb) + : parameter(param) + , callback(cb) + , persistent(v8::Persistent::New(handle)) { } + + NAN_INLINE ~_NanWeakCallbackInfo() { + persistent.Dispose(); + persistent.Clear(); + } + + P* const parameter; + Callback const callback; + v8::Persistent persistent; + }; + + template + class _NanWeakCallbackData { + public: + NAN_INLINE _NanWeakCallbackData(_NanWeakCallbackInfo *info) + : info_(info) { } + + NAN_INLINE v8::Local GetValue() const { + return NanNew(info_->persistent); + } + + NAN_INLINE P* GetParameter() const { return info_->parameter; } + + NAN_INLINE bool IsNearDeath() const { + return info_->persistent.IsNearDeath(); + } + + NAN_INLINE void Revive() const; + + NAN_INLINE _NanWeakCallbackInfo* GetCallbackInfo() const { + return info_; + } + + NAN_DEPRECATED NAN_INLINE void Dispose() const { + } + + private: + _NanWeakCallbackInfo* info_; + }; + + template + static void _NanWeakPersistentDispatcher( + v8::Persistent object, void *data) { + _NanWeakCallbackInfo* info = + static_cast<_NanWeakCallbackInfo*>(data); + _NanWeakCallbackData wcbd(info); + info->callback(wcbd); + if (wcbd.IsNearDeath()) { + delete wcbd.GetCallbackInfo(); + } + } + + template + NAN_INLINE void _NanWeakCallbackData::Revive() const { + info_->persistent.MakeWeak( + info_ + , &_NanWeakPersistentDispatcher); + } + + template + NAN_INLINE _NanWeakCallbackInfo* NanMakeWeakPersistent( + v8::Handle handle + , P* parameter + , typename _NanWeakCallbackInfo::Callback callback) { + _NanWeakCallbackInfo *cbinfo = + new _NanWeakCallbackInfo(handle, parameter, callback); + cbinfo->persistent.MakeWeak( + cbinfo + , &_NanWeakPersistentDispatcher); + return cbinfo; + } + +# define NAN_WEAK_CALLBACK(name) \ + template \ + static void name(const _NanWeakCallbackData &data) + +# define _NAN_ERROR(fun, errmsg) \ + fun(v8::String::New(errmsg)) + +# define _NAN_THROW_ERROR(fun, errmsg) \ + do { \ + NanScope(); \ + return v8::Local::New( \ + v8::ThrowException(_NAN_ERROR(fun, errmsg))); \ + } while (0); + + NAN_INLINE v8::Local NanError(const char* errmsg) { + return _NAN_ERROR(v8::Exception::Error, errmsg); + } + + NAN_INLINE v8::Local NanThrowError(const char* errmsg) { + _NAN_THROW_ERROR(v8::Exception::Error, errmsg); + } + + NAN_INLINE v8::Local NanThrowError( + v8::Handle error + ) { + NanScope(); + return v8::Local::New(v8::ThrowException(error)); + } + + NAN_INLINE v8::Local NanError( + const char *msg + , const int errorNumber + ) { + v8::Local err = v8::Exception::Error(v8::String::New(msg)); + v8::Local obj = err.As(); + obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber)); + return err; + } + + NAN_INLINE v8::Local NanThrowError( + const char *msg + , const int errorNumber + ) { + return NanThrowError(NanError(msg, errorNumber)); + } + + NAN_INLINE v8::Local NanTypeError(const char* errmsg) { + return _NAN_ERROR(v8::Exception::TypeError, errmsg); + } + + NAN_INLINE v8::Local NanThrowTypeError( + const char* errmsg + ) { + _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); + } + + NAN_INLINE v8::Local NanRangeError( + const char* errmsg + ) { + return _NAN_ERROR(v8::Exception::RangeError, errmsg); + } + + NAN_INLINE v8::Local NanThrowRangeError( + const char* errmsg + ) { + _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); + } + + template + NAN_INLINE void NanDisposePersistent( + v8::Persistent &handle) { // NOLINT(runtime/references) + handle.Dispose(); + handle.Clear(); + } + + NAN_INLINE v8::Local NanNewBufferHandle ( + char *data + , size_t length + , node::Buffer::free_callback callback + , void *hint + ) { + return NanNew( + node::Buffer::New(data, length, callback, hint)->handle_); + } + + NAN_INLINE v8::Local NanNewBufferHandle ( + const char *data + , uint32_t size + ) { +#if NODE_MODULE_VERSION >= 0x000B + return NanNew(node::Buffer::New(data, size)->handle_); +#else + return NanNew( + node::Buffer::New(const_cast(data), size)->handle_); +#endif + } + + NAN_INLINE v8::Local NanNewBufferHandle (uint32_t size) { + return NanNew(node::Buffer::New(size)->handle_); + } + + NAN_INLINE void FreeData(char *data, void *hint) { + delete[] data; + } + + NAN_INLINE v8::Local NanBufferUse( + char* data + , uint32_t size + ) { + return NanNew( + node::Buffer::New(data, size, FreeData, NULL)->handle_); + } + + NAN_INLINE bool NanHasInstance( + const v8::Persistent& function_template + , v8::Handle value + ) { + return function_template->HasInstance(value); + } + + NAN_INLINE v8::Local NanNewContextHandle( + v8::ExtensionConfiguration* extensions = NULL + , v8::Handle tmpl = v8::Handle() + , v8::Handle obj = v8::Handle() + ) { + v8::Persistent ctx = v8::Context::New(extensions, tmpl, obj); + v8::Local lctx = NanNew(ctx); + ctx.Dispose(); + return lctx; + } + + NAN_INLINE v8::Local NanCompileScript( + v8::Local s + , const v8::ScriptOrigin& origin + ) { + return v8::Script::Compile(s, const_cast(&origin)); + } + + NAN_INLINE v8::Local NanCompileScript( + v8::Local s + ) { + return v8::Script::Compile(s); + } + + NAN_INLINE v8::Local NanRunScript(v8::Handle script) { + return script->Run(); + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , v8::Handle func + , int argc + , v8::Handle* argv) { +# if NODE_VERSION_AT_LEAST(0, 8, 0) + return NanNew(node::MakeCallback(target, func, argc, argv)); +# else + v8::TryCatch try_catch; + v8::Local result = func->Call(target, argc, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + return result; +# endif + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , v8::Handle symbol + , int argc + , v8::Handle* argv) { +# if NODE_VERSION_AT_LEAST(0, 8, 0) + return NanNew(node::MakeCallback(target, symbol, argc, argv)); +# else + v8::Local callback = target->Get(symbol).As(); + return NanMakeCallback(target, callback, argc, argv); +# endif + } + + NAN_INLINE v8::Local NanMakeCallback( + v8::Handle target + , const char* method + , int argc + , v8::Handle* argv) { +# if NODE_VERSION_AT_LEAST(0, 8, 0) + return NanNew(node::MakeCallback(target, method, argc, argv)); +# else + return NanMakeCallback(target, NanNew(method), argc, argv); +# endif + } + + template + NAN_INLINE void NanSetIsolateData( + v8::Isolate *isolate + , T *data + ) { + isolate->SetData(data); + } + + template + NAN_INLINE T *NanGetIsolateData( + v8::Isolate *isolate + ) { + return static_cast(isolate->GetData()); + } + + class NanAsciiString { + public: + NAN_INLINE explicit NanAsciiString(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Length(); + buf = new char[size + 1]; + size = toStr->WriteAscii(buf); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + + NAN_INLINE char* operator*() { return buf; } + NAN_INLINE const char* operator*() const { return buf; } + + NAN_INLINE ~NanAsciiString() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanAsciiString(const NanAsciiString&); + void operator=(const NanAsciiString&); + + char *buf; + int size; + }; + + class NanUtf8String { + public: + NAN_INLINE explicit NanUtf8String(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Utf8Length(); + buf = new char[size + 1]; + toStr->WriteUtf8(buf); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + NAN_INLINE char* operator*() { return buf; } + NAN_INLINE const char* operator*() const { return buf; } + + NAN_INLINE ~NanUtf8String() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanUtf8String(const NanUtf8String&); + void operator=(const NanUtf8String&); + + char *buf; + int size; + }; + + class NanUcs2String { + public: + NAN_INLINE explicit NanUcs2String(v8::Handle from) { + v8::Local toStr = from->ToString(); + size = toStr->Length(); + buf = new uint16_t[size + 1]; + toStr->Write(buf); + } + + NAN_DEPRECATED NAN_INLINE int Size() const { + return size; + } + + NAN_INLINE int length() const { + return size; + } + + NAN_INLINE uint16_t* operator*() { return buf; } + NAN_INLINE const uint16_t* operator*() const { return buf; } + + NAN_INLINE ~NanUcs2String() { + delete[] buf; + } + + private: + // disallow copying and assigning + NanUcs2String(const NanUcs2String&); + void operator=(const NanUcs2String&); + + uint16_t *buf; + int size; + }; + +#endif // NODE_MODULE_VERSION + +typedef void (*NanFreeCallback)(char *data, void *hint); + +#define NAN_METHOD(name) _NAN_METHOD_RETURN_TYPE name(_NAN_METHOD_ARGS) +#define NAN_GETTER(name) \ + _NAN_GETTER_RETURN_TYPE name( \ + v8::Local property \ + , _NAN_GETTER_ARGS) +#define NAN_SETTER(name) \ + _NAN_SETTER_RETURN_TYPE name( \ + v8::Local property \ + , v8::Local value \ + , _NAN_SETTER_ARGS) +#define NAN_PROPERTY_GETTER(name) \ + _NAN_PROPERTY_GETTER_RETURN_TYPE name( \ + v8::Local property \ + , _NAN_PROPERTY_GETTER_ARGS) +#define NAN_PROPERTY_SETTER(name) \ + _NAN_PROPERTY_SETTER_RETURN_TYPE name( \ + v8::Local property \ + , v8::Local value \ + , _NAN_PROPERTY_SETTER_ARGS) +#define NAN_PROPERTY_ENUMERATOR(name) \ + _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE name(_NAN_PROPERTY_ENUMERATOR_ARGS) +#define NAN_PROPERTY_DELETER(name) \ + _NAN_PROPERTY_DELETER_RETURN_TYPE name( \ + v8::Local property \ + , _NAN_PROPERTY_DELETER_ARGS) +#define NAN_PROPERTY_QUERY(name) \ + _NAN_PROPERTY_QUERY_RETURN_TYPE name( \ + v8::Local property \ + , _NAN_PROPERTY_QUERY_ARGS) +# define NAN_INDEX_GETTER(name) \ + _NAN_INDEX_GETTER_RETURN_TYPE name(uint32_t index, _NAN_INDEX_GETTER_ARGS) +#define NAN_INDEX_SETTER(name) \ + _NAN_INDEX_SETTER_RETURN_TYPE name( \ + uint32_t index \ + , v8::Local value \ + , _NAN_INDEX_SETTER_ARGS) +#define NAN_INDEX_ENUMERATOR(name) \ + _NAN_INDEX_ENUMERATOR_RETURN_TYPE name(_NAN_INDEX_ENUMERATOR_ARGS) +#define NAN_INDEX_DELETER(name) \ + _NAN_INDEX_DELETER_RETURN_TYPE name( \ + uint32_t index \ + , _NAN_INDEX_DELETER_ARGS) +#define NAN_INDEX_QUERY(name) \ + _NAN_INDEX_QUERY_RETURN_TYPE name(uint32_t index, _NAN_INDEX_QUERY_ARGS) + +class NanCallback { + public: + NanCallback() { + NanScope(); + v8::Local obj = NanNew(); + NanAssignPersistent(handle, obj); + } + + explicit NanCallback(const v8::Handle &fn) { + NanScope(); + v8::Local obj = NanNew(); + NanAssignPersistent(handle, obj); + SetFunction(fn); + } + + ~NanCallback() { + if (handle.IsEmpty()) return; + NanDisposePersistent(handle); + } + + NAN_INLINE void SetFunction(const v8::Handle &fn) { + NanScope(); + NanNew(handle)->Set(kCallbackIndex, fn); + } + + NAN_INLINE v8::Local GetFunction() const { + NanEscapableScope(); + return NanEscapeScope(NanNew(handle)->Get(kCallbackIndex) + .As()); + } + + NAN_INLINE bool IsEmpty() const { + NanScope(); + return NanNew(handle)->Get(kCallbackIndex)->IsUndefined(); + } + + v8::Handle Call(int argc, v8::Handle argv[]) const { + NanEscapableScope(); +#if (NODE_MODULE_VERSION > 0x000B) // 0.11.12+ + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local callback = NanNew(handle)-> + Get(kCallbackIndex).As(); + return NanEscapeScope(node::MakeCallback( + isolate + , isolate->GetCurrentContext()->Global() + , callback + , argc + , argv + )); +#else +#if NODE_VERSION_AT_LEAST(0, 8, 0) + v8::Local callback = handle-> + Get(kCallbackIndex).As(); + return NanEscapeScope(node::MakeCallback( + v8::Context::GetCurrent()->Global() + , callback + , argc + , argv + )); +#else + v8::Local callback = handle-> + Get(kCallbackIndex).As(); + return NanEscapeScope(NanMakeCallback( + v8::Context::GetCurrent()->Global(), callback, argc, argv)); +#endif +#endif + } + + private: + v8::Persistent handle; + static const uint32_t kCallbackIndex = 0; +}; + +/* abstract */ class NanAsyncWorker { + public: + explicit NanAsyncWorker(NanCallback *callback_) + : callback(callback_), errmsg_(NULL) { + request.data = this; + + NanScope(); + v8::Local obj = NanNew(); + NanAssignPersistent(persistentHandle, obj); + } + + virtual ~NanAsyncWorker() { + NanScope(); + + if (!persistentHandle.IsEmpty()) + NanDisposePersistent(persistentHandle); + if (callback) + delete callback; + if (errmsg_) + delete[] errmsg_; + } + + virtual void WorkComplete() { + NanScope(); + + if (errmsg_ == NULL) + HandleOKCallback(); + else + HandleErrorCallback(); + delete callback; + callback = NULL; + } + + NAN_INLINE void SaveToPersistent( + const char *key, const v8::Local &obj) { + v8::Local handle = NanNew(persistentHandle); + handle->Set(NanNew(key), obj); + } + + v8::Local GetFromPersistent(const char *key) const { + NanEscapableScope(); + v8::Local handle = NanNew(persistentHandle); + return NanEscapeScope(handle->Get(NanNew(key)).As()); + } + + virtual void Execute() = 0; + + uv_work_t request; + + virtual void Destroy() { + delete this; + } + + protected: + v8::Persistent persistentHandle; + NanCallback *callback; + + virtual void HandleOKCallback() { + callback->Call(0, NULL); + } + + virtual void HandleErrorCallback() { + NanScope(); + + v8::Local argv[] = { + v8::Exception::Error(NanNew(ErrorMessage())) + }; + callback->Call(1, argv); + } + + void SetErrorMessage(const char *msg) { + if (errmsg_) { + delete[] errmsg_; + } + + size_t size = strlen(msg) + 1; + errmsg_ = new char[size]; + memcpy(errmsg_, msg, size); + } + + const char* ErrorMessage() const { + return errmsg_; + } + + private: + char *errmsg_; +}; + +/* abstract */ class NanAsyncProgressWorker : public NanAsyncWorker { + public: + explicit NanAsyncProgressWorker(NanCallback *callback_) + : NanAsyncWorker(callback_), asyncdata_(NULL), asyncsize_(0) { + async = new uv_async_t; + uv_async_init( + uv_default_loop() + , async + , AsyncProgress_ + ); + async->data = this; + + uv_mutex_init(&async_lock); + } + + virtual ~NanAsyncProgressWorker() { + uv_mutex_destroy(&async_lock); + + if (asyncdata_) { + delete[] asyncdata_; + } + } + + void WorkProgress() { + uv_mutex_lock(&async_lock); + char *data = asyncdata_; + size_t size = asyncsize_; + asyncdata_ = NULL; + uv_mutex_unlock(&async_lock); + + // Dont send progress events after we've already completed. + if (callback) { + HandleProgressCallback(data, size); + } + delete[] data; + } + + class ExecutionProgress { + friend class NanAsyncProgressWorker; + public: + // You could do fancy generics with templates here. + void Send(const char* data, size_t size) const { + that_->SendProgress_(data, size); + } + + private: + explicit ExecutionProgress(NanAsyncProgressWorker* that) : that_(that) {} + // Prohibit copying and assignment. + ExecutionProgress(const ExecutionProgress&); + void operator=(const ExecutionProgress&); + #if __cplusplus >= 201103L + // Prohibit C++11 move semantics. + ExecutionProgress(ExecutionProgress&&) = delete; + void operator=(ExecutionProgress&&) = delete; + #endif + NanAsyncProgressWorker* const that_; + }; + + virtual void Execute(const ExecutionProgress& progress) = 0; + virtual void HandleProgressCallback(const char *data, size_t size) = 0; + + virtual void Destroy() { + uv_close(reinterpret_cast(async), AsyncClose_); + } + + private: + void Execute() /*final override*/ { + ExecutionProgress progress(this); + Execute(progress); + } + + void SendProgress_(const char *data, size_t size) { + char *new_data = new char[size]; + memcpy(new_data, data, size); + + uv_mutex_lock(&async_lock); + char *old_data = asyncdata_; + asyncdata_ = new_data; + asyncsize_ = size; + uv_mutex_unlock(&async_lock); + + if (old_data) { + delete[] old_data; + } + uv_async_send(async); + } + + NAN_INLINE static NAUV_WORK_CB(AsyncProgress_) { + NanAsyncProgressWorker *worker = + static_cast(async->data); + worker->WorkProgress(); + } + + NAN_INLINE static void AsyncClose_(uv_handle_t* handle) { + NanAsyncProgressWorker *worker = + static_cast(handle->data); + delete reinterpret_cast(handle); + delete worker; + } + + uv_async_t *async; + uv_mutex_t async_lock; + char *asyncdata_; + size_t asyncsize_; +}; + +NAN_INLINE void NanAsyncExecute (uv_work_t* req) { + NanAsyncWorker *worker = static_cast(req->data); + worker->Execute(); +} + +NAN_INLINE void NanAsyncExecuteComplete (uv_work_t* req) { + NanAsyncWorker* worker = static_cast(req->data); + worker->WorkComplete(); + worker->Destroy(); +} + +NAN_INLINE void NanAsyncQueueWorker (NanAsyncWorker* worker) { + uv_queue_work( + uv_default_loop() + , &worker->request + , NanAsyncExecute + , (uv_after_work_cb)NanAsyncExecuteComplete + ); +} + +//// Base 64 //// + +#define _nan_base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4) + +// Doesn't check for padding at the end. Can be 1-2 bytes over. +NAN_INLINE size_t _nan_base64_decoded_size_fast(size_t size) { + size_t remainder = size % 4; + + size = (size / 4) * 3; + if (remainder) { + if (size == 0 && remainder == 1) { + // special case: 1-byte input cannot be decoded + size = 0; + } else { + // non-padded input, add 1 or 2 extra bytes + size += 1 + (remainder == 3); + } + } + + return size; +} + +template +NAN_INLINE size_t _nan_base64_decoded_size( + const T* src + , size_t size +) { + if (size == 0) + return 0; + + if (src[size - 1] == '=') + size--; + if (size > 0 && src[size - 1] == '=') + size--; + + return _nan_base64_decoded_size_fast(size); +} + +// supports regular and URL-safe base64 +static const int _nan_unbase64_table[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + , -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63 + , 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1 + , -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + , 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63 + , -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 + , 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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, -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, -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, -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, -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 +}; + +#define _nan_unbase64(x) _nan_unbase64_table[(uint8_t)(x)] + +template static size_t _nan_base64_decode( + char* buf + , size_t len + , const T* src + , const size_t srcLen +) { + char* dst = buf; + char* dstEnd = buf + len; + const T* srcEnd = src + srcLen; + + while (src < srcEnd && dst < dstEnd) { + ptrdiff_t remaining = srcEnd - src; + char a, b, c, d; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining == 0 || *src == '=') break; + a = _nan_unbase64(*src++); + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 1 || *src == '=') break; + b = _nan_unbase64(*src++); + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (dst == dstEnd) break; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 2 || *src == '=') break; + c = _nan_unbase64(*src++); + + *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); + if (dst == dstEnd) break; + + while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 3 || *src == '=') break; + d = _nan_unbase64(*src++); + + *dst++ = ((c & 0x03) << 6) | (d & 0x3F); + } + + return dst - buf; +} + +//// HEX //// + +template unsigned _nan_hex2bin(T c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + return static_cast(-1); +} + +template static size_t _nan_hex_decode( + char* buf + , size_t len + , const T* src + , const size_t srcLen +) { + size_t i; + for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { + unsigned a = _nan_hex2bin(src[i * 2 + 0]); + unsigned b = _nan_hex2bin(src[i * 2 + 1]); + if (!~a || !~b) return i; + buf[i] = a * 16 + b; + } + + return i; +} + +namespace NanIntern { + +inline +NanExternalOneByteStringResource const* +GetExternalResource(v8::Local str) { +#if NODE_MODULE_VERSION < 42 + return str->GetExternalAsciiStringResource(); +#else // io.js v1.0.0 + return str->GetExternalOneByteStringResource(); +#endif +} + +inline +bool +IsExternal(v8::Local str) { +#if NODE_MODULE_VERSION < 42 + return str->IsExternalAscii(); +#else // io.js v1.0.0 + return str->IsExternalOneByte(); +#endif +} + +} // end of namespace NanIntern + +static bool _NanGetExternalParts( + v8::Handle val + , const char** data + , size_t* len +) { + if (node::Buffer::HasInstance(val)) { + *data = node::Buffer::Data(val.As()); + *len = node::Buffer::Length(val.As()); + return true; + } + + assert(val->IsString()); + v8::Local str = NanNew(val.As()); + + if (NanIntern::IsExternal(str)) { + const NanExternalOneByteStringResource* ext; + ext = NanIntern::GetExternalResource(str); + *data = ext->data(); + *len = ext->length(); + return true; + } + + if (str->IsExternal()) { + const v8::String::ExternalStringResource* ext; + ext = str->GetExternalStringResource(); + *data = reinterpret_cast(ext->data()); + *len = ext->length(); + return true; + } + + return false; +} + +namespace Nan { + enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER}; +} + +/* NAN_DEPRECATED */ NAN_INLINE void* _NanRawString( + v8::Handle from + , enum Nan::Encoding encoding + , size_t *datalen + , void *buf + , size_t buflen + , int flags +) { + NanScope(); + + size_t sz_; + size_t term_len = !(flags & v8::String::NO_NULL_TERMINATION); + char *data = NULL; + size_t len; + bool is_extern = _NanGetExternalParts( + from + , const_cast(&data) + , &len); + + if (is_extern && !term_len) { + NanSetPointerSafe(datalen, len); + return data; + } + + v8::Local toStr = from->ToString(); + + char *to = static_cast(buf); + + switch (encoding) { + case Nan::ASCII: +#if NODE_MODULE_VERSION < 0x000C + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } + NanSetPointerSafe( + datalen + , toStr->WriteAscii(to, 0, static_cast(sz_ + term_len), flags)); + return to; +#endif + case Nan::BINARY: + case Nan::BUFFER: + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } +#if NODE_MODULE_VERSION < 0x000C + { + uint16_t* twobytebuf = new uint16_t[sz_ + term_len]; + + size_t somelen = toStr->Write(twobytebuf, 0, + static_cast(sz_ + term_len), flags); + + for (size_t i = 0; i < sz_ + term_len && i < somelen + term_len; i++) { + unsigned char *b = reinterpret_cast(&twobytebuf[i]); + to[i] = *b; + } + + NanSetPointerSafe(datalen, somelen); + + delete[] twobytebuf; + return to; + } +#else + NanSetPointerSafe( + datalen, + toStr->WriteOneByte( + reinterpret_cast(to) + , 0 + , static_cast(sz_ + term_len) + , flags)); + return to; +#endif + case Nan::UTF8: + sz_ = toStr->Utf8Length(); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len && "too small buffer"); + } + NanSetPointerSafe( + datalen + , toStr->WriteUtf8(to, static_cast(sz_ + term_len) + , NULL, flags) + - term_len); + return to; + case Nan::BASE64: + { + v8::String::Value value(toStr); + sz_ = _nan_base64_decoded_size(*value, value.length()); + if (to == NULL) { + to = new char[sz_ + term_len]; + } else { + assert(buflen >= sz_ + term_len); + } + NanSetPointerSafe( + datalen + , _nan_base64_decode(to, sz_, *value, value.length())); + if (term_len) { + to[sz_] = '\0'; + } + return to; + } + case Nan::UCS2: + { + sz_ = toStr->Length(); + if (to == NULL) { + to = new char[(sz_ + term_len) * 2]; + } else { + assert(buflen >= (sz_ + term_len) * 2 && "too small buffer"); + } + + int bc = 2 * toStr->Write( + reinterpret_cast(to) + , 0 + , static_cast(sz_ + term_len) + , flags); + NanSetPointerSafe(datalen, bc); + return to; + } + case Nan::HEX: + { + v8::String::Value value(toStr); + sz_ = value.length(); + assert(!(sz_ & 1) && "bad hex data"); + if (to == NULL) { + to = new char[sz_ / 2 + term_len]; + } else { + assert(buflen >= sz_ / 2 + term_len && "too small buffer"); + } + NanSetPointerSafe( + datalen + , _nan_hex_decode(to, sz_ / 2, *value, value.length())); + } + if (term_len) { + to[sz_ / 2] = '\0'; + } + return to; + default: + assert(0 && "unknown encoding"); + } + return to; +} + +NAN_DEPRECATED NAN_INLINE void* NanRawString( + v8::Handle from + , enum Nan::Encoding encoding + , size_t *datalen + , void *buf + , size_t buflen + , int flags +) { + return _NanRawString(from, encoding, datalen, buf, buflen, flags); +} + + +NAN_DEPRECATED NAN_INLINE char* NanCString( + v8::Handle from + , size_t *datalen + , char *buf = NULL + , size_t buflen = 0 + , int flags = v8::String::NO_OPTIONS +) { + return static_cast( + _NanRawString(from, Nan::UTF8, datalen, buf, buflen, flags) + ); +} + +NAN_INLINE void NanSetPrototypeTemplate( + v8::Local templ + , const char *name + , v8::Handle value +) { + NanSetTemplate(templ->PrototypeTemplate(), name, value); +} + +NAN_INLINE void NanSetPrototypeTemplate( + v8::Local templ + , v8::Handle name + , v8::Handle value + , v8::PropertyAttribute attributes +) { + NanSetTemplate(templ->PrototypeTemplate(), name, value, attributes); +} + +NAN_INLINE void NanSetInstanceTemplate( + v8::Local templ + , const char *name + , v8::Handle value +) { + NanSetTemplate(templ->InstanceTemplate(), name, value); +} + +NAN_INLINE void NanSetInstanceTemplate( + v8::Local templ + , v8::Handle name + , v8::Handle value + , v8::PropertyAttribute attributes +) { + NanSetTemplate(templ->InstanceTemplate(), name, value, attributes); +} + +//=== Export ================================================================== + +inline +void +NanExport(v8::Handle target, const char * name, + NanFunctionCallback f) { + target->Set(NanNew(name), + NanNew(f)->GetFunction()); +} + +//=== Tap Reverse Binding ===================================================== + +struct NanTap { + explicit NanTap(v8::Handle t) : t_() { + NanAssignPersistent(t_, t->ToObject()); + } + + ~NanTap() { NanDisposePersistent(t_); } // not sure if neccessary + + inline void plan(int i) { + v8::Handle arg = NanNew(i); + NanMakeCallback(NanNew(t_), "plan", 1, &arg); + } + + inline void ok(bool isOk, const char * msg = NULL) { + v8::Handle args[2]; + args[0] = NanNew(isOk); + if (msg) args[1] = NanNew(msg); + NanMakeCallback(NanNew(t_), "ok", msg ? 2 : 1, args); + } + + private: + v8::Persistent t_; +}; + +#define NAN_STRINGIZE2(x) #x +#define NAN_STRINGIZE(x) NAN_STRINGIZE2(x) +#define NAN_TEST_EXPRESSION(expression) \ + ( expression ), __FILE__ ":" NAN_STRINGIZE(__LINE__) ": " #expression + +#define return_NanValue(v) NanReturnValue(v) +#define return_NanUndefined() NanReturnUndefined() +#define NAN_EXPORT(target, function) NanExport(target, #function, function) + +#endif // NAN_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h b/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h new file mode 100644 index 0000000..5f0bff0 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h @@ -0,0 +1,253 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2015 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_IMPLEMENTATION_12_INL_H_ +#define NAN_IMPLEMENTATION_12_INL_H_ +//============================================================================== +// node v0.11 implementation +//============================================================================== + +#if defined(_MSC_VER) +# pragma warning( disable : 4530 ) +# include +# pragma warning( default : 4530 ) +#else +# include +#endif + +namespace NanIntern { + +//=== Array ==================================================================== + +Factory::return_t +Factory::New() { + return v8::Array::New(v8::Isolate::GetCurrent()); +} + +Factory::return_t +Factory::New(int length) { + return v8::Array::New(v8::Isolate::GetCurrent(), length); +} + +//=== Boolean ================================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::Boolean::New(v8::Isolate::GetCurrent(), value); +} + +//=== Boolean Object =========================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::BooleanObject::New(value).As(); +} + +//=== Date ===================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Date::New(v8::Isolate::GetCurrent(), value).As(); +} + +//=== External ================================================================= + +Factory::return_t +Factory::New(void * value) { + return v8::External::New(v8::Isolate::GetCurrent(), value); +} + +//=== Function ================================================================= + +Factory::return_t +Factory::New( NanFunctionCallback callback + , v8::Handle data) { + return v8::Function::New( v8::Isolate::GetCurrent() + , callback + , data); +} + +//=== Function Template ======================================================== + +Factory::return_t +Factory::New( NanFunctionCallback callback + , v8::Handle data + , v8::Handle signature) { + return v8::FunctionTemplate::New( v8::Isolate::GetCurrent() + , callback + , data + , signature); +} + +//=== Number =================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Number::New(v8::Isolate::GetCurrent(), value); +} + +//=== Number Object ============================================================ + +Factory::return_t +Factory::New(double value) { + return v8::NumberObject::New( v8::Isolate::GetCurrent() + , value).As(); +} + +//=== Integer, Int32 and Uint32 ================================================ + +template +typename IntegerFactory::return_t +IntegerFactory::New(int32_t value) { + return To(T::New(v8::Isolate::GetCurrent(), value)); +} + +template +typename IntegerFactory::return_t +IntegerFactory::New(uint32_t value) { + return To(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +Factory::return_t +Factory::New(int32_t value) { + return To( + v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +Factory::return_t +Factory::New(uint32_t value) { + return To( + v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +//=== Object =================================================================== + +Factory::return_t +Factory::New() { + return v8::Object::New(v8::Isolate::GetCurrent()); +} + +//=== Object Template ========================================================== + +Factory::return_t +Factory::New() { + return v8::ObjectTemplate::New(v8::Isolate::GetCurrent()); +} + +//=== RegExp =================================================================== + +Factory::return_t +Factory::New( + v8::Handle pattern + , v8::RegExp::Flags flags) { + return v8::RegExp::New(pattern, flags); +} + +//=== Script =================================================================== + +Factory::return_t +Factory::New( v8::Local source) { + v8::ScriptCompiler::Source src(source); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::ScriptCompiler::Source src(source, origin); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); +} + +//=== Signature ================================================================ + +Factory::return_t +Factory::New( Factory::FTH receiver + , int argc + , Factory::FTH argv[]) { + return v8::Signature::New(v8::Isolate::GetCurrent(), receiver, argc, argv); +} + +//=== String =================================================================== + +Factory::return_t +Factory::New() { + return v8::String::Empty(v8::Isolate::GetCurrent()); +} + +Factory::return_t +Factory::New(const char * value, int length) { + return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); +} + +Factory::return_t +Factory::New(std::string const& value) { + assert(value.size() <= INT_MAX && "string too long"); + return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), + value.data(), v8::String::kNormalString, static_cast(value.size())); +} + +Factory::return_t +Factory::New(const uint8_t * value, int length) { + return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); +} + +Factory::return_t +Factory::New(const uint16_t * value, int length) { + return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); +} + +Factory::return_t +Factory::New(v8::String::ExternalStringResource * value) { + return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); +} + +Factory::return_t +Factory::New(NanExternalOneByteStringResource * value) { + return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); +} + +//=== String Object ============================================================ + +Factory::return_t +Factory::New(v8::Handle value) { + return v8::StringObject::New(value).As(); +} + +//=== Unbound Script =========================================================== + +Factory::return_t +Factory::New(v8::Local source) { + v8::ScriptCompiler::Source src(source); + return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::ScriptCompiler::Source src(source, origin); + return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); +} + +} // end of namespace NanIntern + +//=== Presistents and Handles ================================================== + +template +inline v8::Local NanNew(v8::Handle h) { + return v8::Local::New(v8::Isolate::GetCurrent(), h); +} + +template +inline v8::Local NanNew(v8::Persistent const& p) { + return v8::Local::New(v8::Isolate::GetCurrent(), p); +} + +#endif // NAN_IMPLEMENTATION_12_INL_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h b/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h new file mode 100644 index 0000000..4c4ae11 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h @@ -0,0 +1,256 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2015 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_ +#define NAN_IMPLEMENTATION_PRE_12_INL_H_ + +#include + +#if defined(_MSC_VER) +# pragma warning( disable : 4530 ) +# include +# include +# pragma warning( default : 4530 ) +#else +# include +# include +#endif + +//============================================================================== +// node v0.10 implementation +//============================================================================== + +namespace NanIntern { + +//=== Array ==================================================================== + +Factory::return_t +Factory::New() { + return v8::Array::New(); +} + +Factory::return_t +Factory::New(int length) { + return v8::Array::New(length); +} + +//=== Boolean ================================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::Boolean::New(value)->ToBoolean(); +} + +//=== Boolean Object =========================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::BooleanObject::New(value).As(); +} + +//=== Date ===================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Date::New(value).As(); +} + +//=== External ================================================================= + +Factory::return_t +Factory::New(void * value) { + return v8::External::New(value); +} + +//=== Function ================================================================= + +Factory::return_t +Factory::New( NanFunctionCallback callback + , v8::Handle data) { + return Factory::New( callback + , data + , v8::Handle() + )->GetFunction(); +} + + +//=== FunctionTemplate ========================================================= + +Factory::return_t +Factory::New( NanFunctionCallback callback + , v8::Handle data + , v8::Handle signature) { + // Note(agnat): Emulate length argument here. Unfortunately, I couldn't find + // a way. Have at it though... + return v8::FunctionTemplate::New( callback + , data + , signature); +} + +//=== Number =================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Number::New(value); +} + +//=== Number Object ============================================================ + +Factory::return_t +Factory::New(double value) { + return v8::NumberObject::New(value).As(); +} + +//=== Integer, Int32 and Uint32 ================================================ + +template +typename IntegerFactory::return_t +IntegerFactory::New(int32_t value) { + return To(T::New(value)); +} + +template +typename IntegerFactory::return_t +IntegerFactory::New(uint32_t value) { + return To(T::NewFromUnsigned(value)); +} + +Factory::return_t +Factory::New(int32_t value) { + return To(v8::Uint32::NewFromUnsigned(value)); +} + +Factory::return_t +Factory::New(uint32_t value) { + return To(v8::Uint32::NewFromUnsigned(value)); +} + + +//=== Object =================================================================== + +Factory::return_t +Factory::New() { + return v8::Object::New(); +} + +//=== Object Template ========================================================== + +Factory::return_t +Factory::New() { + return v8::ObjectTemplate::New(); +} + +//=== RegExp =================================================================== + +Factory::return_t +Factory::New( + v8::Handle pattern + , v8::RegExp::Flags flags) { + return v8::RegExp::New(pattern, flags); +} + +//=== Script =================================================================== + +Factory::return_t +Factory::New( v8::Local source) { + return v8::Script::New(source); +} +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + return v8::Script::New(source, const_cast(&origin)); +} + +//=== Signature ================================================================ + +Factory::return_t +Factory::New( Factory::FTH receiver + , int argc + , Factory::FTH argv[]) { + return v8::Signature::New(receiver, argc, argv); +} + +//=== String =================================================================== + +Factory::return_t +Factory::New() { + return v8::String::Empty(); +} + +Factory::return_t +Factory::New(const char * value, int length) { + return v8::String::New(value, length); +} + +Factory::return_t +Factory::New(std::string const& value) { + assert(value.size() <= INT_MAX && "string too long"); + return v8::String::New( value.data(), static_cast(value.size())); +} + +inline +void +widenString(std::vector *ws, const uint8_t *s, int l = -1) { + size_t len = static_cast(l); + if (l < 0) { + len = strlen(reinterpret_cast(s)); + } + assert(len <= INT_MAX && "string too long"); + ws->resize(len); + std::copy(s, s + len, ws->begin()); +} + +Factory::return_t +Factory::New(const uint16_t * value, int length) { + return v8::String::New(value, length); +} + +Factory::return_t +Factory::New(const uint8_t * value, int length) { + std::vector wideString; + widenString(&wideString, value, length); + if (wideString.size() == 0) { + return v8::String::Empty(); + } else { + return v8::String::New(&wideString.front() + , static_cast(wideString.size())); + } +} + +Factory::return_t +Factory::New(v8::String::ExternalStringResource * value) { + return v8::String::NewExternal(value); +} + +Factory::return_t +Factory::New(v8::String::ExternalAsciiStringResource * value) { + return v8::String::NewExternal(value); +} + +//=== String Object ============================================================ + +Factory::return_t +Factory::New(v8::Handle value) { + return v8::StringObject::New(value).As(); +} + +} // end of namespace NanIntern + +//=== Presistents and Handles ================================================== + +template +inline v8::Local NanNew(v8::Handle h) { + return v8::Local::New(h); +} + +template +inline v8::Local NanNew(v8::Persistent const& p) { + return v8::Local::New(p); +} + +#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_new.h b/scripts/external/three/canvas/node_modules/nan/nan_new.h new file mode 100644 index 0000000..7058d12 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/nan_new.h @@ -0,0 +1,320 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2015 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_NEW_H_ +#define NAN_NEW_H_ + +#if defined(_MSC_VER) +# pragma warning( disable : 4530 ) +# include +# pragma warning( default : 4530 ) +#else +# include +#endif + +namespace NanIntern { // scnr + +// TODO(agnat): Generalize +template v8::Local To(v8::Handle i); + +template <> +inline +v8::Local +To(v8::Handle i) { return i->ToInteger(); } + +template <> +inline +v8::Local +To(v8::Handle i) { return i->ToInt32(); } + +template <> +inline +v8::Local +To(v8::Handle i) { return i->ToUint32(); } + +template struct FactoryBase { typedef v8::Local return_t; }; + +template struct Factory; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); + static inline return_t New(int length); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(bool value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(bool value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(double value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(void *value); +}; + +template <> +struct Factory : FactoryBase { + static inline + return_t + New( NanFunctionCallback callback + , v8::Handle data = v8::Handle()); +}; + +template <> +struct Factory : FactoryBase { + static inline + return_t + New( NanFunctionCallback callback = NULL + , v8::Handle data = v8::Handle() + , v8::Handle signature = v8::Handle()); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(double value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(double value); +}; + +template +struct IntegerFactory : FactoryBase { + typedef typename FactoryBase::return_t return_t; + static inline return_t New(int32_t value); + static inline return_t New(uint32_t value); +}; + +template <> +struct Factory : IntegerFactory {}; + +template <> +struct Factory : IntegerFactory {}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(int32_t value); + static inline return_t New(uint32_t value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New( + v8::Handle pattern, v8::RegExp::Flags flags); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New( v8::Local source); + static inline return_t New( v8::Local source + , v8::ScriptOrigin const& origin); +}; + +template <> +struct Factory : FactoryBase { + typedef v8::Handle FTH; + static inline + return_t + New( FTH receiver = FTH(), int argc = 0, FTH argv[] = NULL ); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); + static inline return_t New(const char *value, int length = -1); + static inline return_t New(const uint16_t *value, int length = -1); + static inline return_t New(std::string const& value); + + static inline return_t New(v8::String::ExternalStringResource * value); + static inline return_t New(NanExternalOneByteStringResource * value); + + // TODO(agnat): Deprecate. + static inline return_t New(const uint8_t * value, int length = -1); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(v8::Handle value); +}; + +} // end of namespace NanIntern + +#if (NODE_MODULE_VERSION >= 12) + +namespace NanIntern { + +template <> +struct Factory : FactoryBase { + static inline return_t New( v8::Local source); + static inline return_t New( v8::Local source + , v8::ScriptOrigin const& origin); +}; + +} // end of namespace NanIntern + +# include "nan_implementation_12_inl.h" + +#else // NODE_MODULE_VERSION >= 12 + +# include "nan_implementation_pre_12_inl.h" + +#endif + +//=== API ====================================================================== + +template +typename NanIntern::Factory::return_t +NanNew() { + return NanIntern::Factory::New(); +} + +template +typename NanIntern::Factory::return_t +NanNew(A0 arg0) { + return NanIntern::Factory::New(arg0); +} + +template +typename NanIntern::Factory::return_t +NanNew(A0 arg0, A1 arg1) { + return NanIntern::Factory::New(arg0, arg1); +} + +template +typename NanIntern::Factory::return_t +NanNew(A0 arg0, A1 arg1, A2 arg2) { + return NanIntern::Factory::New(arg0, arg1, arg2); +} + +template +typename NanIntern::Factory::return_t +NanNew(A0 arg0, A1 arg1, A2 arg2, A3 arg3) { + return NanIntern::Factory::New(arg0, arg1, arg2, arg3); +} + +// Note(agnat): When passing overloaded function pointers to template functions +// as generic arguments the compiler needs help in picking the right overload. +// These two functions handle NanNew and NanNew with +// all argument variations. + +// v8::Function and v8::FunctionTemplate with one or two arguments +template +typename NanIntern::Factory::return_t +NanNew( NanFunctionCallback callback + , v8::Handle data = v8::Handle()) { + return NanIntern::Factory::New(callback, data); +} + +// v8::Function and v8::FunctionTemplate with three arguments +template +typename NanIntern::Factory::return_t +NanNew( NanFunctionCallback callback + , v8::Handle data = v8::Handle() + , A2 a2 = A2()) { + return NanIntern::Factory::New(callback, data, a2); +} + +// Convenience + +template inline v8::Local NanNew(v8::Handle h); +template inline v8::Local NanNew(v8::Persistent const& p); + +inline +NanIntern::Factory::return_t +NanNew(bool value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(int32_t value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(uint32_t value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(double value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(std::string const& value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(const char * value, int length) { + return NanNew(value, length); +} + +inline +NanIntern::Factory::return_t +NanNew(const char * value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(const uint8_t * value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(const uint16_t * value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(v8::String::ExternalStringResource * value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(NanExternalOneByteStringResource * value) { + return NanNew(value); +} + +inline +NanIntern::Factory::return_t +NanNew(v8::Handle pattern, v8::RegExp::Flags flags) { + return NanNew(pattern, flags); +} + +#endif // NAN_NEW_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/package.json b/scripts/external/three/canvas/node_modules/nan/package.json new file mode 100644 index 0000000..3d51cc5 --- /dev/null +++ b/scripts/external/three/canvas/node_modules/nan/package.json @@ -0,0 +1,69 @@ +{ + "name": "nan", + "version": "1.5.3", + "description": "Native Abstractions for Node.js: C++ header for Node 0.8->0.12 compatibility", + "main": "include_dirs.js", + "repository": { + "type": "git", + "url": "git://github.com/rvagg/nan.git" + }, + "scripts": { + "test": "tap --gc test/js/*-test.js", + "rebuild-tests": "node-gyp rebuild --directory test" + }, + "contributors": [ + { + "name": "Rod Vagg", + "email": "r@va.gg", + "url": "https://github.com/rvagg" + }, + { + "name": "Benjamin Byholm", + "email": "bbyholm@abo.fi", + "url": "https://github.com/kkoopa/" + }, + { + "name": "Trevor Norris", + "email": "trev.norris@gmail.com", + "url": "https://github.com/trevnorris" + }, + { + "name": "Nathan Rajlich", + "email": "nathan@tootallnate.net", + "url": "https://github.com/TooTallNate" + }, + { + "name": "Brett Lawson", + "email": "brett19@gmail.com", + "url": "https://github.com/brett19" + }, + { + "name": "Ben Noordhuis", + "email": "info@bnoordhuis.nl", + "url": "https://github.com/bnoordhuis" + }, + { + "name": "David Siegel", + "email": "david@artcom.de", + "url": "https://github.com/agnat" + } + ], + "devDependencies": { + "bindings": "~1.2.1", + "node-gyp": "~1.0.2", + "tap": "~0.5.0", + "xtend": "~4.0.0" + }, + "license": "MIT", + "readme": "Native Abstractions for Node.js\n===============================\n\n**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.**\n\n***Current version: 1.5.2***\n\n*(See [CHANGELOG.md](https://github.com/rvagg/nan/blob/master/CHANGELOG.md) for complete ChangeLog)*\n\n[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/)\n\n[![Build Status](https://secure.travis-ci.org/rvagg/nan.png)](http://travis-ci.org/rvagg/nan)\n[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan)\n\nThanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle.\n\nThis project also contains some helper utilities that make addon development a bit more pleasant.\n\n * **[News & Updates](#news)**\n * **[Usage](#usage)**\n * **[Example](#example)**\n * **[API](#api)**\n * **[Tests](#tests)**\n\n\n## News & Updates\n\n### Jan-2015: 1.5.0 release\n\n* Support [io.js](https://github.com/iojs/io.js) thanks to [Ben Noordhuis](bnoordhuis)\n* Rewritten NanNew internals thanks to [David Siegel](agnat)\n* NanAsyncWorker now supports progress reporting thanks to [Brett Lawson](brett19)\n\n### Aug-2014: 1.3.0 release\n\n* `NanCString()` and `NanRawString()` have been deprecated in favour of new NanAsciiString, NanUtf8String and NanUcs2String. These classes manage the underlying memory for you in a safer way than just handing off an allocated array. You should now `*NanAsciiString(handle)` to access the raw `char` data, you can also allocate on the heap if you need to keep a reference.\n* Two more NanMakeCallback overloads have been added to for parity with Node core.\n* You can now `NanNew(std::string)` (use `NanNew(std::string&)` to pass by reference)\n* NanSetTemplate, NanSetPrototypeTemplate and NanSetInstanceTemplate have been added.\n\n### May-2014: 1.1.0 release\n\n* We've deprecated `NanSymbol()`, you should just use `NanNew()` now.\n* `NanNull()`, `NanUndefined()`, `NanTrue()`, `NanFalse()` all return `Local`s now.\n* `nan_isolate` is gone, it was intended to be internal-only but if you were using it then you should switch to `v8::Isolate::GetCurrent()`.\n* `NanNew()` has received some additional overload-love so you should be able to give it many kinds of values without specifying the ``.\n* Lots of small fixes and additions to expand the V8 API coverage, *use the source, Luke*.\n\n\n### May-2014: Major changes for V8 3.25 / Node 0.11.13\n\nNode 0.11.11 and 0.11.12 were both broken releases for native add-ons, you simply can't properly compile against either of them for different reasons. But we now have a 0.11.13 release that jumps a couple of versions of V8 ahead and includes some more, major (traumatic) API changes.\n\nBecause we are now nearing Node 0.12 and estimate that the version of V8 we are using in Node 0.11.13 will be close to the API we get for 0.12, we have taken the opportunity to not only *fix* NAN for 0.11.13 but make some major changes to improve the NAN API.\n\nWe have **removed support for Node 0.11 versions prior to 0.11.13**. As usual, our tests are run against (and pass) the last 5 versions of Node 0.8 and Node 0.10. We also include Node 0.11.13 obviously.\n\nThe major change is something that [Benjamin Byholm](kkoopa) has put many hours in to. We now have a fantastic new `NanNew(args)` interface for creating new `Local`s, this replaces `NanNewLocal()` and much more. If you look in [./nan.h](nan.h) you'll see a large number of overloaded versions of this method. In general you should be able to `NanNew(arguments)` for any type you want to make a `Local` from. This includes `Persistent` types, so we now have a `Local NanNew(const Persistent arg)` to replace `NanPersistentToLocal()`.\n\nWe also now have `NanUndefined()`, `NanNull()`, `NanTrue()` and `NanFalse()`. Mainly because of the new requirement for an `Isolate` argument for each of the native V8 versions of this.\n\nV8 has now introduced an `EscapableHandleScope` from which you `scope.Escape(Local value)` to *return* a value from a one scope to another. This replaces the standard `HandleScope` and `scope.Close(Local value)`, although `HandleScope` still exists for when you don't need to return a handle to the caller. For NAN we are exposing it as `NanEscapableScope()` and `NanEscapeScope()`, while `NanScope()` is still how you create a new scope that doesn't need to return handles. For older versions of Node/V8, it'll still map to the older `HandleScope` functionality.\n\n`NanFromV8String()` was deprecated and has now been removed. You should use `NanCString()` or `NanRawString()` instead.\n\nBecause `node::MakeCallback()` now takes an `Isolate`, and because it doesn't exist in older versions of Node, we've introduced `NanMakeCallback()`. You should *always* use this when calling a JavaScript function from C++.\n\nThere's lots more, check out the Changelog in nan.h or look through [#86](https://github.com/rvagg/nan/pull/86) for all the gory details.\n\n### Dec-2013: NanCString and NanRawString\n\nTwo new functions have been introduced to replace the functionality that's been provided by `NanFromV8String` until now. NanCString has sensible defaults so it's super easy to fetch a null-terminated c-style string out of a `v8::String`. `NanFromV8String` is still around and has defaults that allow you to pass a single handle to fetch a `char*` while `NanRawString` requires a little more attention to arguments.\n\n### Nov-2013: Node 0.11.9+ breaking V8 change\n\nThe version of V8 that's shipping with Node 0.11.9+ has changed the signature for new `Local`s to: `v8::Local::New(isolate, value)`, i.e. introducing the `isolate` argument and therefore breaking all new `Local` declarations for previous versions. NAN 0.6+ now includes a `NanNewLocal(value)` that can be used in place to work around this incompatibility and maintain compatibility with 0.8->0.11.9+ (minus a few early 0.11 releases).\n\nFor example, if you wanted to return a `null` on a callback you will have to change the argument from `v8::Local::New(v8::Null())` to `NanNewLocal(v8::Null())`.\n\n### Nov-2013: Change to binding.gyp `\"include_dirs\"` for NAN\n\nInclusion of NAN in a project's binding.gyp is now greatly simplified. You can now just use `\"\n## Usage\n\nSimply add **NAN** as a dependency in the *package.json* of your Node addon:\n\n``` bash\n$ npm install --save nan\n```\n\nPull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files:\n\n``` python\n\"include_dirs\" : [\n \"` when compiling your addon.\n\n\n## Example\n\nSee **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use.\n\nFor a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**.\n\nFor another example, see **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon.\n\nCompare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work).\n\nNote that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class.\n\n```c++\n// addon.cc\n#include \n#include \n// ...\n\nusing v8::FunctionTemplate;\nusing v8::Handle;\nusing v8::Object;\nusing v8::String;\n\nvoid InitAll(Handle exports) {\n exports->Set(NanNew(\"calculateSync\"),\n NanNew(CalculateSync)->GetFunction());\n\n exports->Set(NanNew(\"calculateAsync\"),\n NanNew(CalculateAsync)->GetFunction());\n}\n\nNODE_MODULE(addon, InitAll)\n```\n\n```c++\n// sync.h\n#include \n#include \n\nNAN_METHOD(CalculateSync);\n```\n\n```c++\n// sync.cc\n#include \n#include \n#include \"./sync.h\"\n// ...\n\nusing v8::Number;\n\n// Simple synchronous access to the `Estimate()` function\nNAN_METHOD(CalculateSync) {\n NanScope();\n\n // expect a number as the first argument\n int points = args[0]->Uint32Value();\n double est = Estimate(points);\n\n NanReturnValue(NanNew(est));\n}\n```\n\n```c++\n// async.h\n#include \n#include \n\nNAN_METHOD(CalculateAsync);\n```\n\n```c++\n// async.cc\n#include \n#include \n#include \"./async.h\"\n\n// ...\n\nusing v8::Function;\nusing v8::Local;\nusing v8::Null;\nusing v8::Number;\nusing v8::Value;\n\nclass PiWorker : public NanAsyncWorker {\n public:\n PiWorker(NanCallback *callback, int points)\n : NanAsyncWorker(callback), points(points) {}\n ~PiWorker() {}\n\n // Executed inside the worker-thread.\n // It is not safe to access V8, or V8 data structures\n // here, so everything we need for input and output\n // should go on `this`.\n void Execute () {\n estimate = Estimate(points);\n }\n\n // Executed when the async work is complete\n // this function will be run inside the main event loop\n // so it is safe to use V8 again\n void HandleOKCallback () {\n NanScope();\n\n Local argv[] = {\n NanNull()\n , NanNew(estimate)\n };\n\n callback->Call(2, argv);\n };\n\n private:\n int points;\n double estimate;\n};\n\n// Asynchronous access to the `Estimate()` function\nNAN_METHOD(CalculateAsync) {\n NanScope();\n\n int points = args[0]->Uint32Value();\n NanCallback *callback = new NanCallback(args[1].As());\n\n NanAsyncQueueWorker(new PiWorker(callback, points));\n NanReturnUndefined();\n}\n```\n\n\n## API\n\n * NAN_METHOD\n * NAN_GETTER\n * NAN_SETTER\n * NAN_PROPERTY_GETTER\n * NAN_PROPERTY_SETTER\n * NAN_PROPERTY_ENUMERATOR\n * NAN_PROPERTY_DELETER\n * NAN_PROPERTY_QUERY\n * NAN_INDEX_GETTER\n * NAN_INDEX_SETTER\n * NAN_INDEX_ENUMERATOR\n * NAN_INDEX_DELETER\n * NAN_INDEX_QUERY\n * NAN_GC_CALLBACK\n * NAN_WEAK_CALLBACK\n * NAN_DEPRECATED\n * NAN_INLINE\n * NanNew\n * NanUndefined\n * NanNull\n * NanTrue\n * NanFalse\n * NanReturnValue\n * NanReturnUndefined\n * NanReturnNull\n * NanReturnEmptyString\n * NanReturnThis\n * NanReturnHolder\n * NanScope\n * NanEscapableScope\n * NanEscapeScope\n * NanLocker\n * NanUnlocker\n * NanGetInternalFieldPointer\n * NanSetInternalFieldPointer\n * NanObjectWrapHandle\n * NanSymbol\n * NanGetPointerSafe\n * NanSetPointerSafe\n * NanRawString\n * NanCString\n * NanAsciiString\n * NanUtf8String\n * NanUcs2String\n * NanBooleanOptionValue\n * NanUInt32OptionValue\n * NanError, NanTypeError, NanRangeError\n * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int)\n * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t)\n * NanBufferUse(char *, uint32_t)\n * NanNewContextHandle\n * NanGetCurrentContext\n * NanHasInstance\n * NanDisposePersistent\n * NanAssignPersistent\n * NanMakeWeakPersistent\n * NanSetTemplate\n * NanSetPrototypeTemplate\n * NanSetInstanceTemplate\n * NanMakeCallback\n * NanCompileScript\n * NanRunScript\n * NanAdjustExternalMemory\n * NanAddGCEpilogueCallback\n * NanAddGCPrologueCallback\n * NanRemoveGCEpilogueCallback\n * NanRemoveGCPrologueCallback\n * NanGetHeapStatistics\n * NanCallback\n * NanAsyncWorker\n * NanAsyncQueueWorker\n\n\n### NAN_METHOD(methodname)\n\nUse `NAN_METHOD` to define your V8 accessible methods:\n\n```c++\n// .h:\nclass Foo : public node::ObjectWrap {\n ...\n\n static NAN_METHOD(Bar);\n static NAN_METHOD(Baz);\n}\n\n\n// .cc:\nNAN_METHOD(Foo::Bar) {\n ...\n}\n\nNAN_METHOD(Foo::Baz) {\n ...\n}\n```\n\nThe reason for this macro is because of the method signature change in 0.11:\n\n```c++\n// 0.10 and below:\nHandle name(const Arguments& args)\n\n// 0.11 and above\nvoid name(const FunctionCallbackInfo& args)\n```\n\nThe introduction of `FunctionCallbackInfo` brings additional complications:\n\n\n### NAN_GETTER(methodname)\n\nUse `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`.\n\n\n### NAN_SETTER(methodname)\n\nUse `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_PROPERTY_GETTER(cbname)\nUse `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`.\n\n\n### NAN_PROPERTY_SETTER(cbname)\nUse `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_PROPERTY_ENUMERATOR(cbname)\nUse `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`.\n\n\n### NAN_PROPERTY_DELETER(cbname)\nUse `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`.\n\n\n### NAN_PROPERTY_QUERY(cbname)\nUse `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`.\n\n\n### NAN_INDEX_GETTER(cbname)\nUse `NAN_INDEX_GETTER` to declare your V8 accessible index getters. You get a `uint32_t` `index` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_GETTER`.\n\n\n### NAN_INDEX_SETTER(cbname)\nUse `NAN_INDEX_SETTER` to declare your V8 accessible index setters. Same as `NAN_INDEX_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_INDEX_ENUMERATOR(cbname)\nUse `NAN_INDEX_ENUMERATOR` to declare your V8 accessible index enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_INDEX_GETTER` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_ENUMERATOR`.\n\n\n### NAN_INDEX_DELETER(cbname)\nUse `NAN_INDEX_DELETER` to declare your V8 accessible index deleters. Same as `NAN_INDEX_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_DELETER`.\n\n\n### NAN_INDEX_QUERY(cbname)\nUse `NAN_INDEX_QUERY` to declare your V8 accessible index queries. Same as `NAN_INDEX_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_QUERY`.\n\n\n### NAN_GC_CALLBACK(cbname)\nUse `NAN_GC_CALLBACK` to declare your callbacks for `NanAddGCEpilogueCallback` and `NanAddGCPrologueCallback`. You get arguments `GCType type` and `GCCallbackFlags flags`.\n\n```c++\nstatic Persistent callback;\n\nNAN_GC_CALLBACK(gcPrologueCallback) {\n Local argv[] = {NanNew(\"prologue\")};\n NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(callback), 1, argv);\n}\n\nNAN_METHOD(Hook) {\n NanScope();\n NanAssignPersistent(callback, args[0].As());\n NanAddGCPrologueCallback(gcPrologueCallback);\n NanReturnValue(args.Holder());\n}\n```\n\n\n### NAN_WEAK_CALLBACK(cbname)\n\nUse `NAN_WEAK_CALLBACK` to define your V8 WeakReference callbacks. There is an argument object `const _NanWeakCallbackData &data` allowing access to the weak object and the supplied parameter through its `GetValue` and `GetParameter` methods. You can even access the weak callback info object through the `GetCallbackInfo()`method, but you probably should not. `Revive()` keeps the weak object alive until the next GC round.\n\n```c++\nNAN_WEAK_CALLBACK(weakCallback) {\n int *parameter = data.GetParameter();\n NanMakeCallback(NanGetCurrentContext()->Global(), data.GetValue(), 0, NULL);\n if ((*parameter)++ == 0) {\n data.Revive();\n } else {\n delete parameter;\n }\n}\n```\n\n\n### NAN_DEPRECATED\nDeclares a function as deprecated.\n\n```c++\nstatic NAN_DEPRECATED NAN_METHOD(foo) {\n ...\n}\n```\n\n\n### NAN_INLINE\nInlines a function.\n\n```c++\nNAN_INLINE int foo(int bar) {\n ...\n}\n```\n\n\n### Local<T> NanNew<T>( ... )\n\nUse `NanNew` to construct almost all v8 objects (bound `Script`s are constructed with `NanCompileScript(Handle)`) and make new local handles.\n\n```c++\nLocal s = NanNew(\"value\");\n\n...\n\nPersistent o;\n\n...\n\nLocal lo = NanNew(o);\n\n```\n\n\n### Local<Primitive> NanUndefined()\n\nUse instead of `Undefined()`\n\n\n### Local<Primitive> NanNull()\n\nUse instead of `Null()`\n\n\n### Local<Boolean> NanTrue()\n\nUse instead of `True()`\n\n\n### Local<Boolean> NanFalse()\n\nUse instead of `False()`\n\n\n### NanReturnValue(Handle<Value>)\n\nUse `NanReturnValue` when you want to return a value from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n ...\n\n NanReturnValue(NanNew(\"FooBar!\"));\n}\n```\n\nNo `return` statement required.\n\n\n### NanReturnUndefined()\n\nUse `NanReturnUndefined` when you don't want to return anything from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnUndefined();\n}\n```\n\n\n### NanReturnNull()\n\nUse `NanReturnNull` when you want to return `Null` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnNull();\n}\n```\n\n\n### NanReturnEmptyString()\n\nUse `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnEmptyString();\n}\n```\n\n\n### NanReturnThis()\n\nUse `NanReturnThis` when you want to return `This` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnThis();\n}\n```\n\n\n### NanReturnHolder()\n\nUse `NanReturnHolder` when you want to return `Holder` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnHolder();\n}\n```\n\n\n### NanScope()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope` when you do not wish to return handles (`Handle` or `Local`) to the surrounding scope (or in functions directly exposed to V8, as they do not return values in the normal sense):\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanScope();\n\n NanReturnValue(NanNew(\"FooBar!\"));\n}\n```\n\nThis method is not directly exposed to V8, nor does it return a handle, so it uses an unescapable scope:\n\n```c++\nbool Foo::Bar() {\n NanScope();\n\n Local val = NanFalse();\n ...\n return val->Value();\n}\n```\n\n\n### NanEscapableScope()\n\nThe separation of handle scopes into escapable and inescapable scopes makes `NanEscapableScope()` necessary, use it in place of `HandleScope scope` when you later wish to return a handle (`Handle` or `Local`) from the scope, this is for internal functions not directly exposed to V8:\n\n```c++\nHandle Foo::Bar() {\n NanEscapableScope();\n\n return NanEscapeScope(NanNew(\"FooBar!\"));\n}\n```\n\n\n### Local<T> NanEscapeScope(Handle<T> value);\nUse together with `NanEscapableScope` to escape the scope. Corresponds to `HandleScope::Close` or `EscapableHandleScope::Escape`.\n\n\n### NanLocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### NanUnlocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### void * NanGetInternalFieldPointer(Handle<Object>, int)\n\nGets a pointer to the internal field with at `index` from a V8 `Object` handle.\n\n```c++\nLocal obj;\n...\nNanGetInternalFieldPointer(obj, 0);\n```\n\n### void NanSetInternalFieldPointer(Handle<Object>, int, void *)\n\nSets the value of the internal field at `index` on a V8 `Object` handle.\n\n```c++\nstatic Persistent dataWrapperCtor;\n...\nLocal wrapper = NanNew(dataWrapperCtor)->NewInstance();\nNanSetInternalFieldPointer(wrapper, 0, this);\n```\n\n\n### Local<Object> NanObjectWrapHandle(Object)\n\nWhen you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`:\n\n```c++\nNanObjectWrapHandle(iterator)->Get(NanNew(\"end\"))\n```\n\n\n### ~~Local<String> NanSymbol(const char *)~~\n\nDeprecated. Use `NanNew` instead.\n~~Use to create string symbol objects (i.e. `v8::String::NewSymbol(x)`), for getting and setting object properties, or names of objects.~~\n\n```c++\nbool foo = false;\nif (obj->Has(NanNew(\"foo\")))\n foo = optionsObj->Get(NanNew(\"foo\"))->BooleanValue()\n```\n\n\n### Type NanGetPointerSafe(Type *[, Type])\n\nA helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to.\n\n```c++\nchar *plugh(uint32_t *optional) {\n char res[] = \"xyzzy\";\n uint32_t param = NanGetPointerSafe(optional, 0x1337);\n switch (param) {\n ...\n }\n NanSetPointerSafe(optional, 0xDEADBEEF);\n} \n```\n\n\n### bool NanSetPointerSafe(Type *, Type)\n\nA helper for setting optional argument pointers. If the pointer is `NULL`, the function simply returns `false`. Otherwise, the value is assigned to the variable the pointer points to.\n\n```c++\nconst char *plugh(size_t *outputsize) {\n char res[] = \"xyzzy\";\n if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) {\n ...\n }\n\n ...\n}\n```\n\n\n### ~~void* NanRawString(Handle<Value>, enum Nan::Encoding, size_t *, void *, size_t, int)~~\n\nDeprecated. Use something else.\n\n~~When you want to convert a V8 `String` to a `char*` buffer, use `NanRawString`. You have to supply an encoding as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows setting `String::WriteOptions`.\nJust remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~\n\n```c++\nsize_t count;\nvoid* decoded = NanRawString(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED);\n...\ndelete[] reinterpret_cast(decoded);\n```\n\n\n### ~~char* NanCString(Handle<Value>, size_t *[, char *, size_t, int])~~\n\nDeprecated. Use `String::Utf8Value` or `NanUtf8String` instead.\n\n~~When you want to convert a V8 `String` to a null-terminated C `char*` use `NanCString`. The resulting `char*` will be UTF-8-encoded, and you need to supply a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `v8::String::NO_OPTIONS`.\nJust remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~\n\n```c++\nsize_t count;\nchar* name = NanCString(args[0], &count);\n...\ndelete[] name;\n```\n\n\n### NanAsciiString\n\nContrary to the name, this is not actually an ASCII string, it is a one-byte string with no particular encoding. Do not use unless you actually need this incorrect legacy behavior. Consider fixing your broken code instead. If you actually have a proper ASCII-string, use UTF-8, which is a proper superset of ASCII.\nConvert a `String` to zero-terminated, sort-of Ascii-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanAsciiString(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanAsciiString baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanAsciiString *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanAsciiString(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n### NanUtf8String\n\nEquivalent to `String::Utf8Value`, it only exists for the sake of completeness.\nConvert a `String` to zero-terminated, Utf8-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanUtf8String(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanUtf8String baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanUtf8String *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanUtf8String(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n\n### NanUcs2String\n\nEquivalent to `String::Value`, it only exists for the sake of completeness.\nConvert a `String` to zero-terminated, Ucs2-encoded `uint16_t *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanUcs2String(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanUcs2String baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanUcs2String *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanUcs2String(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool])\n\nWhen you have an \"options\" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`.\n\nThe optional last parameter is the *default* value, which is `false` if left off:\n\n```c++\n// `foo` is false unless the user supplies a truthy value for it\nbool foo = NanBooleanOptionValue(optionsObj, NanNew(\"foo\"));\n// `bar` is true unless the user supplies a falsy value for it\nbool bar = NanBooleanOptionValueDefTrue(optionsObj, NanNew(\"bar\"), true);\n```\n\n\n### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t)\n\nSimilar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer.\n\nRequires all 3 arguments as a default is not optional:\n\n```c++\nuint32_t count = NanUInt32OptionValue(optionsObj, NanNew(\"count\"), 1024);\n```\n\n\n### NanError(message), NanTypeError(message), NanRangeError(message)\n\nFor making `Error`, `TypeError` and `RangeError` objects.\n\n```c++\nLocal res = NanError(\"you must supply a callback argument\");\n```\n\n\n### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int)\n\nFor throwing `Error`, `TypeError` and `RangeError` objects.\n\n```c++\nNanThrowError(\"you must supply a callback argument\");\n```\n\nCan also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`.\n\n\n### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t)\n\nThe `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation:\n\n```c++\nNanNewBufferHandle((char*)value.data(), value.size());\n```\n\nCan also be used to initialize a `Buffer` with just a `size` argument.\n\nCan also be supplied with a `NanFreeCallback` and a hint for the garbage collector.\n\n\n### Local<Object> NanBufferUse(char*, uint32_t)\n\n`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data.\nWhile it was possible to get around this, it required a shim by passing a\ncallback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove\nneeding to use this shim.\n\n`NanBufferUse` uses the `char*` passed as the backing data, and will free the\nmemory automatically when the weak callback is called. Keep this in mind, as\ncareless use can lead to \"double free or corruption\" and other cryptic failures.\n\n\n### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)\n\nCan be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for.\n\n\n### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>])\nCreates a new `Local` handle.\n\n```c++\nLocal ftmpl = NanNew();\nLocal otmpl = ftmpl->InstanceTemplate();\nLocal ctx = NanNewContextHandle(NULL, otmpl);\n```\n\n\n### Local<Context> NanGetCurrentContext()\n\nGets the current context.\n\n```c++\nLocal ctx = NanGetCurrentContext();\n```\n\n\n### void NanDisposePersistent(Persistent<T> &)\n\nUse `NanDisposePersistent` to dispose a `Persistent` handle.\n\n```c++\nNanDisposePersistent(persistentHandle);\n```\n\n\n### NanAssignPersistent(handle, object)\n\nUse `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier.\n\nIn general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`:\n\n```c++\nPersistent persistentHandle;\n\n...\n\nLocal obj = NanNew();\nobj->Set(NanNew(\"key\"), keyHandle); // where keyHandle might be a Local\nNanAssignPersistent(persistentHandle, obj)\n```\n\n\n### _NanWeakCallbackInfo<T, P>* NanMakeWeakPersistent(Handle<T>, P*, _NanWeakCallbackInfo<T, P>::Callback)\n\nCreates a weak persistent handle with the supplied parameter and `NAN_WEAK_CALLBACK`.\n\n```c++\nNAN_WEAK_CALLBACK(weakCallback) {\n\n...\n\n}\n\nLocal func;\n\n...\n\nint *parameter = new int(0);\nNanMakeWeakPersistent(func, parameter, &weakCallback);\n```\n\n\n### NanSetTemplate(templ, name, value [, attributes])\n\nUse to add properties on object and function templates.\n\n\n### NanSetPrototypeTemplate(templ, name, value [, attributes])\n\nUse to add prototype properties on function templates.\n\n\n### NanSetInstanceTemplate(templ, name, value [, attributes])\n\nUse to add instance properties on function templates.\n\n\n### NanMakeCallback(target, func, argc, argv)\n\nUse instead of `node::MakeCallback` to call javascript functions. This (or `NanCallback`) is the only proper way of calling functions. You must _*never, ever*_ directly use `Function::Call`, it will lead to run-time failures.\n\n\n### NanCompileScript(Handle s [, const ScriptOrigin& origin])\n\nUse to create new scripts bound to the current context.\n\n\n### NanRunScript(script)\n\nUse to run both bound and unbound scripts.\n\n\n### NanAdjustExternalMemory(int change_in_bytes)\n\nSimply does `AdjustAmountOfExternalAllocatedMemory`, note that the argument and returned value have type `int`.\n\n\n### NanAddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll)\n\nSimply does `AddGCEpilogueCallback`\n\n\n### NanAddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll)\n\nSimply does `AddGCPrologueCallback`\n\n\n### NanRemoveGCEpilogueCallback(GCEpilogueCallback callback)\n\nSimply does `RemoveGCEpilogueCallback`\n\n\n### NanRemoveGCPrologueCallback(GCPrologueCallback callback)\n\nSimply does `RemoveGCPrologueCallback`\n\n\n### NanGetHeapStatistics(HeapStatistics *heap_statistics)\n\nSimply does `GetHeapStatistics`\n\n\n### NanCallback\n\nBecause of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Handle` is annoyingly tricky. `NanCallback` makes it easier by taking your handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`.\n\n```c++\nLocal callbackHandle = args[0].As();\nNanCallback *callback = new NanCallback(callbackHandle);\n// pass `callback` around and it's safe from GC until you:\ndelete callback;\n```\n\nYou can execute the callback like so:\n\n```c++\n// no arguments:\ncallback->Call(0, NULL);\n\n// an error argument:\nHandle argv[] = {\n NanError(NanNew(\"fail!\"))\n};\ncallback->Call(1, argv);\n\n// a success argument:\nHandle argv[] = {\n NanNull(),\n NanNew(\"w00t!\")\n};\ncallback->Call(2, argv);\n```\n\n`NanCallback` also has a `Local GetFunction()` method that you can use\nto fetch a local handle to the underlying callback function, as well as a\n`void SetFunction(Handle)` for setting the callback on the\n`NanCallback`. You can check if a `NanCallback` is empty with the `bool IsEmpty()` method. Additionally a generic constructor is available for using\n`NanCallback` without performing heap allocations.\n\n\n### NanAsyncWorker\n\n`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress.\n\nSee a rough outline of the implementation:\n\n```c++\nclass NanAsyncWorker {\npublic:\n NanAsyncWorker (NanCallback *callback);\n\n // Clean up persistent handles and delete the *callback\n virtual ~NanAsyncWorker ();\n\n // Check the `ErrorMessage()` and call HandleOKCallback()\n // or HandleErrorCallback depending on whether it has been set or not\n virtual void WorkComplete ();\n\n // You must implement this to do some async work. If there is an\n // error then use `SetErrorMessage()` to set an error message and the callback will\n // be passed that string in an Error object\n virtual void Execute ();\n\n // Save a V8 object in a Persistent handle to protect it from GC\n void SaveToPersistent(const char *key, Local &obj);\n\n // Fetch a stored V8 object (don't call from within `Execute()`)\n Local GetFromPersistent(const char *key);\n\n // Get the error message (or NULL)\n const char *ErrorMessage();\n\n // Set an error message\n void SetErrorMessage(const char *msg);\n\nprotected:\n // Default implementation calls the callback function with no arguments.\n // Override this to return meaningful data\n virtual void HandleOKCallback ();\n\n // Default implementation calls the callback function with an Error object\n // wrapping the `errmsg` string\n virtual void HandleErrorCallback ();\n};\n```\n\n\n### NanAsyncQueueWorker(NanAsyncWorker *)\n\n`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`.\n\n\n### Tests\n\nTo run the NAN tests do:\n\n``` sh\nnpm install\nnpm run-script rebuild-tests\nnpm test\n```\n\nOr just:\n\n``` sh\nnpm install\nmake test\n```\n\n### Contributors\n\nNAN is only possible due to the excellent work of the following contributors:\n\n\n\n\n\n\n\n\n\n
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnat-
\n\nLicence & copyright\n-----------------------\n\nCopyright (c) 2015 NAN contributors (listed above).\n\nNative Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/rvagg/nan/issues" + }, + "_id": "nan@1.5.3", + "dist": { + "shasum": "f07ee4ad6ab18083cf8c826542ff391387cf5215" + }, + "_from": "nan@~1.5.1", + "_resolved": "https://registry.npmjs.org/nan/-/nan-1.5.3.tgz" +} diff --git a/scripts/external/three/canvas/package.json b/scripts/external/three/canvas/package.json new file mode 100644 index 0000000..33b3b4f --- /dev/null +++ b/scripts/external/three/canvas/package.json @@ -0,0 +1,67 @@ +{ + "name": "canvas", + "description": "Canvas graphics API backed by Cairo", + "version": "1.2.1", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@learnboost.com" + }, + "contributors": [ + { + "name": "Nathan Rajlich", + "email": "nathan@tootallnate.net" + }, + { + "name": "Rod Vagg", + "email": "r@va.gg" + }, + { + "name": "Juriy Zaytsev", + "email": "kangax@gmail.com" + } + ], + "keywords": [ + "canvas", + "graphic", + "graphics", + "pixman", + "cairo", + "image", + "images", + "pdf" + ], + "homepage": "https://github.com/learnboost/node-canvas", + "repository": { + "type": "git", + "url": "git://github.com/learnboost/node-canvas" + }, + "scripts": { + "test": "make test", + "install": "node-gyp rebuild" + }, + "dependencies": { + "nan": "~1.5.1" + }, + "devDependencies": { + "express": "3.0", + "jade": "0.28.1", + "mocha": "*", + "should": "*" + }, + "engines": { + "node": ">= 0.6.0" + }, + "main": "./lib/canvas.js", + "gypfile": true, + "readme": "node-canvas\n===========\n### Canvas graphics API backed by Cairo\n[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas)\n[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas)\n\n node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org).\n\n## Authors\n\n - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))\n - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate))\n - Rod Vagg ([rvagg](http://github.com/rvagg))\n - Juriy Zaytsev ([kangax](http://github.com/kangax))\n\n## Installation\n\n```bash\n$ npm install canvas\n```\n\nUnless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/LearnBoost/node-canvas/wiki/_pages).\n\nYou can quickly install Cairo and its dependencies for OS X using the one liner below:\n\n```bash\n$ wget https://raw.githubusercontent.com/LearnBoost/node-canvas/master/install -O - | sh\n```\n\nor if you use MacPorts\n\n```bash\nsudo port install pkgconfig libpng giflib freetype libpixman cairo\n```\n\n## Screencasts\n\n - [Introduction](http://screenr.com/CTk)\n\n## Example\n\n```javascript\nvar Canvas = require('canvas')\n , Image = Canvas.Image\n , canvas = new Canvas(200,200)\n , ctx = canvas.getContext('2d');\n\nctx.font = '30px Impact';\nctx.rotate(.1);\nctx.fillText(\"Awesome!\", 50, 100);\n\nvar te = ctx.measureText('Awesome!');\nctx.strokeStyle = 'rgba(0,0,0,0.5)';\nctx.beginPath();\nctx.lineTo(50, 102);\nctx.lineTo(50 + te.width, 102);\nctx.stroke();\n\nconsole.log('');\n```\n\n## Non-Standard API\n\n node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers.\n\n### Image#src=Buffer\n\n node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O.\n\n```javascript\nfs.readFile(__dirname + '/images/squid.png', function(err, squid){\n if (err) throw err;\n img = new Image;\n img.src = squid;\n ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4);\n});\n```\n\n Below is an example of a canvas drawing it-self as the source several time:\n\n```javascript\nvar img = new Image;\nimg.src = canvas.toBuffer();\nctx.drawImage(img, 0, 0, 50, 50);\nctx.drawImage(img, 50, 0, 50, 50);\nctx.drawImage(img, 100, 0, 50, 50);\n```\n\n### Image#dataMode\n\nnode-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs).\n\nWhen mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering.\n\n```javascript\nvar img = new Image;\nimg.dataMode = Image.MODE_IMAGE; // Only image data tracked\nimg.dataMode = Image.MODE_MIME; // Only mime data tracked\nimg.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked\n```\n\nIf image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.\n\n### Canvas#pngStream()\n\n To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted.\n\n```javascript\nvar fs = require('fs')\n , out = fs.createWriteStream(__dirname + '/text.png')\n , stream = canvas.pngStream();\n\nstream.on('data', function(chunk){\n out.write(chunk);\n});\n\nstream.on('end', function(){\n console.log('saved png');\n});\n```\n\nCurrently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`.\n\n### Canvas#jpegStream() and Canvas#syncJPEGStream()\n\nYou can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with\nsome optional parameters; functionality is otherwise identical to\n`pngStream()`. See `examples/crop.js` for an example.\n\n_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both\nare synchronous_\n\n```javascript\nvar stream = canvas.jpegStream({\n bufsize: 4096 // output buffer size in bytes, default: 4096\n , quality: 75 // JPEG quality (0-100) default: 75\n , progressive: false // true for progressive compression, default: false\n});\n```\n\n### Canvas#toBuffer()\n\nA call to `Canvas#toBuffer()` will return a node `Buffer` instance containing all of the PNG data.\n\n```javascript\ncanvas.toBuffer();\n```\n\n### Canvas#toBuffer() async\n\nOptionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`.\n\n```javascript\ncanvas.toBuffer(function(err, buf){\n\n});\n```\n\n### Canvas#toDataURL() async\n\nOptionally we may pass a callback function to `Canvas#toDataURL()`, and this process will be performed asynchronously, and will `callback(err, str)`.\n\n```javascript\ncanvas.toDataURL(function(err, str){\n\n});\n```\n\nor specify the mime type:\n\n```javascript\ncanvas.toDataURL('image/png', function(err, str){\n\n});\n```\n\n### CanvasRenderingContext2d#patternQuality\n\nGiven one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.\n\n - fast\n - good\n - best\n - nearest\n - bilinear\n\n### CanvasRenderingContext2d#textDrawingMode\n\nCan be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill.\n\nDefaults to _path_.\n\nThis property is tracked as part of the canvas state in save/restore.\n\n### CanvasRenderingContext2d#filter\n\nLike `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_.\n\n - fast\n - good\n - best\n - nearest\n - bilinear\n\n### Global Composite Operations\n\nIn addition to those specified and commonly implemented by browsers, the following have been added:\n\n - multiply\n - screen\n - overlay\n - hard-light\n - soft-light\n - hsl-hue\n - hsl-saturation\n - hsl-color\n - hsl-luminosity\n\n## Anti-Aliasing\n\n Set anti-aliasing mode\n\n - default\n - none\n - gray\n - subpixel\n\n For example:\n\n```javascript\nctx.antialias = 'none';\n```\n\n## PDF Support\n\n Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating\n a PDF on initialization, using the \"pdf\" string:\n\n```js\nvar canvas = new Canvas(200, 500, 'pdf');\n```\n\n An additional method `.addPage()` is then available to create\n multiple page PDFs:\n\n```js\nctx.font = '22px Helvetica';\nctx.fillText('Hello World', 50, 80);\nctx.addPage();\n\nctx.font = '22px Helvetica';\nctx.fillText('Hello World 2', 50, 80);\nctx.addPage();\n\nctx.font = '22px Helvetica';\nctx.fillText('Hello World 3', 50, 80);\nctx.addPage();\n```\n\n## SVG support\n\n Just like PDF support, make sure to install cairo with `--enable-svg=yes`.\n You also need to tell node-canvas that it is working on SVG upon its initialization:\n\n```js\nvar canvas = new Canvas(200, 500, 'svg');\n// Use the normal primitives.\nfs.writeFile('out.svg', canvas.toBuffer());\n```\n\n## Benchmarks\n\n Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself.\n\n## Contribute\n\n Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/LearnBoost/node-canvas/issues) for existing issues.\n\n## Examples\n\n Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser.\n\n## Testing\n\nIf you have not previously, init git submodules:\n\n $ git submodule update --init\n\nBuild node-canvas:\n\n $ node-gyp rebuild\n\nUnit tests:\n\n $ make test\n\nVisual tests:\n\n $ make test-server\n\n## Versions\n\nTested with and designed for:\n\n - node 0.4.2\n - cairo 1.8.6\n\nFor node 0.2.x `node-canvas` <= 0.4.3 may be used,\n0.5.0 and above are designed for node 0.4.x only.\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2010 LearnBoost, and contributors <dev@learnboost.com>\n\nCopyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/learnboost/node-canvas/issues" + }, + "_id": "canvas@1.2.1", + "dist": { + "shasum": "fed6cff0dc4d978badbf71bb8f9077b617450bc8" + }, + "_from": "canvas@", + "_resolved": "https://registry.npmjs.org/canvas/-/canvas-1.2.1.tgz" +} diff --git a/scripts/external/three/canvas/src/Canvas.cc b/scripts/external/three/canvas/src/Canvas.cc new file mode 100644 index 0000000..93f0329 --- /dev/null +++ b/scripts/external/three/canvas/src/Canvas.cc @@ -0,0 +1,575 @@ +// +// Canvas.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "Canvas.h" +#include "PNG.h" +#include "CanvasRenderingContext2d.h" +#include +#include +#include +#include +#include +#include +#include +#include "closure.h" + +#ifdef HAVE_JPEG +#include "JPEGStream.h" +#endif + +Persistent Canvas::constructor; + +/* + * Initialize Canvas. + */ + +void +Canvas::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(Canvas::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("Canvas")); + + // Prototype + Local proto = ctor->PrototypeTemplate(); + NODE_SET_PROTOTYPE_METHOD(ctor, "toBuffer", ToBuffer); + NODE_SET_PROTOTYPE_METHOD(ctor, "streamPNGSync", StreamPNGSync); +#ifdef HAVE_JPEG + NODE_SET_PROTOTYPE_METHOD(ctor, "streamJPEGSync", StreamJPEGSync); +#endif + proto->SetAccessor(NanNew("type"), GetType); + proto->SetAccessor(NanNew("width"), GetWidth, SetWidth); + proto->SetAccessor(NanNew("height"), GetHeight, SetHeight); + + NanSetTemplate(proto, "PNG_NO_FILTERS", NanNew(PNG_NO_FILTERS)); + NanSetTemplate(proto, "PNG_FILTER_NONE", NanNew(PNG_FILTER_NONE)); + NanSetTemplate(proto, "PNG_FILTER_SUB", NanNew(PNG_FILTER_SUB)); + NanSetTemplate(proto, "PNG_FILTER_UP", NanNew(PNG_FILTER_UP)); + NanSetTemplate(proto, "PNG_FILTER_AVG", NanNew(PNG_FILTER_AVG)); + NanSetTemplate(proto, "PNG_FILTER_PAETH", NanNew(PNG_FILTER_PAETH)); + NanSetTemplate(proto, "PNG_ALL_FILTERS", NanNew(PNG_ALL_FILTERS)); + + target->Set(NanNew("Canvas"), ctor->GetFunction()); +} + +/* + * Initialize a Canvas with the given width and height. + */ + +NAN_METHOD(Canvas::New) { + NanScope(); + int width = 0, height = 0; + canvas_type_t type = CANVAS_TYPE_IMAGE; + if (args[0]->IsNumber()) width = args[0]->Uint32Value(); + if (args[1]->IsNumber()) height = args[1]->Uint32Value(); + if (args[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(args[2])) + ? CANVAS_TYPE_PDF + : !strcmp("svg", *String::Utf8Value(args[2])) + ? CANVAS_TYPE_SVG + : CANVAS_TYPE_IMAGE; + Canvas *canvas = new Canvas(width, height, type); + canvas->Wrap(args.This()); + NanReturnValue(args.This()); +} + +/* + * Get type string. + */ + +NAN_GETTER(Canvas::GetType) { + NanScope(); + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image")); +} + +/* + * Get width. + */ + +NAN_GETTER(Canvas::GetWidth) { + NanScope(); + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(canvas->width)); +} + +/* + * Set width. + */ + +NAN_SETTER(Canvas::SetWidth) { + NanScope(); + if (value->IsNumber()) { + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + canvas->width = value->Uint32Value(); + canvas->resurface(args.This()); + } +} + +/* + * Get height. + */ + +NAN_GETTER(Canvas::GetHeight) { + NanScope(); + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(canvas->height)); +} + +/* + * Set height. + */ + +NAN_SETTER(Canvas::SetHeight) { + NanScope(); + if (value->IsNumber()) { + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + canvas->height = value->Uint32Value(); + canvas->resurface(args.This()); + } +} + +/* + * Canvas::ToBuffer callback. + */ + +static cairo_status_t +toBuffer(void *c, const uint8_t *data, unsigned len) { + closure_t *closure = (closure_t *) c; + + if (closure->len + len > closure->max_len) { + uint8_t *data; + unsigned max = closure->max_len; + + do { + max *= 2; + } while (closure->len + len > max); + + data = (uint8_t *) realloc(closure->data, max); + if (!data) return CAIRO_STATUS_NO_MEMORY; + closure->data = data; + closure->max_len = max; + } + + memcpy(closure->data + closure->len, data, len); + closure->len += len; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * EIO toBuffer callback. + */ + +#if NODE_VERSION_AT_LEAST(0, 6, 0) +void +Canvas::ToBufferAsync(uv_work_t *req) { +#elif NODE_VERSION_AT_LEAST(0, 5, 4) +void +Canvas::EIO_ToBuffer(eio_req *req) { +#else +int +Canvas::EIO_ToBuffer(eio_req *req) { +#endif + closure_t *closure = (closure_t *) req->data; + + closure->status = canvas_write_to_png_stream( + closure->canvas->surface() + , toBuffer + , closure); + +#if !NODE_VERSION_AT_LEAST(0, 5, 4) + return 0; +#endif +} + +/* + * EIO after toBuffer callback. + */ + +#if NODE_VERSION_AT_LEAST(0, 6, 0) +void +Canvas::ToBufferAsyncAfter(uv_work_t *req) { +#else +int +Canvas::EIO_AfterToBuffer(eio_req *req) { +#endif + + NanScope(); + closure_t *closure = (closure_t *) req->data; +#if NODE_VERSION_AT_LEAST(0, 6, 0) + delete req; +#else + ev_unref(EV_DEFAULT_UC); +#endif + + if (closure->status) { + Local argv[1] = { Canvas::Error(closure->status) }; + closure->pfn->Call(1, argv); + } else { + Local buf = NanNewBufferHandle((char*)closure->data, closure->len); + memcpy(Buffer::Data(buf), closure->data, closure->len); + Local argv[2] = { NanNew(NanNull()), buf }; + closure->pfn->Call(2, argv); + } + + closure->canvas->Unref(); + delete closure->pfn; + closure_destroy(closure); + free(closure); + +#if !NODE_VERSION_AT_LEAST(0, 6, 0) + return 0; +#endif +} + +/* + * Convert PNG data to a node::Buffer, async when a + * callback function is passed. + */ + +NAN_METHOD(Canvas::ToBuffer) { + NanScope(); + cairo_status_t status; + uint32_t compression_level = 6; + uint32_t filter = PNG_ALL_FILTERS; + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + + // TODO: async / move this out + if (canvas->isPDF() || canvas->isSVG()) { + cairo_surface_finish(canvas->surface()); + closure_t *closure = (closure_t *) canvas->closure(); + + Local buf = NanNewBufferHandle((char*) closure->data, closure->len); + NanReturnValue(buf); + } + + if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { + if (!args[1]->StrictEquals(NanUndefined())) { + bool good = true; + if (args[1]->IsNumber()) { + compression_level = args[1]->Uint32Value(); + } else if (args[1]->IsString()) { + if (args[1]->StrictEquals(NanNew("0"))) { + compression_level = 0; + } else { + uint32_t tmp = args[1]->Uint32Value(); + if (tmp == 0) { + good = false; + } else { + compression_level = tmp; + } + } + } else { + good = false; + } + + if (good) { + if (compression_level > 9) { + return NanThrowRangeError("Allowed compression levels lie in the range [0, 9]."); + } + } else { + return NanThrowTypeError("Compression level must be a number."); + } + } + + if (!args[2]->StrictEquals(NanUndefined())) { + if (args[2]->IsUint32()) { + filter = args[2]->Uint32Value(); + } else { + return NanThrowTypeError("Invalid filter value."); + } + } + } + + // Async + if (args[0]->IsFunction()) { + closure_t *closure = (closure_t *) malloc(sizeof(closure_t)); + status = closure_init(closure, canvas, compression_level, filter); + + // ensure closure is ok + if (status) { + closure_destroy(closure); + free(closure); + return NanThrowError(Canvas::Error(status)); + } + + // TODO: only one callback fn in closure + canvas->Ref(); + closure->pfn = new NanCallback(args[0].As()); + +#if NODE_VERSION_AT_LEAST(0, 6, 0) + uv_work_t* req = new uv_work_t; + req->data = closure; + uv_queue_work(uv_default_loop(), req, ToBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter); +#else + eio_custom(EIO_ToBuffer, EIO_PRI_DEFAULT, EIO_AfterToBuffer, closure); + ev_ref(EV_DEFAULT_UC); +#endif + + NanReturnUndefined(); + // Sync + } else { + closure_t closure; + status = closure_init(&closure, canvas, compression_level, filter); + + // ensure closure is ok + if (status) { + closure_destroy(&closure); + return NanThrowError(Canvas::Error(status)); + } + + TryCatch try_catch; + status = canvas_write_to_png_stream(canvas->surface(), toBuffer, &closure); + + if (try_catch.HasCaught()) { + closure_destroy(&closure); + NanReturnValue(try_catch.ReThrow()); + } else if (status) { + closure_destroy(&closure); + return NanThrowError(Canvas::Error(status)); + } else { + Local buf = NanNewBufferHandle((char *)closure.data, closure.len); + closure_destroy(&closure); + NanReturnValue(buf); + } + } +} + +/* + * Canvas::StreamPNG callback. + */ + +static cairo_status_t +streamPNG(void *c, const uint8_t *data, unsigned len) { + NanScope(); + closure_t *closure = (closure_t *) c; + Local buf = NanNewBufferHandle((char *)data, len); + Local argv[3] = { + NanNew(NanNull()) + , buf + , NanNew(len) }; + NanMakeCallback(NanGetCurrentContext()->Global(), closure->fn, 3, argv); + return CAIRO_STATUS_SUCCESS; +} + +/* + * Stream PNG data synchronously. + */ + +NAN_METHOD(Canvas::StreamPNGSync) { + NanScope(); + uint32_t compression_level = 6; + uint32_t filter = PNG_ALL_FILTERS; + // TODO: async as well + if (!args[0]->IsFunction()) + return NanThrowTypeError("callback function required"); + + if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { + if (!args[1]->StrictEquals(NanUndefined())) { + bool good = true; + if (args[1]->IsNumber()) { + compression_level = args[1]->Uint32Value(); + } else if (args[1]->IsString()) { + if (args[1]->StrictEquals(NanNew("0"))) { + compression_level = 0; + } else { + uint32_t tmp = args[1]->Uint32Value(); + if (tmp == 0) { + good = false; + } else { + compression_level = tmp; + } + } + } else { + good = false; + } + + if (good) { + if (compression_level > 9) { + return NanThrowRangeError("Allowed compression levels lie in the range [0, 9]."); + } + } else { + return NanThrowTypeError("Compression level must be a number."); + } + } + + if (!args[2]->StrictEquals(NanUndefined())) { + if (args[2]->IsUint32()) { + filter = args[1]->Uint32Value(); + } else { + return NanThrowTypeError("Invalid filter value."); + } + } + } + + + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + closure_t closure; + closure.fn = Handle::Cast(args[0]); + closure.compression_level = compression_level; + closure.filter = filter; + + TryCatch try_catch; + + cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure); + + if (try_catch.HasCaught()) { + NanReturnValue(try_catch.ReThrow()); + } else if (status) { + Local argv[1] = { Canvas::Error(status) }; + NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); + } else { + Local argv[3] = { + NanNew(NanNull()) + , NanNew(NanNull()) + , NanNew(0) }; + NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); + } + NanReturnUndefined(); +} + +/* + * Stream JPEG data synchronously. + */ + +#ifdef HAVE_JPEG + +NAN_METHOD(Canvas::StreamJPEGSync) { + NanScope(); + // TODO: async as well + if (!args[0]->IsNumber()) + return NanThrowTypeError("buffer size required"); + if (!args[1]->IsNumber()) + return NanThrowTypeError("quality setting required"); + if (!args[2]->IsBoolean()) + return NanThrowTypeError("progressive setting required"); + if (!args[3]->IsFunction()) + return NanThrowTypeError("callback function required"); + + Canvas *canvas = ObjectWrap::Unwrap(args.This()); + closure_t closure; + closure.fn = Handle::Cast(args[3]); + + TryCatch try_catch; + write_to_jpeg_stream(canvas->surface(), args[0]->NumberValue(), args[1]->NumberValue(), args[2]->BooleanValue(), &closure); + + if (try_catch.HasCaught()) + NanReturnValue(try_catch.ReThrow()); + NanReturnUndefined(); +} + +#endif + +/* + * Initialize cairo surface. + */ + +Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { + type = t; + width = w; + height = h; + _surface = NULL; + _closure = NULL; + + if (CANVAS_TYPE_PDF == t) { + _closure = malloc(sizeof(closure_t)); + assert(_closure); + cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + assert(status == CAIRO_STATUS_SUCCESS); + _surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h); + } else if (CANVAS_TYPE_SVG == t) { + _closure = malloc(sizeof(closure_t)); + assert(_closure); + cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + assert(status == CAIRO_STATUS_SUCCESS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h); + } else { + _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + assert(_surface); + NanAdjustExternalMemory(4 * w * h); + } +} + +/* + * Destroy cairo surface. + */ + +Canvas::~Canvas() { + switch (type) { + case CANVAS_TYPE_PDF: + case CANVAS_TYPE_SVG: + cairo_surface_finish(_surface); + closure_destroy((closure_t *) _closure); + free(_closure); + cairo_surface_destroy(_surface); + break; + case CANVAS_TYPE_IMAGE: + cairo_surface_destroy(_surface); + NanAdjustExternalMemory(-4 * width * height); + break; + } +} + +/* + * Re-alloc the surface, destroying the previous. + */ + +void +Canvas::resurface(Handle canvas) { + NanScope(); + Handle context; + switch (type) { + case CANVAS_TYPE_PDF: + cairo_pdf_surface_set_size(_surface, width, height); + break; + case CANVAS_TYPE_SVG: + // Re-surface + cairo_surface_finish(_surface); + closure_destroy((closure_t *) _closure); + cairo_surface_destroy(_surface); + closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height); + + // Reset context + context = canvas->Get(NanNew("context")); + if (!context->IsUndefined()) { + Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); + cairo_t *prev = context2d->context(); + context2d->setContext(cairo_create(surface())); + cairo_destroy(prev); + } + break; + case CANVAS_TYPE_IMAGE: + // Re-surface + int old_width = cairo_image_surface_get_width(_surface); + int old_height = cairo_image_surface_get_height(_surface); + cairo_surface_destroy(_surface); + _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + NanAdjustExternalMemory(4 * (width * height - old_width * old_height)); + + // Reset context + context = canvas->Get(NanNew("context")); + if (!context->IsUndefined()) { + Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); + cairo_t *prev = context2d->context(); + context2d->setContext(cairo_create(surface())); + cairo_destroy(prev); + } + break; + } +} + +/* + * Construct an Error from the given cairo status. + */ + +Local +Canvas::Error(cairo_status_t status) { + return Exception::Error(NanNew(cairo_status_to_string(status))); +} diff --git a/scripts/external/three/canvas/src/Canvas.h b/scripts/external/three/canvas/src/Canvas.h new file mode 100644 index 0000000..90ef1e5 --- /dev/null +++ b/scripts/external/three/canvas/src/Canvas.h @@ -0,0 +1,96 @@ + +// +// Canvas.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_CANVAS_H__ +#define __NODE_CANVAS_H__ + +#include +#include +#include +#include + +#if HAVE_PANGO +#include +#else +#include +#endif + +#include + +using namespace v8; +using namespace node; + +/* + * Maxmimum states per context. + * TODO: remove/resize + */ + +#ifndef CANVAS_MAX_STATES +#define CANVAS_MAX_STATES 64 +#endif + +/* + * Canvas types. + */ + +typedef enum { + CANVAS_TYPE_IMAGE, + CANVAS_TYPE_PDF, + CANVAS_TYPE_SVG +} canvas_type_t; + +/* + * Canvas. + */ + +class Canvas: public node::ObjectWrap { + public: + int width; + int height; + canvas_type_t type; + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_METHOD(ToBuffer); + static NAN_GETTER(GetType); + static NAN_GETTER(GetWidth); + static NAN_GETTER(GetHeight); + static NAN_SETTER(SetWidth); + static NAN_SETTER(SetHeight); + static NAN_METHOD(StreamPNGSync); + static NAN_METHOD(StreamJPEGSync); + static Local Error(cairo_status_t status); +#if NODE_VERSION_AT_LEAST(0, 6, 0) + static void ToBufferAsync(uv_work_t *req); + static void ToBufferAsyncAfter(uv_work_t *req); +#else + static +#if NODE_VERSION_AT_LEAST(0, 5, 4) + void +#else + int +#endif + EIO_ToBuffer(eio_req *req); + static int EIO_AfterToBuffer(eio_req *req); +#endif + + inline bool isPDF(){ return CANVAS_TYPE_PDF == type; } + inline bool isSVG(){ return CANVAS_TYPE_SVG == type; } + inline cairo_surface_t *surface(){ return _surface; } + inline void *closure(){ return _closure; } + inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } + inline int stride(){ return cairo_image_surface_get_stride(_surface); } + Canvas(int width, int height, canvas_type_t type); + void resurface(Handle canvas); + + private: + ~Canvas(); + cairo_surface_t *_surface; + void *_closure; +}; + +#endif diff --git a/scripts/external/three/canvas/src/CanvasGradient.cc b/scripts/external/three/canvas/src/CanvasGradient.cc new file mode 100644 index 0000000..9e41c58 --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasGradient.cc @@ -0,0 +1,121 @@ + +// +// Gradient.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "color.h" +#include "Canvas.h" +#include "CanvasGradient.h" + +Persistent Gradient::constructor; + +/* + * Initialize CanvasGradient. + */ + +void +Gradient::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(Gradient::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("CanvasGradient")); + + // Prototype + NODE_SET_PROTOTYPE_METHOD(ctor, "addColorStop", AddColorStop); + target->Set(NanNew("CanvasGradient"), ctor->GetFunction()); +} + +/* + * Initialize a new CanvasGradient. + */ + +NAN_METHOD(Gradient::New) { + NanScope(); + + // Linear + if (4 == args.Length()) { + Gradient *grad = new Gradient( + args[0]->NumberValue() + , args[1]->NumberValue() + , args[2]->NumberValue() + , args[3]->NumberValue()); + grad->Wrap(args.This()); + NanReturnValue(args.This()); + } + + // Radial + if (6 == args.Length()) { + Gradient *grad = new Gradient( + args[0]->NumberValue() + , args[1]->NumberValue() + , args[2]->NumberValue() + , args[3]->NumberValue() + , args[4]->NumberValue() + , args[5]->NumberValue()); + grad->Wrap(args.This()); + NanReturnValue(args.This()); + } + + return NanThrowTypeError("invalid arguments"); +} + +/* + * Add color stop. + */ + +NAN_METHOD(Gradient::AddColorStop) { + NanScope(); + if (!args[0]->IsNumber()) + return NanThrowTypeError("offset required"); + if (!args[1]->IsString()) + return NanThrowTypeError("color string required"); + + Gradient *grad = ObjectWrap::Unwrap(args.This()); + short ok; + String::Utf8Value str(args[1]); + uint32_t rgba = rgba_from_string(*str, &ok); + + if (ok) { + rgba_t color = rgba_create(rgba); + cairo_pattern_add_color_stop_rgba( + grad->pattern() + , args[0]->NumberValue() + , color.r + , color.g + , color.b + , color.a); + } else { + return NanThrowTypeError("parse color failed"); + } + + NanReturnUndefined(); +} + +/* + * Initialize linear gradient. + */ + +Gradient::Gradient(double x0, double y0, double x1, double y1) { + _pattern = cairo_pattern_create_linear(x0, y0, x1, y1); +} + +/* + * Initialize radial gradient. + */ + +Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) { + _pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1); +} + +/* + * Destroy the pattern. + */ + +Gradient::~Gradient() { + cairo_pattern_destroy(_pattern); +} diff --git a/scripts/external/three/canvas/src/CanvasGradient.h b/scripts/external/three/canvas/src/CanvasGradient.h new file mode 100644 index 0000000..bcc531a --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasGradient.h @@ -0,0 +1,28 @@ + +// +// CanvasGradient.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_GRADIENT_H__ +#define __NODE_GRADIENT_H__ + +#include "Canvas.h" + +class Gradient: public node::ObjectWrap { + public: + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_METHOD(AddColorStop); + Gradient(double x0, double y0, double x1, double y1); + Gradient(double x0, double y0, double r0, double x1, double y1, double r1); + inline cairo_pattern_t *pattern(){ return _pattern; } + + private: + ~Gradient(); + cairo_pattern_t *_pattern; +}; + +#endif diff --git a/scripts/external/three/canvas/src/CanvasPattern.cc b/scripts/external/three/canvas/src/CanvasPattern.cc new file mode 100644 index 0000000..38c86d7 --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasPattern.cc @@ -0,0 +1,91 @@ + +// +// Pattern.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "Canvas.h" +#include "Image.h" +#include "CanvasPattern.h" + +Persistent Pattern::constructor; + +/* + * Initialize CanvasPattern. + */ + +void +Pattern::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(Pattern::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("CanvasPattern")); + + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("CanvasPattern")); + + // Prototype + target->Set(NanNew("CanvasPattern"), ctor->GetFunction()); +} + +/* + * Initialize a new CanvasPattern. + */ + +NAN_METHOD(Pattern::New) { + NanScope(); + + int w = 0 + , h = 0; + cairo_surface_t *surface; + + Local obj = args[0]->ToObject(); + + // Image + if (NanHasInstance(Image::constructor, obj)) { + Image *img = ObjectWrap::Unwrap(obj); + if (!img->isComplete()) { + return NanThrowError("Image given has not completed loading"); + } + w = img->width; + h = img->height; + surface = img->surface(); + + // Canvas + } else if (NanHasInstance(Canvas::constructor, obj)) { + Canvas *canvas = ObjectWrap::Unwrap(obj); + w = canvas->width; + h = canvas->height; + surface = canvas->surface(); + + // Invalid + } else { + return NanThrowTypeError("Image or Canvas expected"); + } + + Pattern *pattern = new Pattern(surface,w,h); + pattern->Wrap(args.This()); + NanReturnValue(args.This()); +} + + +/* + * Initialize linear gradient. + */ + +Pattern::Pattern(cairo_surface_t *surface, int w, int h): + _width(w), _height(h) { + _pattern = cairo_pattern_create_for_surface(surface); +} + +/* + * Destroy the pattern. + */ + +Pattern::~Pattern() { + cairo_pattern_destroy(_pattern); +} diff --git a/scripts/external/three/canvas/src/CanvasPattern.h b/scripts/external/three/canvas/src/CanvasPattern.h new file mode 100644 index 0000000..ea3faeb --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasPattern.h @@ -0,0 +1,28 @@ + +// +// CanvasPattern.h +// +// Copyright (c) 2011 LearnBoost +// + +#ifndef __NODE_PATTERN_H__ +#define __NODE_PATTERN_H__ + +#include "Canvas.h" + +class Pattern: public node::ObjectWrap { + public: + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + Pattern(cairo_surface_t *surface, int w, int h); + inline cairo_pattern_t *pattern(){ return _pattern; } + + private: + ~Pattern(); + int _width, _height; + // TODO REPEAT/REPEAT_X/REPEAT_Y + cairo_pattern_t *_pattern; +}; + +#endif diff --git a/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc b/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc new file mode 100755 index 0000000..74b5924 --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc @@ -0,0 +1,2403 @@ + +// +// CanvasRenderingContext2d.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include +#include +#include +#include +#include +#include "Canvas.h" +#include "Point.h" +#include "Image.h" +#include "ImageData.h" +#include "CanvasRenderingContext2d.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" + +#ifdef HAVE_FREETYPE +#include "FontFace.h" +#endif + +// Windows doesn't support the C99 names for these +#ifndef isnan +#define isnan(x) _isnan(x) +#define isinf(x) (!_finite(x)) +#endif + +Persistent Context2d::constructor; + +/* + * Rectangle arg assertions. + */ + +#define RECT_ARGS \ + if (!args[0]->IsNumber() \ + ||!args[1]->IsNumber() \ + ||!args[2]->IsNumber() \ + ||!args[3]->IsNumber()) NanReturnUndefined(); \ + double x = args[0]->NumberValue(); \ + double y = args[1]->NumberValue(); \ + double width = args[2]->NumberValue(); \ + double height = args[3]->NumberValue(); + +/* + * Text baselines. + */ + +enum { + TEXT_BASELINE_ALPHABETIC + , TEXT_BASELINE_TOP + , TEXT_BASELINE_BOTTOM + , TEXT_BASELINE_MIDDLE + , TEXT_BASELINE_IDEOGRAPHIC + , TEXT_BASELINE_HANGING +}; + +#if HAVE_PANGO + +/* + * State helper function + */ + +void state_assign_fontFamily(canvas_state_t *state, const char *str) { + free(state->fontFamily); + state->fontFamily = strndup(str, 100); +} + + +/* + * Simple helper macro for a rather verbose function call. + */ + +#define PANGO_LAYOUT_GET_METRICS(LAYOUT) pango_context_get_metrics( \ + pango_layout_get_context(LAYOUT), \ + pango_layout_get_font_description(LAYOUT), \ + pango_context_get_language(pango_layout_get_context(LAYOUT))) + +#endif + +/* + * Initialize Context2d. + */ + +void +Context2d::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(Context2d::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("CanvasRenderingContext2d")); + + // Prototype + Local proto = ctor->PrototypeTemplate(); + NODE_SET_PROTOTYPE_METHOD(ctor, "drawImage", DrawImage); + NODE_SET_PROTOTYPE_METHOD(ctor, "putImageData", PutImageData); + NODE_SET_PROTOTYPE_METHOD(ctor, "addPage", AddPage); + NODE_SET_PROTOTYPE_METHOD(ctor, "save", Save); + NODE_SET_PROTOTYPE_METHOD(ctor, "restore", Restore); + NODE_SET_PROTOTYPE_METHOD(ctor, "rotate", Rotate); + NODE_SET_PROTOTYPE_METHOD(ctor, "translate", Translate); + NODE_SET_PROTOTYPE_METHOD(ctor, "transform", Transform); + NODE_SET_PROTOTYPE_METHOD(ctor, "resetTransform", ResetTransform); + NODE_SET_PROTOTYPE_METHOD(ctor, "isPointInPath", IsPointInPath); + NODE_SET_PROTOTYPE_METHOD(ctor, "scale", Scale); + NODE_SET_PROTOTYPE_METHOD(ctor, "clip", Clip); + NODE_SET_PROTOTYPE_METHOD(ctor, "fill", Fill); + NODE_SET_PROTOTYPE_METHOD(ctor, "stroke", Stroke); + NODE_SET_PROTOTYPE_METHOD(ctor, "fillText", FillText); + NODE_SET_PROTOTYPE_METHOD(ctor, "strokeText", StrokeText); + NODE_SET_PROTOTYPE_METHOD(ctor, "fillRect", FillRect); + NODE_SET_PROTOTYPE_METHOD(ctor, "strokeRect", StrokeRect); + NODE_SET_PROTOTYPE_METHOD(ctor, "clearRect", ClearRect); + NODE_SET_PROTOTYPE_METHOD(ctor, "rect", Rect); + NODE_SET_PROTOTYPE_METHOD(ctor, "measureText", MeasureText); + NODE_SET_PROTOTYPE_METHOD(ctor, "moveTo", MoveTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "lineTo", LineTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "bezierCurveTo", BezierCurveTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "quadraticCurveTo", QuadraticCurveTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "beginPath", BeginPath); + NODE_SET_PROTOTYPE_METHOD(ctor, "closePath", ClosePath); + NODE_SET_PROTOTYPE_METHOD(ctor, "arc", Arc); + NODE_SET_PROTOTYPE_METHOD(ctor, "arcTo", ArcTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "setLineDash", SetLineDash); + NODE_SET_PROTOTYPE_METHOD(ctor, "getLineDash", GetLineDash); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setFont", SetFont); +#ifdef HAVE_FREETYPE + NODE_SET_PROTOTYPE_METHOD(ctor, "_setFontFace", SetFontFace); +#endif + NODE_SET_PROTOTYPE_METHOD(ctor, "_setFillColor", SetFillColor); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setStrokeColor", SetStrokeColor); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setFillPattern", SetFillPattern); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setStrokePattern", SetStrokePattern); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextBaseline", SetTextBaseline); + NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextAlignment", SetTextAlignment); + proto->SetAccessor(NanNew("patternQuality"), GetPatternQuality, SetPatternQuality); + proto->SetAccessor(NanNew("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); + proto->SetAccessor(NanNew("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); + proto->SetAccessor(NanNew("shadowColor"), GetShadowColor, SetShadowColor); + proto->SetAccessor(NanNew("fillColor"), GetFillColor); + proto->SetAccessor(NanNew("strokeColor"), GetStrokeColor); + proto->SetAccessor(NanNew("miterLimit"), GetMiterLimit, SetMiterLimit); + proto->SetAccessor(NanNew("lineWidth"), GetLineWidth, SetLineWidth); + proto->SetAccessor(NanNew("lineCap"), GetLineCap, SetLineCap); + proto->SetAccessor(NanNew("lineJoin"), GetLineJoin, SetLineJoin); + proto->SetAccessor(NanNew("lineDashOffset"), GetLineDashOffset, SetLineDashOffset); + proto->SetAccessor(NanNew("shadowOffsetX"), GetShadowOffsetX, SetShadowOffsetX); + proto->SetAccessor(NanNew("shadowOffsetY"), GetShadowOffsetY, SetShadowOffsetY); + proto->SetAccessor(NanNew("shadowBlur"), GetShadowBlur, SetShadowBlur); + proto->SetAccessor(NanNew("antialias"), GetAntiAlias, SetAntiAlias); + proto->SetAccessor(NanNew("textDrawingMode"), GetTextDrawingMode, SetTextDrawingMode); + proto->SetAccessor(NanNew("filter"), GetFilter, SetFilter); + target->Set(NanNew("CanvasRenderingContext2d"), ctor->GetFunction()); +} + +/* + * Create a cairo context. + */ + +Context2d::Context2d(Canvas *canvas) { + _canvas = canvas; + _context = cairo_create(canvas->surface()); +#if HAVE_PANGO + _layout = pango_cairo_create_layout(_context); +#endif + cairo_set_line_width(_context, 1); + state = states[stateno = 0] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); + state->shadowBlur = 0; + state->shadowOffsetX = state->shadowOffsetY = 0; + state->globalAlpha = 1; + state->textAlignment = -1; + state->fillPattern = state->strokePattern = NULL; + state->fillGradient = state->strokeGradient = NULL; + state->textBaseline = TEXT_BASELINE_ALPHABETIC; + rgba_t transparent = { 0,0,0,1 }; + rgba_t transparent_black = { 0,0,0,0 }; + state->fill = transparent; + state->stroke = transparent; + state->shadow = transparent_black; + state->patternQuality = CAIRO_FILTER_GOOD; + state->textDrawingMode = TEXT_DRAW_PATHS; +#if HAVE_PANGO + state->fontWeight = PANGO_WEIGHT_NORMAL; + state->fontStyle = PANGO_STYLE_NORMAL; + state->fontSize = 10; + state->fontFamily = NULL; + state_assign_fontFamily(state, "sans serif"); + setFontFromState(); +#endif +} + +/* + * Destroy cairo context. + */ + +Context2d::~Context2d() { + while(stateno >= 0) { +#if HAVE_PANGO + free(states[stateno]->fontFamily); +#endif + free(states[stateno--]); + } +#if HAVE_PANGO + g_object_unref(_layout); +#endif + cairo_destroy(_context); +} + +/* + * Save cairo / canvas state. + */ + +void +Context2d::save() { + cairo_save(_context); + saveState(); +} + +/* + * Restore cairo / canvas state. + */ + +void +Context2d::restore() { + cairo_restore(_context); + restoreState(); +} + +/* + * Save the current state. + */ + +void +Context2d::saveState() { + if (stateno == CANVAS_MAX_STATES) return; + states[++stateno] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); + memcpy(states[stateno], state, sizeof(canvas_state_t)); +#if HAVE_PANGO + states[stateno]->fontFamily = strndup(state->fontFamily, 100); +#endif + state = states[stateno]; +} + +/* + * Restore state. + */ + +void +Context2d::restoreState() { + if (0 == stateno) return; + // Olaf (2011-02-21): Free old state data +#if HAVE_PANGO + free(states[stateno]->fontFamily); +#endif + free(states[stateno]); + states[stateno] = NULL; + state = states[--stateno]; +#if HAVE_PANGO + setFontFromState(); +#endif +} + +/* + * Save flat path. + */ + +void +Context2d::savePath() { + _path = cairo_copy_path_flat(_context); + cairo_new_path(_context); +} + +/* + * Restore flat path. + */ + +void +Context2d::restorePath() { + cairo_new_path(_context); + cairo_append_path(_context, _path); + cairo_path_destroy(_path); +} + +/* + * Fill and apply shadow. + */ + +void +Context2d::fill(bool preserve) { + if (state->fillPattern) { + cairo_set_source(_context, state->fillPattern); + cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT); + // TODO repeat/repeat-x/repeat-y + } else if (state->fillGradient) { + cairo_pattern_set_filter(state->fillGradient, state->patternQuality); + cairo_set_source(_context, state->fillGradient); + } else { + setSourceRGBA(state->fill); + } + + if (preserve) { + hasShadow() + ? shadow(cairo_fill_preserve) + : cairo_fill_preserve(_context); + } else { + hasShadow() + ? shadow(cairo_fill) + : cairo_fill(_context); + } +} + +/* + * Stroke and apply shadow. + */ + +void +Context2d::stroke(bool preserve) { + if (state->strokePattern) { + cairo_set_source(_context, state->strokePattern); + cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT); + } else if (state->strokeGradient) { + cairo_pattern_set_filter(state->strokeGradient, state->patternQuality); + cairo_set_source(_context, state->strokeGradient); + } else { + setSourceRGBA(state->stroke); + } + + if (preserve) { + hasShadow() + ? shadow(cairo_stroke_preserve) + : cairo_stroke_preserve(_context); + } else { + hasShadow() + ? shadow(cairo_stroke) + : cairo_stroke(_context); + } +} + +/* + * Apply shadow with the given draw fn. + */ + +void +Context2d::shadow(void (fn)(cairo_t *cr)) { + cairo_path_t *path = cairo_copy_path_flat(_context); + cairo_save(_context); + + // shadowOffset is unaffected by current transform + cairo_matrix_t path_matrix; + cairo_get_matrix(_context, &path_matrix); + cairo_identity_matrix(_context); + + // Apply shadow + cairo_push_group(_context); + + // No need to invoke blur if shadowBlur is 0 + if (state->shadowBlur) { + // find out extent of path + double x1, y1, x2, y2; + if (fn == cairo_fill || fn == cairo_fill_preserve) { + cairo_fill_extents(_context, &x1, &y1, &x2, &y2); + } else { + cairo_stroke_extents(_context, &x1, &y1, &x2, &y2); + } + + // create new image surface that size + padding for blurring + double dx = x2-x1, dy = y2-y1; + cairo_user_to_device_distance(_context, &dx, &dy); + int pad = state->shadowBlur * 2; + cairo_surface_t *surface = cairo_get_group_target(_context); + cairo_surface_t *shadow_surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, + dx + 2 * pad, + dy + 2 * pad); + cairo_t *shadow_context = cairo_create(shadow_surface); + + // transform path to the right place + cairo_translate(shadow_context, pad-x1, pad-y1); + cairo_transform(shadow_context, &path_matrix); + + // draw the path and blur + cairo_set_line_width(shadow_context, cairo_get_line_width(_context)); + cairo_new_path(shadow_context); + cairo_append_path(shadow_context, path); + setSourceRGBA(shadow_context, state->shadow); + fn(shadow_context); + blur(shadow_surface, state->shadowBlur); + + // paint to original context + cairo_set_source_surface(_context, shadow_surface, + x1 - pad + state->shadowOffsetX + 1, + y1 - pad + state->shadowOffsetY + 1); + cairo_paint(_context); + cairo_destroy(shadow_context); + cairo_surface_destroy(shadow_surface); + } else { + // Offset first, then apply path's transform + cairo_translate( + _context + , state->shadowOffsetX + , state->shadowOffsetY); + cairo_transform(_context, &path_matrix); + + // Apply shadow + cairo_new_path(_context); + cairo_append_path(_context, path); + setSourceRGBA(state->shadow); + + fn(_context); + } + + // Paint the shadow + cairo_pop_group_to_source(_context); + cairo_paint(_context); + + // Restore state + cairo_restore(_context); + cairo_new_path(_context); + cairo_append_path(_context, path); + fn(_context); + + cairo_path_destroy(path); +} + +/* + * Set source RGBA for the current context + */ + +void +Context2d::setSourceRGBA(rgba_t color) { + setSourceRGBA(_context, color); +} + +/* + * Set source RGBA + */ + +void +Context2d::setSourceRGBA(cairo_t *ctx, rgba_t color) { + cairo_set_source_rgba( + ctx + , color.r + , color.g + , color.b + , color.a * state->globalAlpha); +} + +/* + * Check if the context has a drawable shadow. + */ + +bool +Context2d::hasShadow() { + return state->shadow.a + && (state->shadowBlur || state->shadowOffsetX || state->shadowOffsetY); +} + +/* + * Blur the given surface with the given radius. + */ + +void +Context2d::blur(cairo_surface_t *surface, int radius) { + // Steve Hanov, 2009 + // Released into the public domain. + radius = radius * 0.57735f + 0.5f; + // get width, height + int width = cairo_image_surface_get_width( surface ); + int height = cairo_image_surface_get_height( surface ); + unsigned* precalc = + (unsigned*)malloc(width*height*sizeof(unsigned)); + cairo_surface_flush( surface ); + unsigned char* src = cairo_image_surface_get_data( surface ); + double mul=1.f/((radius*2)*(radius*2)); + int channel; + + // The number of times to perform the averaging. According to wikipedia, + // three iterations is good enough to pass for a gaussian. + const int MAX_ITERATIONS = 3; + int iteration; + + for ( iteration = 0; iteration < MAX_ITERATIONS; iteration++ ) { + for( channel = 0; channel < 4; channel++ ) { + int x,y; + + // precomputation step. + unsigned char* pix = src; + unsigned* pre = precalc; + + pix += channel; + for (y=0;y0) tot+=pre[-1]; + if (y>0) tot+=pre[-width]; + if (x>0 && y>0) tot-=pre[-width-1]; + *pre++=tot; + pix += 4; + } + } + + // blur step. + pix = src + (int)radius * width * 4 + (int)radius * 4 + channel; + for (y=radius;y= width ? width - 1 : x + radius; + int b = y + radius >= height ? height - 1 : y + radius; + int tot = precalc[r+b*width] + precalc[l+t*width] - + precalc[l+b*width] - precalc[r+t*width]; + *pix=(unsigned char)(tot*mul); + pix += 4; + } + pix += (int)radius * 2 * 4; + } + } + } + + cairo_surface_mark_dirty(surface); + free(precalc); +} + +/* + * Initialize a new Context2d with the given canvas. + */ + +NAN_METHOD(Context2d::New) { + NanScope(); + Local obj = args[0]->ToObject(); + if (!NanHasInstance(Canvas::constructor, obj)) + return NanThrowTypeError("Canvas expected"); + Canvas *canvas = ObjectWrap::Unwrap(obj); + Context2d *context = new Context2d(canvas); + context->Wrap(args.This()); + NanReturnValue(args.This()); +} + +/* + * Create a new page. + */ + +NAN_METHOD(Context2d::AddPage) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + if (!context->canvas()->isPDF()) { + return NanThrowError("only PDF canvases support .nextPage()"); + } + cairo_show_page(context->context()); + NanReturnUndefined(); +} + +/* + * Put image data. + * + * - imageData, dx, dy + * - imageData, dx, dy, sx, sy, sw, sh + * + */ + +NAN_METHOD(Context2d::PutImageData) { + NanScope(); + + Local obj = args[0]->ToObject(); + if (!NanHasInstance(ImageData::constructor, obj)) + return NanThrowTypeError("ImageData expected"); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + ImageData *imageData = ObjectWrap::Unwrap(obj); + PixelArray *arr = imageData->pixelArray(); + + uint8_t *src = arr->data(); + uint8_t *dst = context->canvas()->data(); + + int srcStride = arr->stride() + , dstStride = context->canvas()->stride(); + + int sx = 0 + , sy = 0 + , sw = 0 + , sh = 0 + , dx = args[1]->Int32Value() + , dy = args[2]->Int32Value() + , rows + , cols; + + switch (args.Length()) { + // imageData, dx, dy + case 3: + cols = std::min(arr->width(), context->canvas()->width - dx); + rows = std::min(arr->height(), context->canvas()->height - dy); + break; + // imageData, dx, dy, sx, sy, sw, sh + case 7: + sx = args[3]->Int32Value(); + sy = args[4]->Int32Value(); + sw = args[5]->Int32Value(); + sh = args[6]->Int32Value(); + if (sx < 0) sw += sx, sx = 0; + if (sy < 0) sh += sy, sy = 0; + if (sx + sw > arr->width()) sw = arr->width() - sx; + if (sy + sh > arr->height()) sh = arr->height() - sy; + dx += sx; + dy += sy; + cols = std::min(sw, context->canvas()->width - dx); + rows = std::min(sh, context->canvas()->height - dy); + break; + default: + return NanThrowError("invalid arguments"); + } + + if (cols <= 0 || rows <= 0) NanReturnUndefined(); + + uint8_t *srcRows = src + sy * srcStride + sx * 4; + for (int y = 0; y < rows; ++y) { + uint32_t *row = (uint32_t *)(dst + dstStride * (y + dy)); + for (int x = 0; x < cols; ++x) { + int bx = x * 4; + uint32_t *pixel = row + x + dx; + + // RGBA + uint8_t a = srcRows[bx + 3]; + uint8_t r = srcRows[bx + 0]; + uint8_t g = srcRows[bx + 1]; + uint8_t b = srcRows[bx + 2]; + float alpha = (float) a / 255; + + // ARGB + *pixel = a << 24 + | (int)((float) r * alpha) << 16 + | (int)((float) g * alpha) << 8 + | (int)((float) b * alpha); + } + srcRows += srcStride; + } + + cairo_surface_mark_dirty_rectangle( + context->canvas()->surface() + , dx + , dy + , cols + , rows); + + NanReturnUndefined(); +} + +/* + * Draw image src image to the destination (context). + * + * - dx, dy + * - dx, dy, dw, dh + * - sx, sy, sw, sh, dx, dy, dw, dh + * + */ + +NAN_METHOD(Context2d::DrawImage) { + NanScope(); + + if (args.Length() < 3) + return NanThrowTypeError("invalid arguments"); + + float sx = 0 + , sy = 0 + , sw = 0 + , sh = 0 + , dx, dy, dw, dh; + + cairo_surface_t *surface; + + Local obj = args[0]->ToObject(); + + // Image + if (NanHasInstance(Image::constructor, obj)) { + Image *img = ObjectWrap::Unwrap(obj); + if (!img->isComplete()) { + return NanThrowError("Image given has not completed loading"); + } + sw = img->width; + sh = img->height; + surface = img->surface(); + + // Canvas + } else if (NanHasInstance(Canvas::constructor, obj)) { + Canvas *canvas = ObjectWrap::Unwrap(obj); + sw = canvas->width; + sh = canvas->height; + surface = canvas->surface(); + + // Invalid + } else { + return NanThrowTypeError("Image or Canvas expected"); + } + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + // Arguments + switch (args.Length()) { + // img, sx, sy, sw, sh, dx, dy, dw, dh + case 9: + sx = args[1]->NumberValue(); + sy = args[2]->NumberValue(); + sw = args[3]->NumberValue(); + sh = args[4]->NumberValue(); + dx = args[5]->NumberValue(); + dy = args[6]->NumberValue(); + dw = args[7]->NumberValue(); + dh = args[8]->NumberValue(); + break; + // img, dx, dy, dw, dh + case 5: + dx = args[1]->NumberValue(); + dy = args[2]->NumberValue(); + dw = args[3]->NumberValue(); + dh = args[4]->NumberValue(); + break; + // img, dx, dy + case 3: + dx = args[1]->NumberValue(); + dy = args[2]->NumberValue(); + dw = sw; + dh = sh; + break; + default: + return NanThrowTypeError("invalid arguments"); + } + + // Start draw + cairo_save(ctx); + + // Scale src + if (dw != sw || dh != sh) { + float fx = (float) dw / sw; + float fy = (float) dh / sh; + cairo_scale(ctx, fx, fy); + dx /= fx; + dy /= fy; + } + + if (context->hasShadow()) { + context->setSourceRGBA(context->state->shadow); + cairo_mask_surface(ctx, surface, + dx - sx + context->state->shadowOffsetX, + dy - sy + context->state->shadowOffsetY); + } + + context->savePath(); + cairo_rectangle(ctx, dx, dy, dw, dh); + cairo_clip(ctx); + context->restorePath(); + + // Paint + cairo_set_source_surface(ctx, surface, dx - sx, dy - sy); + cairo_pattern_set_filter(cairo_get_source(ctx), context->state->patternQuality); + cairo_paint_with_alpha(ctx, context->state->globalAlpha); + + cairo_restore(ctx); + + NanReturnUndefined(); +} + +/* + * Get global alpha. + */ + +NAN_GETTER(Context2d::GetGlobalAlpha) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(context->state->globalAlpha)); +} + +/* + * Set global alpha. + */ + +NAN_SETTER(Context2d::SetGlobalAlpha) { + double n = value->NumberValue(); + if (n >= 0 && n <= 1) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->globalAlpha = n; + } +} + +/* + * Get global composite operation. + */ + +NAN_GETTER(Context2d::GetGlobalCompositeOperation) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + const char *op = "source-over"; + switch (cairo_get_operator(ctx)) { + case CAIRO_OPERATOR_ATOP: op = "source-atop"; break; + case CAIRO_OPERATOR_IN: op = "source-in"; break; + case CAIRO_OPERATOR_OUT: op = "source-out"; break; + case CAIRO_OPERATOR_XOR: op = "xor"; break; + case CAIRO_OPERATOR_DEST_ATOP: op = "destination-atop"; break; + case CAIRO_OPERATOR_DEST_IN: op = "destination-in"; break; + case CAIRO_OPERATOR_DEST_OUT: op = "destination-out"; break; + case CAIRO_OPERATOR_DEST_OVER: op = "destination-over"; break; + case CAIRO_OPERATOR_CLEAR: op = "clear"; break; + case CAIRO_OPERATOR_SOURCE: op = "source"; break; + case CAIRO_OPERATOR_DEST: op = "dest"; break; + case CAIRO_OPERATOR_OVER: op = "over"; break; + case CAIRO_OPERATOR_SATURATE: op = "saturate"; break; + // Non-standard + // supported by resent versions of cairo +#if CAIRO_VERSION_MINOR >= 10 + case CAIRO_OPERATOR_LIGHTEN: op = "lighten"; break; + case CAIRO_OPERATOR_ADD: op = "add"; break; + case CAIRO_OPERATOR_DARKEN: op = "darker"; break; + case CAIRO_OPERATOR_MULTIPLY: op = "multiply"; break; + case CAIRO_OPERATOR_SCREEN: op = "screen"; break; + case CAIRO_OPERATOR_OVERLAY: op = "overlay"; break; + case CAIRO_OPERATOR_HARD_LIGHT: op = "hard-light"; break; + case CAIRO_OPERATOR_SOFT_LIGHT: op = "soft-light"; break; + case CAIRO_OPERATOR_HSL_HUE: op = "hsl-hue"; break; + case CAIRO_OPERATOR_HSL_SATURATION: op = "hsl-saturation"; break; + case CAIRO_OPERATOR_HSL_COLOR: op = "hsl-color"; break; + case CAIRO_OPERATOR_HSL_LUMINOSITY: op = "hsl-luminosity"; break; + case CAIRO_OPERATOR_COLOR_DODGE: op = "color-dodge"; break; + case CAIRO_OPERATOR_COLOR_BURN: op = "color-burn"; break; + case CAIRO_OPERATOR_DIFFERENCE: op = "difference"; break; + case CAIRO_OPERATOR_EXCLUSION: op = "exclusion"; break; +#else + case CAIRO_OPERATOR_ADD: op = "lighter"; break; +#endif + } + + NanReturnValue(NanNew(op)); +} + +/* + * Set pattern quality. + */ + +NAN_SETTER(Context2d::SetPatternQuality) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + String::Utf8Value quality(value->ToString()); + if (0 == strcmp("fast", *quality)) { + context->state->patternQuality = CAIRO_FILTER_FAST; + } else if (0 == strcmp("good", *quality)) { + context->state->patternQuality = CAIRO_FILTER_GOOD; + } else if (0 == strcmp("best", *quality)) { + context->state->patternQuality = CAIRO_FILTER_BEST; + } else if (0 == strcmp("nearest", *quality)) { + context->state->patternQuality = CAIRO_FILTER_NEAREST; + } else if (0 == strcmp("bilinear", *quality)) { + context->state->patternQuality = CAIRO_FILTER_BILINEAR; + } +} + +/* + * Get pattern quality. + */ + +NAN_GETTER(Context2d::GetPatternQuality) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *quality; + switch (context->state->patternQuality) { + case CAIRO_FILTER_FAST: quality = "fast"; break; + case CAIRO_FILTER_BEST: quality = "best"; break; + case CAIRO_FILTER_NEAREST: quality = "nearest"; break; + case CAIRO_FILTER_BILINEAR: quality = "bilinear"; break; + default: quality = "good"; + } + NanReturnValue(NanNew(quality)); +} + +/* + * Set global composite operation. + */ + +NAN_SETTER(Context2d::SetGlobalCompositeOperation) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + String::Utf8Value type(value->ToString()); + if (0 == strcmp("xor", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_XOR); + } else if (0 == strcmp("source-atop", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_ATOP); + } else if (0 == strcmp("source-in", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_IN); + } else if (0 == strcmp("source-out", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_OUT); + } else if (0 == strcmp("destination-atop", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_ATOP); + } else if (0 == strcmp("destination-in", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_IN); + } else if (0 == strcmp("destination-out", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_OUT); + } else if (0 == strcmp("destination-over", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_OVER); + } else if (0 == strcmp("clear", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); + } else if (0 == strcmp("source", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); + } else if (0 == strcmp("dest", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DEST); + } else if (0 == strcmp("saturate", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_SATURATE); + } else if (0 == strcmp("over", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); + // Non-standard + // supported by resent versions of cairo +#if CAIRO_VERSION_MINOR >= 10 + } else if (0 == strcmp("add", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_ADD); + } else if (0 == strcmp("lighten", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_LIGHTEN); + } else if (0 == strcmp("darker", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DARKEN); + } else if (0 == strcmp("multiply", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_MULTIPLY); + } else if (0 == strcmp("screen", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_SCREEN); + } else if (0 == strcmp("overlay", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_OVERLAY); + } else if (0 == strcmp("hard-light", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_HARD_LIGHT); + } else if (0 == strcmp("soft-light", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_SOFT_LIGHT); + } else if (0 == strcmp("hsl-hue", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_HUE); + } else if (0 == strcmp("hsl-saturation", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_SATURATION); + } else if (0 == strcmp("hsl-color", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_COLOR); + } else if (0 == strcmp("hsl-luminosity", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_LUMINOSITY); + } else if (0 == strcmp("color-dodge", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_COLOR_DODGE); + } else if (0 == strcmp("color-burn", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_COLOR_BURN); + } else if (0 == strcmp("difference", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_DIFFERENCE); + } else if (0 == strcmp("exclusion", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_EXCLUSION); +#endif + } else if (0 == strcmp("lighter", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_ADD); + } else { + cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); + } +} + +/* + * Get shadow offset x. + */ + +NAN_GETTER(Context2d::GetShadowOffsetX) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(context->state->shadowOffsetX)); +} + +/* + * Set shadow offset x. + */ + +NAN_SETTER(Context2d::SetShadowOffsetX) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->shadowOffsetX = value->NumberValue(); +} + +/* + * Get shadow offset y. + */ + +NAN_GETTER(Context2d::GetShadowOffsetY) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(context->state->shadowOffsetY)); +} + +/* + * Set shadow offset y. + */ + +NAN_SETTER(Context2d::SetShadowOffsetY) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->shadowOffsetY = value->NumberValue(); +} + +/* + * Get shadow blur. + */ + +NAN_GETTER(Context2d::GetShadowBlur) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(context->state->shadowBlur)); +} + +/* + * Set shadow blur. + */ + +NAN_SETTER(Context2d::SetShadowBlur) { + int n = value->NumberValue(); + if (n >= 0) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->shadowBlur = n; + } +} + +/* + * Get current antialiasing setting. + */ + +NAN_GETTER(Context2d::GetAntiAlias) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *aa; + switch (cairo_get_antialias(context->context())) { + case CAIRO_ANTIALIAS_NONE: aa = "none"; break; + case CAIRO_ANTIALIAS_GRAY: aa = "gray"; break; + case CAIRO_ANTIALIAS_SUBPIXEL: aa = "subpixel"; break; + default: aa = "default"; + } + NanReturnValue(NanNew(aa)); +} + +/* + * Set antialiasing. + */ + +NAN_SETTER(Context2d::SetAntiAlias) { + String::Utf8Value str(value->ToString()); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + cairo_antialias_t a; + if (0 == strcmp("none", *str)) { + a = CAIRO_ANTIALIAS_NONE; + } else if (0 == strcmp("default", *str)) { + a = CAIRO_ANTIALIAS_DEFAULT; + } else if (0 == strcmp("gray", *str)) { + a = CAIRO_ANTIALIAS_GRAY; + } else if (0 == strcmp("subpixel", *str)) { + a = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + a = cairo_get_antialias(ctx); + } + cairo_set_antialias(ctx, a); +} + +/* + * Get text drawing mode. + */ + +NAN_GETTER(Context2d::GetTextDrawingMode) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *mode; + if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { + mode = "path"; + } else if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { + mode = "glyph"; + } else { + mode = "unknown"; + } + NanReturnValue(NanNew(mode)); +} + +/* + * Set text drawing mode. + */ + +NAN_SETTER(Context2d::SetTextDrawingMode) { + String::Utf8Value str(value->ToString()); + Context2d *context = ObjectWrap::Unwrap(args.This()); + if (0 == strcmp("path", *str)) { + context->state->textDrawingMode = TEXT_DRAW_PATHS; + } else if (0 == strcmp("glyph", *str)) { + context->state->textDrawingMode = TEXT_DRAW_GLYPHS; + } +} + +/* + * Get filter. + */ + +NAN_GETTER(Context2d::GetFilter) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *filter; + switch (cairo_pattern_get_filter(cairo_get_source(context->context()))) { + case CAIRO_FILTER_FAST: filter = "fast"; break; + case CAIRO_FILTER_BEST: filter = "best"; break; + case CAIRO_FILTER_NEAREST: filter = "nearest"; break; + case CAIRO_FILTER_BILINEAR: filter = "bilinear"; break; + default: filter = "good"; + } + NanReturnValue(NanNew(filter)); +} + +/* + * Set filter. + */ + +NAN_SETTER(Context2d::SetFilter) { + String::Utf8Value str(value->ToString()); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_filter_t filter; + if (0 == strcmp("fast", *str)) { + filter = CAIRO_FILTER_FAST; + } else if (0 == strcmp("best", *str)) { + filter = CAIRO_FILTER_BEST; + } else if (0 == strcmp("nearest", *str)) { + filter = CAIRO_FILTER_NEAREST; + } else if (0 == strcmp("bilinear", *str)) { + filter = CAIRO_FILTER_BILINEAR; + } else { + filter = CAIRO_FILTER_GOOD; + } + cairo_pattern_set_filter(cairo_get_source(context->context()), filter); +} + +/* + * Get miter limit. + */ + +NAN_GETTER(Context2d::GetMiterLimit) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(cairo_get_miter_limit(context->context()))); +} + +/* + * Set miter limit. + */ + +NAN_SETTER(Context2d::SetMiterLimit) { + double n = value->NumberValue(); + if (n > 0) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_set_miter_limit(context->context(), n); + } +} + +/* + * Get line width. + */ + +NAN_GETTER(Context2d::GetLineWidth) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(cairo_get_line_width(context->context()))); +} + +/* + * Set line width. + */ + +NAN_SETTER(Context2d::SetLineWidth) { + double n = value->NumberValue(); + if (n > 0) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_set_line_width(context->context(), n); + } +} + +/* + * Get line join. + */ + +NAN_GETTER(Context2d::GetLineJoin) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *join; + switch (cairo_get_line_join(context->context())) { + case CAIRO_LINE_JOIN_BEVEL: join = "bevel"; break; + case CAIRO_LINE_JOIN_ROUND: join = "round"; break; + default: join = "miter"; + } + NanReturnValue(NanNew(join)); +} + +/* + * Set line join. + */ + +NAN_SETTER(Context2d::SetLineJoin) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + String::Utf8Value type(value->ToString()); + if (0 == strcmp("round", *type)) { + cairo_set_line_join(ctx, CAIRO_LINE_JOIN_ROUND); + } else if (0 == strcmp("bevel", *type)) { + cairo_set_line_join(ctx, CAIRO_LINE_JOIN_BEVEL); + } else { + cairo_set_line_join(ctx, CAIRO_LINE_JOIN_MITER); + } +} + +/* + * Get line cap. + */ + +NAN_GETTER(Context2d::GetLineCap) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + const char *cap; + switch (cairo_get_line_cap(context->context())) { + case CAIRO_LINE_CAP_ROUND: cap = "round"; break; + case CAIRO_LINE_CAP_SQUARE: cap = "square"; break; + default: cap = "butt"; + } + NanReturnValue(NanNew(cap)); +} + +/* + * Set line cap. + */ + +NAN_SETTER(Context2d::SetLineCap) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + String::Utf8Value type(value->ToString()); + if (0 == strcmp("round", *type)) { + cairo_set_line_cap(ctx, CAIRO_LINE_CAP_ROUND); + } else if (0 == strcmp("square", *type)) { + cairo_set_line_cap(ctx, CAIRO_LINE_CAP_SQUARE); + } else { + cairo_set_line_cap(ctx, CAIRO_LINE_CAP_BUTT); + } +} + +/* + * Check if the given point is within the current path. + */ + +NAN_METHOD(Context2d::IsPointInPath) { + NanScope(); + if (args[0]->IsNumber() && args[1]->IsNumber()) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double x = args[0]->NumberValue() + , y = args[1]->NumberValue(); + NanReturnValue(NanNew(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y))); + } + NanReturnValue(NanFalse()); +} + +/* + * Set fill pattern, useV internally for fillStyle= + */ + +NAN_METHOD(Context2d::SetFillPattern) { + NanScope(); + + Local obj = args[0]->ToObject(); + if (NanHasInstance(Gradient::constructor, obj)){ + Context2d *context = ObjectWrap::Unwrap(args.This()); + Gradient *grad = ObjectWrap::Unwrap(obj); + context->state->fillGradient = grad->pattern(); + } else if(NanHasInstance(Pattern::constructor, obj)){ + Context2d *context = ObjectWrap::Unwrap(args.This()); + Pattern *pattern = ObjectWrap::Unwrap(obj); + context->state->fillPattern = pattern->pattern(); + } else { + return NanThrowTypeError("Gradient or Pattern expected"); + } + NanReturnUndefined(); +} + +/* + * Set stroke pattern, used internally for strokeStyle= + */ + +NAN_METHOD(Context2d::SetStrokePattern) { + NanScope(); + + Local obj = args[0]->ToObject(); + if (NanHasInstance(Gradient::constructor, obj)){ + Context2d *context = ObjectWrap::Unwrap(args.This()); + Gradient *grad = ObjectWrap::Unwrap(obj); + context->state->strokeGradient = grad->pattern(); + } else if(NanHasInstance(Pattern::constructor, obj)){ + Context2d *context = ObjectWrap::Unwrap(args.This()); + Pattern *pattern = ObjectWrap::Unwrap(obj); + context->state->strokePattern = pattern->pattern(); + } else { + return NanThrowTypeError("Gradient or Pattern expected"); + } + + NanReturnUndefined(); +} + +/* + * Set shadow color. + */ + +NAN_SETTER(Context2d::SetShadowColor) { + short ok; + String::Utf8Value str(value->ToString()); + uint32_t rgba = rgba_from_string(*str, &ok); + if (ok) { + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->shadow = rgba_create(rgba); + } +} + +/* + * Get shadow color. + */ + +NAN_GETTER(Context2d::GetShadowColor) { + NanScope(); + char buf[64]; + Context2d *context = ObjectWrap::Unwrap(args.This()); + rgba_to_string(context->state->shadow, buf, sizeof(buf)); + NanReturnValue(NanNew(buf)); +} + +/* + * Set fill color, used internally for fillStyle= + */ + +NAN_METHOD(Context2d::SetFillColor) { + NanScope(); + short ok; + if (!args[0]->IsString()) NanReturnUndefined(); + String::Utf8Value str(args[0]); + uint32_t rgba = rgba_from_string(*str, &ok); + if (!ok) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->fillPattern = context->state->fillGradient = NULL; + context->state->fill = rgba_create(rgba); + NanReturnUndefined(); +} + +/* + * Get fill color. + */ + +NAN_GETTER(Context2d::GetFillColor) { + NanScope(); + char buf[64]; + Context2d *context = ObjectWrap::Unwrap(args.This()); + rgba_to_string(context->state->fill, buf, sizeof(buf)); + NanReturnValue(NanNew(buf)); +} + +/* + * Set stroke color, used internally for strokeStyle= + */ + +NAN_METHOD(Context2d::SetStrokeColor) { + NanScope(); + short ok; + if (!args[0]->IsString()) NanReturnUndefined(); + String::Utf8Value str(args[0]); + uint32_t rgba = rgba_from_string(*str, &ok); + if (!ok) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->strokePattern = context->state->strokeGradient = NULL; + context->state->stroke = rgba_create(rgba); + NanReturnUndefined(); +} + +/* + * Get stroke color. + */ + +NAN_GETTER(Context2d::GetStrokeColor) { + NanScope(); + char buf[64]; + Context2d *context = ObjectWrap::Unwrap(args.This()); + rgba_to_string(context->state->stroke, buf, sizeof(buf)); + NanReturnValue(NanNew(buf)); +} + +/* + * Bezier curve. + */ + +NAN_METHOD(Context2d::BezierCurveTo) { + NanScope(); + + if (!args[0]->IsNumber() + ||!args[1]->IsNumber() + ||!args[2]->IsNumber() + ||!args[3]->IsNumber() + ||!args[4]->IsNumber() + ||!args[5]->IsNumber()) NanReturnUndefined(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_curve_to(context->context() + , args[0]->NumberValue() + , args[1]->NumberValue() + , args[2]->NumberValue() + , args[3]->NumberValue() + , args[4]->NumberValue() + , args[5]->NumberValue()); + + NanReturnUndefined(); +} + +/* + * Quadratic curve approximation from libsvg-cairo. + */ + +NAN_METHOD(Context2d::QuadraticCurveTo) { + NanScope(); + + if (!args[0]->IsNumber() + ||!args[1]->IsNumber() + ||!args[2]->IsNumber() + ||!args[3]->IsNumber()) NanReturnUndefined(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + double x, y + , x1 = args[0]->NumberValue() + , y1 = args[1]->NumberValue() + , x2 = args[2]->NumberValue() + , y2 = args[3]->NumberValue(); + + cairo_get_current_point(ctx, &x, &y); + + if (0 == x && 0 == y) { + x = x1; + y = y1; + } + + cairo_curve_to(ctx + , x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y) + , x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2) + , x2 + , y2); + + NanReturnUndefined(); +} + +/* + * Save state. + */ + +NAN_METHOD(Context2d::Save) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->save(); + NanReturnUndefined(); +} + +/* + * Restore state. + */ + +NAN_METHOD(Context2d::Restore) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->restore(); + NanReturnUndefined(); +} + +/* + * Creates a new subpath. + */ + +NAN_METHOD(Context2d::BeginPath) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_new_path(context->context()); + NanReturnUndefined(); +} + +/* + * Marks the subpath as closed. + */ + +NAN_METHOD(Context2d::ClosePath) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_close_path(context->context()); + NanReturnUndefined(); +} + +/* + * Rotate transformation. + */ + +NAN_METHOD(Context2d::Rotate) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_rotate(context->context() + , args[0]->IsNumber() ? args[0]->NumberValue() : 0); + NanReturnUndefined(); +} + +/* + * Modify the CTM. + */ + +NAN_METHOD(Context2d::Transform) { + NanScope(); + + cairo_matrix_t matrix; + cairo_matrix_init(&matrix + , args[0]->IsNumber() ? args[0]->NumberValue() : 0 + , args[1]->IsNumber() ? args[1]->NumberValue() : 0 + , args[2]->IsNumber() ? args[2]->NumberValue() : 0 + , args[3]->IsNumber() ? args[3]->NumberValue() : 0 + , args[4]->IsNumber() ? args[4]->NumberValue() : 0 + , args[5]->IsNumber() ? args[5]->NumberValue() : 0); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_transform(context->context(), &matrix); + + NanReturnUndefined(); +} + +/* + * Reset the CTM, used internally by setTransform(). + */ + +NAN_METHOD(Context2d::ResetTransform) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_identity_matrix(context->context()); + NanReturnUndefined(); +} + +/* + * Translate transformation. + */ + +NAN_METHOD(Context2d::Translate) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_translate(context->context() + , args[0]->IsNumber() ? args[0]->NumberValue() : 0 + , args[1]->IsNumber() ? args[1]->NumberValue() : 0); + NanReturnUndefined(); +} + +/* + * Scale transformation. + */ + +NAN_METHOD(Context2d::Scale) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_scale(context->context() + , args[0]->IsNumber() ? args[0]->NumberValue() : 0 + , args[1]->IsNumber() ? args[1]->NumberValue() : 0); + NanReturnUndefined(); +} + +/* + * Use path as clipping region. + */ + +NAN_METHOD(Context2d::Clip) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + cairo_clip_preserve(ctx); + NanReturnUndefined(); +} + +/* + * Fill the path. + */ + +NAN_METHOD(Context2d::Fill) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->fill(true); + NanReturnUndefined(); +} + +/* + * Stroke the path. + */ + +NAN_METHOD(Context2d::Stroke) { + NanScope(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->stroke(true); + NanReturnUndefined(); +} + +/* + * Fill text at (x, y). + */ + +NAN_METHOD(Context2d::FillText) { + NanScope(); + + if (!args[1]->IsNumber() + || !args[2]->IsNumber()) NanReturnUndefined(); + + String::Utf8Value str(args[0]->ToString()); + double x = args[1]->NumberValue(); + double y = args[2]->NumberValue(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + + context->savePath(); + if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { + context->fill(); + context->setTextPath(*str, x, y); + } else if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { + context->setTextPath(*str, x, y); + context->fill(); + } + context->restorePath(); + + NanReturnUndefined(); +} + +/* + * Stroke text at (x ,y). + */ + +NAN_METHOD(Context2d::StrokeText) { + NanScope(); + + if (!args[1]->IsNumber() + || !args[2]->IsNumber()) NanReturnUndefined(); + + String::Utf8Value str(args[0]->ToString()); + double x = args[1]->NumberValue(); + double y = args[2]->NumberValue(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + + context->savePath(); + if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { + context->stroke(); + context->setTextPath(*str, x, y); + } else if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { + context->setTextPath(*str, x, y); + context->stroke(); + } + context->restorePath(); + + NanReturnUndefined(); +} + +/* + * Set text path for the given string at (x, y). + */ + +void +Context2d::setTextPath(const char *str, double x, double y) { +#if HAVE_PANGO + + PangoRectangle ink_rect, logical_rect; + PangoFontMetrics *metrics = NULL; + + pango_layout_set_text(_layout, str, -1); + pango_cairo_update_layout(_context, _layout); + + switch (state->textAlignment) { + // center + case 0: + pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect); + x -= logical_rect.width / 2; + break; + // right + case 1: + pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect); + x -= logical_rect.width; + break; + } + + switch (state->textBaseline) { + case TEXT_BASELINE_ALPHABETIC: + metrics = PANGO_LAYOUT_GET_METRICS(_layout); + y -= pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; + break; + case TEXT_BASELINE_MIDDLE: + metrics = PANGO_LAYOUT_GET_METRICS(_layout); + y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE); + break; + case TEXT_BASELINE_BOTTOM: + metrics = PANGO_LAYOUT_GET_METRICS(_layout); + y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; + break; + } + + if (metrics) pango_font_metrics_unref(metrics); + + cairo_move_to(_context, x, y); + if (state->textDrawingMode == TEXT_DRAW_PATHS) { + pango_cairo_layout_path(_context, _layout); + } else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { + pango_cairo_show_layout(_context, _layout); + } + +#else + + cairo_text_extents_t te; + cairo_font_extents_t fe; + + // Alignment + switch (state->textAlignment) { + // center + case 0: + // Olaf (2011-02-19): te.x_bearing does not concern the alignment + cairo_text_extents(_context, str, &te); + x -= te.width / 2; + break; + // right + case 1: + // Olaf (2011-02-19): te.x_bearing does not concern the alignment + cairo_text_extents(_context, str, &te); + x -= te.width; + break; + } + + // Baseline approx + switch (state->textBaseline) { + case TEXT_BASELINE_TOP: + case TEXT_BASELINE_HANGING: + // Olaf (2011-02-26): fe.ascent approximates the distance between + // the top of the em square and the alphabetic baseline + cairo_font_extents(_context, &fe); + y += fe.ascent; + break; + case TEXT_BASELINE_MIDDLE: + // Olaf (2011-02-26): fe.ascent approximates the distance between + // the top of the em square and the alphabetic baseline + cairo_font_extents(_context, &fe); + y += (fe.ascent - fe.descent)/2; + break; + case TEXT_BASELINE_BOTTOM: + // Olaf (2011-02-26): we need to know the distance between the alphabetic + // baseline and the bottom of the em square + cairo_font_extents(_context, &fe); + y -= fe.descent; + break; + } + + cairo_move_to(_context, x, y); + if (state->textDrawingMode == TEXT_DRAW_PATHS) { + cairo_text_path(_context, str); + } else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { + cairo_show_text(_context, str); + } + +#endif +} + +/* + * Adds a point to the current subpath. + */ + +NAN_METHOD(Context2d::LineTo) { + NanScope(); + + if (!args[0]->IsNumber()) + return NanThrowTypeError("lineTo() x must be a number"); + if (!args[1]->IsNumber()) + return NanThrowTypeError("lineTo() y must be a number"); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_line_to(context->context() + , args[0]->NumberValue() + , args[1]->NumberValue()); + + NanReturnUndefined(); +} + +/* + * Creates a new subpath at the given point. + */ + +NAN_METHOD(Context2d::MoveTo) { + NanScope(); + + if (!args[0]->IsNumber()) + return NanThrowTypeError("moveTo() x must be a number"); + if (!args[1]->IsNumber()) + return NanThrowTypeError("moveTo() y must be a number"); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_move_to(context->context() + , args[0]->NumberValue() + , args[1]->NumberValue()); + + NanReturnUndefined(); +} + +/* + * Set font face. + */ + +#ifdef HAVE_FREETYPE +NAN_METHOD(Context2d::SetFontFace) { + NanScope(); + + // Ignore invalid args + if (!args[0]->IsObject() + || !args[1]->IsNumber()) + return NanThrowTypeError("Expected object and number"); + + Local obj = args[0]->ToObject(); + + if (!NanHasInstance(FontFace::constructor, obj)) + return NanThrowTypeError("FontFace expected"); + + FontFace *face = ObjectWrap::Unwrap(obj); + double size = args[1]->NumberValue(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + cairo_set_font_size(ctx, size); + cairo_set_font_face(ctx, face->cairoFace()); + + NanReturnUndefined(); +} +#endif + +/* + * Set font: + * - weight + * - style + * - size + * - unit + * - family + */ + +NAN_METHOD(Context2d::SetFont) { + NanScope(); + + // Ignore invalid args + if (!args[0]->IsString() + || !args[1]->IsString() + || !args[2]->IsNumber() + || !args[3]->IsString() + || !args[4]->IsString()) NanReturnUndefined(); + + String::Utf8Value weight(args[0]); + String::Utf8Value style(args[1]); + double size = args[2]->NumberValue(); + String::Utf8Value unit(args[3]); + String::Utf8Value family(args[4]); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + +#if HAVE_PANGO + + if (strlen(*family) > 0) state_assign_fontFamily(context->state, *family); + + if (size > 0) context->state->fontSize = size; + + PangoStyle s = PANGO_STYLE_NORMAL; + if (strlen(*style) > 0) { + if (0 == strcmp("italic", *style)) { + s = PANGO_STYLE_ITALIC; + } else if (0 == strcmp("oblique", *style)) { + s = PANGO_STYLE_OBLIQUE; + } + } + context->state->fontStyle = s; + + PangoWeight w = PANGO_WEIGHT_NORMAL; + if (strlen(*weight) > 0) { + if (0 == strcmp("bold", *weight)) { + w = PANGO_WEIGHT_BOLD; + } else if (0 == strcmp("200", *weight)) { + w = PANGO_WEIGHT_ULTRALIGHT; + } else if (0 == strcmp("300", *weight)) { + w = PANGO_WEIGHT_LIGHT; + } else if (0 == strcmp("400", *weight)) { + w = PANGO_WEIGHT_NORMAL; + } else if (0 == strcmp("500", *weight)) { + w = PANGO_WEIGHT_MEDIUM; + } else if (0 == strcmp("600", *weight)) { + w = PANGO_WEIGHT_SEMIBOLD; + } else if (0 == strcmp("700", *weight)) { + w = PANGO_WEIGHT_BOLD; + } else if (0 == strcmp("800", *weight)) { + w = PANGO_WEIGHT_ULTRABOLD; + } else if (0 == strcmp("900", *weight)) { + w = PANGO_WEIGHT_HEAVY; + } + } + context->state->fontWeight = w; + + context->setFontFromState(); + +#else + + cairo_t *ctx = context->context(); + + // Size + cairo_set_font_size(ctx, size); + + // Style + cairo_font_slant_t s = CAIRO_FONT_SLANT_NORMAL; + if (0 == strcmp("italic", *style)) { + s = CAIRO_FONT_SLANT_ITALIC; + } else if (0 == strcmp("oblique", *style)) { + s = CAIRO_FONT_SLANT_OBLIQUE; + } + + // Weight + cairo_font_weight_t w = CAIRO_FONT_WEIGHT_NORMAL; + if (0 == strcmp("bold", *weight)) { + w = CAIRO_FONT_WEIGHT_BOLD; + } + + cairo_select_font_face(ctx, *family, s, w); + +#endif + + NanReturnUndefined(); +} + +#if HAVE_PANGO + +/* + * Sets PangoLayout options from the current font state + */ + +void +Context2d::setFontFromState() { + PangoFontDescription *fd = pango_font_description_new(); + + pango_font_description_set_family(fd, state->fontFamily); + pango_font_description_set_absolute_size(fd, state->fontSize * PANGO_SCALE); + pango_font_description_set_style(fd, state->fontStyle); + pango_font_description_set_weight(fd, state->fontWeight); + + pango_layout_set_font_description(_layout, fd); + pango_font_description_free(fd); +} + +#endif + +/* + * Return the given text extents. + * TODO: Support for: + * hangingBaseline, ideographicBaseline, + * fontBoundingBoxAscent, fontBoundingBoxDescent + */ + +NAN_METHOD(Context2d::MeasureText) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + String::Utf8Value str(args[0]->ToString()); + Local obj = NanNew(); + +#if HAVE_PANGO + + PangoRectangle ink_rect, logical_rect; + PangoFontMetrics *metrics; + PangoLayout *layout = context->layout(); + + pango_layout_set_text(layout, *str, -1); + pango_cairo_update_layout(ctx, layout); + + pango_layout_get_pixel_extents(layout, &ink_rect, &logical_rect); + metrics = PANGO_LAYOUT_GET_METRICS(layout); + + double x_offset; + switch (context->state->textAlignment) { + case 0: // center + x_offset = logical_rect.width / 2; + break; + case 1: // right + x_offset = logical_rect.width; + break; + default: // left + x_offset = 0.0; + } + + double y_offset; + switch (context->state->textBaseline) { + case TEXT_BASELINE_ALPHABETIC: + y_offset = -pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; + break; + case TEXT_BASELINE_MIDDLE: + y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE); + break; + case TEXT_BASELINE_BOTTOM: + y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; + break; + default: + y_offset = 0.0; + } + + obj->Set(NanNew("width"), NanNew(logical_rect.width)); + obj->Set(NanNew("actualBoundingBoxLeft"), + NanNew(x_offset - PANGO_LBEARING(logical_rect))); + obj->Set(NanNew("actualBoundingBoxRight"), + NanNew(x_offset + PANGO_RBEARING(logical_rect))); + obj->Set(NanNew("actualBoundingBoxAscent"), + NanNew(-(y_offset+ink_rect.y))); + obj->Set(NanNew("actualBoundingBoxDescent"), + NanNew((PANGO_DESCENT(ink_rect) + y_offset))); + obj->Set(NanNew("emHeightAscent"), + NanNew(PANGO_ASCENT(logical_rect) - y_offset)); + obj->Set(NanNew("emHeightDescent"), + NanNew(PANGO_DESCENT(logical_rect) + y_offset)); + obj->Set(NanNew("alphabeticBaseline"), + NanNew((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) + + y_offset)); + + pango_font_metrics_unref(metrics); + +#else + + cairo_text_extents_t te; + cairo_font_extents_t fe; + + cairo_text_extents(ctx, *str, &te); + cairo_font_extents(ctx, &fe); + + double x_offset; + switch (context->state->textAlignment) { + case 0: // center + x_offset = te.width / 2; + break; + case 1: // right + x_offset = te.width; + break; + default: // left + x_offset = 0.0; + } + + double y_offset; + switch (context->state->textBaseline) { + case TEXT_BASELINE_TOP: + case TEXT_BASELINE_HANGING: + y_offset = fe.ascent; + break; + case TEXT_BASELINE_MIDDLE: + y_offset = (fe.ascent - fe.descent)/2; + break; + case TEXT_BASELINE_BOTTOM: + y_offset = -fe.descent; + break; + default: + y_offset = 0.0; + } + + obj->Set(NanNew("width"), NanNew(te.x_advance)); + obj->Set(NanNew("actualBoundingBoxLeft"), + NanNew(x_offset - te.x_bearing)); + obj->Set(NanNew("actualBoundingBoxRight"), + NanNew((te.x_bearing + te.width) - x_offset)); + obj->Set(NanNew("actualBoundingBoxAscent"), + NanNew(-(te.y_bearing + y_offset))); + obj->Set(NanNew("actualBoundingBoxDescent"), + NanNew(te.height + te.y_bearing + y_offset)); + obj->Set(NanNew("emHeightAscent"), NanNew(fe.ascent - y_offset)); + obj->Set(NanNew("emHeightDescent"), NanNew(fe.descent + y_offset)); + obj->Set(NanNew("alphabeticBaseline"), NanNew(y_offset)); + +#endif + + NanReturnValue(obj); +} + +/* + * Set text baseline. + */ + +NAN_METHOD(Context2d::SetTextBaseline) { + NanScope(); + + if (!args[0]->IsInt32()) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->textBaseline = args[0]->Int32Value(); + + NanReturnUndefined(); +} + +/* + * Set text alignment. -1 0 1 + */ + +NAN_METHOD(Context2d::SetTextAlignment) { + NanScope(); + + if (!args[0]->IsInt32()) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->textAlignment = args[0]->Int32Value(); + + NanReturnUndefined(); +} + +/* + * Set line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::SetLineDash) { + NanScope(); + + if (!args[0]->IsArray()) NanReturnUndefined(); + Handle dash = Handle::Cast(args[0]); + uint32_t dashes = dash->Length() & 1 ? dash->Length() * 2 : dash->Length(); + + std::vector a(dashes); + for (uint32_t i=0; i d = dash->Get(i % dash->Length()); + if (!d->IsNumber()) NanReturnUndefined(); + a[i] = d->NumberValue(); + if (a[i] < 0 || isnan(a[i]) || isinf(a[i])) NanReturnUndefined(); + } + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + cairo_set_dash(ctx, a.data(), dashes, offset); + NanReturnUndefined(); +} + +/* + * Get line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::GetLineDash) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + int dashes = cairo_get_dash_count(ctx); + std::vector a(dashes); + cairo_get_dash(ctx, a.data(), NULL); + + Local dash = NanNew(dashes); + for (int i=0; iSet(NanNew(i), NanNew(a[i])); + + NanReturnValue(dash); +} + +/* + * Set line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_SETTER(Context2d::SetLineDashOffset) { + NanScope(); + + double offset = value->NumberValue(); + if (isnan(offset) || isinf(offset)) return; + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + int dashes = cairo_get_dash_count(ctx); + std::vector a(dashes); + cairo_get_dash(ctx, a.data(), NULL); + cairo_set_dash(ctx, a.data(), dashes, offset); +} + +/* + * Get line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_GETTER(Context2d::GetLineDashOffset) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + + NanReturnValue(NanNew(offset)); +} + +/* + * Fill the rectangle defined by x, y, width and height. + */ + +NAN_METHOD(Context2d::FillRect) { + NanScope(); + RECT_ARGS; + if (0 == width || 0 == height) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + context->savePath(); + cairo_rectangle(ctx, x, y, width, height); + context->fill(); + context->restorePath(); + NanReturnUndefined(); +} + +/* + * Stroke the rectangle defined by x, y, width and height. + */ + +NAN_METHOD(Context2d::StrokeRect) { + NanScope(); + RECT_ARGS; + if (0 == width && 0 == height) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + context->savePath(); + cairo_rectangle(ctx, x, y, width, height); + context->stroke(); + context->restorePath(); + NanReturnUndefined(); +} + +/* + * Clears all pixels defined by x, y, width and height. + */ + +NAN_METHOD(Context2d::ClearRect) { + NanScope(); + RECT_ARGS; + if (0 == width || 0 == height) NanReturnUndefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + cairo_save(ctx); + context->savePath(); + cairo_rectangle(ctx, x, y, width, height); + cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); + cairo_fill(ctx); + context->restorePath(); + cairo_restore(ctx); + NanReturnUndefined(); +} + +/* + * Adds a rectangle subpath. + */ + +NAN_METHOD(Context2d::Rect) { + NanScope(); + RECT_ARGS; + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + if (width == 0) { + cairo_move_to(ctx, x, y); + cairo_line_to(ctx, x, y + height); + } else if (height == 0) { + cairo_move_to(ctx, x, y); + cairo_line_to(ctx, x + width, y); + } else { + cairo_rectangle(ctx, x, y, width, height); + } + NanReturnUndefined(); +} + +/* + * Adds an arc at x, y with the given radis and start/end angles. + */ + +NAN_METHOD(Context2d::Arc) { + NanScope(); + + if (!args[0]->IsNumber() + || !args[1]->IsNumber() + || !args[2]->IsNumber() + || !args[3]->IsNumber() + || !args[4]->IsNumber()) NanReturnUndefined(); + + bool anticlockwise = args[5]->BooleanValue(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + if (anticlockwise && M_PI * 2 != args[4]->NumberValue()) { + cairo_arc_negative(ctx + , args[0]->NumberValue() + , args[1]->NumberValue() + , args[2]->NumberValue() + , args[3]->NumberValue() + , args[4]->NumberValue()); + } else { + cairo_arc(ctx + , args[0]->NumberValue() + , args[1]->NumberValue() + , args[2]->NumberValue() + , args[3]->NumberValue() + , args[4]->NumberValue()); + } + + NanReturnUndefined(); +} + +/* + * Adds an arcTo point (x0,y0) to (x1,y1) with the given radius. + * + * Implementation influenced by WebKit. + */ + +NAN_METHOD(Context2d::ArcTo) { + NanScope(); + + if (!args[0]->IsNumber() + || !args[1]->IsNumber() + || !args[2]->IsNumber() + || !args[3]->IsNumber() + || !args[4]->IsNumber()) NanReturnUndefined(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + // Current path point + double x, y; + cairo_get_current_point(ctx, &x, &y); + Point p0(x, y); + + // Point (x0,y0) + Point p1(args[0]->NumberValue(), args[1]->NumberValue()); + + // Point (x1,y1) + Point p2(args[2]->NumberValue(), args[3]->NumberValue()); + + float radius = args[4]->NumberValue(); + + if ((p1.x == p0.x && p1.y == p0.y) + || (p1.x == p2.x && p1.y == p2.y) + || radius == 0.f) { + cairo_line_to(ctx, p1.x, p1.y); + NanReturnUndefined(); + } + + Point p1p0((p0.x - p1.x),(p0.y - p1.y)); + Point p1p2((p2.x - p1.x),(p2.y - p1.y)); + float p1p0_length = sqrtf(p1p0.x * p1p0.x + p1p0.y * p1p0.y); + float p1p2_length = sqrtf(p1p2.x * p1p2.x + p1p2.y * p1p2.y); + + double cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length); + // all points on a line logic + if (-1 == cos_phi) { + cairo_line_to(ctx, p1.x, p1.y); + NanReturnUndefined(); + } + + if (1 == cos_phi) { + // add infinite far away point + unsigned int max_length = 65535; + double factor_max = max_length / p1p0_length; + Point ep((p0.x + factor_max * p1p0.x), (p0.y + factor_max * p1p0.y)); + cairo_line_to(ctx, ep.x, ep.y); + NanReturnUndefined(); + } + + float tangent = radius / tan(acos(cos_phi) / 2); + float factor_p1p0 = tangent / p1p0_length; + Point t_p1p0((p1.x + factor_p1p0 * p1p0.x), (p1.y + factor_p1p0 * p1p0.y)); + + Point orth_p1p0(p1p0.y, -p1p0.x); + float orth_p1p0_length = sqrt(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y); + float factor_ra = radius / orth_p1p0_length; + + double cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length); + if (cos_alpha < 0.f) + orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y); + + Point p((t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y)); + + orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y); + float sa = acos(orth_p1p0.x / orth_p1p0_length); + if (orth_p1p0.y < 0.f) + sa = 2 * M_PI - sa; + + bool anticlockwise = false; + + float factor_p1p2 = tangent / p1p2_length; + Point t_p1p2((p1.x + factor_p1p2 * p1p2.x), (p1.y + factor_p1p2 * p1p2.y)); + Point orth_p1p2((t_p1p2.x - p.x),(t_p1p2.y - p.y)); + float orth_p1p2_length = sqrtf(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y); + float ea = acos(orth_p1p2.x / orth_p1p2_length); + + if (orth_p1p2.y < 0) ea = 2 * M_PI - ea; + if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true; + if ((sa < ea) && ((ea - sa) > M_PI)) anticlockwise = true; + + cairo_line_to(ctx, t_p1p0.x, t_p1p0.y); + + if (anticlockwise && M_PI * 2 != radius) { + cairo_arc_negative(ctx + , p.x + , p.y + , radius + , sa + , ea); + } else { + cairo_arc(ctx + , p.x + , p.y + , radius + , sa + , ea); + } + + NanReturnUndefined(); +} diff --git a/scripts/external/three/canvas/src/CanvasRenderingContext2d.h b/scripts/external/three/canvas/src/CanvasRenderingContext2d.h new file mode 100644 index 0000000..b5920a5 --- /dev/null +++ b/scripts/external/three/canvas/src/CanvasRenderingContext2d.h @@ -0,0 +1,183 @@ + +// +// CanvasRenderingContext2d.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_CONTEXT2D_H__ +#define __NODE_CONTEXT2D_H__ + +#include "color.h" +#include "Canvas.h" +#include "CanvasGradient.h" + +#ifdef HAVE_FREETYPE +#include +#include +#include FT_FREETYPE_H +#endif + +#include +using namespace std; + +typedef enum { + TEXT_DRAW_PATHS, + TEXT_DRAW_GLYPHS +} canvas_draw_mode_t; + +/* + * State struct. + * + * Used in conjunction with Save() / Restore() since + * cairo's gstate maintains only a single source pattern at a time. + */ + +typedef struct { + rgba_t fill; + rgba_t stroke; + cairo_filter_t patternQuality; + cairo_pattern_t *fillPattern; + cairo_pattern_t *strokePattern; + cairo_pattern_t *fillGradient; + cairo_pattern_t *strokeGradient; + float globalAlpha; + short textAlignment; + short textBaseline; + rgba_t shadow; + int shadowBlur; + double shadowOffsetX; + double shadowOffsetY; + canvas_draw_mode_t textDrawingMode; + +#if HAVE_PANGO + PangoWeight fontWeight; + PangoStyle fontStyle; + double fontSize; + char *fontFamily; +#endif + +} canvas_state_t; + +#if HAVE_PANGO +void state_assign_fontFamily(canvas_state_t *state, const char *str); +#endif + +class Context2d: public node::ObjectWrap { + public: + short stateno; + canvas_state_t *states[CANVAS_MAX_STATES]; + canvas_state_t *state; + Context2d(Canvas *canvas); + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_METHOD(DrawImage); + static NAN_METHOD(PutImageData); + static NAN_METHOD(Save); + static NAN_METHOD(Restore); + static NAN_METHOD(Rotate); + static NAN_METHOD(Translate); + static NAN_METHOD(Scale); + static NAN_METHOD(Transform); + static NAN_METHOD(ResetTransform); + static NAN_METHOD(IsPointInPath); + static NAN_METHOD(BeginPath); + static NAN_METHOD(ClosePath); + static NAN_METHOD(AddPage); + static NAN_METHOD(Clip); + static NAN_METHOD(Fill); + static NAN_METHOD(Stroke); + static NAN_METHOD(FillText); + static NAN_METHOD(StrokeText); + static NAN_METHOD(SetFont); +#ifdef HAVE_FREETYPE + static NAN_METHOD(SetFontFace); +#endif + static NAN_METHOD(SetFillColor); + static NAN_METHOD(SetStrokeColor); + static NAN_METHOD(SetFillPattern); + static NAN_METHOD(SetStrokePattern); + static NAN_METHOD(SetTextBaseline); + static NAN_METHOD(SetTextAlignment); + static NAN_METHOD(SetLineDash); + static NAN_METHOD(GetLineDash); + static NAN_METHOD(MeasureText); + static NAN_METHOD(BezierCurveTo); + static NAN_METHOD(QuadraticCurveTo); + static NAN_METHOD(LineTo); + static NAN_METHOD(MoveTo); + static NAN_METHOD(FillRect); + static NAN_METHOD(StrokeRect); + static NAN_METHOD(ClearRect); + static NAN_METHOD(Rect); + static NAN_METHOD(Arc); + static NAN_METHOD(ArcTo); + static NAN_GETTER(GetPatternQuality); + static NAN_GETTER(GetGlobalCompositeOperation); + static NAN_GETTER(GetGlobalAlpha); + static NAN_GETTER(GetShadowColor); + static NAN_GETTER(GetFillColor); + static NAN_GETTER(GetStrokeColor); + static NAN_GETTER(GetMiterLimit); + static NAN_GETTER(GetLineCap); + static NAN_GETTER(GetLineJoin); + static NAN_GETTER(GetLineWidth); + static NAN_GETTER(GetLineDashOffset); + static NAN_GETTER(GetShadowOffsetX); + static NAN_GETTER(GetShadowOffsetY); + static NAN_GETTER(GetShadowBlur); + static NAN_GETTER(GetAntiAlias); + static NAN_GETTER(GetTextDrawingMode); + static NAN_GETTER(GetFilter); + static NAN_SETTER(SetPatternQuality); + static NAN_SETTER(SetGlobalCompositeOperation); + static NAN_SETTER(SetGlobalAlpha); + static NAN_SETTER(SetShadowColor); + static NAN_SETTER(SetMiterLimit); + static NAN_SETTER(SetLineCap); + static NAN_SETTER(SetLineJoin); + static NAN_SETTER(SetLineWidth); + static NAN_SETTER(SetLineDashOffset); + static NAN_SETTER(SetShadowOffsetX); + static NAN_SETTER(SetShadowOffsetY); + static NAN_SETTER(SetShadowBlur); + static NAN_SETTER(SetAntiAlias); + static NAN_SETTER(SetTextDrawingMode); + static NAN_SETTER(SetFilter); + inline void setContext(cairo_t *ctx) { _context = ctx; } + inline cairo_t *context(){ return _context; } + inline Canvas *canvas(){ return _canvas; } + inline bool hasShadow(); + void inline setSourceRGBA(rgba_t color); + void inline setSourceRGBA(cairo_t *ctx, rgba_t color); + void setTextPath(const char *str, double x, double y); + void blur(cairo_surface_t *surface, int radius); + void shadow(void (fn)(cairo_t *cr)); + void shadowStart(); + void shadowApply(); + void savePath(); + void restorePath(); + void saveState(); + void restoreState(); + void fill(bool preserve = false); + void stroke(bool preserve = false); + void save(); + void restore(); + +#if HAVE_PANGO + void setFontFromState(); + inline PangoLayout *layout(){ return _layout; } +#endif + + private: + ~Context2d(); + Canvas *_canvas; + cairo_t *_context; + cairo_path_t *_path; +#if HAVE_PANGO + PangoLayout *_layout; +#endif +}; + +#endif diff --git a/scripts/external/three/canvas/src/FontFace.cc b/scripts/external/three/canvas/src/FontFace.cc new file mode 100755 index 0000000..2028f9b --- /dev/null +++ b/scripts/external/three/canvas/src/FontFace.cc @@ -0,0 +1,112 @@ +// +// FontFace.cc +// +// Copyright (c) 2012 Julian Viereck +// + +#include "FontFace.h" + +#include + +Persistent FontFace::constructor; + +/* + * Destroy ft_face. + */ + +FontFace::~FontFace() { + // Decrement extra reference count added in ::New(...). + // Once there is no reference left to crFace, cairo will release the + // free type font face as well. + cairo_font_face_destroy(_crFace); +} + +/* + * Initialize FontFace. + */ + +void +FontFace::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(FontFace::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("FontFace")); + + // Prototype + target->Set(NanNew("FontFace"), ctor->GetFunction()); +} + +/* + * Initialize a new FontFace object. + */ + +FT_Library library; /* handle to library */ + +bool FontFace::_initLibrary = true; +static cairo_user_data_key_t key; + +/* + * Initialize a new FontFace. + */ + +NAN_METHOD(FontFace::New) { + NanScope(); + + if (!args[0]->IsString() + || !args[1]->IsNumber()) { + return NanThrowError("Wrong argument types passed to FontFace constructor"); + } + + String::Utf8Value filePath(args[0]); + int faceIdx = int(args[1]->NumberValue()); + + FT_Face ftFace; + FT_Error ftError; + cairo_font_face_t *crFace; + + if (_initLibrary) { + _initLibrary = false; + ftError = FT_Init_FreeType(&library); + if (ftError) { + return NanThrowError("Could not load library"); + } + } + + // Create new freetype font face. + ftError = FT_New_Face(library, *filePath, faceIdx, &ftFace); + if (ftError) { + return NanThrowError("Could not load font file"); + } + + #if HAVE_PANGO + // Load the font file in fontconfig + FcBool ok = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(*filePath)); + if (!ok) { + return NanThrowError("Could not load font in FontConfig"); + } + #endif + + // Create new cairo font face. + crFace = cairo_ft_font_face_create_for_ft_face(ftFace, 0); + + // If the cairo font face is released, release the FreeType font face as well. + int status = cairo_font_face_set_user_data (crFace, &key, + ftFace, (cairo_destroy_func_t) FT_Done_Face); + if (status) { + cairo_font_face_destroy (crFace); + FT_Done_Face (ftFace); + return NanThrowError("Failed to setup cairo font face user data"); + } + + // Explicit reference count the cairo font face. Otherwise the font face might + // get released by cairo although the JS font face object is still alive. + cairo_font_face_reference(crFace); + + FontFace *face = new FontFace(ftFace, crFace); + face->Wrap(args.This()); + NanReturnValue(args.This()); +} + diff --git a/scripts/external/three/canvas/src/FontFace.h b/scripts/external/three/canvas/src/FontFace.h new file mode 100644 index 0000000..b1e13e4 --- /dev/null +++ b/scripts/external/three/canvas/src/FontFace.h @@ -0,0 +1,33 @@ +// +// FontFace.h +// +// Copyright (c) 2012 Julian Viereck +// + +#ifndef __NODE_TRUE_TYPE_FONT_FACE_H__ +#define __NODE_TRUE_TYPE_FONT_FACE_H__ + +#include "Canvas.h" + +#include +#include +#include FT_FREETYPE_H + +class FontFace: public node::ObjectWrap { + public: + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + FontFace(FT_Face ftFace, cairo_font_face_t *crFace) + :_ftFace(ftFace), _crFace(crFace) {} + + inline cairo_font_face_t *cairoFace(){ return _crFace; } + private: + ~FontFace(); + FT_Face _ftFace; + cairo_font_face_t *_crFace; + static bool _initLibrary; +}; + +#endif + diff --git a/scripts/external/three/canvas/src/Image.cc b/scripts/external/three/canvas/src/Image.cc new file mode 100644 index 0000000..d47ab9c --- /dev/null +++ b/scripts/external/three/canvas/src/Image.cc @@ -0,0 +1,971 @@ +// +// Image.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "Canvas.h" +#include "Image.h" +#include +#include +#include +#include + +#ifdef HAVE_GIF +typedef struct { + uint8_t *buf; + unsigned len; + unsigned pos; +} gif_data_t; +#endif + +/* + * Read closure used by loadFromBuffer. + */ + +typedef struct { + unsigned len; + uint8_t *buf; +} read_closure_t; + +Persistent Image::constructor; + +/* + * Initialize Image. + */ + +void +Image::Initialize(Handle target) { + NanScope(); + + Local ctor = NanNew(Image::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("Image")); + + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("Image")); + + // Prototype + Local proto = ctor->PrototypeTemplate(); + proto->SetAccessor(NanNew("source"), GetSource, SetSource); + proto->SetAccessor(NanNew("complete"), GetComplete); + proto->SetAccessor(NanNew("width"), GetWidth); + proto->SetAccessor(NanNew("height"), GetHeight); + proto->SetAccessor(NanNew("onload"), GetOnload, SetOnload); + proto->SetAccessor(NanNew("onerror"), GetOnerror, SetOnerror); +#if CAIRO_VERSION_MINOR >= 10 + proto->SetAccessor(NanNew("dataMode"), GetDataMode, SetDataMode); + ctor->Set(NanNew("MODE_IMAGE"), NanNew(DATA_IMAGE)); + ctor->Set(NanNew("MODE_MIME"), NanNew(DATA_MIME)); +#endif + target->Set(NanNew("Image"), ctor->GetFunction()); +} + +/* + * Initialize a new Image. + */ + +NAN_METHOD(Image::New) { + NanScope(); + Image *img = new Image; + img->data_mode = DATA_IMAGE; + img->Wrap(args.This()); + NanReturnValue(args.This()); +} + +/* + * Get complete boolean. + */ + +NAN_GETTER(Image::GetComplete) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(Image::COMPLETE == img->state)); +} + +#if CAIRO_VERSION_MINOR >= 10 + +/* + * Get dataMode. + */ + +NAN_GETTER(Image::GetDataMode) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(img->data_mode)); +} + +/* + * Set dataMode. + */ + +NAN_SETTER(Image::SetDataMode) { + if (value->IsNumber()) { + Image *img = ObjectWrap::Unwrap(args.This()); + int mode = value->Uint32Value(); + img->data_mode = (data_mode_t) mode; + } +} + +#endif + +/* + * Get width. + */ + +NAN_GETTER(Image::GetWidth) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(img->width)); +} +/* + * Get height. + */ + +NAN_GETTER(Image::GetHeight) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(img->height)); +} + +/* + * Get src path. + */ + +NAN_GETTER(Image::GetSource) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(img->filename ? img->filename : "")); +} + +/* + * Clean up assets and variables. + */ + +void +Image::clearData() { + if (_surface) { + cairo_surface_destroy(_surface); + NanAdjustExternalMemory(-_data_len); + _data_len = 0; + _surface = NULL; + } + + free(_data); + _data = NULL; + + free(filename); + filename = NULL; + + width = height = 0; + state = DEFAULT; +} + +/* + * Set src path. + */ + +NAN_SETTER(Image::SetSource) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + cairo_status_t status = CAIRO_STATUS_READ_ERROR; + + img->clearData(); + + // url string + if (value->IsString()) { + String::Utf8Value src(value); + if (img->filename) free(img->filename); + img->filename = strdup(*src); + status = img->load(); + // Buffer + } else if (Buffer::HasInstance(value)) { + uint8_t *buf = (uint8_t *) Buffer::Data(value->ToObject()); + unsigned len = Buffer::Length(value->ToObject()); + status = img->loadFromBuffer(buf, len); + } + + // check status + if (status) { + img->error(Canvas::Error(status)); + } else { + img->loaded(); + } +} + +/* + * Load image data from `buf` by sniffing + * the bytes to determine format. + */ + +cairo_status_t +Image::loadFromBuffer(uint8_t *buf, unsigned len) { + if (isPNG(buf)) return loadPNGFromBuffer(buf); +#ifdef HAVE_GIF + if (isGIF(buf)) return loadGIFFromBuffer(buf, len); +#endif +#ifdef HAVE_JPEG +#if CAIRO_VERSION_MINOR < 10 + if (isJPEG(buf)) return loadJPEGFromBuffer(buf, len); +#else + if (isJPEG(buf)) { + if (DATA_IMAGE == data_mode) return loadJPEGFromBuffer(buf, len); + if (DATA_MIME == data_mode) return decodeJPEGBufferIntoMimeSurface(buf, len); + if ((DATA_IMAGE | DATA_MIME) == data_mode) { + cairo_status_t status; + status = loadJPEGFromBuffer(buf, len); + if (status) return status; + return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); + } + } +#endif +#endif + return CAIRO_STATUS_READ_ERROR; +} + +/* + * Load PNG data from `buf`. + */ + +cairo_status_t +Image::loadPNGFromBuffer(uint8_t *buf) { + read_closure_t closure; + closure.len = 0; + closure.buf = buf; + _surface = cairo_image_surface_create_from_png_stream(readPNG, &closure); + cairo_status_t status = cairo_surface_status(_surface); + if (status) return status; + return CAIRO_STATUS_SUCCESS; +} + +/* + * Read PNG data. + */ + +cairo_status_t +Image::readPNG(void *c, uint8_t *data, unsigned int len) { + read_closure_t *closure = (read_closure_t *) c; + memcpy(data, closure->buf + closure->len, len); + closure->len += len; + return CAIRO_STATUS_SUCCESS; +} + +/* + * Get onload callback. + */ + +NAN_GETTER(Image::GetOnload) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + if (img->onload) { + NanReturnValue(img->onload->GetFunction()); + } else { + NanReturnNull(); + } +} + +/* + * Set onload callback. + */ + +NAN_SETTER(Image::SetOnload) { + if (value->IsFunction()) { + Image *img = ObjectWrap::Unwrap(args.This()); + img->onload = new NanCallback(value.As()); + } +} + +/* + * Get onerror callback. + */ + +NAN_GETTER(Image::GetOnerror) { + NanScope(); + Image *img = ObjectWrap::Unwrap(args.This()); + if (img->onerror) { + NanReturnValue(img->onerror->GetFunction()); + } else { + NanReturnNull(); + } +} + +/* + * Set onerror callback. + */ + +NAN_SETTER(Image::SetOnerror) { + if (value->IsFunction()) { + Image *img = ObjectWrap::Unwrap(args.This()); + img->onerror = new NanCallback(value.As()); + } +} + +/* + * Initialize a new Image. + */ + +Image::Image() { + filename = NULL; + _data = NULL; + _data_len = 0; + _surface = NULL; + width = height = 0; + state = DEFAULT; + onload = NULL; + onerror = NULL; +} + +/* + * Destroy image and associated surface. + */ + +Image::~Image() { + clearData(); + + if (onerror) { + delete onerror; + onerror = NULL; + } + + if (onload) { + delete onload; + onload = NULL; + } +} + +/* + * Initiate image loading. + */ + +cairo_status_t +Image::load() { + if (LOADING != state) { + state = LOADING; + return loadSurface(); + } + return CAIRO_STATUS_READ_ERROR; +} + +/* + * Invoke onload (when assigned) and assign dimensions. + */ + +void +Image::loaded() { + NanScope(); + state = COMPLETE; + + width = cairo_image_surface_get_width(_surface); + height = cairo_image_surface_get_height(_surface); + _data_len = height * cairo_image_surface_get_stride(_surface); + NanAdjustExternalMemory(_data_len); + + if (onload != NULL) { + onload->Call(0, NULL); + delete onload; + onload = NULL; + } +} + +/* + * Invoke onerror (when assigned) with the given err. + */ + +void +Image::error(Local err) { + NanScope(); + if (onerror != NULL) { + Local argv[1] = { err }; + onerror->Call(1, argv); + delete onerror; + onerror = NULL; + } +} + +/* + * Load cairo surface from the image src. + * + * TODO: support more formats + * TODO: use node IO or at least thread pool + */ + +cairo_status_t +Image::loadSurface() { + FILE *stream = fopen(filename, "rb"); + if (!stream) return CAIRO_STATUS_READ_ERROR; + uint8_t buf[5]; + if (1 != fread(&buf, 5, 1, stream)) { + fclose(stream); + return CAIRO_STATUS_READ_ERROR; + } + fseek(stream, 0, SEEK_SET); + + // png + if (isPNG(buf)) { + fclose(stream); + return loadPNG(); + } + + // gif +#ifdef HAVE_GIF + if (isGIF(buf)) return loadGIF(stream); +#endif + + // jpeg +#ifdef HAVE_JPEG + if (isJPEG(buf)) return loadJPEG(stream); +#endif + + fclose(stream); + return CAIRO_STATUS_READ_ERROR; +} + +/* + * Load PNG. + */ + +cairo_status_t +Image::loadPNG() { + _surface = cairo_image_surface_create_from_png(filename); + return cairo_surface_status(_surface); +} + +// GIF support + +#ifdef HAVE_GIF + +/* + * Return the alpha color for `gif` at `frame`, or -1. + */ + +int +get_gif_transparent_color(GifFileType *gif, int frame) { + ExtensionBlock *ext = gif->SavedImages[frame].ExtensionBlocks; + int len = gif->SavedImages[frame].ExtensionBlockCount; + for (int x = 0; x < len; ++x, ++ext) { + if ((ext->Function == GRAPHICS_EXT_FUNC_CODE) && (ext->Bytes[0] & 1)) { + return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3]; + } + } + return -1; +} + +/* + * Memory GIF reader callback. + */ + +int +read_gif_from_memory(GifFileType *gif, GifByteType *buf, int len) { + gif_data_t *data = (gif_data_t *) gif->UserData; + if ((data->pos + len) > data->len) len = data->len - data->pos; + memcpy(buf, data->pos + data->buf, len); + data->pos += len; + return len; +} + +/* + * Load GIF. + */ + +cairo_status_t +Image::loadGIF(FILE *stream) { + struct stat s; + int fd = fileno(stream); + + // stat + if (fstat(fd, &s) < 0) { + fclose(stream); + return CAIRO_STATUS_READ_ERROR; + } + + uint8_t *buf = (uint8_t *) malloc(s.st_size); + + if (!buf) { + fclose(stream); + return CAIRO_STATUS_NO_MEMORY; + } + + size_t read = fread(buf, s.st_size, 1, stream); + fclose(stream); + + cairo_status_t result = CAIRO_STATUS_READ_ERROR; + if (1 == read) result = loadGIFFromBuffer(buf, s.st_size); + free(buf); + + return result; +} + +/* + * Load give from `buf` and the given `len`. + */ + +cairo_status_t +Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) { + int i = 0; + GifFileType* gif; + + gif_data_t gifd = { buf, len, 0 }; + +#if GIFLIB_MAJOR >= 5 + int errorcode; + if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory, &errorcode)) == NULL) + return CAIRO_STATUS_READ_ERROR; +#else + if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory)) == NULL) + return CAIRO_STATUS_READ_ERROR; +#endif + + if (GIF_OK != DGifSlurp(gif)) { + GIF_CLOSE_FILE(gif); + return CAIRO_STATUS_READ_ERROR; + } + + width = gif->SWidth; + height = gif->SHeight; + + uint8_t *data = (uint8_t *) malloc(width * height * 4); + if (!data) { + GIF_CLOSE_FILE(gif); + return CAIRO_STATUS_NO_MEMORY; + } + + GifImageDesc *img = &gif->SavedImages[i].ImageDesc; + + // local colormap takes precedence over global + ColorMapObject *colormap = img->ColorMap + ? img->ColorMap + : gif->SColorMap; + + int bgColor = 0; + int alphaColor = get_gif_transparent_color(gif, i); + if (gif->SColorMap) bgColor = (uint8_t) gif->SBackGroundColor; + else if(alphaColor >= 0) bgColor = alphaColor; + + uint8_t *src_data = (uint8_t*) gif->SavedImages[i].RasterBits; + uint32_t *dst_data = (uint32_t*) data; + + if (!gif->Image.Interlace) { + if (width == img->Width && height == img->Height) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24 + | colormap->Colors[*src_data].Red << 16 + | colormap->Colors[*src_data].Green << 8 + | colormap->Colors[*src_data].Blue; + + dst_data++; + src_data++; + } + } + } else { + // Image does not take up whole "screen" so we need to fill-in the background + int bottom = img->Top + img->Height; + int right = img->Left + img->Width; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + if (y < img->Top || y >= bottom || x < img->Left || x >= right) { + *dst_data = ((bgColor == alphaColor) ? 0 : 255) << 24 + | colormap->Colors[bgColor].Red << 16 + | colormap->Colors[bgColor].Green << 8 + | colormap->Colors[bgColor].Blue; + } else { + *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24 + | colormap->Colors[*src_data].Red << 16 + | colormap->Colors[*src_data].Green << 8 + | colormap->Colors[*src_data].Blue; + } + + dst_data++; + src_data++; + } + } + } + } else { + // Image is interlaced so that it streams nice over 14.4k and 28.8k modems :) + // We first load in 1/8 of the image, followed by another 1/8, followed by + // 1/4 and finally the remaining 1/2. + int ioffs[] = { 0, 4, 2, 1 }; + int ijumps[] = { 8, 8, 4, 2 }; + + uint8_t *src_ptr = src_data; + uint32_t *dst_ptr; + + for(int z = 0; z < 4; z++) { + for(int y = ioffs[z]; y < height; y += ijumps[z]) { + dst_ptr = dst_data + width * y; + for(int x = 0; x < width; ++x) { + *dst_ptr = ((*src_ptr == alphaColor) ? 0 : 255) << 24 + | (colormap->Colors[*src_ptr].Red) << 16 + | (colormap->Colors[*src_ptr].Green) << 8 + | (colormap->Colors[*src_ptr].Blue); + + dst_ptr++; + src_ptr++; + } + } + } + } + + GIF_CLOSE_FILE(gif); + + // New image surface + _surface = cairo_image_surface_create_for_data( + data + , CAIRO_FORMAT_ARGB32 + , width + , height + , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + + cairo_status_t status = cairo_surface_status(_surface); + + if (status) { + free(data); + return status; + } + + _data = data; + + return CAIRO_STATUS_SUCCESS; +} +#endif /* HAVE_GIF */ + +// JPEG support + +#ifdef HAVE_JPEG + +// libjpeg 6.2 does not have jpeg_mem_src; define it ourselves here unless +// libjpeg 8 is installed. +#if JPEG_LIB_VERSION < 80 + +/* Read JPEG image from a memory segment */ +static void +init_source(j_decompress_ptr cinfo) {} + +static boolean +fill_input_buffer(j_decompress_ptr cinfo) { + ERREXIT(cinfo, JERR_INPUT_EMPTY); + return TRUE; +} +static void +skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src; + if (num_bytes > 0) { + src->next_input_byte += (size_t) num_bytes; + src->bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void term_source (j_decompress_ptr cinfo) {} +static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes) { + struct jpeg_source_mgr* src; + + if (cinfo->src == NULL) { + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(struct jpeg_source_mgr)); + } + + src = (struct jpeg_source_mgr*) cinfo->src; + src->init_source = init_source; + src->fill_input_buffer = fill_input_buffer; + src->skip_input_data = skip_input_data; + src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->term_source = term_source; + src->bytes_in_buffer = nbytes; + src->next_input_byte = (JOCTET*)buffer; +} + +#endif + +/* + * Takes an initialised jpeg_decompress_struct and decodes the + * data into _surface. + */ + +cairo_status_t +Image::decodeJPEGIntoSurface(jpeg_decompress_struct *args) { + int stride = width * 4; + cairo_status_t status; + + uint8_t *data = (uint8_t *) malloc(width * height * 4); + if (!data) { + jpeg_abort_decompress(args); + jpeg_destroy_decompress(args); + return CAIRO_STATUS_NO_MEMORY; + } + + uint8_t *src = (uint8_t *) malloc(width * args->output_components); + if (!src) { + free(data); + jpeg_abort_decompress(args); + jpeg_destroy_decompress(args); + return CAIRO_STATUS_NO_MEMORY; + } + + for (int y = 0; y < height; ++y) { + jpeg_read_scanlines(args, &src, 1); + uint32_t *row = (uint32_t *)(data + stride * y); + for (int x = 0; x < width; ++x) { + if (args->jpeg_color_space == 1) { + uint32_t *pixel = row + x; + *pixel = 255 << 24 + | src[x] << 16 + | src[x] << 8 + | src[x]; + } else { + int bx = 3 * x; + uint32_t *pixel = row + x; + *pixel = 255 << 24 + | src[bx + 0] << 16 + | src[bx + 1] << 8 + | src[bx + 2]; + } + } + } + + _surface = cairo_image_surface_create_for_data( + data + , CAIRO_FORMAT_ARGB32 + , width + , height + , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + + jpeg_finish_decompress(args); + jpeg_destroy_decompress(args); + status = cairo_surface_status(_surface); + + if (status) { + free(data); + free(src); + return status; + } + + free(src); + + _data = data; + + return CAIRO_STATUS_SUCCESS; +} + +#if CAIRO_VERSION_MINOR >= 10 + +/* + * Takes a jpeg data buffer and assigns it as mime data to a + * dummy surface + */ + +cairo_status_t +Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) { + // TODO: remove this duplicate logic + // JPEG setup + struct jpeg_decompress_struct args; + struct jpeg_error_mgr err; + args.err = jpeg_std_error(&err); + jpeg_create_decompress(&args); + + jpeg_mem_src(&args, buf, len); + + jpeg_read_header(&args, 1); + jpeg_start_decompress(&args); + width = args.output_width; + height = args.output_height; + + // Data alloc + // 8 pixels per byte using Alpha Channel format to reduce memory requirement. + int buf_size = height * cairo_format_stride_for_width(CAIRO_FORMAT_A1, width); + uint8_t *data = (uint8_t *) malloc(buf_size); + if (!data) return CAIRO_STATUS_NO_MEMORY; + + // New image surface + _surface = cairo_image_surface_create_for_data( + data + , CAIRO_FORMAT_A1 + , width + , height + , cairo_format_stride_for_width(CAIRO_FORMAT_A1, width)); + + // Cleanup + jpeg_abort_decompress(&args); + jpeg_destroy_decompress(&args); + cairo_status_t status = cairo_surface_status(_surface); + + if (status) { + free(data); + return status; + } + + _data = data; + + return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); +} + +/* + * Helper function for disposing of a mime data closure. + */ + +void +clearMimeData(void *closure) { + NanAdjustExternalMemory(-((read_closure_t *)closure)->len); + free(((read_closure_t *) closure)->buf); + free(closure); +} + +/* + * Assign a given buffer as mime data against the surface. + * The provided buffer will be copied, and the copy will + * be automatically freed when the surface is destroyed. + */ + +cairo_status_t +Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) { + uint8_t *mime_data = (uint8_t *) malloc(len); + if (!mime_data) return CAIRO_STATUS_NO_MEMORY; + + read_closure_t *mime_closure = (read_closure_t *) malloc(sizeof(read_closure_t)); + if (!mime_closure) { + free(mime_data); + return CAIRO_STATUS_NO_MEMORY; + } + + memcpy(mime_data, data, len); + + mime_closure->buf = mime_data; + mime_closure->len = len; + + NanAdjustExternalMemory(len); + + return cairo_surface_set_mime_data(_surface + , mime_type + , mime_data + , len + , clearMimeData + , mime_closure); +} + +#endif + +/* + * Load jpeg from buffer. + */ + +cairo_status_t +Image::loadJPEGFromBuffer(uint8_t *buf, unsigned len) { + // TODO: remove this duplicate logic + // JPEG setup + struct jpeg_decompress_struct args; + struct jpeg_error_mgr err; + args.err = jpeg_std_error(&err); + jpeg_create_decompress(&args); + + jpeg_mem_src(&args, buf, len); + + jpeg_read_header(&args, 1); + jpeg_start_decompress(&args); + width = args.output_width; + height = args.output_height; + + return decodeJPEGIntoSurface(&args); +} + +/* + * Load JPEG, convert RGB to ARGB. + */ + +cairo_status_t +Image::loadJPEG(FILE *stream) { + cairo_status_t status; + + if (data_mode == DATA_IMAGE) { // Can lazily read in the JPEG. + // JPEG setup + struct jpeg_decompress_struct args; + struct jpeg_error_mgr err; + args.err = jpeg_std_error(&err); + jpeg_create_decompress(&args); + + jpeg_stdio_src(&args, stream); + + jpeg_read_header(&args, 1); + jpeg_start_decompress(&args); + width = args.output_width; + height = args.output_height; + + status = decodeJPEGIntoSurface(&args); + fclose(stream); + } else { // We'll need the actual source jpeg data, so read fully. +#if CAIRO_VERSION_MINOR >= 10 + uint8_t *buf; + unsigned len; + + fseek(stream, 0, SEEK_END); + len = ftell(stream); + fseek(stream, 0, SEEK_SET); + + buf = (uint8_t *) malloc(len); + if (!buf) return CAIRO_STATUS_NO_MEMORY; + + if (fread(buf, len, 1, stream) != 1) { + status = CAIRO_STATUS_READ_ERROR; + } else if ((DATA_IMAGE | DATA_MIME) == data_mode) { + status = loadJPEGFromBuffer(buf, len); + if (!status) status = assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); + } else if (DATA_MIME == data_mode) { + status = decodeJPEGBufferIntoMimeSurface(buf, len); + } else { + status = CAIRO_STATUS_READ_ERROR; + } + + fclose(stream); + free(buf); +#else + status = CAIRO_STATUS_READ_ERROR; +#endif + } + + return status; +} + +#endif /* HAVE_JPEG */ + +/* + * Return UNKNOWN, JPEG, or PNG based on the filename. + */ + +Image::type +Image::extension(const char *filename) { + size_t len = strlen(filename); + filename += len; + if (len >= 5 && 0 == strcmp(".jpeg", filename - 5)) return Image::JPEG; + if (len >= 4 && 0 == strcmp(".gif", filename - 4)) return Image::GIF; + if (len >= 4 && 0 == strcmp(".jpg", filename - 4)) return Image::JPEG; + if (len >= 4 && 0 == strcmp(".png", filename - 4)) return Image::PNG; + return Image::UNKNOWN; +} + +/* + * Sniff bytes for JPEG's magic number ff d8. + */ + +int +Image::isJPEG(uint8_t *data) { + return 0xff == data[0] && 0xd8 == data[1]; +} + +/* + * Sniff bytes 0..2 for "GIF". + */ + +int +Image::isGIF(uint8_t *data) { + return 'G' == data[0] && 'I' == data[1] && 'F' == data[2]; +} + +/* + * Sniff bytes 1..3 for "PNG". + */ + +int +Image::isPNG(uint8_t *data) { + return 'P' == data[1] && 'N' == data[2] && 'G' == data[3]; +} diff --git a/scripts/external/three/canvas/src/Image.h b/scripts/external/three/canvas/src/Image.h new file mode 100644 index 0000000..805fb80 --- /dev/null +++ b/scripts/external/three/canvas/src/Image.h @@ -0,0 +1,108 @@ + +// +// Image.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_IMAGE_H__ +#define __NODE_IMAGE_H__ + +#include "Canvas.h" + +#ifdef HAVE_JPEG +#include +#include +#endif + +#ifdef HAVE_GIF +#include + + #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 + #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL) + #else + #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif) + #endif +#endif + + + +class Image: public node::ObjectWrap { + public: + char *filename; + int width, height; + NanCallback *onload; + NanCallback *onerror; + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_GETTER(GetSource); + static NAN_GETTER(GetOnload); + static NAN_GETTER(GetOnerror); + static NAN_GETTER(GetComplete); + static NAN_GETTER(GetWidth); + static NAN_GETTER(GetHeight); + static NAN_GETTER(GetDataMode); + static NAN_SETTER(SetSource); + static NAN_SETTER(SetOnload); + static NAN_SETTER(SetOnerror); + static NAN_SETTER(SetDataMode); + inline cairo_surface_t *surface(){ return _surface; } + inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } + inline int stride(){ return cairo_image_surface_get_stride(_surface); } + static int isPNG(uint8_t *data); + static int isJPEG(uint8_t *data); + static int isGIF(uint8_t *data); + static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len); + inline int isComplete(){ return COMPLETE == state; } + cairo_status_t loadSurface(); + cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len); + cairo_status_t loadPNGFromBuffer(uint8_t *buf); + cairo_status_t loadPNG(); + void clearData(); +#ifdef HAVE_GIF + cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len); + cairo_status_t loadGIF(FILE *stream); +#endif +#ifdef HAVE_JPEG + cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len); + cairo_status_t loadJPEG(FILE *stream); + cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info); +#if CAIRO_VERSION_MINOR >= 10 + cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len); + cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type); +#endif +#endif + void error(Local error); + void loaded(); + cairo_status_t load(); + Image(); + + enum { + DEFAULT + , LOADING + , COMPLETE + } state; + + enum data_mode_t { + DATA_IMAGE = 1 + , DATA_MIME = 2 + } data_mode; + + typedef enum { + UNKNOWN + , GIF + , JPEG + , PNG + } type; + + static type extension(const char *filename); + + private: + cairo_surface_t *_surface; + uint8_t *_data; + int _data_len; + ~Image(); +}; + +#endif diff --git a/scripts/external/three/canvas/src/ImageData.cc b/scripts/external/three/canvas/src/ImageData.cc new file mode 100644 index 0000000..bbacb75 --- /dev/null +++ b/scripts/external/three/canvas/src/ImageData.cc @@ -0,0 +1,69 @@ + +// +// ImageData.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "ImageData.h" + +Persistent ImageData::constructor; + +/* + * Initialize ImageData. + */ + +void +ImageData::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(ImageData::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("ImageData")); + + // Prototype + Local proto = ctor->PrototypeTemplate(); + proto->SetAccessor(NanNew("width"), GetWidth); + proto->SetAccessor(NanNew("height"), GetHeight); + target->Set(NanNew("ImageData"), ctor->GetFunction()); +} + +/* + * Initialize a new ImageData object. + */ + +NAN_METHOD(ImageData::New) { + NanScope(); + Local obj = args[0]->ToObject(); + + if (!NanHasInstance(PixelArray::constructor, obj)) + return NanThrowTypeError("CanvasPixelArray expected"); + + PixelArray *arr = ObjectWrap::Unwrap(obj); + ImageData *imageData = new ImageData(arr); + args.This()->Set(NanNew("data"), args[0]); + imageData->Wrap(args.This()); + NanReturnValue(args.This()); +} + +/* + * Get width. + */ + +NAN_GETTER(ImageData::GetWidth) { + NanScope(); + ImageData *imageData = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(imageData->pixelArray()->width())); +} + +/* + * Get height. + */ + +NAN_GETTER(ImageData::GetHeight) { + NanScope(); + ImageData *imageData = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(imageData->pixelArray()->height())); +} diff --git a/scripts/external/three/canvas/src/ImageData.h b/scripts/external/three/canvas/src/ImageData.h new file mode 100644 index 0000000..150f662 --- /dev/null +++ b/scripts/external/three/canvas/src/ImageData.h @@ -0,0 +1,28 @@ + +// +// ImageData.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_IMAGE_DATA_H__ +#define __NODE_IMAGE_DATA_H__ + +#include "Canvas.h" +#include "PixelArray.h" +#include + +class ImageData: public node::ObjectWrap { + public: + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_GETTER(GetWidth); + static NAN_GETTER(GetHeight); + inline PixelArray *pixelArray(){ return _arr; } + ImageData(PixelArray *arr): _arr(arr) {} + private: + PixelArray *_arr; +}; + +#endif diff --git a/scripts/external/three/canvas/src/JPEGStream.h b/scripts/external/three/canvas/src/JPEGStream.h new file mode 100644 index 0000000..95962e3 --- /dev/null +++ b/scripts/external/three/canvas/src/JPEGStream.h @@ -0,0 +1,155 @@ + +// +// JPEGStream.h +// + +#ifndef __NODE_JPEG_STREAM_H__ +#define __NODE_JPEG_STREAM_H__ + +#include "Canvas.h" +#include +#include + +/* + * Expanded data destination object for closure output, + * inspired by IJG's jdatadst.c + */ + +typedef struct { + struct jpeg_destination_mgr pub; + closure_t *closure; + JOCTET *buffer; + int bufsize; +} closure_destination_mgr; + +void +init_closure_destination(j_compress_ptr cinfo){ + // we really don't have to do anything here +} + +boolean +empty_closure_output_buffer(j_compress_ptr cinfo){ + NanScope(); + closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest; + Local buf = NanNewBufferHandle((char *)dest->buffer, dest->bufsize); + Local argv[3] = { + NanNew(NanNull()) + , NanNew(buf) + , NanNew(dest->bufsize) + }; + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, argv); + cinfo->dest->next_output_byte = dest->buffer; + cinfo->dest->free_in_buffer = dest->bufsize; + return true; +} + +void +term_closure_destination(j_compress_ptr cinfo){ + NanScope(); + closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest; + /* emit remaining data */ + size_t remaining = dest->bufsize - cinfo->dest->free_in_buffer; + Local buf = NanNewBufferHandle((char *)dest->buffer, remaining); + + Local data_argv[3] = { + NanNew(NanNull()) + , NanNew(buf) + , NanNew(remaining) + }; + + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, data_argv); + + // emit "end" + Local end_argv[3] = { + NanNew(NanNull()) + , NanNew(NanNull()) + , NanNew(0) + }; + + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, end_argv); +} + +void +jpeg_closure_dest(j_compress_ptr cinfo, closure_t * closure, int bufsize){ + closure_destination_mgr * dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same buffer without re-executing jpeg_mem_dest. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(closure_destination_mgr)); + } + + dest = (closure_destination_mgr *) cinfo->dest; + + cinfo->dest->init_destination = &init_closure_destination; + cinfo->dest->empty_output_buffer = &empty_closure_output_buffer; + cinfo->dest->term_destination = &term_closure_destination; + + dest->closure = closure; + dest->bufsize = bufsize; + dest->buffer = (JOCTET *)malloc(bufsize); + + cinfo->dest->next_output_byte = dest->buffer; + cinfo->dest->free_in_buffer = dest->bufsize; +} + +void +jpeg_free_custom_allocations(j_compress_ptr cinfo){ + closure_destination_mgr * dest; + dest = (closure_destination_mgr *) cinfo->dest; + if (dest->buffer) { + free(dest->buffer); + dest->buffer = NULL; + } +} + +void +write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, int quality, bool progressive, closure_t *closure){ + int w = cairo_image_surface_get_width(surface); + int h = cairo_image_surface_get_height(surface); + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPROW slr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + cinfo.image_width = w; + cinfo.image_height = h; + jpeg_set_defaults(&cinfo); + if (progressive) + jpeg_simple_progression(&cinfo); + jpeg_set_quality(&cinfo, quality, (quality<25)?0:1); + jpeg_closure_dest(&cinfo, closure, bufsize); + + jpeg_start_compress(&cinfo, TRUE); + unsigned char *dst; + unsigned int *src = (unsigned int *) cairo_image_surface_get_data(surface); + int sl = 0; + dst = (unsigned char *) malloc(w * 3); + while (sl < h) { + unsigned char *dp = dst; + int x = 0; + while (x < w) { + dp[0] = (*src >> 16) & 255; + dp[1] = (*src >> 8) & 255; + dp[2] = *src & 255; + src++; + dp += 3; + x++; + } + slr = dst; + jpeg_write_scanlines(&cinfo, &slr, 1); + sl++; + } + free(dst); + jpeg_finish_compress(&cinfo); + jpeg_free_custom_allocations(&cinfo); + jpeg_destroy_compress(&cinfo); +} + +#endif diff --git a/scripts/external/three/canvas/src/PNG.h b/scripts/external/three/canvas/src/PNG.h new file mode 100644 index 0000000..d3ba4f1 --- /dev/null +++ b/scripts/external/three/canvas/src/PNG.h @@ -0,0 +1,227 @@ +#ifndef _CANVAS_PNG_H +#define _CANVAS_PNG_H +#include +#include +#include +#include +#include +#include "closure.h" + +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define likely(expr) (__builtin_expect (!!(expr), 1)) +#define unlikely(expr) (__builtin_expect (!!(expr), 0)) +#else +#define likely(expr) (expr) +#define unlikely(expr) (expr) +#endif + +#ifndef CAIRO_FORMAT_INVALID +#define CAIRO_FORMAT_INVALID -1 +#endif + +static void canvas_png_flush(png_structp png_ptr) { + /* Do nothing; fflush() is said to be just a waste of energy. */ + (void) png_ptr; /* Stifle compiler warning */ +} + +/* Converts native endian xRGB => RGBx bytes */ +static void canvas_convert_data_to_bytes(png_structp png, png_row_infop row_info, png_bytep data) { + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *b = &data[i]; + uint32_t pixel; + + memcpy(&pixel, b, sizeof (uint32_t)); + + b[0] = (pixel & 0xff0000) >> 16; + b[1] = (pixel & 0x00ff00) >> 8; + b[2] = (pixel & 0x0000ff) >> 0; + b[3] = 0; + } +} + +/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ +static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) { + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *b = &data[i]; + uint32_t pixel; + uint8_t alpha; + + memcpy(&pixel, b, sizeof (uint32_t)); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; + b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; + b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; + b[3] = alpha; + } + } +} + +struct canvas_png_write_closure_t { + cairo_write_func_t write_func; + void *closure; +}; + +static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) { + unsigned int i; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + uint8_t *data; + png_structp png; + png_infop info; + png_bytep *volatile rows = NULL; + png_color_16 white; + int png_color_type; + int bpc; + unsigned int width = cairo_image_surface_get_width(surface); + unsigned int height = cairo_image_surface_get_height(surface); + + data = cairo_image_surface_get_data(surface); + if (data == NULL) { + status = CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + return status; + } + cairo_surface_flush(surface); + + if (width == 0 || height == 0) { + status = CAIRO_STATUS_WRITE_ERROR; + return status; + } + + rows = (png_bytep *) malloc(height * sizeof (png_byte*)); + if (unlikely(rows == NULL)) { + status = CAIRO_STATUS_NO_MEMORY; + return status; + } + + for (i = 0; i < height; i++) { + rows[i] = (png_byte *) data + i * cairo_image_surface_get_stride(surface); + } + +#ifdef PNG_USER_MEM_SUPPORTED + png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL); +#else + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +#endif + + if (unlikely(png == NULL)) { + status = CAIRO_STATUS_NO_MEMORY; + free(rows); + return status; + } + + info = png_create_info_struct (png); + if (unlikely(info == NULL)) { + status = CAIRO_STATUS_NO_MEMORY; + png_destroy_write_struct(&png, &info); + free(rows); + return status; + + } + +#ifdef PNG_SETJMP_SUPPORTED + if (setjmp (png_jmpbuf (png))) { + png_destroy_write_struct(&png, &info); + free(rows); + return status; + } +#endif + + png_set_write_fn(png, closure, write_func, canvas_png_flush); + png_set_compression_level(png, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->compression_level); + png_set_filter(png, 0, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->filter); + + switch (cairo_image_surface_get_format(surface)) { + case CAIRO_FORMAT_ARGB32: + bpc = 8; + png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; +#ifdef CAIRO_FORMAT_RGB30 + case CAIRO_FORMAT_RGB30: + bpc = 10; + png_color_type = PNG_COLOR_TYPE_RGB; + break; +#endif + case CAIRO_FORMAT_RGB24: + bpc = 8; + png_color_type = PNG_COLOR_TYPE_RGB; + break; + case CAIRO_FORMAT_A8: + bpc = 8; + png_color_type = PNG_COLOR_TYPE_GRAY; + break; + case CAIRO_FORMAT_A1: + bpc = 1; + png_color_type = PNG_COLOR_TYPE_GRAY; +#ifndef WORDS_BIGENDIAN + png_set_packswap(png); +#endif + break; + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + default: + status = CAIRO_STATUS_INVALID_FORMAT; + png_destroy_write_struct(&png, &info); + free(rows); + return status; + } + + png_set_IHDR(png, info, width, height, bpc, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + white.gray = (1 << bpc) - 1; + white.red = white.blue = white.green = white.gray; + png_set_bKGD(png, info, &white); + + /* We have to call png_write_info() before setting up the write + * transformation, since it stores data internally in 'png' + * that is needed for the write transformation functions to work. + */ + png_write_info(png, info); + if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + png_set_write_user_transform_fn(png, canvas_unpremultiply_data); + } else if (png_color_type == PNG_COLOR_TYPE_RGB) { + png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes); + png_set_filler(png, 0, PNG_FILLER_AFTER); + } + + png_write_image(png, rows); + png_write_end(png, info); + + png_destroy_write_struct(&png, &info); + free(rows); + return status; +} + +static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) { + cairo_status_t status; + struct canvas_png_write_closure_t *png_closure; + + png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png); + status = png_closure->write_func(png_closure->closure, data, size); + if (unlikely(status)) { + cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png); + if (*error == CAIRO_STATUS_SUCCESS) { + *error = status; + } + png_error(png, NULL); + } +} + +static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) { + struct canvas_png_write_closure_t png_closure; + + if (cairo_surface_status(surface)) { + return cairo_surface_status(surface); + } + + png_closure.write_func = write_func; + png_closure.closure = closure; + + return canvas_write_png(surface, canvas_stream_write_func, &png_closure); +} +#endif diff --git a/scripts/external/three/canvas/src/PixelArray.cc b/scripts/external/three/canvas/src/PixelArray.cc new file mode 100644 index 0000000..0a773cc --- /dev/null +++ b/scripts/external/three/canvas/src/PixelArray.cc @@ -0,0 +1,154 @@ + +// +// PixelArray.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "PixelArray.h" +#include +#include + +Persistent PixelArray::constructor; + +/* + * Initialize PixelArray. + */ + +void +PixelArray::Initialize(Handle target) { + NanScope(); + + // Constructor + Local ctor = NanNew(PixelArray::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("CanvasPixelArray")); + + // Prototype + Local proto = ctor->InstanceTemplate(); + proto->SetAccessor(NanNew("length"), GetLength); + target->Set(NanNew("CanvasPixelArray"), ctor->GetFunction()); +} + +/* + * Initialize a new PixelArray. + */ + +NAN_METHOD(PixelArray::New) { + NanScope(); + PixelArray *arr; + Local obj = args[0]->ToObject(); + + switch (args.Length()) { + // width, height + case 2: + arr = new PixelArray( + args[0]->Int32Value() + , args[1]->Int32Value()); + break; + // canvas, x, y, width, height + case 5: { + if (!NanHasInstance(Canvas::constructor, obj)) + return NanThrowTypeError("Canvas expected"); + + Canvas *canvas = ObjectWrap::Unwrap(obj); + arr = new PixelArray( + canvas + , args[1]->Int32Value() + , args[2]->Int32Value() + , args[3]->Int32Value() + , args[4]->Int32Value()); + } + break; + default: + return NanThrowTypeError("invalid arguments"); + } + + // Let v8 handle accessors (and clamping) + args.This()->SetIndexedPropertiesToPixelData( + arr->data() + , arr->length()); + + arr->Wrap(args.This()); + NanReturnValue(args.This()); +} + +/* + * Get length. + */ + +NAN_GETTER(PixelArray::GetLength) { + NanScope(); + NanReturnValue(NanNew(args.This()->GetIndexedPropertiesPixelDataLength())); +} + +/* + * Initialize a new PixelArray copying data + * from the canvas surface using the given rect. + */ + +PixelArray::PixelArray(Canvas *canvas, int sx, int sy, int width, int height): + _width(width), _height(height) { + + // Alloc space for our new data + uint8_t *dst = alloc(); + uint8_t *src = canvas->data(); + int srcStride = canvas->stride() + , dstStride = stride(); + + if (sx < 0) width += sx, sx = 0; + if (sy < 0) height += sy, sy = 0; + if (sx + width > canvas->width) width = canvas->width - sx; + if (sy + height > canvas->height) height = canvas->height - sy; + if (width <= 0 || height <= 0) return; + + // Normalize data (argb -> rgba) + for (int y = 0; y < height; ++y) { + uint32_t *row = (uint32_t *)(src + srcStride * (y + sy)); + for (int x = 0; x < width; ++x) { + int bx = x * 4; + uint32_t *pixel = row + x + sx; + uint8_t a = *pixel >> 24; + uint8_t r = *pixel >> 16; + uint8_t g = *pixel >> 8; + uint8_t b = *pixel; + dst[bx + 3] = a; + float alpha = (float) a / 255; + dst[bx + 0] = (int)((float) r / alpha); + dst[bx + 1] = (int)((float) g / alpha); + dst[bx + 2] = (int)((float) b / alpha); + } + dst += dstStride; + } +} + +/* + * Initialize an empty PixelArray with the given dimensions. + */ + +PixelArray::PixelArray(int width, int height): + _width(width), _height(height) { + alloc(); +} + +/* + * Allocate / zero data buffer. Hint mem adjustment. + */ + +uint8_t * +PixelArray::alloc() { + int len = length(); + _data = (uint8_t *) calloc(1, len); + NanAdjustExternalMemory(len); + return _data; +} + +/* + * Hint mem adjustment. + */ + +PixelArray::~PixelArray() { + NanAdjustExternalMemory(-length()); + free(_data); +} diff --git a/scripts/external/three/canvas/src/PixelArray.h b/scripts/external/three/canvas/src/PixelArray.h new file mode 100644 index 0000000..21e68f1 --- /dev/null +++ b/scripts/external/three/canvas/src/PixelArray.h @@ -0,0 +1,33 @@ + +// +// PixelArray.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_PIXEL_ARRAY_H__ +#define __NODE_PIXEL_ARRAY_H__ + +#include "Canvas.h" + +class PixelArray: public node::ObjectWrap { + public: + static Persistent constructor; + static void Initialize(Handle target); + static NAN_METHOD(New); + static NAN_GETTER(GetLength); + inline int length(){ return _width * _height * 4; } + inline int width(){ return _width; } + inline int height(){ return _height; } + inline int stride(){ return _width * 4; } + inline uint8_t *data(){ return _data; } + PixelArray(Canvas *canvas, int x, int y, int width, int height); + PixelArray(int width, int height); + ~PixelArray(); + private: + uint8_t *alloc(); + uint8_t *_data; + int _width, _height; +}; + +#endif diff --git a/scripts/external/three/canvas/src/Point.h b/scripts/external/three/canvas/src/Point.h new file mode 100644 index 0000000..5baef10 --- /dev/null +++ b/scripts/external/three/canvas/src/Point.h @@ -0,0 +1,19 @@ + + +// +// Point.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_POINT_H__ +#define __NODE_POINT_H__ + +template +class Point { + public: + T x, y; + Point(T x, T y): x(x), y(y) {} +}; + +#endif /* __NODE_POINT_H__ */ diff --git a/scripts/external/three/canvas/src/closure.h b/scripts/external/three/canvas/src/closure.h new file mode 100644 index 0000000..3ac6632 --- /dev/null +++ b/scripts/external/three/canvas/src/closure.h @@ -0,0 +1,65 @@ + +// +// closure.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __NODE_CLOSURE_H__ +#define __NODE_CLOSURE_H__ + +#ifdef __unix__ + #include +#endif + +#ifndef PAGE_SIZE + #define PAGE_SIZE 4096 +#endif + +#include + +/* + * PNG stream closure. + */ + +typedef struct { + NanCallback *pfn; + Handle fn; + unsigned len; + unsigned max_len; + uint8_t *data; + Canvas *canvas; + cairo_status_t status; + uint32_t compression_level; + uint32_t filter; +} closure_t; + +/* + * Initialize the given closure. + */ + +cairo_status_t +closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level, unsigned int filter) { + closure->len = 0; + closure->canvas = canvas; + closure->data = (uint8_t *) malloc(closure->max_len = PAGE_SIZE); + if (!closure->data) return CAIRO_STATUS_NO_MEMORY; + closure->compression_level = compression_level; + closure->filter = filter; + return CAIRO_STATUS_SUCCESS; +} + +/* + * Free the given closure's data, + * and hint V8 at the memory dealloc. + */ + +void +closure_destroy(closure_t *closure) { + if (closure->len) { + free(closure->data); + NanAdjustExternalMemory(-((intptr_t) closure->max_len)); + } +} + +#endif /* __NODE_CLOSURE_H__ */ diff --git a/scripts/external/three/canvas/src/color.cc b/scripts/external/three/canvas/src/color.cc new file mode 100644 index 0000000..effcf89 --- /dev/null +++ b/scripts/external/three/canvas/src/color.cc @@ -0,0 +1,739 @@ + +// +// color.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "color.h" +#include +#include +#include + +/* + * Parse integer value + */ + +template +static bool +parse_integer(const char** pStr, parsed_t *pParsed) { + parsed_t& c = *pParsed; + const char*& str = *pStr; + int8_t sign=1; + + c = 0; + if (*str == '-') { + sign=-1; + ++str; + } + else if (*str == '+') + ++str; + + if (*str >= '0' && *str <= '9') { + do { + c *= 10; + c += *str++ - '0'; + } while (*str >= '0' && *str <= '9'); + } else { + return false; + } + if (sign<0) + c=-c; + return true; +} + + +/* + * Parse CSS value + * Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html + */ + +template +static bool +parse_css_number(const char** pStr, parsed_t *pParsed) { + parsed_t &parsed = *pParsed; + const char*& str = *pStr; + const char* startStr = str; + if (!str || !*str) + return false; + parsed_t integerPart = 0; + parsed_t fractionPart = 0; + int divisorForFraction = 1; + int sign = 1; + int exponent = 0; + int digits = 0; + bool inFraction = false; + + if (*str == '-') { + ++str; + sign = -1; + } + else if (*str == '+') + ++str; + while (*str != '\0') { + if (*str >= '0' && *str <= '9') { + if (digits>=std::numeric_limits::digits10) { + if (!inFraction) + return false; + } + else { + ++digits; + + if (inFraction) { + fractionPart = fractionPart*10 + (*str - '0'); + divisorForFraction *= 10; + } + else { + integerPart = integerPart*10 + (*str - '0'); + } + } + } + else if (*str == '.') { + if (inFraction) + break; + else + inFraction = true; + } + else if (*str == 'e') { + ++str; + if (!parse_integer(&str, &exponent)) + return false; + break; + } + else + break; + ++str; + } + if (str != startStr) { + parsed = sign * (integerPart + fractionPart/divisorForFraction); + for (;exponent>0;--exponent) + parsed *= 10; + for (;exponent<0;++exponent) + parsed /= 10; + return true; + } + return false; +} + +/* + * Clip value to the range [minValue, maxValue] + */ + +template +static T +clip(T value, T minValue, T maxValue) { + if (value > maxValue) + value = maxValue; + if (value < minValue) + value = minValue; + return value; +} + +/* + * Wrap value to the range [0, limit] + */ + +template +static T +wrap_float(T value, T limit) { + return fmod(fmod(value, limit) + limit, limit); +} + +/* + * Wrap value to the range [0, limit] - currently-unused integer version of wrap_float + */ + +// template +// static T wrap_int(T value, T limit) { +// return (value % limit + limit) % limit; +// } + +/* + * Parse color channel value + */ + +static bool +parse_rgb_channel(const char** pStr, uint8_t *pChannel) { + int channel; + if (parse_integer(pStr, &channel)) { + *pChannel = clip(channel, 0, 255); + return true; + } + return false; +} + +/* + * Parse a value in degrees + */ + +static bool +parse_degrees(const char** pStr, float *pDegrees) { + float degrees; + if (parse_css_number(pStr, °rees)) { + *pDegrees = wrap_float(degrees, 360.0f); + return true; + } + return false; +} + +/* + * Parse and clip a percentage value. Returns a float in the range [0, 1]. + */ + +static bool +parse_clipped_percentage(const char** pStr, float *pFraction) { + float percentage; + bool result = parse_css_number(pStr,&percentage); + const char*& str = *pStr; + if (result) { + if (*str == '%') { + ++str; + *pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f; + return result; + } + } + return false; +} + +/* + * Macros to help with parsing inside rgba_from_*_string + */ + +#define WHITESPACE \ + while (' ' == *str) ++str; + +#define WHITESPACE_OR_COMMA \ + while (' ' == *str || ',' == *str) ++str; + +#define CHANNEL(NAME) \ + if (!parse_rgb_channel(&str, &NAME)) \ + return 0; \ + +#define HUE(NAME) \ + if (!parse_degrees(&str, &NAME)) \ + return 0; + +#define SATURATION(NAME) \ + if (!parse_clipped_percentage(&str, &NAME)) \ + return 0; + +#define LIGHTNESS(NAME) SATURATION(NAME) + +#define ALPHA(NAME) \ + if (*str >= '1' && *str <= '9') { \ + NAME = 1; \ + } else { \ + if ('0' == *str) ++str; \ + if ('.' == *str) { \ + ++str; \ + float n = .1f; \ + while (*str >= '0' && *str <= '9') { \ + NAME += (*str++ - '0') * n; \ + n *= .1f; \ + } \ + } \ + } \ + do {} while (0) // require trailing semicolon + +/* + * Named colors. + */ + +static struct named_color { + const char *name; + uint32_t val; +} named_colors[] = { + { "transparent", 0xFFFFFF00} + , { "aliceblue", 0xF0F8FFFF } + , { "antiquewhite", 0xFAEBD7FF } + , { "aqua", 0x00FFFFFF } + , { "aquamarine", 0x7FFFD4FF } + , { "azure", 0xF0FFFFFF } + , { "beige", 0xF5F5DCFF } + , { "bisque", 0xFFE4C4FF } + , { "black", 0x000000FF } + , { "blanchedalmond", 0xFFEBCDFF } + , { "blue", 0x0000FFFF } + , { "blueviolet", 0x8A2BE2FF } + , { "brown", 0xA52A2AFF } + , { "burlywood", 0xDEB887FF } + , { "cadetblue", 0x5F9EA0FF } + , { "chartreuse", 0x7FFF00FF } + , { "chocolate", 0xD2691EFF } + , { "coral", 0xFF7F50FF } + , { "cornflowerblue", 0x6495EDFF } + , { "cornsilk", 0xFFF8DCFF } + , { "crimson", 0xDC143CFF } + , { "cyan", 0x00FFFFFF } + , { "darkblue", 0x00008BFF } + , { "darkcyan", 0x008B8BFF } + , { "darkgoldenrod", 0xB8860BFF } + , { "darkgray", 0xA9A9A9FF } + , { "darkgreen", 0x006400FF } + , { "darkgrey", 0xA9A9A9FF } + , { "darkkhaki", 0xBDB76BFF } + , { "darkmagenta", 0x8B008BFF } + , { "darkolivegreen", 0x556B2FFF } + , { "darkorange", 0xFF8C00FF } + , { "darkorchid", 0x9932CCFF } + , { "darkred", 0x8B0000FF } + , { "darksalmon", 0xE9967AFF } + , { "darkseagreen", 0x8FBC8FFF } + , { "darkslateblue", 0x483D8BFF } + , { "darkslategray", 0x2F4F4FFF } + , { "darkslategrey", 0x2F4F4FFF } + , { "darkturquoise", 0x00CED1FF } + , { "darkviolet", 0x9400D3FF } + , { "deeppink", 0xFF1493FF } + , { "deepskyblue", 0x00BFFFFF } + , { "dimgray", 0x696969FF } + , { "dimgrey", 0x696969FF } + , { "dodgerblue", 0x1E90FFFF } + , { "firebrick", 0xB22222FF } + , { "floralwhite", 0xFFFAF0FF } + , { "forestgreen", 0x228B22FF } + , { "fuchsia", 0xFF00FFFF } + , { "gainsboro", 0xDCDCDCFF } + , { "ghostwhite", 0xF8F8FFFF } + , { "gold", 0xFFD700FF } + , { "goldenrod", 0xDAA520FF } + , { "gray", 0x808080FF } + , { "green", 0x008000FF } + , { "greenyellow", 0xADFF2FFF } + , { "grey", 0x808080FF } + , { "honeydew", 0xF0FFF0FF } + , { "hotpink", 0xFF69B4FF } + , { "indianred", 0xCD5C5CFF } + , { "indigo", 0x4B0082FF } + , { "ivory", 0xFFFFF0FF } + , { "khaki", 0xF0E68CFF } + , { "lavender", 0xE6E6FAFF } + , { "lavenderblush", 0xFFF0F5FF } + , { "lawngreen", 0x7CFC00FF } + , { "lemonchiffon", 0xFFFACDFF } + , { "lightblue", 0xADD8E6FF } + , { "lightcoral", 0xF08080FF } + , { "lightcyan", 0xE0FFFFFF } + , { "lightgoldenrodyellow", 0xFAFAD2FF } + , { "lightgray", 0xD3D3D3FF } + , { "lightgreen", 0x90EE90FF } + , { "lightgrey", 0xD3D3D3FF } + , { "lightpink", 0xFFB6C1FF } + , { "lightsalmon", 0xFFA07AFF } + , { "lightseagreen", 0x20B2AAFF } + , { "lightskyblue", 0x87CEFAFF } + , { "lightslategray", 0x778899FF } + , { "lightslategrey", 0x778899FF } + , { "lightsteelblue", 0xB0C4DEFF } + , { "lightyellow", 0xFFFFE0FF } + , { "lime", 0x00FF00FF } + , { "limegreen", 0x32CD32FF } + , { "linen", 0xFAF0E6FF } + , { "magenta", 0xFF00FFFF } + , { "maroon", 0x800000FF } + , { "mediumaquamarine", 0x66CDAAFF } + , { "mediumblue", 0x0000CDFF } + , { "mediumorchid", 0xBA55D3FF } + , { "mediumpurple", 0x9370DBFF } + , { "mediumseagreen", 0x3CB371FF } + , { "mediumslateblue", 0x7B68EEFF } + , { "mediumspringgreen", 0x00FA9AFF } + , { "mediumturquoise", 0x48D1CCFF } + , { "mediumvioletred", 0xC71585FF } + , { "midnightblue", 0x191970FF } + , { "mintcream", 0xF5FFFAFF } + , { "mistyrose", 0xFFE4E1FF } + , { "moccasin", 0xFFE4B5FF } + , { "navajowhite", 0xFFDEADFF } + , { "navy", 0x000080FF } + , { "oldlace", 0xFDF5E6FF } + , { "olive", 0x808000FF } + , { "olivedrab", 0x6B8E23FF } + , { "orange", 0xFFA500FF } + , { "orangered", 0xFF4500FF } + , { "orchid", 0xDA70D6FF } + , { "palegoldenrod", 0xEEE8AAFF } + , { "palegreen", 0x98FB98FF } + , { "paleturquoise", 0xAFEEEEFF } + , { "palevioletred", 0xDB7093FF } + , { "papayawhip", 0xFFEFD5FF } + , { "peachpuff", 0xFFDAB9FF } + , { "peru", 0xCD853FFF } + , { "pink", 0xFFC0CBFF } + , { "plum", 0xDDA0DDFF } + , { "powderblue", 0xB0E0E6FF } + , { "purple", 0x800080FF } + , { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft + , { "red", 0xFF0000FF } + , { "rosybrown", 0xBC8F8FFF } + , { "royalblue", 0x4169E1FF } + , { "saddlebrown", 0x8B4513FF } + , { "salmon", 0xFA8072FF } + , { "sandybrown", 0xF4A460FF } + , { "seagreen", 0x2E8B57FF } + , { "seashell", 0xFFF5EEFF } + , { "sienna", 0xA0522DFF } + , { "silver", 0xC0C0C0FF } + , { "skyblue", 0x87CEEBFF } + , { "slateblue", 0x6A5ACDFF } + , { "slategray", 0x708090FF } + , { "slategrey", 0x708090FF } + , { "snow", 0xFFFAFAFF } + , { "springgreen", 0x00FF7FFF } + , { "steelblue", 0x4682B4FF } + , { "tan", 0xD2B48CFF } + , { "teal", 0x008080FF } + , { "thistle", 0xD8BFD8FF } + , { "tomato", 0xFF6347FF } + , { "turquoise", 0x40E0D0FF } + , { "violet", 0xEE82EEFF } + , { "wheat", 0xF5DEB3FF } + , { "white", 0xFFFFFFFF } + , { "whitesmoke", 0xF5F5F5FF } + , { "yellow", 0xFFFF00FF } + , { "yellowgreen", 0x9ACD32FF } + , { NULL, 0 } +}; + +/* + * Hex digit int val. + */ + +static int +h(char c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return c - '0'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return (c - 'a') + 10; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return (c - 'A') + 10; + } + return 0; +} + +/* + * Return rgba_t from rgba. + */ + +rgba_t +rgba_create(uint32_t rgba) { + rgba_t color; + color.r = (double) (rgba >> 24) / 255; + color.g = (double) (rgba >> 16 & 0xff) / 255; + color.b = (double) (rgba >> 8 & 0xff) / 255; + color.a = (double) (rgba & 0xff) / 255; + return color; +} + +/* + * Return a string representation of the color. + */ + +void +rgba_to_string(rgba_t rgba, char *buf, size_t len) { + if (1 == rgba.a) { + snprintf(buf, len, "#%.2x%.2x%.2x" + , (int) (rgba.r * 255) + , (int) (rgba.g * 255) + , (int) (rgba.b * 255)); + } else { + snprintf(buf, len, "rgba(%d, %d, %d, %.2f)" + , (int) (rgba.r * 255) + , (int) (rgba.g * 255) + , (int) (rgba.b * 255) + , rgba.a); + } +} + +/* + * Return rgba from (r,g,b,a). + */ + +static inline int32_t +rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return + r << 24 + | g << 16 + | b << 8 + | a; +} + +/* + * Helper function used in rgba_from_hsla(). + * Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb + */ + +static float +hue_to_rgb(float t1, float t2, float hue) { + if (hue < 0) + hue += 6; + if (hue >= 6) + hue -= 6; + + if (hue < 1) + return (t2 - t1) * hue + t1; + else if (hue < 3) + return t2; + else if (hue < 4) + return (t2 - t1) * (4 - hue) + t1; + else + return t1; +} + +/* + * Return rgba from (h,s,l,a). + * Expects h values in the range [0, 360), and s, l, a in the range [0, 1]. + * Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb + */ + +static inline int32_t +rgba_from_hsla(float h_deg, float s, float l, float a) { + uint8_t r, g, b; + float h = (6 * h_deg) / 360.0f, m1, m2; + + if (l<=0.5) + m2=l*(s+1); + else + m2=l+s-l*s; + m1 = l*2 - m2; + + // Scale and round the RGB components + r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5); + g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5); + b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5); + + return rgba_from_rgba(r, g, b, (uint8_t) (a * 255)); +} + +/* + * Return rgba from (h,s,l). + * Expects h values in the range [0, 360), and s, l in the range [0, 1]. + */ + +static inline int32_t +rgba_from_hsl(float h_deg, float s, float l) { + return rgba_from_hsla(h_deg, s, l, 1.0); +} + + +/* + * Return rgba from (r,g,b). + */ + +static int32_t +rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { + return rgba_from_rgba(r, g, b, 255); +} + +/* + * Return rgb from "#RRGGBB". + */ + +static int32_t +rgba_from_hex6_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[3]) + , (h(str[4]) << 4) + h(str[5]) + ); +} + +/* + * Return rgb from "#RGB" + */ + +static int32_t +rgba_from_hex3_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[0]) + , (h(str[1]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[2]) + ); +} + +/* + * Return rgb from "rgb()" + */ + +static int32_t +rgba_from_rgb_string(const char *str, short *ok) { + if (str == strstr(str, "rgb(")) { + str += 4; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + CHANNEL(r); + WHITESPACE_OR_COMMA; + CHANNEL(g); + WHITESPACE_OR_COMMA; + CHANNEL(b); + WHITESPACE; + return *ok = 1, rgba_from_rgb(r, g, b); + } + return *ok = 0; +} + +/* + * Return rgb from "rgba()" + */ + +static int32_t +rgba_from_rgba_string(const char *str, short *ok) { + if (str == strstr(str, "rgba(")) { + str += 5; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + float a = 0; + CHANNEL(r); + WHITESPACE_OR_COMMA; + CHANNEL(g); + WHITESPACE_OR_COMMA; + CHANNEL(b); + WHITESPACE_OR_COMMA; + ALPHA(a); + WHITESPACE; + return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255)); + } + return *ok = 0; +} + +/* + * Return rgb from "hsla()" + */ + +static int32_t +rgba_from_hsla_string(const char *str, short *ok) { + if (str == strstr(str, "hsla(")) { + str += 5; + WHITESPACE; + float h_deg = 0; + float s = 0, l = 0; + float a = 0; + HUE(h_deg); + WHITESPACE_OR_COMMA; + SATURATION(s); + WHITESPACE_OR_COMMA; + LIGHTNESS(l); + WHITESPACE_OR_COMMA; + ALPHA(a); + WHITESPACE; + return *ok = 1, rgba_from_hsla(h_deg, s, l, a); + } + return *ok = 0; +} + +/* + * Return rgb from "hsl()" + */ + +static int32_t +rgba_from_hsl_string(const char *str, short *ok) { + if (str == strstr(str, "hsl(")) { + str += 4; + WHITESPACE; + float h_deg = 0; + float s = 0, l = 0; + HUE(h_deg); + WHITESPACE_OR_COMMA; + SATURATION(s); + WHITESPACE_OR_COMMA; + LIGHTNESS(l); + WHITESPACE; + return *ok = 1, rgba_from_hsl(h_deg, s, l); + } + return *ok = 0; +} + + +/* + * Return rgb from: + * + * - "#RGB" + * - "#RRGGBB" + * + */ + +static int32_t +rgba_from_hex_string(const char *str, short *ok) { + size_t len = strlen(str); + *ok = 1; + if (6 == len) return rgba_from_hex6_string(str); + if (3 == len) return rgba_from_hex3_string(str); + return *ok = 0; +} + +/* + * Return named color value. + */ + +static int32_t +rgba_from_name_string(const char *str, short *ok) { + int i = 0; + struct named_color color; + while ((color = named_colors[i++]).name) { + if (*str == *color.name && 0 == strcmp(str, color.name)) + return *ok = 1, color.val; + } + return *ok = 0; +} + +/* + * Return rgb from: + * + * - #RGB + * - #RRGGBB + * - rgb(r,g,b) + * - rgba(r,g,b,a) + * - hsl(h,s,l) + * - hsla(h,s,l,a) + * - name + * + */ + +int32_t +rgba_from_string(const char *str, short *ok) { + if ('#' == str[0]) + return rgba_from_hex_string(++str, ok); + if (str == strstr(str, "rgba")) + return rgba_from_rgba_string(str, ok); + if (str == strstr(str, "rgb")) + return rgba_from_rgb_string(str, ok); + if (str == strstr(str, "hsla")) + return rgba_from_hsla_string(str, ok); + if (str == strstr(str, "hsl")) + return rgba_from_hsl_string(str, ok); + return rgba_from_name_string(str, ok); +} + +/* + * Inspect the given rgba color. + */ + +void +rgba_inspect(int32_t rgba) { + printf("rgba(%d,%d,%d,%d)\n" + , rgba >> 24 & 0xff + , rgba >> 16 & 0xff + , rgba >> 8 & 0xff + , rgba & 0xff + ); +} diff --git a/scripts/external/three/canvas/src/color.h b/scripts/external/three/canvas/src/color.h new file mode 100644 index 0000000..c570c4a --- /dev/null +++ b/scripts/external/three/canvas/src/color.h @@ -0,0 +1,40 @@ + +// +// color.h +// +// Copyright (c) 2010 LearnBoost +// + +#ifndef __COLOR_PARSER_H__ +#define __COLOR_PARSER_H__ + +#include +#include +#include +#include + +/* + * RGBA struct. + */ + +typedef struct { + double r, g, b, a; +} rgba_t; + +/* + * Prototypes. + */ + +rgba_t +rgba_create(uint32_t rgba); + +int32_t +rgba_from_string(const char *str, short *ok); + +void +rgba_to_string(rgba_t rgba, char *buf, size_t len); + +void +rgba_inspect(int32_t rgba); + +#endif /* __COLOR_PARSER_H__ */ diff --git a/scripts/external/three/canvas/src/init.cc b/scripts/external/three/canvas/src/init.cc new file mode 100755 index 0000000..6628cee --- /dev/null +++ b/scripts/external/three/canvas/src/init.cc @@ -0,0 +1,74 @@ + +// +// init.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include +#include "Canvas.h" +#include "Image.h" +#include "ImageData.h" +#include "PixelArray.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasRenderingContext2d.h" + +#ifdef HAVE_FREETYPE +#include "FontFace.h" +#endif + +extern "C" void +init (Handle target) { + NanScope(); + Canvas::Initialize(target); + Image::Initialize(target); + ImageData::Initialize(target); + PixelArray::Initialize(target); + Context2d::Initialize(target); + Gradient::Initialize(target); + Pattern::Initialize(target); +#ifdef HAVE_FREETYPE + FontFace::Initialize(target); +#endif + + target->Set(NanNew("cairoVersion"), NanNew(cairo_version_string())); +#ifdef HAVE_JPEG + +#ifndef JPEG_LIB_VERSION_MAJOR +#ifdef JPEG_LIB_VERSION +#define JPEG_LIB_VERSION_MAJOR (JPEG_LIB_VERSION / 10) +#else +#define JPEG_LIB_VERSION_MAJOR 0 +#endif +#endif + +#ifndef JPEG_LIB_VERSION_MINOR +#ifdef JPEG_LIB_VERSION +#define JPEG_LIB_VERSION_MINOR (JPEG_LIB_VERSION % 10) +#else +#define JPEG_LIB_VERSION_MINOR 0 +#endif +#endif + + char jpeg_version[10]; + if (JPEG_LIB_VERSION_MINOR > 0) { + snprintf(jpeg_version, 10, "%d%c", JPEG_LIB_VERSION_MAJOR, JPEG_LIB_VERSION_MINOR + 'a' - 1); + } else { + snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR); + } + target->Set(NanNew("jpegVersion"), NanNew(jpeg_version)); +#endif + +#ifdef HAVE_GIF +#ifndef GIF_LIB_VERSION + char gif_version[10]; + snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE); + target->Set(NanNew("gifVersion"), NanNew(gif_version)); +#else + target->Set(NanNew("gifVersion"), NanNew(GIF_LIB_VERSION)); +#endif +#endif +} + +NODE_MODULE(canvas,init); diff --git a/scripts/external/three/canvas/util/cairo_include.sh b/scripts/external/three/canvas/util/cairo_include.sh new file mode 100755 index 0000000..57ec476 --- /dev/null +++ b/scripts/external/three/canvas/util/cairo_include.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Make pkg-config lookup include files from the build directory. +export PKG_CONFIG_PATH=$(cd "$(dirname "$0")"; pwd)/../build_cairo/lib/pkgconfig; + +pkg-config cairo --cflags-only-I | sed s/-I//g \ No newline at end of file diff --git a/scripts/external/three/canvas/util/has_cairo_freetype.sh b/scripts/external/three/canvas/util/has_cairo_freetype.sh new file mode 100755 index 0000000..91bdd47 --- /dev/null +++ b/scripts/external/three/canvas/util/has_cairo_freetype.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +has_freetype() { + pkg-config cairo --cflags-only-I | grep freetype2 +} + +has_freetype > /dev/null + +if test $? -eq 0; then + echo true +else + echo false +fi diff --git a/scripts/external/three/canvas/util/has_lib.sh b/scripts/external/three/canvas/util/has_lib.sh new file mode 100755 index 0000000..27911b6 --- /dev/null +++ b/scripts/external/three/canvas/util/has_lib.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +has_lib() { + local regex="lib$1.+(so|dylib)" + + # Add /sbin to path as ldconfig is located there on some systems - e.g. Debian + # (and it still can be used by unprivileged users): + PATH="$PATH:/sbin" + export PATH + # Try using ldconfig on linux systems + for LINE in `which ldconfig > /dev/null && ldconfig -p 2>/dev/null | grep -E $regex`; do + return 0 + done + + # Try just checking common library locations + for dir in /lib /usr/lib /usr/local/lib /opt/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu; do + test -d $dir && ls $dir | grep -E $regex && return 0 + done + + return 1 +} + +has_lib $1 > /dev/null +if test $? -eq 0; then + echo true +else + echo false +fi diff --git a/scripts/external/three/canvas/util/lib_lookup.sh b/scripts/external/three/canvas/util/lib_lookup.sh new file mode 100755 index 0000000..8f19ce2 --- /dev/null +++ b/scripts/external/three/canvas/util/lib_lookup.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Make pkg-config lookup include files from the build directory. +export PKG_CONFIG_PATH=$(cd "$(dirname "$0")"; pwd)/../build_cairo/lib/pkgconfig; + +pkg-config $1 --libs \ No newline at end of file diff --git a/scripts/external/three/nodethree.js b/scripts/external/three/nodethree.js new file mode 100644 index 0000000..b4bd217 --- /dev/null +++ b/scripts/external/three/nodethree.js @@ -0,0 +1,38346 @@ +var Canvas = require('./canvas'); + +var self = {}; + +var ratio = 16/9.0; + +var canvasWidth = 1024; +var canvasHeight = Math.round(1024 / ratio); + +var window = { + innerWidth: canvasWidth, + innerHeight: canvasHeight + +}; +var document = { + createElement: function(name) { + if (name == "canvas") { +// console.log("Creating canvas " + canvasWidth + ", " + canvasHeight); + return new Canvas(canvasWidth, canvasHeight); + } + } +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Larry Battle / http://bateru.com/news + * @author bhouston / http://exocortex.com + */ + +var THREE = { REVISION: '67dev' }; + +self.console = self.console || { + + info: function () {}, + log: function () {}, + debug: function () {}, + warn: function () {}, + error: function () {} + +}; + +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +// requestAnimationFrame polyfill by Erik Möller +// fixes from Paul Irish and Tino Zijdel +// using 'self' instead of 'window' for compatibility with both NodeJS and IE10. +( function () { + + var lastTime = 0; + var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; + + for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { + + self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; + self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; + + } + + if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { + + self.requestAnimationFrame = function ( callback ) { + + var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); + var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); + lastTime = currTime + timeToCall; + return id; + + }; + + } + + if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { + + self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; + + } + +}() ); + +// GL STATE CONSTANTS + +THREE.CullFaceNone = 0; +THREE.CullFaceBack = 1; +THREE.CullFaceFront = 2; +THREE.CullFaceFrontBack = 3; + +THREE.FrontFaceDirectionCW = 0; +THREE.FrontFaceDirectionCCW = 1; + +// SHADOWING TYPES + +THREE.BasicShadowMap = 0; +THREE.PCFShadowMap = 1; +THREE.PCFSoftShadowMap = 2; + +// MATERIAL CONSTANTS + +// side + +THREE.FrontSide = 0; +THREE.BackSide = 1; +THREE.DoubleSide = 2; + +// shading + +THREE.NoShading = 0; +THREE.FlatShading = 1; +THREE.SmoothShading = 2; + +// colors + +THREE.NoColors = 0; +THREE.FaceColors = 1; +THREE.VertexColors = 2; + +// blending modes + +THREE.NoBlending = 0; +THREE.NormalBlending = 1; +THREE.AdditiveBlending = 2; +THREE.SubtractiveBlending = 3; +THREE.MultiplyBlending = 4; +THREE.CustomBlending = 5; + +// custom blending equations +// (numbers start from 100 not to clash with other +// mappings to OpenGL constants defined in Texture.js) + +THREE.AddEquation = 100; +THREE.SubtractEquation = 101; +THREE.ReverseSubtractEquation = 102; + +// custom blending destination factors + +THREE.ZeroFactor = 200; +THREE.OneFactor = 201; +THREE.SrcColorFactor = 202; +THREE.OneMinusSrcColorFactor = 203; +THREE.SrcAlphaFactor = 204; +THREE.OneMinusSrcAlphaFactor = 205; +THREE.DstAlphaFactor = 206; +THREE.OneMinusDstAlphaFactor = 207; + +// custom blending source factors + +//THREE.ZeroFactor = 200; +//THREE.OneFactor = 201; +//THREE.SrcAlphaFactor = 204; +//THREE.OneMinusSrcAlphaFactor = 205; +//THREE.DstAlphaFactor = 206; +//THREE.OneMinusDstAlphaFactor = 207; +THREE.DstColorFactor = 208; +THREE.OneMinusDstColorFactor = 209; +THREE.SrcAlphaSaturateFactor = 210; + + +// TEXTURE CONSTANTS + +THREE.MultiplyOperation = 0; +THREE.MixOperation = 1; +THREE.AddOperation = 2; + +// Mapping modes + +THREE.UVMapping = function () {}; + +THREE.CubeReflectionMapping = function () {}; +THREE.CubeRefractionMapping = function () {}; + +THREE.SphericalReflectionMapping = function () {}; +THREE.SphericalRefractionMapping = function () {}; + +// Wrapping modes + +THREE.RepeatWrapping = 1000; +THREE.ClampToEdgeWrapping = 1001; +THREE.MirroredRepeatWrapping = 1002; + +// Filters + +THREE.NearestFilter = 1003; +THREE.NearestMipMapNearestFilter = 1004; +THREE.NearestMipMapLinearFilter = 1005; +THREE.LinearFilter = 1006; +THREE.LinearMipMapNearestFilter = 1007; +THREE.LinearMipMapLinearFilter = 1008; + +// Data types + +THREE.UnsignedByteType = 1009; +THREE.ByteType = 1010; +THREE.ShortType = 1011; +THREE.UnsignedShortType = 1012; +THREE.IntType = 1013; +THREE.UnsignedIntType = 1014; +THREE.FloatType = 1015; + +// Pixel types + +//THREE.UnsignedByteType = 1009; +THREE.UnsignedShort4444Type = 1016; +THREE.UnsignedShort5551Type = 1017; +THREE.UnsignedShort565Type = 1018; + +// Pixel formats + +THREE.AlphaFormat = 1019; +THREE.RGBFormat = 1020; +THREE.RGBAFormat = 1021; +THREE.LuminanceFormat = 1022; +THREE.LuminanceAlphaFormat = 1023; + +// Compressed texture formats + +THREE.RGB_S3TC_DXT1_Format = 2001; +THREE.RGBA_S3TC_DXT1_Format = 2002; +THREE.RGBA_S3TC_DXT3_Format = 2003; +THREE.RGBA_S3TC_DXT5_Format = 2004; + +/* +// Potential future PVRTC compressed texture formats +THREE.RGB_PVRTC_4BPPV1_Format = 2100; +THREE.RGB_PVRTC_2BPPV1_Format = 2101; +THREE.RGBA_PVRTC_4BPPV1_Format = 2102; +THREE.RGBA_PVRTC_2BPPV1_Format = 2103; +*/ + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Color = function ( color ) { + + if ( arguments.length === 3 ) { + + return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); + + } + + return this.set( color ) + +}; + +THREE.Color.prototype = { + + constructor: THREE.Color, + + r: 1, g: 1, b: 1, + + set: function ( value ) { + + if ( value instanceof THREE.Color ) { + + this.copy( value ); + + } else if ( typeof value === 'number' ) { + + this.setHex( value ); + + } else if ( typeof value === 'string' ) { + + this.setStyle( value ); + + } + + 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 ( h, s, l ) { + + // h,s,l ranges are in 0.0 - 1.0 + + if ( s === 0 ) { + + this.r = this.g = this.b = l; + + } else { + + var hue2rgb = function ( 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; + + }; + + 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 ) { + + // rgb(255,0,0) + + if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { + + var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); + + 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; + + return this; + + } + + // rgb(100%,0%,0%) + + if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { + + var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); + + 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; + + return this; + + } + + // #ff0000 + + if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { + + var color = /^\#([0-9a-f]{6})$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ], 16 ) ); + + return this; + + } + + // #f00 + + if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { + + var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); + + return this; + + } + + // red + + if ( /^(\w+)$/i.test( style ) ) { + + this.setHex( THREE.ColorKeywords[ style ] ); + + return this; + + } + + + }, + + copy: function ( color ) { + + this.r = color.r; + this.g = color.g; + this.b = color.b; + + return this; + + }, + + copyGammaToLinear: function ( color ) { + + this.r = color.r * color.r; + this.g = color.g * color.g; + this.b = color.b * color.b; + + return this; + + }, + + copyLinearToGamma: function ( color ) { + + this.r = Math.sqrt( color.r ); + this.g = Math.sqrt( color.g ); + this.b = Math.sqrt( color.b ); + + 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; + + }, + + 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 ) { + + this.r = array[ 0 ]; + this.g = array[ 1 ]; + this.b = array[ 2 ]; + + return this; + + }, + + toArray: function () { + + return [ this.r, this.g, this.b ]; + + }, + + clone: function () { + + return new THREE.Color().setRGB( this.r, this.g, this.b ); + + } + +}; + +THREE.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 mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Quaternion = function ( x, y, z, w ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; + +}; + +THREE.Quaternion.prototype = { + + constructor: THREE.Quaternion, + + _x: 0,_y: 0, _z: 0, _w: 0, + + _euler: undefined, + + _updateEuler: function ( callback ) { + + if ( this._euler !== undefined ) { + + this._euler.setFromQuaternion( this, undefined, false ); + + } + + }, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this._updateEuler(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this._updateEuler(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this._updateEuler(); + + }, + + get w () { + + return this._w; + + }, + + set w ( value ) { + + this._w = value; + this._updateEuler(); + + }, + + set: function ( x, y, z, w ) { + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._updateEuler(); + + return this; + + }, + + copy: function ( quaternion ) { + + this._x = quaternion._x; + this._y = quaternion._y; + this._z = quaternion._z; + this._w = quaternion._w; + + this._updateEuler(); + + return this; + + }, + + setFromEuler: function ( euler, update ) { + + if ( euler instanceof THREE.Euler === false ) { + + throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + } + + // 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 ); + + if ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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._updateEuler(); + + 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._updateEuler(); + + 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._updateEuler(); + + return this; + + }, + + setFromUnitVectors: function () { + + // http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors + + // assumes direction vectors vFrom and vTo are normalized + + var v1; + + return function( vFrom, vTo ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.crossVectors( vFrom, vTo ); + + this.set( v1.x, v1.y, v1.z, vFrom.dot( vTo ) + 1 ).normalize(); + + this._updateEuler(); + + return this; + + } + + }(), + + inverse: function () { + + this.conjugate().normalize(); + + return this; + + }, + + conjugate: function () { + + this._x *= -1; + this._y *= -1; + this._z *= -1; + + this._updateEuler(); + + return this; + + }, + + 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; + + } + + return this; + + }, + + multiply: function ( q, p ) { + + if ( p !== undefined ) { + + console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); + + } + + return this.multiplyQuaternions( this, q ); + + }, + + 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._updateEuler(); + + return this; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); + + }, + + slerp: function ( qb, t ) { + + 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 halfTheta = Math.acos( cosHalfTheta ); + 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 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._updateEuler(); + + 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 ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + this._w = array[ 3 ]; + + this._updateEuler(); + + return this; + + }, + + toArray: function () { + + return [ this._x, this._y, this._z, this._w ]; + + }, + + clone: function () { + + return new THREE.Quaternion( this._x, this._y, this._z, this._w ); + + } + +}; + +THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { + + return qm.copy( qa ).slerp( qb, t ); + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author philogb / http://blog.thejit.org/ + * @author egraether / http://egraether.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.Vector2 = function ( x, y ) { + + this.x = x || 0; + this.y = y || 0; + +}; + +THREE.Vector2.prototype = { + + constructor: THREE.Vector2, + + set: function ( x, y ) { + + this.x = x; + this.y = y; + + 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 ); + + } + + }, + + 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 ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector2\'s .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; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector2\'s .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; + + }, + + 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 ( s ) { + + this.x *= s; + this.y *= s; + + return this; + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + + return this; + + }, + + divideScalar: function ( scalar ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + 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 + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + return this; + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector2(); + max = new THREE.Vector2(); + + } + + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + 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 () { + + return this.multiplyScalar( - 1 ); + + }, + + 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 ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + 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; + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + + return this; + + }, + + equals: function( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y ]; + + }, + + clone: function () { + + return new THREE.Vector2( this.x, this.y ); + + } + +}; + +/** + * @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 + */ + +THREE.Vector3 = function ( x, y, z ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + +}; + +THREE.Vector3.prototype = { + + constructor: THREE.Vector3, + + set: function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + 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 ); + + } + + }, + + 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 ); + + } + + }, + + 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( 'DEPRECATED: Vector3\'s .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; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .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; + + }, + + 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( 'DEPRECATED: Vector3\'s .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 ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + 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 ( euler ) { + + if ( euler instanceof THREE.Euler === false ) { + + console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + + } + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromEuler( euler ) ); + + return this; + + }; + + }(), + + applyAxisAngle: function () { + + var quaternion; + + return function ( axis, angle ) { + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + + return this; + + }; + + }(), + + applyMatrix3: function ( m ) { + + var x = this.x; + var y = this.y; + var 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 ) { + + // input: THREE.Matrix4 affine matrix + + 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]; + + return this; + + }, + + applyProjection: function ( m ) { + + // input: THREE.Matrix4 projection matrix + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide + + this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; + this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; + this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; + + return this; + + }, + + applyQuaternion: function ( q ) { + + var x = this.x; + var y = this.y; + var z = this.z; + + var qx = q.x; + var qy = q.y; + var qz = q.z; + var 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; + + }, + + 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; + + this.normalize(); + + return this; + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + }, + + divideScalar: function ( scalar ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + 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 + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + return this; + + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector3(); + max = new THREE.Vector3(); + + } + + min.set( minVal, minVal, minVal ); + max.set( 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 ); + + 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 () { + + return this.multiplyScalar( - 1 ); + + }, + + 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 ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + 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; + + }, + + cross: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .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 () { + + var v1, dot; + + return function ( vector ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.copy( vector ).normalize(); + + dot = this.dot( v1 ); + + return this.copy( v1 ).multiplyScalar( dot ); + + }; + + }(), + + projectOnPlane: function () { + + var v1; + + return function ( planeNormal ) { + + if ( v1 === undefined ) v1 = new THREE.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 ( normal ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + } + + }(), + + angleTo: function ( v ) { + + var theta = this.dot( v ) / ( this.length() * v.length() ); + + // clamp, to handle numerical problems + + return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x; + var dy = this.y - v.y; + var dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + }, + + setEulerFromRotationMatrix: function ( m, order ) { + + console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); + + }, + + setEulerFromQuaternion: function ( q, order ) { + + console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); + + }, + + getPositionFromMatrix: function ( m ) { + + console.warn( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); + + return this.setFromMatrixPosition( m ); + + }, + + getScaleFromMatrix: function ( m ) { + + console.warn( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); + + return this.setFromMatrixScale( m ); + }, + + getColumnFromMatrix: function ( index, matrix ) { + + console.warn( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); + + return this.setFromMatrixColumn( index, matrix ); + + }, + + setFromMatrixPosition: function ( m ) { + + this.x = m.elements[ 12 ]; + this.y = m.elements[ 13 ]; + this.z = m.elements[ 14 ]; + + return this; + + }, + + setFromMatrixScale: function ( m ) { + + var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); + var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); + var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + }, + + setFromMatrixColumn: function ( index, matrix ) { + + var offset = index * 4; + + var me = matrix.elements; + + this.x = me[ offset ]; + this.y = me[ offset + 1 ]; + this.z = me[ offset + 2 ]; + + return this; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + this.z = array[ 2 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y, this.z ]; + + }, + + clone: function () { + + return new THREE.Vector3( this.x, this.y, this.z ); + + } + +}; +/** + * @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 + */ + +THREE.Vector4 = function ( x, y, z, w ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; + +}; + +THREE.Vector4.prototype = { + + constructor: THREE.Vector4, + + set: function ( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + 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 ); + + } + + }, + + 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 ); + + } + + }, + + 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( 'DEPRECATED: Vector4\'s .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; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector4\'s .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; + + }, + + 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 ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; + + return this; + + }, + + applyMatrix4: function ( m ) { + + var x = this.x; + var y = this.y; + var z = this.z; + var 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 ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + this.w *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + + } + + return this; + + }, + + 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 ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + if ( this.w > v.w ) { + + this.w = v.w; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + this.z = v.z; + + } + + if ( this.w < v.w ) { + + 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 + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + if ( this.w < min.w ) { + + this.w = min.w; + + } else if ( this.w > max.w ) { + + this.w = max.w; + + } + + return this; + + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector4(); + max = new THREE.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 () { + + return this.multiplyScalar( -1 ); + + }, + + 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 ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + + } + + return this; + + }, + + 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; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + this.z = array[ 2 ]; + this.w = array[ 3 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y, this.z, this.w ]; + + }, + + clone: function () { + + return new THREE.Vector4( this.x, this.y, this.z, this.w ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.TypedVector2 = function ( array, offset ) { + + this.array = array; + this.offset = offset; + +}; + +THREE.TypedVector2.prototype = Object.create( THREE.Vector2.prototype ); + +Object.defineProperties( THREE.TypedVector2.prototype, { + 'x': { + get: function () { return this.array[ this.offset ]; }, + set: function ( v ) { this.array[ this.offset ] = v; } + }, + 'y': { + get: function () { return this.array[ this.offset + 1 ]; }, + set: function ( v ) { this.array[ this.offset + 1 ] = v; } + } +} ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.TypedVector3 = function ( array, offset ) { + + this.array = array; + this.offset = offset; + +}; + +THREE.TypedVector3.prototype = Object.create( THREE.Vector3.prototype ); + +Object.defineProperties( THREE.TypedVector3.prototype, { + 'x': { + get: function () { return this.array[ this.offset ]; }, + set: function ( v ) { this.array[ this.offset ] = v; } + }, + 'y': { + get: function () { return this.array[ this.offset + 1 ]; }, + set: function ( v ) { this.array[ this.offset + 1 ] = v; } + }, + 'z': { + get: function () { return this.array[ this.offset + 2 ]; }, + set: function ( v ) { this.array[ this.offset + 2 ] = v; } + } +} ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Euler = function ( x, y, z, order ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || THREE.Euler.DefaultOrder; + +}; + +THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + +THREE.Euler.DefaultOrder = 'XYZ'; + +THREE.Euler.prototype = { + + constructor: THREE.Euler, + + _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, + + _quaternion: undefined, + + _updateQuaternion: function () { + + if ( this._quaternion !== undefined ) { + + this._quaternion.setFromEuler( this, false ); + + } + + }, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this._updateQuaternion(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this._updateQuaternion(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this._updateQuaternion(); + + }, + + get order () { + + return this._order; + + }, + + set order ( value ) { + + this._order = value; + this._updateQuaternion(); + + }, + + set: function ( x, y, z, order ) { + + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; + + this._updateQuaternion(); + + return this; + + }, + + copy: function ( euler ) { + + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._updateQuaternion(); + + return this; + + }, + + setFromRotationMatrix: function ( m, order ) { + + var clamp = THREE.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( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) + + } + + this._order = order; + + this._updateQuaternion(); + + return this; + + }, + + setFromQuaternion: function ( q, order, update ) { + + var clamp = THREE.Math.clamp; + + // q is assumed to be normalized + + // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m + + var sqx = q.x * q.x; + var sqy = q.y * q.y; + var sqz = q.z * q.z; + var sqw = q.w * q.w; + + order = order || this._order; + + if ( order === 'XYZ' ) { + + this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); + this._y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ), -1, 1 ) ); + this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); + + } else if ( order === 'YXZ' ) { + + this._x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ), -1, 1 ) ); + this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); + this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); + + } else if ( order === 'ZXY' ) { + + this._x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ), -1, 1 ) ); + this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); + this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); + + } else if ( order === 'ZYX' ) { + + this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); + this._y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ), -1, 1 ) ); + this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); + + } else if ( order === 'YZX' ) { + + this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); + this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); + this._z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ), -1, 1 ) ); + + } else if ( order === 'XZY' ) { + + this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); + this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); + this._z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ), -1, 1 ) ); + + } else { + + console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order ) + + } + + this._order = order; + + if ( update !== false ) this._updateQuaternion(); + + return this; + + }, + + reorder: function () { + + // WARNING: this discards revolution information -bhouston + + var q = new THREE.Quaternion(); + + return function ( newOrder ) { + + q.setFromEuler( this ); + this.setFromQuaternion( q, newOrder ); + + }; + + + }(), + + fromArray: function ( array ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + + this._updateQuaternion(); + + return this; + + }, + + toArray: function () { + + return [ this._x, this._y, this._z, this._order ]; + + }, + + equals: function ( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + }, + + clone: function () { + + return new THREE.Euler( this._x, this._y, this._z, this._order ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Line3 = function ( start, end ) { + + this.start = ( start !== undefined ) ? start : new THREE.Vector3(); + this.end = ( end !== undefined ) ? end : new THREE.Vector3(); + +}; + +THREE.Line3.prototype = { + + constructor: THREE.Line3, + + set: function ( start, end ) { + + this.start.copy( start ); + this.end.copy( end ); + + return this; + + }, + + copy: function ( line ) { + + this.start.copy( line.start ); + this.end.copy( line.end ); + + return this; + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + + }, + + delta: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.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 THREE.Vector3(); + + return this.delta( result ).multiplyScalar( t ).add( this.start ); + + }, + + closestPointToPointParameter: function() { + + var startP = new THREE.Vector3(); + var startEnd = new THREE.Vector3(); + + return function ( 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 = THREE.Math.clamp( t, 0, 1 ); + + } + + return t; + + }; + + }(), + + closestPointToPoint: function ( point, clampToLine, optionalTarget ) { + + var t = this.closestPointToPointParameter( point, clampToLine ); + + var result = optionalTarget || new THREE.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 ); + + }, + + clone: function () { + + return new THREE.Line3().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Box2 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); + +}; + +THREE.Box2.prototype = { + + constructor: THREE.Box2, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + point = points[ i ]; + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function () { + + var v1 = new THREE.Vector2(); + + return function ( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return 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; + + }, + + empty: 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 ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return 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 ) { + + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { + + return true; + + } + + return false; + + }, + + 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 THREE.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 ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function () { + + var v1 = new THREE.Vector2(); + + return function ( 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 ); + + }, + + clone: function () { + + return new THREE.Box2().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Box3 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + +}; + +THREE.Box3.prototype = { + + constructor: THREE.Box3, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + addPoint: function ( point ) { + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + if ( point.z < this.min.z ) { + + this.min.z = point.z; + + } else if ( point.z > this.max.z ) { + + this.max.z = point.z; + + } + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + this.addPoint( points[ i ] ) + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function() { + + var v1 = new THREE.Vector3(); + + return function ( 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() { + + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and childrens', world transforms + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var scope = this; + + object.updateMatrixWorld( true ); + + this.makeEmpty(); + + object.traverse( function ( node ) { + + if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { + + var vertices = node.geometry.vertices; + + for ( var i = 0, il = vertices.length; i < il; i++ ) { + + v1.copy( vertices[ i ] ); + + v1.applyMatrix4( node.matrixWorld ); + + scope.expandByPoint( v1 ); + + } + + } + + } ); + + return 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; + + }, + + empty: 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 ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return 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 ) { + + if ( 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 ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( 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 ) ) { + + return true; + + } + + return false; + + }, + + 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 THREE.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 ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( 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 ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function() { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + getBoundingSphere: function() { + + var v1 = new THREE.Vector3(); + + return function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Sphere(); + + result.center = this.center(); + result.radius = this.size( v1 ).length() * 0.5; + + return result; + + }; + + }(), + + 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; + + }, + + applyMatrix4: function() { + + var points = [ + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3() + ]; + + return function ( matrix ) { + + // 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.makeEmpty(); + 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 ); + + }, + + clone: function () { + + return new THREE.Box3().copy( this ); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + this.elements = new Float32Array(9); + + this.set( + + ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, + n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, + n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 + + ); +}; + +THREE.Matrix3.prototype = { + + constructor: THREE.Matrix3, + + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + var te = this.elements; + + te[0] = n11; te[3] = n12; te[6] = n13; + te[1] = n21; te[4] = n22; te[7] = n23; + te[2] = n31; te[5] = n32; te[8] = n33; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ); + + return this; + + }, + + 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; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); + + }, + + multiplyVector3Array: function ( a ) { + + console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + + applyToVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyMatrix3( this ); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + 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, throwOnInvertible ) { + + // input: THREE.Matrix4 + // ( based on http://code.google.com/p/webgl-mjs/ ) + + var me = matrix.elements; + var te = this.elements; + + te[ 0 ] = me[10] * me[5] - me[6] * me[9]; + te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; + te[ 2 ] = me[6] * me[1] - me[2] * me[5]; + te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; + te[ 4 ] = me[10] * me[0] - me[2] * me[8]; + te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; + te[ 6 ] = me[9] * me[4] - me[5] * me[8]; + te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; + te[ 8 ] = me[5] * me[0] - me[1] * me[4]; + + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; + + // no inverse + + if ( det === 0 ) { + + var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnInvertible || false ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + this.identity(); + + return this; + + } + + this.multiplyScalar( 1.0 / det ); + + 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 ( m ) { + + // input: THREE.Matrix4 + + this.getInverse( m ).transpose(); + + return this; + + }, + + 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 ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { + + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], + te[ 3 ], te[ 4 ], te[ 5 ], + te[ 6 ], te[ 7 ], te[ 8 ] + ]; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix3( + + te[0], te[3], te[6], + te[1], te[4], te[7], + te[2], te[5], te[8] + + ); + + } + +}; + +/** + * @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://exocortex.com + * @author WestLangley / http://github.com/WestLangley + */ + + +THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + this.elements = new Float32Array( 16 ); + + // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix + // we should not support semi specification of Matrix4, it is just weird. + + var te = this.elements; + + te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; + te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; + te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; + te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; + +}; + +THREE.Matrix4.prototype = { + + constructor: THREE.Matrix4, + + 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; + + }, + + copy: function ( m ) { + + this.elements.set( m.elements ); + + return this; + + }, + + extractPosition: function ( m ) { + + console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); + + }, + + 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; + + }, + + extractRotation: function () { + + var v1 = new THREE.Vector3(); + + return function ( m ) { + + var te = this.elements; + var me = m.elements; + + var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); + var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); + var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); + + te[0] = me[0] * scaleX; + te[1] = me[1] * scaleX; + te[2] = me[2] * scaleX; + + te[4] = me[4] * scaleY; + te[5] = me[5] * scaleY; + te[6] = me[6] * scaleY; + + te[8] = me[8] * scaleZ; + te[9] = me[9] * scaleZ; + te[10] = me[10] * scaleZ; + + return this; + + }; + + }(), + + makeRotationFromEuler: function ( euler ) { + + if ( euler instanceof THREE.Euler === false ) { + + console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + + } + + 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; + + }, + + setRotationFromQuaternion: function ( q ) { + + console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); + + return this.makeRotationFromQuaternion( q ); + + }, + + 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 = new THREE.Vector3(); + var y = new THREE.Vector3(); + var z = new THREE.Vector3(); + + return function ( eye, target, up ) { + + var te = this.elements; + + z.subVectors( eye, target ).normalize(); + + if ( z.length() === 0 ) { + + z.z = 1; + + } + + x.crossVectors( up, z ).normalize(); + + if ( x.length() === 0 ) { + + z.x += 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( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); + + } + + return this.multiplyMatrices( this, m ); + + }, + + 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; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + return vector.applyProjection( this ); + + }, + + multiplyVector4: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + + multiplyVector3Array: function ( a ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + + applyToVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyMatrix4( this ); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + rotateAxis: function ( v ) { + + console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + + v.transformDirection( this ); + + }, + + crossVector: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + + 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; + + }, + + flattenToArray: function ( flat ) { + + var te = this.elements; + flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; + flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; + flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; + flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; + + return flat; + + }, + + flattenToArrayOffset: function( flat, offset ) { + + var te = this.elements; + flat[ offset ] = te[0]; + flat[ offset + 1 ] = te[1]; + flat[ offset + 2 ] = te[2]; + flat[ offset + 3 ] = te[3]; + + flat[ offset + 4 ] = te[4]; + flat[ offset + 5 ] = te[5]; + flat[ offset + 6 ] = te[6]; + flat[ offset + 7 ] = te[7]; + + flat[ offset + 8 ] = te[8]; + flat[ offset + 9 ] = te[9]; + flat[ offset + 10 ] = te[10]; + flat[ offset + 11 ] = te[11]; + + flat[ offset + 12 ] = te[12]; + flat[ offset + 13 ] = te[13]; + flat[ offset + 14 ] = te[14]; + flat[ offset + 15 ] = te[15]; + + return flat; + + }, + + getPosition: function() { + + var v1 = new THREE.Vector3(); + + return function () { + + console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + + var te = this.elements; + return v1.set( te[12], te[13], te[14] ); + + }; + + }(), + + setPosition: function ( v ) { + + var te = this.elements; + + te[12] = v.x; + te[13] = v.y; + te[14] = v.z; + + return this; + + }, + + getInverse: function ( m, throwOnInvertible ) { + + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements; + var me = m.elements; + + var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; + var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; + var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; + var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; + + te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; + te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; + te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; + te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; + te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; + te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; + te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; + te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; + te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; + te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; + te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; + te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; + te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; + te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; + te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; + te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; + + var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; + + if ( det == 0 ) { + + var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnInvertible || false ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + this.identity(); + + return this; + } + + this.multiplyScalar( 1 / det ); + + return this; + + }, + + translate: function ( v ) { + + console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); + + }, + + rotateX: function ( angle ) { + + console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); + + }, + + rotateY: function ( angle ) { + + console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); + + }, + + rotateZ: function ( angle ) { + + console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); + + }, + + rotateByAxis: function ( axis, angle ) { + + console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); + + }, + + 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, Math.max( 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; + + }, + + compose: function ( position, quaternion, scale ) { + + this.makeRotationFromQuaternion( quaternion ); + this.scale( scale ); + this.setPosition( position ); + + return this; + + }, + + decompose: function () { + + var vector = new THREE.Vector3(); + var matrix = new THREE.Matrix4(); + + return function ( position, quaternion, scale ) { + + 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; + + }; + + }(), + + makeFrustum: function ( left, right, bottom, top, near, far ) { + + 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; + + }, + + makePerspective: function ( fov, aspect, near, far ) { + + var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); + var ymin = - ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; + + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); + + }, + + makeOrthographic: function ( left, right, top, bottom, near, far ) { + + var te = this.elements; + var w = right - left; + var h = top - bottom; + var p = 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; + + }, + + fromArray: function ( array ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { + + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], + te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], + te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], + te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] + ]; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix4( + + te[0], te[4], te[8], te[12], + te[1], te[5], te[9], te[13], + te[2], te[6], te[10], te[14], + te[3], te[7], te[11], te[15] + + ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Ray = function ( origin, direction ) { + + this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); + this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); + +}; + +THREE.Ray.prototype = { + + constructor: THREE.Ray, + + set: function ( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; + + }, + + at: function ( t, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + + }, + + recast: function () { + + var v1 = new THREE.Vector3(); + + return function ( t ) { + + this.origin.copy( this.at( t, v1 ) ); + + return this; + + }; + + }(), + + closestPointToPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.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 () { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + + // point behind the ray + + if ( directionDistance < 0 ) { + + return this.origin.distanceTo( point ); + + } + + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + return v1.distanceTo( point ); + + }; + + }(), + + distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + + // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp + // 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 + + var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); + var segDir = v1.clone().sub( v0 ).normalize(); + var segExtent = v0.distanceTo( v1 ) * 0.5; + var diff = this.origin.clone().sub( segCenter ); + 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.clone().multiplyScalar( s0 ).add( this.origin ) ); + + } + + if ( optionalPointOnSegment ) { + + optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); + + } + + return sqrDist; + + }, + + isIntersectionSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) <= sphere.radius; + + }, + + isIntersectionPlane: 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; + + }, + + 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 ); + + }, + + isIntersectionBox: function () { + + var v = new THREE.Vector3(); + + return function ( box ) { + + return this.intersectBox( box, v ) !== null; + + } + + }(), + + intersectBox: function ( box , optionalTarget ) { + + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + + 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 ); + + }, + + intersectTriangle: function() { + + // Compute the offset origin, edges, and normal. + var diff = new THREE.Vector3(); + var edge1 = new THREE.Vector3(); + var edge2 = new THREE.Vector3(); + var normal = new THREE.Vector3(); + + return function ( a, b, c, backfaceCulling, optionalTarget ) { + + // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp + + 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 ); + + }, + + clone: function () { + + return new THREE.Ray().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Sphere = function ( center, radius ) { + + this.center = ( center !== undefined ) ? center : new THREE.Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; + +}; + +THREE.Sphere.prototype = { + + constructor: THREE.Sphere, + + set: function ( center, radius ) { + + this.center.copy( center ); + this.radius = radius; + + return this; + }, + + + setFromPoints: function () { + + var box = new THREE.Box3(); + + return function ( points, optionalCenter ) { + + var center = this.center; + + if ( optionalCenter !== undefined ) { + + center.copy( optionalCenter ); + + } else { + + box.setFromPoints( points ).center( 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; + + }; + + }(), + + 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 ); + + }, + + clampPoint: function ( point, optionalTarget ) { + + var deltaLengthSq = this.center.distanceToSquared( point ); + + var result = optionalTarget || new THREE.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 THREE.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 ); + + }, + + clone: function () { + + return new THREE.Sphere().copy( this ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / http://exocortex.com + */ + +THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { + + this.planes = [ + + ( p0 !== undefined ) ? p0 : new THREE.Plane(), + ( p1 !== undefined ) ? p1 : new THREE.Plane(), + ( p2 !== undefined ) ? p2 : new THREE.Plane(), + ( p3 !== undefined ) ? p3 : new THREE.Plane(), + ( p4 !== undefined ) ? p4 : new THREE.Plane(), + ( p5 !== undefined ) ? p5 : new THREE.Plane() + + ]; + +}; + +THREE.Frustum.prototype = { + + constructor: THREE.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; + + }, + + 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 THREE.Sphere(); + + return function ( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.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 THREE.Vector3(), + p2 = new THREE.Vector3(); + + return function( 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; + + }, + + clone: function () { + + return new THREE.Frustum().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Plane = function ( normal, constant ) { + + this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; + +}; + +THREE.Plane.prototype = { + + constructor: THREE.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 THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( 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; + + }; + + }(), + + + 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 THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); + + }, + + isIntersectionLine: 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 ); + + }, + + intersectLine: function() { + + var v1 = new THREE.Vector3(); + + return function ( line, optionalTarget ) { + + var result = optionalTarget || new THREE.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 ); + + }; + + }(), + + + coplanarPoint: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); + + }, + + applyMatrix4: function() { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var m1 = new THREE.Matrix3(); + + return function ( matrix, optionalNormalMatrix ) { + + // compute new normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); + + var newCoplanarPoint = this.coplanarPoint( v2 ); + newCoplanarPoint.applyMatrix4( matrix ); + + this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); + + 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 ); + + }, + + clone: function () { + + return new THREE.Plane().copy( this ); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Math = { + + 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 () { + + 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 value to range + + clamp: function ( x, a, b ) { + + return ( x < a ) ? a : ( ( x > b ) ? b : x ); + + }, + + // Clamp value to range to range + + mapLinear: function ( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + + }, + + // 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 float from <0, 1> with 16 bits of randomness + // (standard Math.random() creates repetitive patterns when applied over larger space) + + random16: function () { + + return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; + + }, + + // 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() ); + + }, + + sign: function ( x ) { + + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; + + }, + + degToRad: function() { + + var degreeToRadiansFactor = Math.PI / 180; + + return function ( degrees ) { + + return degrees * degreeToRadiansFactor; + + }; + + }(), + + radToDeg: function() { + + var radianToDegreesFactor = 180 / Math.PI; + + return function ( radians ) { + + return radians * radianToDegreesFactor; + + }; + + }(), + + isPowerOfTwo: function ( value ) { + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + + } + +}; + +/** + * Spline from Tween.js, slightly optimized (and trashed) + * http://sole.github.com/tween.js/examples/05_spline.html + * + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Spline = function ( points ) { + + this.points = points; + + var c = [], v3 = { x: 0, y: 0, z: 0 }, + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + this.initFromArray = function( a ) { + + this.points = []; + + for ( var i = 0; i < a.length; i++ ) { + + this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; + + } + + }; + + this.getPoint = function ( k ) { + + point = ( this.points.length - 1 ) * k; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; + + pa = this.points[ c[ 0 ] ]; + pb = this.points[ c[ 1 ] ]; + pc = this.points[ c[ 2 ] ]; + pd = this.points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); + v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); + v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); + + return v3; + + }; + + this.getControlPointsArray = function () { + + var i, p, l = this.points.length, + coords = []; + + for ( i = 0; i < l; i ++ ) { + + p = this.points[ i ]; + coords[ i ] = [ p.x, p.y, p.z ]; + + } + + return coords; + + }; + + // approximate length by summing linear segments + + this.getLength = function ( nSubDivisions ) { + + var i, index, nSamples, position, + point = 0, intPoint = 0, oldIntPoint = 0, + oldPosition = new THREE.Vector3(), + tmpVec = new THREE.Vector3(), + chunkLengths = [], + totalLength = 0; + + // first point has 0 length + + chunkLengths[ 0 ] = 0; + + if ( !nSubDivisions ) nSubDivisions = 100; + + nSamples = this.points.length * nSubDivisions; + + oldPosition.copy( this.points[ 0 ] ); + + for ( i = 1; i < nSamples; i ++ ) { + + index = i / nSamples; + + position = this.getPoint( index ); + tmpVec.copy( position ); + + totalLength += tmpVec.distanceTo( oldPosition ); + + oldPosition.copy( position ); + + point = ( this.points.length - 1 ) * index; + intPoint = Math.floor( point ); + + if ( intPoint != oldIntPoint ) { + + chunkLengths[ intPoint ] = totalLength; + oldIntPoint = intPoint; + + } + + } + + // last point ends with total length + + chunkLengths[ chunkLengths.length ] = totalLength; + + return { chunks: chunkLengths, total: totalLength }; + + }; + + this.reparametrizeByArcLength = function ( samplingCoef ) { + + var i, j, + index, indexCurrent, indexNext, + linearDistance, realDistance, + sampling, position, + newpoints = [], + tmpVec = new THREE.Vector3(), + sl = this.getLength(); + + newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); + + for ( i = 1; i < this.points.length; i++ ) { + + //tmpVec.copy( this.points[ i - 1 ] ); + //linearDistance = tmpVec.distanceTo( this.points[ i ] ); + + realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; + + sampling = Math.ceil( samplingCoef * realDistance / sl.total ); + + indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); + indexNext = i / ( this.points.length - 1 ); + + for ( j = 1; j < sampling - 1; j++ ) { + + index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); + + position = this.getPoint( index ); + newpoints.push( tmpVec.copy( position ).clone() ); + + } + + newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); + + } + + this.points = newpoints; + + }; + + // Catmull-Rom + + function interpolate( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + }; + +}; + +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Triangle = function ( a, b, c ) { + + this.a = ( a !== undefined ) ? a : new THREE.Vector3(); + this.b = ( b !== undefined ) ? b : new THREE.Vector3(); + this.c = ( c !== undefined ) ? c : new THREE.Vector3(); + +}; + +THREE.Triangle.normal = function() { + + var v0 = new THREE.Vector3(); + + return function ( a, b, c, optionalTarget ) { + + var result = optionalTarget || new THREE.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 barycoordinates +// based on: http://www.blackpawn.com/texts/pointinpoly/default.html +THREE.Triangle.barycoordFromPoint = function() { + + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( 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 THREE.Vector3(); + + // colinear 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; + + // barycoordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); + + }; + +}(); + +THREE.Triangle.containsPoint = function() { + + var v1 = new THREE.Vector3(); + + return function ( point, a, b, c ) { + + var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); + + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + + }; + +}(); + +THREE.Triangle.prototype = { + + constructor: THREE.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; + + }, + + 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 THREE.Vector3(); + var v1 = new THREE.Vector3(); + + return function () { + + 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 THREE.Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + + }, + + normal: function ( optionalTarget ) { + + return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); + + }, + + plane: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Plane(); + + return result.setFromCoplanarPoints( this.a, this.b, this.c ); + + }, + + barycoordFromPoint: function ( point, optionalTarget ) { + + return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + + }, + + containsPoint: function ( point ) { + + return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); + + }, + + equals: function ( triangle ) { + + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + + }, + + clone: function () { + + return new THREE.Triangle().copy( this ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Vertex = function ( v ) { + + console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') + return v; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.UV = function ( u, v ) { + + console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') + return new THREE.Vector2( u, v ); + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Clock = function ( autoStart ) { + + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; + + this.running = false; + +}; + +THREE.Clock.prototype = { + + constructor: THREE.Clock, + + start: function () { + + this.startTime = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); + + this.oldTime = this.startTime; + 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 = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); + + diff = 0.001 * ( newTime - this.oldTime ); + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } + +}; + +/** + * https://github.com/mrdoob/eventdispatcher.js/ + */ + +THREE.EventDispatcher = function () {} + +THREE.EventDispatcher.prototype = { + + constructor: THREE.EventDispatcher, + + apply: function ( object ) { + + object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; + object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; + object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; + object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; + + }, + + 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; + + if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { + + return true; + + } + + return false; + + }, + + 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 = []; + var length = listenerArray.length; + + for ( var i = 0; i < length; i ++ ) { + + array[ i ] = listenerArray[ i ]; + + } + + for ( var i = 0; i < length; i ++ ) { + + array[ i ].call( this, event ); + + } + + } + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author bhouston / http://exocortex.com/ + * @author stephomi / http://stephaneginier.com/ + */ + +( function ( THREE ) { + + THREE.Raycaster = function ( origin, direction, near, far ) { + + this.ray = new THREE.Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near || 0; + this.far = far || Infinity; + + }; + + var sphere = new THREE.Sphere(); + var localRay = new THREE.Ray(); + var facePlane = new THREE.Plane(); + var intersectPoint = new THREE.Vector3(); + var matrixPosition = new THREE.Vector3(); + + var inverseMatrix = new THREE.Matrix4(); + + var descSort = function ( a, b ) { + + return a.distance - b.distance; + + }; + + var vA = new THREE.Vector3(); + var vB = new THREE.Vector3(); + var vC = new THREE.Vector3(); + + var intersectObject = function ( object, raycaster, intersects ) { + + if ( object instanceof THREE.Sprite ) { + + matrixPosition.setFromMatrixPosition( object.matrixWorld ); + + var distance = raycaster.ray.distanceToPoint( matrixPosition ); + + if ( distance > object.scale.x ) { + + return intersects; + + } + + intersects.push( { + + distance: distance, + point: object.position, + face: null, + object: object + + } ); + + } else if ( object instanceof THREE.LOD ) { + + matrixPosition.setFromMatrixPosition( object.matrixWorld ); + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + + intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); + + } else if ( object instanceof THREE.Mesh ) { + + var geometry = object.geometry; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); + + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + + return intersects; + + } + + // Check boundingBox before continuing + + inverseMatrix.getInverse( object.matrixWorld ); + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + if ( geometry.boundingBox !== null ) { + + if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { + + return intersects; + + } + + } + + if ( geometry instanceof THREE.BufferGeometry ) { + + var material = object.material; + + if ( material === undefined ) return intersects; + + var attributes = geometry.attributes; + + var a, b, c; + var precision = raycaster.precision; + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + var positions = attributes.position.array; + var offsets = geometry.offsets; + + if ( offsets.length === 0 ) { + + offsets = [ { start: 0, count: positions.length, index: 0 } ]; + + } + + for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + a = index + indices[ i ]; + b = index + indices[ i + 1 ]; + c = index + indices[ i + 2 ]; + + vA.set( + positions[ a * 3 ], + positions[ a * 3 + 1 ], + positions[ a * 3 + 2 ] + ); + vB.set( + positions[ b * 3 ], + positions[ b * 3 + 1 ], + positions[ b * 3 + 2 ] + ); + vC.set( + positions[ c * 3 ], + positions[ c * 3 + 1 ], + positions[ c * 3 + 2 ] + ); + + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + indices: [a, b, c], + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } else { + + var offsets = geometry.offsets; + var positions = attributes.position.array; + + for ( var i = 0, il = attributes.position.array.length; i < il; i += 3 ) { + + a = i; + b = i + 1; + c = i + 2; + + vA.set( + positions[ a * 3 ], + positions[ a * 3 + 1 ], + positions[ a * 3 + 2 ] + ); + vB.set( + positions[ b * 3 ], + positions[ b * 3 + 1 ], + positions[ b * 3 + 2 ] + ); + vC.set( + positions[ c * 3 ], + positions[ c * 3 + 1 ], + positions[ c * 3 + 2 ] + ); + + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + indices: [a, b, c], + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? object.material.materials : null; + + var a, b, c, d; + var precision = raycaster.precision; + + var vertices = geometry.vertices; + + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + + var face = geometry.faces[ f ]; + + var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; + + if ( material === undefined ) continue; + + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; + + if ( material.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = object.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.x += ( targets[ face.a ].x - a.x ) * influence; + vA.y += ( targets[ face.a ].y - a.y ) * influence; + vA.z += ( targets[ face.a ].z - a.z ) * influence; + + vB.x += ( targets[ face.b ].x - b.x ) * influence; + vB.y += ( targets[ face.b ].y - b.y ) * influence; + vB.z += ( targets[ face.b ].z - b.z ) * influence; + + vC.x += ( targets[ face.c ].x - c.x ) * influence; + vC.y += ( targets[ face.c ].y - c.y ) * influence; + vC.z += ( targets[ face.c ].z - c.z ) * influence; + + } + + vA.add( a ); + vB.add( b ); + vC.add( c ); + + a = vA; + b = vB; + c = vC; + + } + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + face: face, + faceIndex: f, + object: object + + } ); + + } + + } + + } else if ( object instanceof THREE.Line ) { + + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + // Checking boundingSphere distance to ray + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); + + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + + return intersects; + + } + + inverseMatrix.getInverse( object.matrixWorld ); + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + /* if ( geometry instanceof THREE.BufferGeometry ) { + + } else */ if ( geometry instanceof THREE.Geometry ) { + + var vertices = geometry.vertices; + var nbVertices = vertices.length; + var interSegment = new THREE.Vector3(); + var interRay = new THREE.Vector3(); + var step = object.type === THREE.LineStrip ? 1 : 2; + + for ( var i = 0; i < nbVertices - 1; i = i + step ) { + + var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); + + if ( distSq > precisionSq ) continue; + + var distance = localRay.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( object.matrixWorld ), + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } + + }; + + var intersectDescendants = function ( object, raycaster, intersects ) { + + var descendants = object.getDescendants(); + + for ( var i = 0, l = descendants.length; i < l; i ++ ) { + + intersectObject( descendants[ i ], raycaster, intersects ); + + } + }; + + // + + THREE.Raycaster.prototype.precision = 0.0001; + THREE.Raycaster.prototype.linePrecision = 1; + + THREE.Raycaster.prototype.set = function ( origin, direction ) { + + this.ray.set( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + }; + + THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { + + var intersects = []; + + if ( recursive === true ) { + + intersectDescendants( object, this, intersects ); + + } + + intersectObject( object, this, intersects ); + + intersects.sort( descSort ); + + return intersects; + + }; + + THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { + + var intersects = []; + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + intersectObject( objects[ i ], this, intersects ); + + if ( recursive === true ) { + + intersectDescendants( objects[ i ], this, intersects ); + + } + + } + + intersects.sort( descSort ); + + return intersects; + + }; + +}( THREE ) ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Object3D = function () { + + this.id = THREE.Object3DIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.parent = undefined; + this.children = []; + + this.up = new THREE.Vector3( 0, 1, 0 ); + + this.position = new THREE.Vector3(); + this._rotation = new THREE.Euler(); + this._quaternion = new THREE.Quaternion(); + this.scale = new THREE.Vector3( 1, 1, 1 ); + + // keep rotation and quaternion in sync + + this._rotation._quaternion = this.quaternion; + this._quaternion._euler = this.rotation; + + this.renderDepth = null; + + this.rotationAutoUpdate = true; + + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); + + this.matrixAutoUpdate = true; + this.matrixWorldNeedsUpdate = false; + + this.visible = true; + + this.castShadow = false; + this.receiveShadow = false; + + this.frustumCulled = true; + + this.userData = {}; + +}; + + +THREE.Object3D.prototype = { + + constructor: THREE.Object3D, + + get rotation () { + return this._rotation; + }, + + set rotation ( value ) { + + this._rotation = value; + this._rotation._quaternion = this._quaternion; + this._quaternion._euler = this._rotation; + this._rotation._updateQuaternion(); + + }, + + get quaternion () { + return this._quaternion; + }, + + set quaternion ( value ) { + + this._quaternion = value; + this._quaternion._euler = this._rotation; + this._rotation._quaternion = this._quaternion; + this._quaternion._updateEuler(); + + }, + + get eulerOrder () { + + console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + + return this.rotation.order; + + }, + + set eulerOrder ( value ) { + + console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + + this.rotation.order = value; + + }, + + get useQuaternion () { + + console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + + }, + + set useQuaternion ( value ) { + + console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + + }, + + 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 THREE.Quaternion(); + + return function ( axis, angle ) { + + q1.setFromAxisAngle( axis, angle ); + + this.quaternion.multiply( q1 ); + + return this; + + } + + }(), + + rotateX: function () { + + var v1 = new THREE.Vector3( 1, 0, 0 ); + + return function ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateY: function () { + + var v1 = new THREE.Vector3( 0, 1, 0 ); + + return function ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateZ: function () { + + var v1 = new THREE.Vector3( 0, 0, 1 ); + + return function ( 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 THREE.Vector3(); + + return function ( axis, distance ) { + + v1.copy( axis ); + + v1.applyQuaternion( this.quaternion ); + + this.position.add( v1.multiplyScalar( distance ) ); + + return this; + + } + + }(), + + translate: function ( distance, axis ) { + + console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); + return this.translateOnAxis( axis, distance ); + + }, + + translateX: function () { + + var v1 = new THREE.Vector3( 1, 0, 0 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateY: function () { + + var v1 = new THREE.Vector3( 0, 1, 0 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateZ: function () { + + var v1 = new THREE.Vector3( 0, 0, 1 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + localToWorld: function ( vector ) { + + return vector.applyMatrix4( this.matrixWorld ); + + }, + + worldToLocal: function () { + + var m1 = new THREE.Matrix4(); + + return function ( 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 THREE.Matrix4(); + + return function ( vector ) { + + m1.lookAt( vector, this.position, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + + }(), + + add: function ( object ) { + + if ( object === this ) { + + console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); + return; + + } + + if ( object instanceof THREE.Object3D ) { + + if ( object.parent !== undefined ) { + + object.parent.remove( object ); + + } + + object.parent = this; + object.dispatchEvent( { type: 'added' } ); + + this.children.push( object ); + + // add to scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__addObject( object ); + + } + + } + + }, + + remove: function ( object ) { + + var index = this.children.indexOf( object ); + + if ( index !== - 1 ) { + + object.parent = undefined; + object.dispatchEvent( { type: 'removed' } ); + + this.children.splice( index, 1 ); + + // remove from scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__removeObject( object ); + + } + + } + + }, + + traverse: function ( callback ) { + + callback( this ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].traverse( callback ); + + } + + }, + + getObjectById: function ( id, recursive ) { + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child.id === id ) { + + return child; + + } + + if ( recursive === true ) { + + child = child.getObjectById( id, recursive ); + + if ( child !== undefined ) { + + return child; + + } + + } + + } + + return undefined; + + }, + + getObjectByName: function ( name, recursive ) { + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child.name === name ) { + + return child; + + } + + if ( recursive === true ) { + + child = child.getObjectByName( name, recursive ); + + if ( child !== undefined ) { + + return child; + + } + + } + + } + + return undefined; + + }, + + getChildByName: function ( name, recursive ) { + + console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name, recursive ); + + }, + + getDescendants: function ( array ) { + + if ( array === undefined ) array = []; + + Array.prototype.push.apply( array, this.children ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].getDescendants( array ); + + } + + return array; + + }, + + 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 === undefined ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + + }, + + clone: function ( object, recursive ) { + + if ( object === undefined ) object = new THREE.Object3D(); + if ( recursive === undefined ) recursive = true; + + object.name = this.name; + + object.up.copy( this.up ); + + object.position.copy( this.position ); + object.quaternion.copy( this.quaternion ); + object.scale.copy( this.scale ); + + object.renderDepth = this.renderDepth; + + object.rotationAutoUpdate = this.rotationAutoUpdate; + + object.matrix.copy( this.matrix ); + object.matrixWorld.copy( this.matrixWorld ); + + object.matrixAutoUpdate = this.matrixAutoUpdate; + object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + + object.visible = this.visible; + + object.castShadow = this.castShadow; + object.receiveShadow = this.receiveShadow; + + object.frustumCulled = this.frustumCulled; + + object.userData = JSON.parse( JSON.stringify( this.userData ) ); + + if ( recursive === true ) { + + for ( var i = 0; i < this.children.length; i ++ ) { + + var child = this.children[ i ]; + object.add( child.clone() ); + + } + + } + + return object; + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); + +THREE.Object3DIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author julianwa / https://github.com/julianwa + */ + +THREE.Projector = function () { + + var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, + _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, + _face, _faceCount, _facePool = [], _facePoolLength = 0, + _line, _lineCount, _linePool = [], _linePoolLength = 0, + _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + + _renderData = { objects: [], lights: [], elements: [] }, + + _vA = new THREE.Vector3(), + _vB = new THREE.Vector3(), + _vC = new THREE.Vector3(), + + _vector3 = new THREE.Vector3(), + _vector4 = new THREE.Vector4(), + + _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), + _boundingBox = new THREE.Box3(), + _points3 = new Array( 3 ), + _points4 = new Array( 4 ), + + _viewMatrix = new THREE.Matrix4(), + _viewProjectionMatrix = new THREE.Matrix4(), + + _modelMatrix, + _modelViewProjectionMatrix = new THREE.Matrix4(), + + _normalMatrix = new THREE.Matrix3(), + + _frustum = new THREE.Frustum(), + + _clippedVertex1PositionScreen = new THREE.Vector4(), + _clippedVertex2PositionScreen = new THREE.Vector4(); + + this.projectVector = function ( vector, camera ) { + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + this.unprojectVector = function () { + + var projectionMatrixInverse = new THREE.Matrix4(); + + return function ( vector, camera ) { + + projectionMatrixInverse.getInverse( camera.projectionMatrix ); + _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + }(); + + this.pickingRay = function ( vector, camera ) { + + // set two vectors with opposing z values + vector.z = -1.0; + var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); + + this.unprojectVector( vector, camera ); + this.unprojectVector( end, camera ); + + // find direction from vector to end + end.sub( vector ).normalize(); + + return new THREE.Raycaster( vector, end ); + + }; + + var projectObject = function ( object ) { + + if ( object.visible === false ) return; + + if ( object instanceof THREE.Light ) { + + _renderData.lights.push( object ); + + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { + + if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + + _object = getNextObjectInPool(); + _object.id = object.id; + _object.object = object; + + if ( object.renderDepth !== null ) { + + _object.z = object.renderDepth; + + } else { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + } + + _renderData.objects.push( _object ); + + } + + } + + for ( var i = 0, l = object.children.length; i < l; i ++ ) { + + projectObject( object.children[ i ] ); + + } + + }; + + var projectGraph = function ( root, sortObjects ) { + + _objectCount = 0; + + _renderData.objects.length = 0; + _renderData.lights.length = 0; + + projectObject( root ); + + if ( sortObjects === true ) { + + _renderData.objects.sort( painterSort ); + + } + + }; + + var RenderList = function () { + + var normals = []; + var uvs = []; + + var object = null; + var material = null; + + var normalMatrix = new THREE.Matrix3(); + + var setObject = function ( value ) { + + object = value; + material = object.material; + + normalMatrix.getNormalMatrix( object.matrixWorld ); + + normals.length = 0; + uvs.length = 0; + + }; + + var projectVertex = function ( vertex ) { + + var position = vertex.position; + var positionWorld = vertex.positionWorld; + var positionScreen = vertex.positionScreen; + + positionWorld.copy( position ).applyMatrix4( _modelMatrix ); + positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / positionScreen.w; + + positionScreen.x *= invW; + positionScreen.y *= invW; + positionScreen.z *= invW; + + vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && + positionScreen.y >= -1 && positionScreen.y <= 1 && + positionScreen.z >= -1 && positionScreen.z <= 1; + + }; + + var pushVertex = function ( x, y, z ) { + + _vertex = getNextVertexInPool(); + _vertex.position.set( x, y, z ); + + projectVertex( _vertex ); + + }; + + var pushNormal = function ( x, y, z ) { + + normals.push( x, y, z ); + + }; + + var pushUv = function ( x, y ) { + + uvs.push( x, y ); + + }; + + var checkTriangleVisibility = function ( v1, v2, v3 ) { + + if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; + + _points3[ 0 ] = v1.positionScreen; + _points3[ 1 ] = v2.positionScreen; + _points3[ 2 ] = v3.positionScreen; + + return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ); + + }; + + var checkBackfaceCulling = function ( v1, v2, v3 ) { + + return ( ( v3.positionScreen.x - v1.positionScreen.x ) * + ( v2.positionScreen.y - v1.positionScreen.y ) - + ( v3.positionScreen.y - v1.positionScreen.y ) * + ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; + + }; + + var pushLine = function ( a, b ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.copy( v1 ); + _line.v2.copy( v2 ); + _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; + + _line.material = object.material; + + _renderData.elements.push( _line ); + + }; + + var pushTriangle = function ( a, b, c ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + var v3 = _vertexPool[ c ]; + + if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; + + if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + for ( var i = 0; i < 3; i ++ ) { + + var offset = arguments[ i ] * 3; + var normal = _face.vertexNormalsModel[ i ]; + + normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] ); + normal.applyMatrix3( normalMatrix ).normalize(); + + var offset2 = arguments[ i ] * 2; + + var uv = _face.uvs[ i ]; + uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] ); + + } + + _face.vertexNormalsLength = 3; + + _face.material = object.material; + + _renderData.elements.push( _face ); + + } + + }; + + return { + setObject: setObject, + projectVertex: projectVertex, + checkTriangleVisibility: checkTriangleVisibility, + checkBackfaceCulling: checkBackfaceCulling, + pushVertex: pushVertex, + pushNormal: pushNormal, + pushUv: pushUv, + pushLine: pushLine, + pushTriangle: pushTriangle + } + + }; + + var renderList = new RenderList(); + + this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + + var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, + isFaceMaterial, objectMaterials; + + _faceCount = 0; + _lineCount = 0; + _spriteCount = 0; + + _renderData.elements.length = 0; + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); + + _frustum.setFromMatrix( _viewProjectionMatrix ); + + projectGraph( scene, sortObjects ); + + for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + + object = _renderData.objects[ o ].object; + geometry = object.geometry; + + renderList.setObject( object ); + + _modelMatrix = object.matrixWorld; + + _vertexCount = 0; + + if ( object instanceof THREE.Mesh ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + var offsets = geometry.offsets; + + if ( attributes.position === undefined ) continue; + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + if ( attributes.normal !== undefined ) { + + var normals = attributes.normal.array; + + for ( var i = 0, l = normals.length; i < l; i += 3 ) { + + renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); + + } + + } + + if ( attributes.uv !== undefined ) { + + var uvs = attributes.uv.array; + + for ( var i = 0, l = uvs.length; i < l; i += 2 ) { + + renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); + + } + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + if ( offsets.length > 0 ) { + + for ( var o = 0; o < offsets.length; o ++ ) { + + var offset = offsets[ o ]; + var index = offset.index; + + for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); + + } + + } + + } else { + + for ( var i = 0, l = indices.length; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } + + } + + } else { + + for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { + + renderList.pushTriangle( i, i + 1, i + 2 ); + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + vertices = geometry.vertices; + faces = geometry.faces; + faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + + _normalMatrix.getNormalMatrix( _modelMatrix ); + + isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + objectMaterials = isFaceMaterial === true ? object.material : null; + + for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { + + var vertex = vertices[ v ]; + renderList.pushVertex( vertex.x, vertex.y, vertex.z ); + + } + + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + + face = faces[ f ]; + + var material = isFaceMaterial === true + ? objectMaterials.materials[ face.materialIndex ] + : object.material; + + if ( material === undefined ) continue; + + var side = material.side; + + var v1 = _vertexPool[ face.a ]; + var v2 = _vertexPool[ face.b ]; + var v3 = _vertexPool[ face.c ]; + + if ( material.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = object.morphTargetInfluences; + + var v1p = v1.position; + var v2p = v2.position; + var v3p = v3.position; + + _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.x += ( targets[ face.a ].x - v1p.x ) * influence; + _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; + _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; + + _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; + _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; + _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; + + _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; + _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; + _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; + + } + + v1.position.add( _vA ); + v2.position.add( _vB ); + v3.position.add( _vC ); + + renderList.projectVertex( v1 ); + renderList.projectVertex( v2 ); + renderList.projectVertex( v3 ); + + } + + if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; + + var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); + + if ( side !== THREE.DoubleSide ) { + if ( side === THREE.FrontSide && visible === false ) continue; + if ( side === THREE.BackSide && visible === true ) continue; + } + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + + _face.normalModel.copy( face.normal ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + _face.normalModel.negate(); + + } + + _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); + + faceVertexNormals = face.vertexNormals; + + for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { + + var normalModel = _face.vertexNormalsModel[ n ]; + normalModel.copy( faceVertexNormals[ n ] ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + normalModel.negate(); + + } + + normalModel.applyMatrix3( _normalMatrix ).normalize(); + + } + + _face.vertexNormalsLength = faceVertexNormals.length; + + var vertexUvs = faceVertexUvs[ f ]; + + if ( vertexUvs !== undefined ) { + + for ( var u = 0; u < 3; u ++ ) { + + _face.uvs[ u ].copy( vertexUvs[ u ] ); + + } + + } + + _face.color = face.color; + _face.material = material; + + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + _renderData.elements.push( _face ); + + } + + } + + } else if ( object instanceof THREE.Line ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + + if ( attributes.position !== undefined ) { + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + for ( var i = 0, l = indices.length; i < l; i += 2 ) { + + renderList.pushLine( indices[ i ], indices[ i + 1 ] ); + + } + + } else { + + for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i ++ ) { + + renderList.pushLine( i, i + 1 ); + + } + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + + vertices = object.geometry.vertices; + + if ( vertices.length === 0 ) continue; + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + + // Handle LineStrip and LinePieces + var step = object.type === THREE.LinePieces ? 2 : 1; + + for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + + if ( ( v + 1 ) % step > 0 ) continue; + + v2 = _vertexPool[ _vertexCount - 2 ]; + + _clippedVertex1PositionScreen.copy( v1.positionScreen ); + _clippedVertex2PositionScreen.copy( v2.positionScreen ); + + if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + + // Perform the perspective divide + _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); + _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); + _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + + _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + + _line.material = object.material; + + if ( object.material.vertexColors === THREE.VertexColors ) { + + _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); + _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); + + } + + _renderData.elements.push( _line ); + + } + + } + + } + + } else if ( object instanceof THREE.Sprite ) { + + _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); + _vector4.applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / _vector4.w; + + _vector4.z *= invW; + + if ( _vector4.z >= -1 && _vector4.z <= 1 ) { + + _sprite = getNextSpriteInPool(); + _sprite.id = object.id; + _sprite.x = _vector4.x * invW; + _sprite.y = _vector4.y * invW; + _sprite.z = _vector4.z; + _sprite.object = object; + + _sprite.rotation = object.rotation; + + _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); + _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); + + _sprite.material = object.material; + + _renderData.elements.push( _sprite ); + + } + + } + + } + + if ( sortElements === true ) _renderData.elements.sort( painterSort ); + + return _renderData; + + }; + + // Pools + + function getNextObjectInPool() { + + if ( _objectCount === _objectPoolLength ) { + + var object = new THREE.RenderableObject(); + _objectPool.push( object ); + _objectPoolLength ++; + _objectCount ++; + return object; + + } + + return _objectPool[ _objectCount ++ ]; + + } + + function getNextVertexInPool() { + + if ( _vertexCount === _vertexPoolLength ) { + + var vertex = new THREE.RenderableVertex(); + _vertexPool.push( vertex ); + _vertexPoolLength ++; + _vertexCount ++; + return vertex; + + } + + return _vertexPool[ _vertexCount ++ ]; + + } + + function getNextFaceInPool() { + + if ( _faceCount === _facePoolLength ) { + + var face = new THREE.RenderableFace(); + _facePool.push( face ); + _facePoolLength ++; + _faceCount ++; + return face; + + } + + return _facePool[ _faceCount ++ ]; + + + } + + function getNextLineInPool() { + + if ( _lineCount === _linePoolLength ) { + + var line = new THREE.RenderableLine(); + _linePool.push( line ); + _linePoolLength ++; + _lineCount ++ + return line; + + } + + return _linePool[ _lineCount ++ ]; + + } + + function getNextSpriteInPool() { + + if ( _spriteCount === _spritePoolLength ) { + + var sprite = new THREE.RenderableSprite(); + _spritePool.push( sprite ); + _spritePoolLength ++; + _spriteCount ++ + return sprite; + + } + + return _spritePool[ _spriteCount ++ ]; + + } + + // + + function painterSort( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else if ( a.id !== b.id ) { + + return a.id - b.id; + + } else { + + return 0; + + } + + } + + function clipLine( s1, s2 ) { + + var alpha1 = 0, alpha2 = 1, + + // Calculate the boundary coordinate of each vertex for the near and far clip planes, + // Z = -1 and Z = +1, respectively. + bc1near = s1.z + s1.w, + bc2near = s2.z + s2.w, + bc1far = - s1.z + s1.w, + bc2far = - s2.z + s2.w; + + if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { + + // Both vertices lie entirely within all clip planes. + return true; + + } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { + + // Both vertices lie entirely outside one of the clip planes. + return false; + + } else { + + // The line segment spans at least one clip plane. + + if ( bc1near < 0 ) { + + // v1 lies outside the near plane, v2 inside + alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + + } else if ( bc2near < 0 ) { + + // v2 lies outside the near plane, v1 inside + alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + + } + + if ( bc1far < 0 ) { + + // v1 lies outside the far plane, v2 inside + alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + + } else if ( bc2far < 0 ) { + + // v2 lies outside the far plane, v2 inside + alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + + } + + if ( alpha2 < alpha1 ) { + + // The line segment spans two boundaries, but is outside both of them. + // (This can't happen when we're only clipping against just near/far but good + // to leave the check here for future usage if other clip planes are added.) + return false; + + } else { + + // Update the s1 and s2 vertices to match the clipped line segment. + s1.lerp( s2, alpha1 ); + s2.lerp( s1, 1 - alpha2 ); + + return true; + + } + + } + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { + + this.a = a; + this.b = b; + this.c = c; + + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : [ ]; + + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; + + this.vertexTangents = []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + +}; + +THREE.Face3.prototype = { + + constructor: THREE.Face3, + + clone: function () { + + var face = new THREE.Face3( this.a, this.b, this.c ); + + face.normal.copy( this.normal ); + face.color.copy( this.color ); + + face.materialIndex = this.materialIndex; + + var i, il; + for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); + for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); + for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + + return face; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { + + console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') + + return new THREE.Face3( a, b, c, normal, color, materialIndex ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BufferAttribute = function () {}; + +THREE.BufferAttribute.prototype = { + + constructor: THREE.BufferAttribute, + + get length () { + + return this.array.length; + + }, + + set: function ( value ) { + + this.array.set( value ); + + }, + + setX: function ( index, x ) { + + this.array[ index * this.itemSize ] = x; + + }, + + setY: function ( index, y ) { + + this.array[ index * this.itemSize + 1 ] = y; + + }, + + setZ: function ( index, z ) { + + this.array[ index * this.itemSize + 2 ] = z; + + }, + + setXY: function ( index, x, y ) { + + index *= this.itemSize; + + this.array[ index ] = x; + this.array[ index + 1 ] = y; + + }, + + setXYZ: function ( index, x, y, z ) { + + index *= this.itemSize; + + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + + }, + + setXYZW: function ( index, x, y, z, w ) { + + index *= this.itemSize; + + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; + + } + +}; + +// + +THREE.Int8Attribute = function ( size, itemSize ) { + + this.array = new Int8Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Int8Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Uint8Attribute = function ( size, itemSize ) { + + this.array = new Uint8Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Uint8Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Uint8ClampedAttribute = function ( size, itemSize ) { + + this.array = new Uint8ClampedArray( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Uint8ClampedAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Int16Attribute = function ( size, itemSize ) { + + this.array = new Int16Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Int16Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Uint16Attribute = function ( size, itemSize ) { + + this.array = new Uint16Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Uint16Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Int32Attribute = function ( size, itemSize ) { + + this.array = new Int32Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Int32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Uint32Attribute = function ( size, itemSize ) { + + this.array = new Uint32Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Uint32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Float32Attribute = function ( size, itemSize ) { + + this.array = new Float32Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Float32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + +THREE.Float64Attribute = function ( size, itemSize ) { + + this.array = new Float64Array( size * itemSize ); + this.itemSize = itemSize; + +}; + +THREE.Float64Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.BufferGeometry = function () { + + this.id = THREE.GeometryIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.attributes = {}; + this.drawcalls = []; + this.offsets = this.drawcalls; // backwards compatibility + + this.boundingBox = null; + this.boundingSphere = null; + +}; + +THREE.BufferGeometry.prototype = { + + constructor: THREE.BufferGeometry, + + addAttribute: function ( name, attribute ) { + + if ( attribute instanceof THREE.BufferAttribute === false ) { + + console.warn( 'DEPRECATED: BufferGeometry\'s addAttribute() now expects ( name, attribute ).' ); + + this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; + + return; + + } + + this.attributes[ name ] = attribute; + + }, + + getAttribute: function ( name ) { + + return this.attributes[ name ]; + + }, + + addDrawCall: function ( start, count, indexOffset ) { + + this.drawcalls.push( { + + start: start, + count: count, + index: indexOffset !== undefined ? indexOffset : 0 + + } ); + + }, + + applyMatrix: function ( matrix ) { + + var position = this.attributes.position; + + if ( position !== undefined ) { + + matrix.applyToVector3Array( position.array ); + position.needsUpdate = true; + + } + + var normal = this.attributes.normal; + + if ( normal !== undefined ) { + + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + + normalMatrix.applyToVector3Array( normal.array ); + normal.needsUpdate = true; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new THREE.Box3(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + var bb = this.boundingBox; + + if( positions.length >= 3 ) { + bb.min.x = bb.max.x = positions[ 0 ]; + bb.min.y = bb.max.y = positions[ 1 ]; + bb.min.z = bb.max.z = positions[ 2 ]; + } + + for ( var i = 3, il = positions.length; i < il; i += 3 ) { + + var x = positions[ i ]; + var y = positions[ i + 1 ]; + var z = positions[ i + 2 ]; + + // bounding box + + if ( x < bb.min.x ) { + + bb.min.x = x; + + } else if ( x > bb.max.x ) { + + bb.max.x = x; + + } + + if ( y < bb.min.y ) { + + bb.min.y = y; + + } else if ( y > bb.max.y ) { + + bb.max.y = y; + + } + + if ( z < bb.min.z ) { + + bb.min.z = z; + + } else if ( z > bb.max.z ) { + + bb.max.z = z; + + } + + } + + } + + if ( positions === undefined || positions.length === 0 ) { + + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); + + } + + }, + + computeBoundingSphere: function () { + + var box = new THREE.Box3(); + var vector = new THREE.Vector3(); + + return function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + box.makeEmpty(); + + var center = this.boundingSphere.center; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { + + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + box.addPoint( vector ); + + } + + box.center( center ); + + var maxRadiusSq = 0; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { + + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + } + + } + + }(), + + computeFaceNormals: function () { + + // backwards compatibility + + }, + + computeVertexNormals: function () { + + if ( this.attributes[ "position" ] ) { + + var i, il; + var j, jl; + + var nVertexElements = this.attributes[ "position" ].array.length; + + if ( this.attributes[ "normal" ] === undefined ) { + + this.attributes[ "normal" ] = { + + itemSize: 3, + array: new Float32Array( nVertexElements ) + + }; + + } else { + + // reset existing normals to zero + + for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { + + this.attributes[ "normal" ].array[ i ] = 0; + + } + + } + + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + + var vA, vB, vC, x, y, z, + + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), + + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); + + // indexed elements + + if ( this.attributes[ "index" ] ) { + + var indices = this.attributes[ "index" ].array; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + vA = index + indices[ i ]; + vB = index + indices[ i + 1 ]; + vC = index + indices[ i + 2 ]; + + x = positions[ vA * 3 ]; + y = positions[ vA * 3 + 1 ]; + z = positions[ vA * 3 + 2 ]; + pA.set( x, y, z ); + + x = positions[ vB * 3 ]; + y = positions[ vB * 3 + 1 ]; + z = positions[ vB * 3 + 2 ]; + pB.set( x, y, z ); + + x = positions[ vC * 3 ]; + y = positions[ vC * 3 + 1 ]; + z = positions[ vC * 3 + 2 ]; + pC.set( x, y, z ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ vA * 3 ] += cb.x; + normals[ vA * 3 + 1 ] += cb.y; + normals[ vA * 3 + 2 ] += cb.z; + + normals[ vB * 3 ] += cb.x; + normals[ vB * 3 + 1 ] += cb.y; + normals[ vB * 3 + 2 ] += cb.z; + + normals[ vC * 3 ] += cb.x; + normals[ vC * 3 + 1 ] += cb.y; + normals[ vC * 3 + 2 ] += cb.z; + + } + + } + + // non-indexed elements (unconnected triangle soup) + + } else { + + for ( i = 0, il = positions.length; i < il; i += 9 ) { + + x = positions[ i ]; + y = positions[ i + 1 ]; + z = positions[ i + 2 ]; + pA.set( x, y, z ); + + x = positions[ i + 3 ]; + y = positions[ i + 4 ]; + z = positions[ i + 5 ]; + pB.set( x, y, z ); + + x = positions[ i + 6 ]; + y = positions[ i + 7 ]; + z = positions[ i + 8 ]; + pC.set( x, y, z ); + + 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(); + + this.normalsNeedUpdate = true; + + } + + }, + + 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; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( this.attributes[ "index" ] === undefined || + this.attributes[ "position" ] === undefined || + this.attributes[ "normal" ] === undefined || + this.attributes[ "uv" ] === undefined ) { + + console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); + return; + + } + + var indices = this.attributes[ "index" ].array; + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + var uvs = this.attributes[ "uv" ].array; + + var nVertices = positions.length / 3; + + if ( this.attributes[ "tangent" ] === undefined ) { + + var nTangentElements = 4 * nVertices; + + this.attributes[ "tangent" ] = { + + itemSize: 4, + array: new Float32Array( nTangentElements ) + + }; + + } + + var tangents = this.attributes[ "tangent" ].array; + + var tan1 = [], tan2 = []; + + for ( var k = 0; k < nVertices; k ++ ) { + + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); + + } + + var xA, yA, zA, + xB, yB, zB, + xC, yC, zC, + + uA, vA, + uB, vB, + uC, vC, + + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r; + + var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + + function handleTriangle( a, b, c ) { + + xA = positions[ a * 3 ]; + yA = positions[ a * 3 + 1 ]; + zA = positions[ a * 3 + 2 ]; + + xB = positions[ b * 3 ]; + yB = positions[ b * 3 + 1 ]; + zB = positions[ b * 3 + 2 ]; + + xC = positions[ c * 3 ]; + yC = positions[ c * 3 + 1 ]; + zC = positions[ c * 3 + 2 ]; + + uA = uvs[ a * 2 ]; + vA = uvs[ a * 2 + 1 ]; + + uB = uvs[ b * 2 ]; + vB = uvs[ b * 2 + 1 ]; + + uC = uvs[ c * 2 ]; + vC = uvs[ c * 2 + 1 ]; + + x1 = xB - xA; + x2 = xC - xA; + + y1 = yB - yA; + y2 = yC - yA; + + z1 = zB - zA; + z2 = zC - zA; + + s1 = uB - uA; + s2 = uC - uA; + + t1 = vB - vA; + t2 = vC - vA; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + var i, il; + var j, jl; + var iA, iB, iC; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleTriangle( iA, iB, iC ); + + } + + } + + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; + + function handleVertex( v ) { + + n.x = normals[ v * 3 ]; + n.y = normals[ v * 3 + 1 ]; + n.z = normals[ v * 3 + 2 ]; + + n2.copy( n ); + + t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? -1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; + + } + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleVertex( iA ); + handleVertex( iB ); + handleVertex( iC ); + + } + + } + + }, + + /* + computeOffsets + Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. + This method will effectively rewrite the index buffer and remap all attributes to match the new indices. + WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. + indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks. + */ + computeOffsets: function(indexBufferSize) { + + var size = indexBufferSize; + if(indexBufferSize === undefined) + size = 65535; //WebGL limits type of index buffer values to 16-bit. + + var s = Date.now(); + + var indices = this.attributes['index'].array; + var vertices = this.attributes['position'].array; + + var verticesCount = (vertices.length/3); + var facesCount = (indices.length/3); + + /* + console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); + console.log("Faces to process: "+(indices.length/3)); + console.log("Reordering "+verticesCount+" vertices."); + */ + + var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers + var indexPtr = 0; + var vertexPtr = 0; + + var offsets = [ { start:0, count:0, index:0 } ]; + var offset = offsets[0]; + + var duplicatedVertices = 0; + var newVerticeMaps = 0; + var faceVertices = new Int32Array(6); + var vertexMap = new Int32Array( vertices.length ); + var revVertexMap = new Int32Array( vertices.length ); + for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; } + + /* + Traverse every face and reorder vertices in the proper offsets of 65k. + We can have more than 65k entries in the index buffer per offset, but only reference 65k values. + */ + for(var findex = 0; findex < facesCount; findex++) { + newVerticeMaps = 0; + + for(var vo = 0; vo < 3; vo++) { + var vid = indices[ findex*3 + vo ]; + if(vertexMap[vid] == -1) { + //Unmapped vertice + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = -1; + newVerticeMaps++; + } else if(vertexMap[vid] < offset.index) { + //Reused vertices from previous block (duplicate) + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = -1; + duplicatedVertices++; + } else { + //Reused vertice in the current block + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = vertexMap[vid]; + } + } + + var faceMax = vertexPtr + newVerticeMaps; + if(faceMax > (offset.index + size)) { + var new_offset = { start:indexPtr, count:0, index:vertexPtr }; + offsets.push(new_offset); + offset = new_offset; + + //Re-evaluate reused vertices in light of new offset. + for(var v = 0; v < 6; v+=2) { + var new_vid = faceVertices[v+1]; + if(new_vid > -1 && new_vid < offset.index) + faceVertices[v+1] = -1; + } + } + + //Reindex the face. + for(var v = 0; v < 6; v+=2) { + var vid = faceVertices[v]; + var new_vid = faceVertices[v+1]; + + if(new_vid === -1) + new_vid = vertexPtr++; + + vertexMap[vid] = new_vid; + revVertexMap[new_vid] = vid; + sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit + offset.count++; + } + } + + /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ + this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr); + this.offsets = offsets; + + /* + var orderTime = Date.now(); + console.log("Reorder time: "+(orderTime-s)+"ms"); + console.log("Duplicated "+duplicatedVertices+" vertices."); + console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); + console.log("Draw offsets: "+offsets.length); + */ + + return offsets; + }, + + /* + reoderBuffers: + Reorder attributes based on a new indexBuffer and indexMap. + indexBuffer - Uint16Array of the new ordered indices. + indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. + vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). + */ + reorderBuffers: function(indexBuffer, indexMap, vertexCount) { + + /* Create a copy of all attributes for reordering. */ + var sortedAttributes = {}; + var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + for( var attr in this.attributes ) { + if(attr == 'index') + continue; + var sourceArray = this.attributes[attr].array; + for ( var i = 0, il = types.length; i < il; i++ ) { + var type = types[i]; + if (sourceArray instanceof type) { + sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount ); + break; + } + } + } + + /* Move attribute positions based on the new index map */ + for(var new_vid = 0; new_vid < vertexCount; new_vid++) { + var vid = indexMap[new_vid]; + for ( var attr in this.attributes ) { + if(attr == 'index') + continue; + var attrArray = this.attributes[attr].array; + var attrSize = this.attributes[attr].itemSize; + var sortedAttr = sortedAttributes[attr]; + for(var k = 0; k < attrSize; k++) + sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; + } + } + + /* Carry the new sorted buffers locally */ + this.attributes['index'].array = indexBuffer; + for ( var attr in this.attributes ) { + if(attr == 'index') + continue; + this.attributes[attr].array = sortedAttributes[attr]; + this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount; + } + }, + + clone: function () { + + var geometry = new THREE.BufferGeometry(); + + var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + + for ( var attr in this.attributes ) { + + var sourceAttr = this.attributes[ attr ]; + var sourceArray = sourceAttr.array; + + var attribute = { + + itemSize: sourceAttr.itemSize, + array: null + + }; + + for ( var i = 0, il = types.length; i < il; i ++ ) { + + var type = types[ i ]; + + if ( sourceArray instanceof type ) { + + attribute.array = new type( sourceArray ); + break; + + } + + } + + geometry.attributes[ attr ] = attribute; + + } + + for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { + + var offset = this.offsets[ i ]; + + geometry.offsets.push( { + + start: offset.start, + index: offset.index, + count: offset.count + + } ); + + } + + return geometry; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BufferGeometryManipulator = function ( bufferGeometry ) { + + this.vertices = []; + this.normals = []; + this.uvs = []; + + var attributes = bufferGeometry.attributes; + var length = attributes.position.array.length / 3; + + for ( var i = 0; i < length; i ++ ) { + + this.vertices.push( new THREE.TypedVector3( attributes.position.array, i * 3 ) ); + this.normals.push( new THREE.TypedVector3( attributes.normal.array, i * 3 ) ); + this.uvs.push( new THREE.TypedVector2( attributes.uv.array, i * 2 ) ); + + } + +}; +/** + * @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://exocortex.com + */ + +THREE.Geometry = function () { + + this.id = THREE.GeometryIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.vertices = []; + this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line + + this.faces = []; + + this.faceVertexUvs = [[]]; + + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; + + this.skinWeights = []; + this.skinIndices = []; + + this.lineDistances = []; + + this.boundingBox = null; + this.boundingSphere = null; + + this.hasTangents = false; + + this.dynamic = true; // the intermediate typed arrays will be deleted when set to false + + // update flags + + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.tangentsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + + this.buffersNeedUpdate = false; + +}; + +THREE.Geometry.prototype = { + + constructor: THREE.Geometry, + + applyMatrix: function ( matrix ) { + + var normalMatrix = new THREE.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 instanceof THREE.Box3 ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere instanceof THREE.Sphere ) { + + this.computeBoundingSphere(); + + } + + }, + + computeFaceNormals: function () { + + var cb = new THREE.Vector3(), ab = new THREE.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 ) { + + 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 THREE.Vector3(); + + } + + if ( areaWeighted ) { + + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm + + var vA, vB, vC, vD; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(), + db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.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 { + + 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 ]; + + face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); + face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); + face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); + + } + + }, + + 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 THREE.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 ++ ) { + + face = this.faces[ f ]; + + faceNormal = new THREE.Vector3(); + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.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; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // tangents go to vertices + + var f, fl, v, vl, i, il, vertexIndex, + face, uv, vA, vB, vC, uvA, uvB, uvC, + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r, t, test, + tan1 = [], tan2 = [], + sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), + tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), + n = new THREE.Vector3(), w; + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + tan1[ v ] = new THREE.Vector3(); + tan2[ v ] = new THREE.Vector3(); + + } + + function handleTriangle( context, a, b, c, ua, ub, uc ) { + + vA = context.vertices[ a ]; + vB = context.vertices[ b ]; + vC = context.vertices[ c ]; + + uvA = uv[ ua ]; + uvB = uv[ ub ]; + uvC = uv[ uc ]; + + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; + + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + sdir.set( ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r ); + tdir.set( ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents + + handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); + + } + + var faceIndex = [ 'a', 'b', 'c', 'd' ]; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { + + n.copy( face.vertexNormals[ i ] ); + + vertexIndex = face[ faceIndex[ i ] ]; + + t = tan1[ vertexIndex ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( face.vertexNormals[ i ], t ); + test = tmp2.dot( tan2[ vertexIndex ] ); + w = (test < 0.0) ? -1.0 : 1.0; + + face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); + + } + + } + + this.hasTangents = true; + + }, + + 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 THREE.Box3(); + + } + + this.boundingBox.setFromPoints( this.vertices ); + + }, + + computeBoundingSphere: function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + this.boundingSphere.setFromPoints( this.vertices ); + + }, + + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ + + mergeVertices: function () { + + var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) + var unique = [], changes = []; + + var v, key; + var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i,il, face; + var indices, k, j, jl, u; + + 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 ]; + + var dupIndex = -1; + + // 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 ] ) { + + dupIndex = n; + 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; + + }, + + // Geometry splitting + + makeGroups: ( function () { + + var geometryGroupCounter = 0; + + return function ( usesFaceMaterial, maxVerticesInGroup ) { + + var f, fl, face, materialIndex, + groupHash, hash_map = {}; + + var numMorphTargets = this.morphTargets.length; + var numMorphNormals = this.morphNormals.length; + + this.geometryGroups = {}; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + materialIndex = usesFaceMaterial ? face.materialIndex : 0; + + if ( ! ( materialIndex in hash_map ) ) { + + hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; + + } + + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( ! ( groupHash in this.geometryGroups ) ) { + + this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + if ( this.geometryGroups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { + + hash_map[ materialIndex ].counter += 1; + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( ! ( groupHash in this.geometryGroups ) ) { + + this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + } + + this.geometryGroups[ groupHash ].faces3.push( f ); + this.geometryGroups[ groupHash ].vertices += 3; + + } + + this.geometryGroupsList = []; + + for ( var g in this.geometryGroups ) { + + this.geometryGroups[ g ].id = geometryGroupCounter ++; + + this.geometryGroupsList.push( this.geometryGroups[ g ] ); + + } + + }; + + } )(), + + clone: function () { + + var geometry = new THREE.Geometry(); + + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + geometry.vertices.push( vertices[ i ].clone() ); + + } + + var faces = this.faces; + + for ( var i = 0, il = faces.length; i < il; i ++ ) { + + geometry.faces.push( faces[ i ].clone() ); + + } + + var uvs = this.faceVertexUvs[ 0 ]; + + for ( var i = 0, il = uvs.length; i < il; i ++ ) { + + var uv = uvs[ i ], uvCopy = []; + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + geometry.faceVertexUvs[ 0 ].push( uvCopy ); + + } + + return geometry; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); + +THREE.GeometryIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Geometry2 = function ( vertices, normals, uvs ) { + + THREE.BufferGeometry.call( this ); + + this.attributes[ 'position' ] = { array: vertices, itemSize: 3 }; + this.attributes[ 'normal' ] = { array: normals, itemSize: 3 }; + this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 }; + +}; + +THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.IndexedGeometry2 = function ( indices, vertices, normals, uvs ) { + + THREE.BufferGeometry.call( this ); + + this.attributes[ 'index' ] = { array: indices, itemSize: 1 }; + this.attributes[ 'position' ] = { array: vertices, itemSize: 3 }; + this.attributes[ 'normal' ] = { array: normals, itemSize: 3 }; + this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 }; + +}; + +THREE.IndexedGeometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.Camera = function () { + + THREE.Object3D.call( this ); + + this.matrixWorldInverse = new THREE.Matrix4(); + this.projectionMatrix = new THREE.Matrix4(); + +}; + +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Camera.prototype.lookAt = function () { + + // This routine does not support cameras with rotated and/or translated parent(s) + + var m1 = new THREE.Matrix4(); + + return function ( vector ) { + + m1.lookAt( this.position, vector, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + +}(); + +THREE.Camera.prototype.clone = function (camera) { + + if ( camera === undefined ) camera = new THREE.Camera(); + + THREE.Object3D.prototype.clone.call( this, camera ); + + camera.matrixWorldInverse.copy( this.matrixWorldInverse ); + camera.projectionMatrix.copy( this.projectionMatrix ); + + return camera; +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { + + THREE.Camera.call( this ); + + 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(); + +}; + +THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { + + this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + +}; + +THREE.OrthographicCamera.prototype.clone = function () { + + var camera = new THREE.OrthographicCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); + + camera.left = this.left; + camera.right = this.right; + camera.top = this.top; + camera.bottom = this.bottom; + + camera.near = this.near; + camera.far = this.far; + + return camera; +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { + + THREE.Camera.call( this ); + + this.fov = fov !== undefined ? fov : 50; + this.aspect = aspect !== undefined ? aspect : 1; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + + this.updateProjectionMatrix(); + +}; + +THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); + + +/** + * Uses Focal Length (in mm) to estimate and set FOV + * 35mm (fullframe) camera is used if frame size is not specified; + * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html + */ + +THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); + +} + + +/** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * var w = 1920; + * var h = 1080; + * var fullWidth = w * 3; + * var fullHeight = h * 2; + * + * --A-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ + +THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { + + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + this.updateProjectionMatrix(); + +}; + + +THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { + + if ( this.fullWidth ) { + + var aspect = this.fullWidth / this.fullHeight; + var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; + var bottom = -top; + var left = aspect * bottom; + var right = aspect * top; + var width = Math.abs( right - left ); + var height = Math.abs( top - bottom ); + + this.projectionMatrix.makeFrustum( + left + this.x * width / this.fullWidth, + left + ( this.x + this.width ) * width / this.fullWidth, + top - ( this.y + this.height ) * height / this.fullHeight, + top - this.y * height / this.fullHeight, + this.near, + this.far + ); + + } else { + + this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); + + } + +}; + +THREE.PerspectiveCamera.prototype.clone = function () { + + var camera = new THREE.PerspectiveCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); + + camera.fov = this.fov; + camera.aspect = this.aspect; + camera.near = this.near; + camera.far = this.far; + + return camera; +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Light = function ( color ) { + + THREE.Object3D.call( this ); + + this.color = new THREE.Color( color ); + +}; + +THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Light.prototype.clone = function ( light ) { + + if ( light === undefined ) light = new THREE.Light(); + + THREE.Object3D.prototype.clone.call( this, light ); + + light.color.copy( this.color ); + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AmbientLight = function ( color ) { + + THREE.Light.call( this, color ); + +}; + +THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.AmbientLight.prototype.clone = function () { + + var light = new THREE.AmbientLight(); + + THREE.Light.prototype.clone.call( this, light ); + + return light; + +}; + +/** + * @author MPanknin / http://www.redplant.de/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.AreaLight = function ( color, intensity ) { + + THREE.Light.call( this, color ); + + this.normal = new THREE.Vector3( 0, -1, 0 ); + this.right = new THREE.Vector3( 1, 0, 0 ); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + + this.width = 1.0; + this.height = 1.0; + + this.constantAttenuation = 1.5; + this.linearAttenuation = 0.5; + this.quadraticAttenuation = 0.1; + +}; + +THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); + + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DirectionalLight = function ( color, intensity ) { + + THREE.Light.call( this, color ); + + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + + this.shadowCameraLeft = -500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = -500; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowCascade = false; + + this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); + this.shadowCascadeCount = 2; + + this.shadowCascadeBias = [ 0, 0, 0 ]; + this.shadowCascadeWidth = [ 512, 512, 512 ]; + this.shadowCascadeHeight = [ 512, 512, 512 ]; + + this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + + this.shadowCascadeArray = []; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.DirectionalLight.prototype.clone = function () { + + var light = new THREE.DirectionalLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; + + // + + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; + + light.shadowCameraLeft = this.shadowCameraLeft; + light.shadowCameraRight = this.shadowCameraRight; + light.shadowCameraTop = this.shadowCameraTop; + light.shadowCameraBottom = this.shadowCameraBottom; + + light.shadowCameraVisible = this.shadowCameraVisible; + + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; + + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; + + // + + light.shadowCascade = this.shadowCascade; + + light.shadowCascadeOffset.copy( this.shadowCascadeOffset ); + light.shadowCascadeCount = this.shadowCascadeCount; + + light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 ); + light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 ); + light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 ); + + light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 ); + light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 ); + + return light; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { + + THREE.Light.call( this, skyColor ); + + this.position.set( 0, 100, 0 ); + + this.groundColor = new THREE.Color( groundColor ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; + +}; + +THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.HemisphereLight.prototype.clone = function () { + + var light = new THREE.HemisphereLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.groundColor.copy( this.groundColor ); + light.intensity = this.intensity; + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.PointLight = function ( color, intensity, distance ) { + + THREE.Light.call( this, color ); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + +}; + +THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.PointLight.prototype.clone = function () { + + var light = new THREE.PointLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.intensity = this.intensity; + light.distance = this.distance; + + return light; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { + + THREE.Light.call( this, color ); + + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.exponent = ( exponent !== undefined ) ? exponent : 10; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.SpotLight.prototype.clone = function () { + + var light = new THREE.SpotLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + light.distance = this.distance; + light.angle = this.angle; + light.exponent = this.exponent; + + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; + + // + + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; + light.shadowCameraFov = this.shadowCameraFov; + + light.shadowCameraVisible = this.shadowCameraVisible; + + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; + + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Cache = function () { + + this.files = {}; + +}; + +THREE.Cache.prototype = { + + constructor: THREE.Cache, + + add: function ( key, file ) { + + // console.log( 'THREE.Cache', 'Adding key:', key ); + + this.files[ key ] = file; + + }, + + get: function ( key ) { + + // console.log( 'THREE.Cache', 'Checking key:', key ); + + return this.files[ key ]; + + }, + + remove: function ( key ) { + + delete this.files[ key ]; + + }, + + clear: function () { + + this.files = {} + + } + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Loader = function ( showStatus ) { + + this.showStatus = showStatus; + this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + + this.imageLoader = new THREE.ImageLoader(); + + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; + +}; + +THREE.Loader.prototype = { + + constructor: THREE.Loader, + + crossOrigin: undefined, + + addStatusElement: function () { + + var e = document.createElement( "div" ); + + e.style.position = "absolute"; + e.style.right = "0px"; + e.style.top = "0px"; + e.style.fontSize = "0.8em"; + e.style.textAlign = "left"; + e.style.background = "rgba(0,0,0,0.25)"; + e.style.color = "#fff"; + e.style.width = "120px"; + e.style.padding = "0.5em 0.5em 0.5em 0.5em"; + e.style.zIndex = 1000; + + e.innerHTML = "Loading ..."; + + return e; + + }, + + updateProgress: function ( progress ) { + + var message = "Loaded "; + + if ( progress.total ) { + + message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; + + + } else { + + message += ( progress.loaded / 1024 ).toFixed(2) + " KB"; + + } + + this.statusDomElement.innerHTML = message; + + }, + + extractUrlBase: function ( url ) { + + var parts = url.split( '/' ); + + if ( parts.length === 1 ) return './'; + + parts.pop(); + + return parts.join( '/' ) + '/'; + + }, + + initMaterials: function ( materials, texturePath ) { + + var array = []; + + for ( var i = 0; i < materials.length; ++ i ) { + + array[ i ] = this.createMaterial( materials[ i ], texturePath ); + + } + + return array; + + }, + + needsTangents: function ( materials ) { + + for( var i = 0, il = materials.length; i < il; i ++ ) { + + var m = materials[ i ]; + + if ( m instanceof THREE.ShaderMaterial ) return true; + + } + + return false; + + }, + + createMaterial: function ( m, texturePath ) { + + var scope = this; + + function nearest_pow2( n ) { + + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); + + } + + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { + + var isCompressed = /\.dds$/i.test( sourceFile ); + + var fullPath = texturePath + sourceFile; + + if ( isCompressed ) { + + var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); + + where[ name ] = texture; + + } else { + + var texture = document.createElement( 'canvas' ); + + where[ name ] = new THREE.Texture( texture ); + + } + + where[ name ].sourceFile = sourceFile; + + if( repeat ) { + + where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); + + if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; + + } + + if ( offset ) { + + where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); + + } + + if ( wrap ) { + + var wrapMap = { + "repeat": THREE.RepeatWrapping, + "mirror": THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; + + } + + if ( anisotropy ) { + + where[ name ].anisotropy = anisotropy; + + } + + if ( ! isCompressed ) { + + var texture = where[ name ]; + + scope.imageLoader.crossOrigin = scope.crossOrigin; + scope.imageLoader.load( fullPath, function ( image ) { + + if ( THREE.Math.isPowerOfTwo( image.width ) === false || + THREE.Math.isPowerOfTwo( image.height ) === false ) { + + var width = nearest_pow2( image.width ); + var height = nearest_pow2( image.height ); + + texture.image.width = width; + texture.image.height = height; + texture.image.getContext( '2d' ).drawImage( image, 0, 0, width, height ); + + } else { + + texture.image = image; + + } + + texture.needsUpdate = true; + + } ); + + } + + } + + function rgb2hex( rgb ) { + + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; + + } + + // defaults + + var mtype = "MeshLambertMaterial"; + var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; + + // parameters from model file + + if ( m.shading ) { + + var shading = m.shading.toLowerCase(); + + if ( shading === "phong" ) mtype = "MeshPhongMaterial"; + else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + + } + + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { + + mpars.blending = THREE[ m.blending ]; + + } + + if ( m.transparent !== undefined || m.opacity < 1.0 ) { + + mpars.transparent = m.transparent; + + } + + if ( m.depthTest !== undefined ) { + + mpars.depthTest = m.depthTest; + + } + + if ( m.depthWrite !== undefined ) { + + mpars.depthWrite = m.depthWrite; + + } + + if ( m.visible !== undefined ) { + + mpars.visible = m.visible; + + } + + if ( m.flipSided !== undefined ) { + + mpars.side = THREE.BackSide; + + } + + if ( m.doubleSided !== undefined ) { + + mpars.side = THREE.DoubleSide; + + } + + if ( m.wireframe !== undefined ) { + + mpars.wireframe = m.wireframe; + + } + + if ( m.vertexColors !== undefined ) { + + if ( m.vertexColors === "face" ) { + + mpars.vertexColors = THREE.FaceColors; + + } else if ( m.vertexColors ) { + + mpars.vertexColors = THREE.VertexColors; + + } + + } + + // colors + + if ( m.colorDiffuse ) { + + mpars.color = rgb2hex( m.colorDiffuse ); + + } else if ( m.DbgColor ) { + + mpars.color = m.DbgColor; + + } + + if ( m.colorSpecular ) { + + mpars.specular = rgb2hex( m.colorSpecular ); + + } + + if ( m.colorAmbient ) { + + mpars.ambient = rgb2hex( m.colorAmbient ); + + } + + // modifiers + + if ( m.transparency ) { + + mpars.opacity = m.transparency; + + } + + if ( m.specularCoef ) { + + mpars.shininess = m.specularCoef; + + } + + // textures + + if ( m.mapDiffuse && texturePath ) { + + create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + + } + + if ( m.mapLight && texturePath ) { + + create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + + } + + if ( m.mapBump && texturePath ) { + + create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + + } + + if ( m.mapNormal && texturePath ) { + + create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + + } + + if ( m.mapSpecular && texturePath ) { + + create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + + } + + // + + if ( m.mapBumpScale ) { + + mpars.bumpScale = m.mapBumpScale; + + } + + // special case for normal mapped material + + if ( m.mapNormal ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + uniforms[ "tNormal" ].value = mpars.normalMap; + + if ( m.mapNormalFactor ) { + + uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); + + } + + if ( mpars.map ) { + + uniforms[ "tDiffuse" ].value = mpars.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( mpars.specularMap ) { + + uniforms[ "tSpecular" ].value = mpars.specularMap; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( mpars.lightMap ) { + + uniforms[ "tAO" ].value = mpars.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + // for the moment don't handle displacement texture + + uniforms[ "diffuse" ].value.setHex( mpars.color ); + uniforms[ "specular" ].value.setHex( mpars.specular ); + uniforms[ "ambient" ].value.setHex( mpars.ambient ); + + uniforms[ "shininess" ].value = mpars.shininess; + + if ( mpars.opacity !== undefined ) { + + uniforms[ "opacity" ].value = mpars.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + var material = new THREE.ShaderMaterial( parameters ); + + if ( mpars.transparent ) { + + material.transparent = true; + + } + + } else { + + var material = new THREE[ mtype ]( mpars ); + + } + + if ( m.DbgName !== undefined ) material.name = m.DbgName; + + return material; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.XHRLoader = function ( manager ) { + + this.cache = new THREE.Cache(); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.XHRLoader.prototype = { + + constructor: THREE.XHRLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var cached = scope.cache.get( url ); + + if ( cached !== undefined ) { + + onLoad( cached ); + return; + + } + + var request = new XMLHttpRequest(); + + if ( onLoad !== undefined ) { + + request.addEventListener( 'load', function ( event ) { + + scope.cache.add( url, event.target.responseText ); + + onLoad( event.target.responseText ); + scope.manager.itemEnd( url ); + + }, false ); + + } + + if ( onProgress !== undefined ) { + + request.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + if ( onError !== undefined ) { + + request.addEventListener( 'error', function ( event ) { + + onError( event ); + + }, false ); + + } + + if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + + request.open( 'GET', url, true ); + request.send( null ); + + scope.manager.itemStart( url ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageLoader = function ( manager ) { + + this.cache = new THREE.Cache(); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ImageLoader.prototype = { + + constructor: THREE.ImageLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var cached = scope.cache.get( url ); + + if ( cached !== undefined ) { + + onLoad( cached ); + return; + + } + + var image = document.createElement( 'img' ); + + if ( onLoad !== undefined ) { + + image.addEventListener( 'load', function ( event ) { + + scope.cache.add( url, this ); + + onLoad( this ); + scope.manager.itemEnd( url ); + + }, false ); + + } + + if ( onProgress !== undefined ) { + + image.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + if ( onError !== undefined ) { + + image.addEventListener( 'error', function ( event ) { + + onError( event ); + + }, false ); + + } + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + image.src = url; + + scope.manager.itemStart( url ); + + return image; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.JSONLoader = function ( showStatus ) { + + THREE.Loader.call( this, showStatus ); + + this.withCredentials = false; + +}; + +THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); + +THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { + + var scope = this; + + // todo: unify load API to for easier SceneLoader use + + texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); + + this.onLoadStart(); + this.loadAjaxJSON( this, url, callback, texturePath ); + +}; + +THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { + + var xhr = new XMLHttpRequest(); + + var length = 0; + + xhr.onreadystatechange = function () { + + if ( xhr.readyState === xhr.DONE ) { + + if ( xhr.status === 200 || xhr.status === 0 ) { + + if ( xhr.responseText ) { + + var json = JSON.parse( xhr.responseText ); + + if ( json.metadata !== undefined && json.metadata.type === 'scene' ) { + + console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; + + } + + var result = context.parse( json, texturePath ); + callback( result.geometry, result.materials ); + + } else { + + console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); + + } + + // in context of more complex asset initialization + // do not block on single failed file + // maybe should go even one more level up + + context.onLoadComplete(); + + } else { + + console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + + } + + } else if ( xhr.readyState === xhr.LOADING ) { + + if ( callbackProgress ) { + + if ( length === 0 ) { + + length = xhr.getResponseHeader( 'Content-Length' ); + + } + + callbackProgress( { total: length, loaded: xhr.responseText.length } ); + + } + + } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { + + if ( callbackProgress !== undefined ) { + + length = xhr.getResponseHeader( "Content-Length" ); + + } + + } + + }; + + xhr.open( "GET", url, true ); + xhr.withCredentials = this.withCredentials; + xhr.send( null ); + +}; + +THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { + + var scope = this, + geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); + + parseSkin(); + parseMorphing( scale ); + + 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, color, 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 THREE.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 THREE.Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; + + faceB = new THREE.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 THREE.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 THREE.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 THREE.Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); + + } + + } + + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); + + } else { + + face = new THREE.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 THREE.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 THREE.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 THREE.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 THREE.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 THREE.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.' ); + + } + + + // could change this to json.animations[0] or remove completely + + geometry.animation = json.animation; + geometry.animations = json.animations; + + }; + + function parseMorphing( scale ) { + + if ( json.morphTargets !== undefined ) { + + var i, l, v, vl, dstVertices, srcVertices; + + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; + + dstVertices = geometry.morphTargets[ i ].vertices; + srcVertices = json.morphTargets [ i ].vertices; + + for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + + var vertex = new THREE.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 ) { + + var i, l, c, cl, dstColors, srcColors, color; + + for ( i = 0, l = json.morphColors.length; i < l; i++ ) { + + geometry.morphColors[ i ] = {}; + geometry.morphColors[ i ].name = json.morphColors[ i ].name; + geometry.morphColors[ i ].colors = []; + + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors [ i ].colors; + + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); + + } + + } + + } + + }; + + if ( json.materials === undefined || json.materials.length === 0 ) { + + return { geometry: geometry }; + + } else { + + var materials = this.initMaterials( json.materials, texturePath ); + + if ( this.needsTangents( materials ) ) { + + geometry.computeTangents(); + + } + + return { geometry: geometry, materials: materials }; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LoadingManager = function ( onLoad, onProgress, onError ) { + + var scope = this; + + var loaded = 0, total = 0; + + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; + + this.itemStart = function ( url ) { + + total ++; + + }; + + this.itemEnd = function ( url ) { + + loaded ++; + + if ( scope.onProgress !== undefined ) { + + scope.onProgress( url, loaded, total ); + + } + + if ( loaded === total && scope.onLoad !== undefined ) { + + scope.onLoad(); + + } + + }; + +}; + +THREE.DefaultLoadingManager = new THREE.LoadingManager(); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BufferGeometryLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.BufferGeometryLoader.prototype = { + + constructor: THREE.BufferGeometryLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader(); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometry = new THREE.BufferGeometry(); + + var attributes = json.attributes; + var offsets = json.offsets; + var boundingSphere = json.boundingSphere; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + + geometry.attributes[ key ] = { + itemSize: attribute.itemSize, + array: new self[ attribute.type ]( attribute.array ) + } + + } + + if ( offsets !== undefined ) { + + geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); + + } + + if ( boundingSphere !== undefined ) { + + geometry.boundingSphere = new THREE.Sphere( + new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), + boundingSphere.radius + ); + + } + + return geometry; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MaterialLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.MaterialLoader.prototype = { + + constructor: THREE.MaterialLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader(); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var material = new THREE[ json.type ]; + + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); + 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.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + 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.wireframe !== undefined ) material.wireframe = json.wireframe; + + 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/ + */ + +THREE.ObjectLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ObjectLoader.prototype = { + + constructor: THREE.ObjectLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometries = this.parseGeometries( json.geometries ); + var materials = this.parseMaterials( json.materials ); + var object = this.parseObject( json.object, geometries, materials ); + + return object; + + }, + + parseGeometries: function ( json ) { + + var geometries = {}; + + if ( json !== undefined ) { + + var geometryLoader = new THREE.JSONLoader(); + var bufferGeometryLoader = new THREE.BufferGeometryLoader(); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var geometry; + var data = json[ i ]; + + switch ( data.type ) { + + case 'PlaneGeometry': + + geometry = new THREE.PlaneGeometry( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); + + break; + + case 'BoxGeometry': + case 'CubeGeometry': // DEPRECATED + + geometry = new THREE.BoxGeometry( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); + + break; + + case 'CircleGeometry': + + geometry = new THREE.CircleGeometry( + data.radius, + data.segments + ); + + break; + + case 'CylinderGeometry': + + geometry = new THREE.CylinderGeometry( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded + ); + + break; + + case 'SphereGeometry': + + geometry = new THREE.SphereGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'IcosahedronGeometry': + + geometry = new THREE.IcosahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'TorusGeometry': + + geometry = new THREE.TorusGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); + + break; + + case 'TorusKnotGeometry': + + geometry = new THREE.TorusKnotGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.p, + data.q, + data.heightScale + ); + + break; + + case 'BufferGeometry': + + geometry = bufferGeometryLoader.parse( data.data ); + + break; + + case 'Geometry': + + geometry = geometryLoader.parse( data.data ).geometry; + + break; + + } + + geometry.uuid = data.uuid; + + if ( data.name !== undefined ) geometry.name = data.name; + + geometries[ data.uuid ] = geometry; + + } + + } + + return geometries; + + }, + + parseMaterials: function ( json ) { + + var materials = {}; + + if ( json !== undefined ) { + + var loader = new THREE.MaterialLoader(); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + var material = loader.parse( data ); + + material.uuid = data.uuid; + + if ( data.name !== undefined ) material.name = data.name; + + materials[ data.uuid ] = material; + + } + + } + + return materials; + + }, + + parseObject: function () { + + var matrix = new THREE.Matrix4(); + + return function ( data, geometries, materials ) { + + var object; + + switch ( data.type ) { + + case 'Scene': + + object = new THREE.Scene(); + + break; + + case 'PerspectiveCamera': + + object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + + break; + + case 'OrthographicCamera': + + object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + + break; + + case 'AmbientLight': + + object = new THREE.AmbientLight( data.color ); + + break; + + case 'DirectionalLight': + + object = new THREE.DirectionalLight( data.color, data.intensity ); + + break; + + case 'PointLight': + + object = new THREE.PointLight( data.color, data.intensity, data.distance ); + + break; + + case 'SpotLight': + + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent ); + + break; + + case 'HemisphereLight': + + object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); + + break; + + case 'Mesh': + + var geometry = geometries[ data.geometry ]; + var material = materials[ data.material ]; + + if ( geometry === undefined ) { + + console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); + + } + + if ( material === undefined ) { + + console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + + } + + object = new THREE.Mesh( geometry, material ); + + break; + + case 'Sprite': + + var material = materials[ data.material ]; + + if ( material === undefined ) { + + console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + + } + + object = new THREE.Sprite( material ); + + break; + + default: + + object = new THREE.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.scale !== undefined ) object.scale.fromArray( data.scale ); + + } + + 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 ) ); + + } + + } + + return object; + + } + + }() + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneLoader = function () { + + this.onLoadStart = function () {}; + this.onLoadProgress = function() {}; + this.onLoadComplete = function () {}; + + this.callbackSync = function () {}; + this.callbackProgress = function () {}; + + this.geometryHandlers = {}; + this.hierarchyHandlers = {}; + + this.addGeometryHandler( "ascii", THREE.JSONLoader ); + +}; + +THREE.SceneLoader.prototype = { + + constructor: THREE.SceneLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + scope.parse( JSON.parse( text ), onLoad, url ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + addGeometryHandler: function ( typeID, loaderClass ) { + + this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; + + }, + + addHierarchyHandler: function ( typeID, loaderClass ) { + + this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; + + }, + + parse: function ( json, callbackFinished, url ) { + + var scope = this; + + var urlBase = THREE.Loader.prototype.extractUrlBase( url ); + + var geometry, material, camera, fog, + texture, images, color, + light, hex, intensity, + counter_models, counter_textures, + total_models, total_textures, + result; + + var target_array = []; + + var data = json; + + // async geometry loaders + + for ( var typeID in this.geometryHandlers ) { + + var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; + this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + // async hierachy loaders + + for ( var typeID in this.hierarchyHandlers ) { + + var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; + this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + counter_models = 0; + counter_textures = 0; + + result = { + + scene: new THREE.Scene(), + geometries: {}, + face_materials: {}, + materials: {}, + textures: {}, + objects: {}, + cameras: {}, + lights: {}, + fogs: {}, + empties: {}, + groups: {} + + }; + + if ( data.transform ) { + + var position = data.transform.position, + rotation = data.transform.rotation, + scale = data.transform.scale; + + if ( position ) { + + result.scene.position.fromArray( position ); + + } + + if ( rotation ) { + + result.scene.rotation.fromArray( rotation ); + + } + + if ( scale ) { + + result.scene.scale.fromArray( scale ); + + } + + if ( position || rotation || scale ) { + + result.scene.updateMatrix(); + result.scene.updateMatrixWorld(); + + } + + } + + function get_url( source_url, url_type ) { + + if ( url_type == "relativeToHTML" ) { + + return source_url; + + } else { + + return urlBase + source_url; + + } + + }; + + // toplevel loader function, delegates to handle_children + + function handle_objects() { + + handle_children( result.scene, data.objects ); + + } + + // handle all the children from the loaded json and attach them to given parent + + function handle_children( parent, children ) { + + var mat, dst, pos, rot, scl, quat; + + for ( var objID in children ) { + + // check by id if child has already been handled, + // if not, create new object + + var object = result.objects[ objID ]; + var objJSON = children[ objID ]; + + if ( object === undefined ) { + + // meshes + + if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + + if ( objJSON.loading === undefined ) { + + var reservedTypes = { + "type": 1, "url": 1, "material": 1, + "position": 1, "rotation": 1, "scale" : 1, + "visible": 1, "children": 1, "userData": 1, + "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 + }; + + var loaderParameters = {}; + + for ( var parType in objJSON ) { + + if ( ! ( parType in reservedTypes ) ) { + + loaderParameters[ parType ] = objJSON[ parType ]; + + } + + } + + material = result.materials[ objJSON.material ]; + + objJSON.loading = true; + + var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; + + // ColladaLoader + + if ( loader.options ) { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); + + // UTF8Loader + // OBJLoader + + } else { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); + + } + + } + + } else if ( objJSON.geometry !== undefined ) { + + geometry = result.geometries[ objJSON.geometry ]; + + // geometry already loaded + + if ( geometry ) { + + var needsTangents = false; + + material = result.materials[ objJSON.material ]; + needsTangents = material instanceof THREE.ShaderMaterial; + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + mat = objJSON.matrix; + quat = objJSON.quaternion; + + // use materials from the model file + // if there is no material specified in the object + + if ( ! objJSON.material ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + // use materials from the model file + // if there is just empty face material + // (must create new material as each model has its own face material) + + if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + if ( material instanceof THREE.MeshFaceMaterial ) { + + for ( var i = 0; i < material.materials.length; i ++ ) { + + needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); + + } + + } + + if ( needsTangents ) { + + geometry.computeTangents(); + + } + + if ( objJSON.skin ) { + + object = new THREE.SkinnedMesh( geometry, material ); + + } else if ( objJSON.morph ) { + + object = new THREE.MorphAnimMesh( geometry, material ); + + if ( objJSON.duration !== undefined ) { + + object.duration = objJSON.duration; + + } + + if ( objJSON.time !== undefined ) { + + object.time = objJSON.time; + + } + + if ( objJSON.mirroredLoop !== undefined ) { + + object.mirroredLoop = objJSON.mirroredLoop; + + } + + if ( material.morphNormals ) { + + geometry.computeMorphNormals(); + + } + + } else { + + object = new THREE.Mesh( geometry, material ); + + } + + object.name = objID; + + if ( mat ) { + + object.matrixAutoUpdate = false; + object.matrix.set( + mat[0], mat[1], mat[2], mat[3], + mat[4], mat[5], mat[6], mat[7], + mat[8], mat[9], mat[10], mat[11], + mat[12], mat[13], mat[14], mat[15] + ); + + } else { + + object.position.fromArray( pos ); + + if ( quat ) { + + object.quaternion.fromArray( quat ); + + } else { + + object.rotation.fromArray( rot ); + + } + + object.scale.fromArray( scl ); + + } + + object.visible = objJSON.visible; + object.castShadow = objJSON.castShadow; + object.receiveShadow = objJSON.receiveShadow; + + parent.add( object ); + + result.objects[ objID ] = object; + + } + + // lights + + } else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" || + objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" || + objJSON.type === "HemisphereLight" || objJSON.type === "AreaLight" ) { + + var color = objJSON.color; + var intensity = objJSON.intensity; + var distance = objJSON.distance; + var position = objJSON.position; + var rotation = objJSON.rotation; + + switch ( objJSON.type ) { + + case 'AmbientLight': + light = new THREE.AmbientLight( color ); + break; + + case 'PointLight': + light = new THREE.PointLight( color, intensity, distance ); + light.position.fromArray( position ); + break; + + case 'DirectionalLight': + light = new THREE.DirectionalLight( color, intensity ); + light.position.fromArray( objJSON.direction ); + break; + + case 'SpotLight': + light = new THREE.SpotLight( color, intensity, distance, 1 ); + light.angle = objJSON.angle; + light.position.fromArray( position ); + light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); + light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); + break; + + case 'HemisphereLight': + light = new THREE.DirectionalLight( color, intensity, distance ); + light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); + light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); + break; + + case 'AreaLight': + light = new THREE.AreaLight(color, intensity); + light.position.fromArray( position ); + light.width = objJSON.size; + light.height = objJSON.size_y; + break; + + } + + parent.add( light ); + + light.name = objID; + result.lights[ objID ] = light; + result.objects[ objID ] = light; + + // cameras + + } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { + + pos = objJSON.position; + rot = objJSON.rotation; + quat = objJSON.quaternion; + + if ( objJSON.type === "PerspectiveCamera" ) { + + camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); + + } else if ( objJSON.type === "OrthographicCamera" ) { + + camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); + + } + + camera.name = objID; + camera.position.fromArray( pos ); + + if ( quat !== undefined ) { + + camera.quaternion.fromArray( quat ); + + } else if ( rot !== undefined ) { + + camera.rotation.fromArray( rot ); + + } + + parent.add( camera ); + + result.cameras[ objID ] = camera; + result.objects[ objID ] = camera; + + // pure Object3D + + } else { + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + quat = objJSON.quaternion; + + object = new THREE.Object3D(); + object.name = objID; + object.position.fromArray( pos ); + + if ( quat ) { + + object.quaternion.fromArray( quat ); + + } else { + + object.rotation.fromArray( rot ); + + } + + object.scale.fromArray( scl ); + object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; + + parent.add( object ); + + result.objects[ objID ] = object; + result.empties[ objID ] = object; + + } + + if ( object ) { + + if ( objJSON.userData !== undefined ) { + + for ( var key in objJSON.userData ) { + + var value = objJSON.userData[ key ]; + object.userData[ key ] = value; + + } + + } + + if ( objJSON.groups !== undefined ) { + + for ( var i = 0; i < objJSON.groups.length; i ++ ) { + + var groupID = objJSON.groups[ i ]; + + if ( result.groups[ groupID ] === undefined ) { + + result.groups[ groupID ] = []; + + } + + result.groups[ groupID ].push( objID ); + + } + + } + + } + + } + + if ( object !== undefined && objJSON.children !== undefined ) { + + handle_children( object, objJSON.children ); + + } + + } + + }; + + function handle_mesh( geo, mat, id ) { + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + handle_objects(); + + }; + + function handle_hierarchy( node, id, parent, material, obj ) { + + var p = obj.position; + var r = obj.rotation; + var q = obj.quaternion; + var s = obj.scale; + + node.position.fromArray( p ); + + if ( q ) { + + node.quaternion.fromArray( q ); + + } else { + + node.rotation.fromArray( r ); + + } + + node.scale.fromArray( s ); + + // override children materials + // if object material was specified in JSON explicitly + + if ( material ) { + + node.traverse( function ( child ) { + + child.material = material; + + } ); + + } + + // override children visibility + // with root node visibility as specified in JSON + + var visible = ( obj.visible !== undefined ) ? obj.visible : true; + + node.traverse( function ( child ) { + + child.visible = visible; + + } ); + + parent.add( node ); + + node.name = id; + + result.objects[ id ] = node; + handle_objects(); + + }; + + function create_callback_geometry( id ) { + + return function ( geo, mat ) { + + geo.name = id; + + handle_mesh( geo, mat, id ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_hierachy( id, parent, material, obj ) { + + return function ( event ) { + + var result; + + // loaders which use EventDispatcher + + if ( event.content ) { + + result = event.content; + + // ColladaLoader + + } else if ( event.dae ) { + + result = event.scene; + + + // UTF8Loader + + } else { + + result = event; + + } + + handle_hierarchy( result, id, parent, material, obj ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_embed( id ) { + + return function ( geo, mat ) { + + geo.name = id; + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + + } + + }; + + function async_callback_gate() { + + var progress = { + + totalModels : total_models, + totalTextures : total_textures, + loadedModels : total_models - counter_models, + loadedTextures : total_textures - counter_textures + + }; + + scope.callbackProgress( progress, result ); + + scope.onLoadProgress(); + + if ( counter_models === 0 && counter_textures === 0 ) { + + finalize(); + callbackFinished( result ); + + } + + }; + + function finalize() { + + // take care of targets which could be asynchronously loaded objects + + for ( var i = 0; i < target_array.length; i ++ ) { + + var ta = target_array[ i ]; + + var target = result.objects[ ta.targetName ]; + + if ( target ) { + + ta.object.target = target; + + } else { + + // if there was error and target of specified name doesn't exist in the scene file + // create instead dummy target + // (target must be added to scene explicitly as parent is already added) + + ta.object.target = new THREE.Object3D(); + result.scene.add( ta.object.target ); + + } + + ta.object.target.userData.targetInverse = ta.object; + + } + + }; + + var callbackTexture = function ( count ) { + + counter_textures -= count; + async_callback_gate(); + + scope.onLoadComplete(); + + }; + + // must use this instead of just directly calling callbackTexture + // because of closure in the calling context loop + + var generateTextureCallback = function ( count ) { + + return function () { + + callbackTexture( count ); + + }; + + }; + + function traverse_json_hierarchy( objJSON, callback ) { + + callback( objJSON ); + + if ( objJSON.children !== undefined ) { + + for ( var objChildID in objJSON.children ) { + + traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); + + } + + } + + }; + + // first go synchronous elements + + // fogs + + var fogID, fogJSON; + + for ( fogID in data.fogs ) { + + fogJSON = data.fogs[ fogID ]; + + if ( fogJSON.type === "linear" ) { + + fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); + + } else if ( fogJSON.type === "exp2" ) { + + fog = new THREE.FogExp2( 0x000000, fogJSON.density ); + + } + + color = fogJSON.color; + fog.color.setRGB( color[0], color[1], color[2] ); + + result.fogs[ fogID ] = fog; + + } + + // now come potentially asynchronous elements + + // geometries + + // count how many geometries will be loaded asynchronously + + var geoID, geoJSON; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type in this.geometryHandlers ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + } + + // count how many hierarchies will be loaded asynchronously + + for ( var objID in data.objects ) { + + traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { + + if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + }); + + } + + total_models = counter_models; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type === "cube" ) { + + geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "plane" ) { + + geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "sphere" ) { + + geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "cylinder" ) { + + geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "torus" ) { + + geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "icosahedron" ) { + + geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type in this.geometryHandlers ) { + + var loaderParameters = {}; + + for ( var parType in geoJSON ) { + + if ( parType !== "type" && parType !== "url" ) { + + loaderParameters[ parType ] = geoJSON[ parType ]; + + } + + } + + var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; + loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); + + } else if ( geoJSON.type === "embedded" ) { + + var modelJson = data.embeds[ geoJSON.id ], + texture_path = ""; + + // pass metadata along to jsonLoader so it knows the format version + + modelJson.metadata = data.metadata; + + if ( modelJson ) { + + var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; + var model = jsonLoader.parse( modelJson, texture_path ); + create_callback_embed( geoID )( model.geometry, model.materials ); + + } + + } + + } + + // textures + + // count how many textures will be loaded asynchronously + + var textureID, textureJSON; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.url instanceof Array ) { + + counter_textures += textureJSON.url.length; + + for( var n = 0; n < textureJSON.url.length; n ++ ) { + + scope.onLoadStart(); + + } + + } else { + + counter_textures += 1; + + scope.onLoadStart(); + + } + + } + + total_textures = counter_textures; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { + + textureJSON.mapping = new THREE[ textureJSON.mapping ](); + + } + + if ( textureJSON.url instanceof Array ) { + + var count = textureJSON.url.length; + var url_array = []; + + for( var i = 0; i < count; i ++ ) { + + url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); + + } + + var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } else { + + texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } + + } else { + + var isCompressed = /\.dds$/i.test( textureJSON.url ); + var fullUrl = get_url( textureJSON.url, data.urlBaseType ); + var textureCallback = generateTextureCallback( 1 ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } else { + + texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } + + if ( THREE[ textureJSON.minFilter ] !== undefined ) + texture.minFilter = THREE[ textureJSON.minFilter ]; + + if ( THREE[ textureJSON.magFilter ] !== undefined ) + texture.magFilter = THREE[ textureJSON.magFilter ]; + + if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; + + if ( textureJSON.repeat ) { + + texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); + + if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; + + } + + if ( textureJSON.offset ) { + + texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); + + } + + // handle wrap after repeat so that default repeat can be overriden + + if ( textureJSON.wrap ) { + + var wrapMap = { + "repeat": THREE.RepeatWrapping, + "mirror": THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; + if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; + + } + + } + + result.textures[ textureID ] = texture; + + } + + // materials + + var matID, matJSON; + var parID; + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + for ( parID in matJSON.parameters ) { + + if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { + + matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; + + } else if ( parID === "shading" ) { + + matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; + + } else if ( parID === "side" ) { + + if ( matJSON.parameters[ parID ] == "double" ) { + + matJSON.parameters[ parID ] = THREE.DoubleSide; + + } else if ( matJSON.parameters[ parID ] == "back" ) { + + matJSON.parameters[ parID ] = THREE.BackSide; + + } else { + + matJSON.parameters[ parID ] = THREE.FrontSide; + + } + + } else if ( parID === "blending" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; + + } else if ( parID === "combine" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; + + } else if ( parID === "vertexColors" ) { + + if ( matJSON.parameters[ parID ] == "face" ) { + + matJSON.parameters[ parID ] = THREE.FaceColors; + + // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false + + } else if ( matJSON.parameters[ parID ] ) { + + matJSON.parameters[ parID ] = THREE.VertexColors; + + } + + } else if ( parID === "wrapRGB" ) { + + var v3 = matJSON.parameters[ parID ]; + matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); + + } + + } + + if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { + + matJSON.parameters.transparent = true; + + } + + if ( matJSON.parameters.normalMap ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + var diffuse = matJSON.parameters.color; + var specular = matJSON.parameters.specular; + var ambient = matJSON.parameters.ambient; + var shininess = matJSON.parameters.shininess; + + uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; + + if ( matJSON.parameters.normalScale ) { + + uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); + + } + + if ( matJSON.parameters.map ) { + + uniforms[ "tDiffuse" ].value = matJSON.parameters.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( matJSON.parameters.envMap ) { + + uniforms[ "tCube" ].value = matJSON.parameters.envMap; + uniforms[ "enableReflection" ].value = true; + uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity; + + } + + if ( matJSON.parameters.lightMap ) { + + uniforms[ "tAO" ].value = matJSON.parameters.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + if ( matJSON.parameters.specularMap ) { + + uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( matJSON.parameters.displacementMap ) { + + uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; + uniforms[ "enableDisplacement" ].value = true; + + uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; + uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; + + } + + uniforms[ "diffuse" ].value.setHex( diffuse ); + uniforms[ "specular" ].value.setHex( specular ); + uniforms[ "ambient" ].value.setHex( ambient ); + + uniforms[ "shininess" ].value = shininess; + + if ( matJSON.parameters.opacity ) { + + uniforms[ "opacity" ].value = matJSON.parameters.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + + material = new THREE.ShaderMaterial( parameters ); + + } else { + + material = new THREE[ matJSON.type ]( matJSON.parameters ); + + } + + material.name = matID; + + result.materials[ matID ] = material; + + } + + // second pass through all materials to initialize MeshFaceMaterials + // that could be referring to other materials out of order + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + if ( matJSON.parameters.materials ) { + + var materialArray = []; + + for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { + + var label = matJSON.parameters.materials[ i ]; + materialArray.push( result.materials[ label ] ); + + } + + result.materials[ matID ].materials = materialArray; + + } + + } + + // objects ( synchronous init of procedural primitives ) + + handle_objects(); + + // defaults + + if ( result.cameras && data.defaults.camera ) { + + result.currentCamera = result.cameras[ data.defaults.camera ]; + + } + + if ( result.fogs && data.defaults.fog ) { + + result.scene.fog = result.fogs[ data.defaults.fog ]; + + } + + // synchronous callback + + scope.callbackSync( result ); + + // just in case there are no async elements + + async_callback_gate(); + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.TextureLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.TextureLoader.prototype = { + + constructor: THREE.TextureLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.ImageLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( image ) { + + var texture = new THREE.Texture( image ); + texture.needsUpdate = true; + + if ( onLoad !== undefined ) { + + onLoad( texture ); + + } + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Material = function () { + + this.id = THREE.MaterialIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.side = THREE.FrontSide; + + this.opacity = 1; + this.transparent = false; + + this.blending = THREE.NormalBlending; + + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + + this.depthTest = true; + this.depthWrite = true; + + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; + + this.alphaTest = 0; + + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer + + this.visible = true; + + this.needsUpdate = true; + +}; + +THREE.Material.prototype = { + + constructor: THREE.Material, + + 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; + + } + + if ( key in this ) { + + var currentValue = this[ key ]; + + if ( currentValue instanceof THREE.Color ) { + + currentValue.set( newValue ); + + } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { + + currentValue.copy( newValue ); + + } else if ( key == 'overdraw') { + + // ensure overdraw is backwards-compatable with legacy boolean type + this[ key ] = Number(newValue); + + } else { + + this[ key ] = newValue; + + } + + } + + } + + }, + + clone: function ( material ) { + + if ( material === undefined ) material = new THREE.Material(); + + material.name = this.name; + + material.side = this.side; + + material.opacity = this.opacity; + material.transparent = this.transparent; + + material.blending = this.blending; + + material.blendSrc = this.blendSrc; + material.blendDst = this.blendDst; + material.blendEquation = this.blendEquation; + + material.depthTest = this.depthTest; + material.depthWrite = this.depthWrite; + + material.polygonOffset = this.polygonOffset; + material.polygonOffsetFactor = this.polygonOffsetFactor; + material.polygonOffsetUnits = this.polygonOffsetUnits; + + material.alphaTest = this.alphaTest; + + material.overdraw = this.overdraw; + + material.visible = this.visible; + + return material; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); + +THREE.MaterialIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round", + * + * vertexColors: + * + * fog: + * } + */ + +THREE.LineBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineBasicMaterial.prototype.clone = function () { + + var material = new THREE.LineBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + material.linecap = this.linecap; + material.linejoin = this.linejoin; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: , + * + * vertexColors: + * + * fog: + * } + */ + +THREE.LineDashedMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineDashedMaterial.prototype.clone = function () { + + var material = new THREE.LineDashedMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + + material.scale = this.scale; + material.dashSize = this.dashSize; + material.gapSize = this.gapSize; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * + * fog: + * } + */ + +THREE.MeshBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // emissive + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + + this.setValues( parameters ); + +}; + +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshBasicMaterial.prototype.clone = function () { + + var material = new THREE.MeshBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * ambient: , + * emissive: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.MeshLambertMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0xffffff ); + this.emissive = new THREE.Color( 0x000000 ); + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshLambertMaterial.prototype.clone = function () { + + var material = new THREE.MeshLambertMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * ambient: , + * emissive: , + * specular: , + * shininess: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.MeshPhongMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0xffffff ); + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0x111111 ); + this.shininess = 30; + + this.metal = false; + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + + this.lightMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshPhongMaterial.prototype.clone = function () { + + var material = new THREE.MeshPhongMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + material.specular.copy( this.specular ); + material.shininess = this.shininess; + + material.metal = this.metal; + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; + + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ + +THREE.MeshDepthMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.setValues( parameters ); + +}; + +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshDepthMaterial.prototype.clone = function () { + + var material = new THREE.MeshDepthMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: , + * + * shading: THREE.FlatShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ + +THREE.MeshNormalMaterial = function ( parameters ) { + + THREE.Material.call( this, parameters ); + + this.shading = THREE.FlatShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.morphTargets = false; + + this.setValues( parameters ); + +}; + +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshNormalMaterial.prototype.clone = function () { + + var material = new THREE.MeshNormalMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MeshFaceMaterial = function ( materials ) { + + this.materials = materials instanceof Array ? materials : []; + +}; + +THREE.MeshFaceMaterial.prototype.clone = function () { + + var material = new THREE.MeshFaceMaterial(); + + for ( var i = 0; i < this.materials.length; i ++ ) { + + material.materials.push( this.materials[ i ].clone() ); + + } + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * size: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * vertexColors: , + * + * fog: + * } + */ + +THREE.ParticleSystemMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.map = null; + + this.size = 1; + this.sizeAttenuation = true; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ParticleSystemMaterial.prototype.clone = function () { + + var material = new THREE.ParticleSystemMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.size = this.size; + material.sizeAttenuation = this.sizeAttenuation; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +// backwards compatibility + +THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * fragmentShader: , + * vertexShader: , + * + * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, + * + * defines: { "label" : "value" }, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * lights: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.ShaderMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.fragmentShader = "void main() {}"; + this.vertexShader = "void main() {}"; + this.uniforms = {}; + this.defines = {}; + this.attributes = null; + + this.shading = THREE.SmoothShading; + + 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.vertexColors = THREE.NoColors; // set to use "color" attribute stream + + 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 + + // 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; + + this.setValues( parameters ); + +}; + +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ShaderMaterial.prototype.clone = function () { + + var material = new THREE.ShaderMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.fragmentShader = this.fragmentShader; + material.vertexShader = this.vertexShader; + + material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); + + material.attributes = this.attributes; + material.defines = this.defines; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + material.fog = this.fog; + + material.lights = this.lights; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RawShaderMaterial = function ( parameters ) { + + THREE.ShaderMaterial.call( this, parameters ); + +}; + +THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); + +THREE.RawShaderMaterial.prototype.clone = function () { + + var material = new THREE.RawShaderMaterial(); + + THREE.ShaderMaterial.prototype.clone.call( this, material ); + + return material; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: + * } + */ + +THREE.SpriteMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + // defaults + + this.color = new THREE.Color( 0xffffff ); + this.map = null; + + this.rotation = 0; + + this.fog = false; + + // set parameters + + this.setValues( parameters ); + +}; + +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.SpriteMaterial.prototype.clone = function () { + + var material = new THREE.SpriteMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.map = this.map; + + material.rotation = this.rotation; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * color: , + * program: , + * opacity: , + * blending: THREE.NormalBlending + * } + */ + +THREE.SpriteCanvasMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + this.program = function ( context, color ) {}; + + this.setValues( parameters ); + +}; + +THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.SpriteCanvasMaterial.prototype.clone = function () { + + var material = new THREE.SpriteCanvasMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.program = this.program; + + return material; + +}; + +// backwards compatibility + +THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + this.id = THREE.TextureIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.image = image; + this.mipmaps = []; + + this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); + + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + + this.format = format !== undefined ? format : THREE.RGBAFormat; + this.type = type !== undefined ? type : THREE.UnsignedByteType; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.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) + + this._needsUpdate = false; + this.onUpdate = null; + +}; + +THREE.Texture.prototype = { + + constructor: THREE.Texture, + + get needsUpdate () { + + return this._needsUpdate; + + }, + + set needsUpdate ( value ) { + + if ( value === true ) this.update(); + + this._needsUpdate = value; + + }, + + clone: function ( texture ) { + + if ( texture === undefined ) texture = new THREE.Texture(); + + texture.image = this.image; + texture.mipmaps = this.mipmaps.slice(0); + + texture.mapping = this.mapping; + + texture.wrapS = this.wrapS; + texture.wrapT = this.wrapT; + + texture.magFilter = this.magFilter; + texture.minFilter = this.minFilter; + + texture.anisotropy = this.anisotropy; + + texture.format = this.format; + texture.type = this.type; + + texture.offset.copy( this.offset ); + texture.repeat.copy( this.repeat ); + + texture.generateMipmaps = this.generateMipmaps; + texture.premultiplyAlpha = this.premultiplyAlpha; + texture.flipY = this.flipY; + texture.unpackAlignment = this.unpackAlignment; + + return texture; + + }, + + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); + +THREE.TextureIdCount = 0; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file + +}; + +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.CompressedTexture.prototype.clone = function () { + + var texture = new THREE.CompressedTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { data: data, width: width, height: height }; + +}; + +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.DataTexture.prototype.clone = function () { + + var texture = new THREE.DataTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ParticleSystem = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); + + this.sortParticles = false; + this.frustumCulled = false; + +}; + +THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ParticleSystem.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); + + object.sortParticles = this.sortParticles; + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Line = function ( geometry, material, type ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.type = ( type !== undefined ) ? type : THREE.LineStrip; + +}; + +THREE.LineStrip = 0; +THREE.LinePieces = 1; + +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Line.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ + +THREE.Mesh = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.updateMorphTargets(); + +}; + +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Mesh.prototype.updateMorphTargets = function () { + + if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { + + this.morphTargetBase = -1; + this.morphTargetForcedOrder = []; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; + + } + + } + +}; + +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { + + if ( this.morphTargetDictionary[ name ] !== undefined ) { + + return this.morphTargetDictionary[ name ]; + + } + + console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); + + return 0; + +}; + +THREE.Mesh.prototype.clone = function ( object, recursive ) { + + if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); + + THREE.Object3D.prototype.clone.call( this, object, recursive ); + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Bone = function( belongsToSkin ) { + + THREE.Object3D.call( this ); + + this.skin = belongsToSkin; + this.skinMatrix = new THREE.Matrix4(); + +}; + +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { + + // update local + + if ( this.matrixAutoUpdate ) { + + forceUpdate |= this.updateMatrix(); + + } + + // update skin matrix + + if ( forceUpdate || this.matrixWorldNeedsUpdate ) { + + if ( parentSkinMatrix ) { + + this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); + + } else { + + this.skinMatrix.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + forceUpdate = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].update( this.skinMatrix, forceUpdate ); + + } + +}; + + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { + + THREE.Mesh.call( this, geometry, material ); + + // + + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; + + // init bones + + this.identityMatrix = new THREE.Matrix4(); + + this.bones = []; + this.boneMatrices = []; + + var b, bone, gbone, p, q, s; + + if ( this.geometry && this.geometry.bones !== undefined ) { + + for ( b = 0; b < this.geometry.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + + p = gbone.pos; + q = gbone.rotq; + s = gbone.scl; + + bone = this.addBone(); + + bone.name = gbone.name; + bone.position.set( p[0], p[1], p[2] ); + bone.quaternion.set( q[0], q[1], q[2], q[3] ); + + if ( s !== undefined ) { + + bone.scale.set( s[0], s[1], s[2] ); + + } else { + + bone.scale.set( 1, 1, 1 ); + + } + + } + + for ( b = 0; b < this.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + bone = this.bones[ b ]; + + if ( gbone.parent === -1 ) { + + this.add( bone ); + + } else { + + this.bones[ gbone.parent ].add( bone ); + + } + + } + + // + + var nBones = this.bones.length; + + if ( this.useVertexTexture ) { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones (8 * 8 / 4) + // 16x16 pixel texture max 64 bones (16 * 16 / 4) + // 32x32 pixel texture max 256 bones (32 * 32 / 4) + // 64x64 pixel texture max 1024 bones (64 * 64 / 4) + + var size; + + if ( nBones > 256 ) + size = 64; + else if ( nBones > 64 ) + size = 32; + else if ( nBones > 16 ) + size = 16; + else + size = 8; + + this.boneTextureWidth = size; + this.boneTextureHeight = size; + + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); + this.boneTexture.minFilter = THREE.NearestFilter; + this.boneTexture.magFilter = THREE.NearestFilter; + this.boneTexture.generateMipmaps = false; + this.boneTexture.flipY = false; + + } else { + + this.boneMatrices = new Float32Array( 16 * nBones ); + + } + + this.pose(); + + } + +}; + +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.SkinnedMesh.prototype.addBone = function( bone ) { + + if ( bone === undefined ) { + + bone = new THREE.Bone( this ); + + } + + this.bones.push( bone ); + + return bone; + +}; + +THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { + + var offsetMatrix = new THREE.Matrix4(); + + return function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child instanceof THREE.Bone ) { + + child.update( this.identityMatrix, false ); + + } else { + + child.updateMatrixWorld( true ); + + } + + } + + // make a snapshot of the bones' rest position + + if ( this.boneInverses == undefined ) { + + this.boneInverses = []; + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + var inverse = new THREE.Matrix4(); + + inverse.getInverse( this.bones[ b ].skinMatrix ); + + this.boneInverses.push( inverse ); + + } + + } + + // 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; + + // TODO: we could get rid of this multiplication step if the skinMatrix + // was already representing the offset; however, this requires some + // major changes to the animation system + + offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); + offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); + + } + + if ( this.useVertexTexture ) { + + this.boneTexture.needsUpdate = true; + + } + + }; + +}(); + +THREE.SkinnedMesh.prototype.pose = function () { + + this.updateMatrixWorld( true ); + + this.normalizeSkinWeights(); + +}; + +THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { + + if ( this.geometry instanceof THREE.Geometry ) { + + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { + + var sw = this.geometry.skinWeights[ i ]; + + var scale = 1.0 / sw.lengthManhattan(); + + if ( scale !== Infinity ) { + + sw.multiplyScalar( scale ); + + } else { + + sw.set( 1 ); // this will be normalized by the shader anyway + + } + + } + + } else { + + // skinning weights assumed to be normalized for THREE.BufferGeometry + + } + +}; + +THREE.SkinnedMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) { + + object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); + + } + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.MorphAnimMesh = function ( geometry, material ) { + + THREE.Mesh.call( this, geometry, material ); + + // API + + this.duration = 1000; // milliseconds + this.mirroredLoop = false; + this.time = 0; + + // internals + + this.lastKeyframe = 0; + this.currentKeyframe = 0; + + this.direction = 1; + this.directionBackwards = false; + + this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); + +}; + +THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { + + this.startKeyframe = start; + this.endKeyframe = end; + + this.length = this.endKeyframe - this.startKeyframe + 1; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionForward = function () { + + this.direction = 1; + this.directionBackwards = false; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { + + this.direction = -1; + this.directionBackwards = true; + +}; + +THREE.MorphAnimMesh.prototype.parseAnimations = function () { + + var geometry = this.geometry; + + if ( ! geometry.animations ) geometry.animations = {}; + + var firstAnimation, animations = geometry.animations; + + var pattern = /([a-z]+)(\d+)/; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var parts = morph.name.match( pattern ); + + if ( parts && parts.length > 1 ) { + + var label = parts[ 1 ]; + var num = parts[ 2 ]; + + if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; + + var animation = animations[ label ]; + + if ( i < animation.start ) animation.start = i; + if ( i > animation.end ) animation.end = i; + + if ( ! firstAnimation ) firstAnimation = label; + + } + + } + + geometry.firstAnimation = firstAnimation; + +}; + +THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { + + if ( ! this.geometry.animations ) this.geometry.animations = {}; + + this.geometry.animations[ label ] = { start: start, end: end }; + +}; + +THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { + + var animation = this.geometry.animations[ label ]; + + if ( animation ) { + + this.setFrameRange( animation.start, animation.end ); + this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); + this.time = 0; + + } else { + + console.warn( "animation[" + label + "] undefined" ); + + } + +}; + +THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { + + var frameTime = this.duration / this.length; + + this.time += this.direction * delta; + + if ( this.mirroredLoop ) { + + if ( this.time > this.duration || this.time < 0 ) { + + this.direction *= -1; + + if ( this.time > this.duration ) { + + this.time = this.duration; + this.directionBackwards = true; + + } + + if ( this.time < 0 ) { + + this.time = 0; + this.directionBackwards = false; + + } + + } + + } else { + + this.time = this.time % this.duration; + + if ( this.time < 0 ) this.time += this.duration; + + } + + var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); + + if ( keyframe !== this.currentKeyframe ) { + + this.morphTargetInfluences[ this.lastKeyframe ] = 0; + this.morphTargetInfluences[ this.currentKeyframe ] = 1; + + this.morphTargetInfluences[ keyframe ] = 0; + + this.lastKeyframe = this.currentKeyframe; + this.currentKeyframe = keyframe; + + } + + var mix = ( this.time % frameTime ) / frameTime; + + if ( this.directionBackwards ) { + + mix = 1 - mix; + + } + + this.morphTargetInfluences[ this.currentKeyframe ] = mix; + this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; + +}; + +THREE.MorphAnimMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); + + object.duration = this.duration; + object.mirroredLoop = this.mirroredLoop; + object.time = this.time; + + object.lastKeyframe = this.lastKeyframe; + object.currentKeyframe = this.currentKeyframe; + + object.direction = this.direction; + object.directionBackwards = this.directionBackwards; + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LOD = function () { + + THREE.Object3D.call( this ); + + this.objects = []; + +}; + + +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.LOD.prototype.addLevel = function ( object, distance ) { + + if ( distance === undefined ) distance = 0; + + distance = Math.abs( distance ); + + for ( var l = 0; l < this.objects.length; l ++ ) { + + if ( distance < this.objects[ l ].distance ) { + + break; + + } + + } + + this.objects.splice( l, 0, { distance: distance, object: object } ); + this.add( object ); + +}; + +THREE.LOD.prototype.getObjectForDistance = function ( distance ) { + + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + + if ( distance < this.objects[ i ].distance ) { + + break; + + } + + } + + return this.objects[ i - 1 ].object; + +}; + +THREE.LOD.prototype.update = function () { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( camera ) { + + if ( this.objects.length > 1 ) { + + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); + + var distance = v1.distanceTo( v2 ); + + this.objects[ 0 ].object.visible = true; + + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + + if ( distance >= this.objects[ i ].distance ) { + + this.objects[ i - 1 ].object.visible = false; + this.objects[ i ].object.visible = true; + + } else { + + break; + + } + + } + + for( ; i < l; i ++ ) { + + this.objects[ i ].object.visible = false; + + } + + } + + }; + +}(); + +THREE.LOD.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.LOD(); + + THREE.Object3D.prototype.clone.call( this, object ); + + for ( var i = 0, l = this.objects.length; i < l; i ++ ) { + var x = this.objects[i].object.clone(); + x.visible = i === 0; + object.addLevel( x, this.objects[i].distance ); + } + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Sprite = ( function () { + + var vertices = new THREE.Float32Attribute( 3, 3 ); + vertices.set( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] ); + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', vertices ); + + return function ( material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); + + }; + +} )(); + +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); + +/* + * Custom update matrix + */ + +THREE.Sprite.prototype.updateMatrix = function () { + + this.matrix.compose( this.position, this.quaternion, this.scale ); + + this.matrixWorldNeedsUpdate = true; + +}; + +THREE.Sprite.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Sprite( this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +// Backwards compatibility + +THREE.Particle = THREE.Sprite; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Scene = function () { + + THREE.Object3D.call( this ); + + this.fog = null; + this.overrideMaterial = null; + + this.autoUpdate = true; // checked by the renderer + this.matrixAutoUpdate = false; + + this.__lights = []; + + this.__objectsAdded = []; + this.__objectsRemoved = []; + +}; + +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Scene.prototype.__addObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + if ( this.__lights.indexOf( object ) === - 1 ) { + + this.__lights.push( object ); + + } + + if ( object.target && object.target.parent === undefined ) { + + this.add( object.target ); + + } + + } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { + + this.__objectsAdded.push( object ); + + // check if previously removed + + var i = this.__objectsRemoved.indexOf( object ); + + if ( i !== -1 ) { + + this.__objectsRemoved.splice( i, 1 ); + + } + + } + + this.dispatchEvent( { type: 'objectAdded', object: object } ); + object.dispatchEvent( { type: 'addedToScene', scene: this } ); + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__addObject( object.children[ c ] ); + + } + +}; + +THREE.Scene.prototype.__removeObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + var i = this.__lights.indexOf( object ); + + if ( i !== -1 ) { + + this.__lights.splice( i, 1 ); + + } + + if ( object.shadowCascadeArray ) { + + for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { + + this.__removeObject( object.shadowCascadeArray[ x ] ); + + } + + } + + } else if ( !( object instanceof THREE.Camera ) ) { + + this.__objectsRemoved.push( object ); + + // check if previously added + + var i = this.__objectsAdded.indexOf( object ); + + if ( i !== -1 ) { + + this.__objectsAdded.splice( i, 1 ); + + } + + } + + this.dispatchEvent( { type: 'objectRemoved', object: object } ); + object.dispatchEvent( { type: 'removedFromScene', scene: this } ); + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__removeObject( object.children[ c ] ); + + } + +}; + +THREE.Scene.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Scene(); + + THREE.Object3D.prototype.clone.call(this, object); + + if ( this.fog !== null ) object.fog = this.fog.clone(); + if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); + + object.autoUpdate = this.autoUpdate; + object.matrixAutoUpdate = this.matrixAutoUpdate; + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Fog = function ( color, near, far ) { + + this.name = ''; + + this.color = new THREE.Color( color ); + + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; + +}; + +THREE.Fog.prototype.clone = function () { + + return new THREE.Fog( this.color.getHex(), this.near, this.far ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.FogExp2 = function ( color, density ) { + + this.name = ''; + + this.color = new THREE.Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; + +}; + +THREE.FogExp2.prototype.clone = function () { + + return new THREE.FogExp2( this.color.getHex(), this.density ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CanvasRenderer = function ( parameters ) { + + console.log( 'THREE.CanvasRenderer', THREE.REVISION ); + + var smoothstep = THREE.Math.smoothstep; + + parameters = parameters || {}; + + var _this = this, + _renderData, _elements, _lights, + _projector = new THREE.Projector(), + + _canvas = parameters.canvas !== undefined + ? parameters.canvas + : document.createElement( 'canvas' ), + + _canvasWidth = _canvas.width, + _canvasHeight = _canvas.height, + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), + + _context = _canvas.getContext( '2d', { + alpha: parameters.alpha === true + } ), + + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = 0, + + _contextGlobalAlpha = 1, + _contextGlobalCompositeOperation = 0, + _contextStrokeStyle = null, + _contextFillStyle = null, + _contextLineWidth = null, + _contextLineCap = null, + _contextLineJoin = null, + _contextDashSize = null, + _contextGapSize = 0, + + _camera, + + _v1, _v2, _v3, _v4, + _v5 = new THREE.RenderableVertex(), + _v6 = new THREE.RenderableVertex(), + + _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, + _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, + + _color = new THREE.Color(), + _color1 = new THREE.Color(), + _color2 = new THREE.Color(), + _color3 = new THREE.Color(), + _color4 = new THREE.Color(), + + _diffuseColor = new THREE.Color(), + _emissiveColor = new THREE.Color(), + + _lightColor = new THREE.Color(), + + _patterns = {}, + + _image, _uvs, + _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, + + _clipBox = new THREE.Box2(), + _clearBox = new THREE.Box2(), + _elemBox = new THREE.Box2(), + + _ambientLight = new THREE.Color(), + _directionalLights = new THREE.Color(), + _pointLights = new THREE.Color(), + + _vector3 = new THREE.Vector3(), // Needed for PointLight + _centroid = new THREE.Vector3(), + _normal = new THREE.Vector3(), + _normalViewMatrix = new THREE.Matrix3(); + + // dash+gap fallbacks for Firefox and everything else + + if ( _context.setLineDash === undefined ) { + + if ( _context.mozDash !== undefined ) { + + _context.setLineDash = function ( values ) { + + _context.mozDash = values[ 0 ] !== null ? values : null; + + } + + } else { + + _context.setLineDash = function () {} + + } + + } + + this.domElement = _canvas; + + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : self.devicePixelRatio !== undefined + ? self.devicePixelRatio + : 1; + + this.autoClear = true; + this.sortObjects = true; + this.sortElements = true; + + this.info = { + + render: { + + vertices: 0, + faces: 0 + + } + + } + + // WebGLRenderer compatibility + + this.supportsVertexTextures = function () {}; + this.setFaceCulling = function () {}; + + this.setSize = function ( width, height, updateStyle ) { + + _canvasWidth = width * this.devicePixelRatio; + _canvasHeight = height * this.devicePixelRatio; + + _canvas.width = _canvasWidth; + _canvas.height = _canvasHeight; + + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); + + if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + } + + _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ), + _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); + _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + _contextGlobalAlpha = 1; + _contextGlobalCompositeOperation = 0; + _contextStrokeStyle = null; + _contextFillStyle = null; + _contextLineWidth = null; + _contextLineCap = null; + _contextLineJoin = null; + + this.setViewport( 0, 0, width, height ); + + }; + + this.setViewport = function ( x, y, width, height ) { + + _context.setTransform( width / _canvasWidth, 0, 0, - height / _canvasHeight, x, _canvasHeight - y ); + _context.translate( _canvasWidthHalf, _canvasHeightHalf ); + + }; + + this.setScissor = function () {}; + this.enableScissorTest = function () {}; + + this.setClearColor = function ( color, alpha ) { + + _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; + + _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); + _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + }; + + this.setClearColorHex = function ( hex, alpha ) { + + console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + this.setClearColor( hex, alpha ); + + }; + + this.getMaxAnisotropy = function () { + + return 0; + + }; + + this.clear = function () { + + if ( _clearBox.empty() === false ) { + + _clearBox.intersect( _clipBox ); + _clearBox.expandByScalar( 2 ); + + if ( _clearAlpha < 1 ) { + + _context.clearRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + if ( _clearAlpha > 0 ) { + + setBlending( THREE.NormalBlending ); + setOpacity( 1 ); + + setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); + + _context.fillRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + _clearBox.makeEmpty(); + + } + + }; + + // compatibility + + this.clearColor = function () {}; + this.clearDepth = function () {}; + this.clearStencil = function () {}; + + this.render = function ( scene, camera ) { + + if ( camera instanceof THREE.Camera === false ) { + + console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + if ( this.autoClear === true ) this.clear(); + + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + + _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); + _elements = _renderData.elements; + _lights = _renderData.lights; + _camera = camera; + + _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); + + /* DEBUG + setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); + _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); + */ + + calculateLights(); + + for ( var e = 0, el = _elements.length; e < el; e ++ ) { + + var element = _elements[ e ]; + + var material = element.material; + + if ( material === undefined || material.visible === false ) continue; + + _elemBox.makeEmpty(); + + if ( element instanceof THREE.RenderableSprite ) { + + _v1 = element; + _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; + + renderSprite( _v1, element, material ); + + } else if ( element instanceof THREE.RenderableLine ) { + + _v1 = element.v1; _v2 = element.v2; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + + _elemBox.setFromPoints( [ + _v1.positionScreen, + _v2.positionScreen + ] ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + + renderLine( _v1, _v2, element, material ); + + } + + } else if ( element instanceof THREE.RenderableFace ) { + + _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; + + if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; + if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; + if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; + + if ( material.overdraw > 0 ) { + + expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); + expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); + expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); + + } + + _elemBox.setFromPoints( [ + _v1.positionScreen, + _v2.positionScreen, + _v3.positionScreen + ] ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + + renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); + + } + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); + _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); + */ + + _clearBox.union( _elemBox ); + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); + _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); + */ + + // _context.setTransform( 1, 0, 0, 1, 0, 0 ); + + }; + + // + + function calculateLights() { + + _ambientLight.setRGB( 0, 0, 0 ); + _directionalLights.setRGB( 0, 0, 0 ); + _pointLights.setRGB( 0, 0, 0 ); + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + var lightColor = light.color; + + if ( light instanceof THREE.AmbientLight ) { + + _ambientLight.add( lightColor ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + // for sprites + + _directionalLights.add( lightColor ); + + } else if ( light instanceof THREE.PointLight ) { + + // for sprites + + _pointLights.add( lightColor ); + + } + + } + + } + + function calculateLight( position, normal, color ) { + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + + _lightColor.copy( light.color ); + + if ( light instanceof THREE.DirectionalLight ) { + + var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); + + var amount = normal.dot( lightPosition ); + + if ( amount <= 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } else if ( light instanceof THREE.PointLight ) { + + var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); + + var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); + + if ( amount <= 0 ) continue; + + amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); + + if ( amount == 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } + + } + + } + + function renderSprite( v1, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + var scaleX = element.scale.x * _canvasWidthHalf; + var scaleY = element.scale.y * _canvasHeightHalf; + + var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite + _elemBox.min.set( v1.x - dist, v1.y - dist ); + _elemBox.max.set( v1.x + dist, v1.y + dist ); + + if ( material instanceof THREE.SpriteMaterial || + material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility + + var texture = material.map; + + if ( texture !== null ) { + + if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { + + if ( texture.image !== undefined && texture.image.width > 0 ) { + + textureToPattern( texture ); + + } + + texture.addEventListener( 'update', onTextureUpdate ); + + } + + var pattern = _patterns[ texture.id ]; + + if ( pattern !== undefined ) { + + setFillStyle( pattern ); + + } else { + + setFillStyle( 'rgba( 0, 0, 0, 1 )' ); + + } + + // + + var bitmap = texture.image; + + var ox = bitmap.width * texture.offset.x; + var oy = bitmap.height * texture.offset.y; + + var sx = bitmap.width * texture.repeat.x; + var sy = bitmap.height * texture.repeat.y; + + var cx = scaleX / sx; + var cy = scaleY / sy; + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.translate( - scaleX / 2, - scaleY / 2 ); + _context.scale( cx, cy ); + _context.translate( - ox, - oy ); + _context.fillRect( ox, oy, sx, sy ); + _context.restore(); + + } else { // no texture + + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.scale( scaleX, - scaleY ); + _context.fillRect( - 0.5, - 0.5, 1, 1 ); + _context.restore(); + + } + + } else if ( material instanceof THREE.SpriteCanvasMaterial ) { + + setStrokeStyle( material.color.getStyle() ); + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.scale( scaleX, scaleY ); + + material.program( _context ); + + _context.restore(); + + } + + /* DEBUG + setStrokeStyle( 'rgb(255,255,0)' ); + _context.beginPath(); + _context.moveTo( v1.x - 10, v1.y ); + _context.lineTo( v1.x + 10, v1.y ); + _context.moveTo( v1.x, v1.y - 10 ); + _context.lineTo( v1.x, v1.y + 10 ); + _context.stroke(); + */ + + } + + function renderLine( v1, v2, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _context.beginPath(); + _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); + _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); + + if ( material instanceof THREE.LineBasicMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + + if ( material.vertexColors !== THREE.VertexColors ) { + + setStrokeStyle( material.color.getStyle() ); + + } else { + + var colorStyle1 = element.vertexColors[0].getStyle(); + var colorStyle2 = element.vertexColors[1].getStyle(); + + if ( colorStyle1 === colorStyle2 ) { + + setStrokeStyle( colorStyle1 ); + + } else { + + try { + + var grad = _context.createLinearGradient( + v1.positionScreen.x, + v1.positionScreen.y, + v2.positionScreen.x, + v2.positionScreen.y + ); + grad.addColorStop( 0, colorStyle1 ); + grad.addColorStop( 1, colorStyle2 ); + + } catch ( exception ) { + + grad = colorStyle1; + + } + + setStrokeStyle( grad ); + + } + + } + + _context.stroke(); + _elemBox.expandByScalar( material.linewidth * 2 ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + setStrokeStyle( material.color.getStyle() ); + setDashAndGap( material.dashSize, material.gapSize ); + + _context.stroke(); + + _elemBox.expandByScalar( material.linewidth * 2 ); + + setDashAndGap( null, null ); + + } + + } + + function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { + + _this.info.render.vertices += 3; + _this.info.render.faces ++; + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; + _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; + _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); + + if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { + + _diffuseColor.copy( material.color ); + _emissiveColor.copy( material.emissive ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _diffuseColor.multiply( element.color ); + + } + + _color.copy( _ambientLight ); + + _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 ); + + calculateLight( _centroid, element.normalModel, _color ); + + _color.multiply( _diffuseColor ).add( _emissiveColor ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + + if ( material.map !== null ) { + + if ( material.map.mapping instanceof THREE.UVMapping ) { + + _uvs = element.uvs; + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); + + } + + } else if ( material.envMap !== null ) { + + if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { + + _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); + _uv1x = 0.5 * _normal.x + 0.5; + _uv1y = 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); + _uv2x = 0.5 * _normal.x + 0.5; + _uv2y = 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); + _uv3x = 0.5 * _normal.x + 0.5; + _uv3y = 0.5 * _normal.y + 0.5; + + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + + } else if ( material.envMap.mapping instanceof THREE.SphericalRefractionMapping ) { + + _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); + _uv1x = - 0.5 * _normal.x + 0.5; + _uv1y = - 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); + _uv2x = - 0.5 * _normal.x + 0.5; + _uv2y = - 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); + _uv3x = - 0.5 * _normal.x + 0.5; + _uv3y = - 0.5 * _normal.y + 0.5; + + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + + } + + + } else { + + _color.copy( material.color ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _color.multiply( element.color ); + + } + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); + + _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else { + + _color.setRGB( 1, 1, 1 ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } + + // + + function drawTriangle( x0, y0, x1, y1, x2, y2 ) { + + _context.beginPath(); + _context.moveTo( x0, y0 ); + _context.lineTo( x1, y1 ); + _context.lineTo( x2, y2 ); + _context.closePath(); + + } + + function strokePath( color, linewidth, linecap, linejoin ) { + + setLineWidth( linewidth ); + setLineCap( linecap ); + setLineJoin( linejoin ); + setStrokeStyle( color.getStyle() ); + + _context.stroke(); + + _elemBox.expandByScalar( linewidth * 2 ); + + } + + function fillPath( color ) { + + setFillStyle( color.getStyle() ); + _context.fill(); + + } + + function onTextureUpdate ( event ) { + + textureToPattern( event.target ); + + } + + function textureToPattern( texture ) { + + var repeatX = texture.wrapS === THREE.RepeatWrapping; + var repeatY = texture.wrapT === THREE.RepeatWrapping; + + var image = texture.image; + + var canvas = document.createElement( 'canvas' ); + canvas.width = image.width; + canvas.height = image.height; + + var context = canvas.getContext( '2d' ); + context.setTransform( 1, 0, 0, - 1, 0, image.height ); + context.drawImage( image, 0, 0 ); + + _patterns[ texture.id ] = _context.createPattern( + canvas, repeatX === true && repeatY === true + ? 'repeat' + : repeatX === true && repeatY === false + ? 'repeat-x' + : repeatX === false && repeatY === true + ? 'repeat-y' + : 'no-repeat' + ); + + } + + function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { + + if ( texture instanceof THREE.DataTexture ) return; + + if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { + + if ( texture.image !== undefined && texture.image.width > 0 ) { + + textureToPattern( texture ); + + } + + texture.addEventListener( 'update', onTextureUpdate ); + + } + + var pattern = _patterns[ texture.id ]; + + if ( pattern !== undefined ) { + + setFillStyle( pattern ); + + } else { + + setFillStyle( 'rgba(0,0,0,1)' ); + _context.fill(); + + return; + + } + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + offsetX = texture.offset.x / texture.repeat.x, + offsetY = texture.offset.y / texture.repeat.y, + width = texture.image.width * texture.repeat.x, + height = texture.image.height * texture.repeat.y; + + u0 = ( u0 + offsetX ) * width; + v0 = ( v0 + offsetY ) * height; + + u1 = ( u1 + offsetX ) * width; + v1 = ( v1 + offsetY ) * height; + + u2 = ( u2 + offsetX ) * width; + v2 = ( v2 + offsetY ) * height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + if ( det === 0 ) return; + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.fill(); + _context.restore(); + + } + + function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + width = image.width - 1, + height = image.height - 1; + + u0 *= width; v0 *= height; + u1 *= width; v1 *= height; + u2 *= width; v2 *= height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.clip(); + _context.drawImage( image, 0, 0 ); + _context.restore(); + + } + + // Hide anti-alias gaps + + function expand( v1, v2, pixels ) { + + var x = v2.x - v1.x, y = v2.y - v1.y, + det = x * x + y * y, idet; + + if ( det === 0 ) return; + + idet = pixels / Math.sqrt( det ); + + x *= idet; y *= idet; + + v2.x += x; v2.y += y; + v1.x -= x; v1.y -= y; + + } + + // Context cached methods. + + function setOpacity( value ) { + + if ( _contextGlobalAlpha !== value ) { + + _context.globalAlpha = value; + _contextGlobalAlpha = value; + + } + + } + + function setBlending( value ) { + + if ( _contextGlobalCompositeOperation !== value ) { + + if ( value === THREE.NormalBlending ) { + + _context.globalCompositeOperation = 'source-over'; + + } else if ( value === THREE.AdditiveBlending ) { + + _context.globalCompositeOperation = 'lighter'; + + } else if ( value === THREE.SubtractiveBlending ) { + + _context.globalCompositeOperation = 'darker'; + + } + + _contextGlobalCompositeOperation = value; + + } + + } + + function setLineWidth( value ) { + + if ( _contextLineWidth !== value ) { + + _context.lineWidth = value; + _contextLineWidth = value; + + } + + } + + function setLineCap( value ) { + + // "butt", "round", "square" + + if ( _contextLineCap !== value ) { + + _context.lineCap = value; + _contextLineCap = value; + + } + + } + + function setLineJoin( value ) { + + // "round", "bevel", "miter" + + if ( _contextLineJoin !== value ) { + + _context.lineJoin = value; + _contextLineJoin = value; + + } + + } + + function setStrokeStyle( value ) { + + if ( _contextStrokeStyle !== value ) { + + _context.strokeStyle = value; + _contextStrokeStyle = value; + + } + + } + + function setFillStyle( value ) { + + if ( _contextFillStyle !== value ) { + + _context.fillStyle = value; + _contextFillStyle = value; + + } + + } + + function setDashAndGap( dashSizeValue, gapSizeValue ) { + + if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { + + _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); + _contextDashSize = dashSizeValue; + _contextGapSize = gapSizeValue; + + } + + } + +}; + +/** + * Shader chunks for WebLG Shader library + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.ShaderChunk = { + + // FOG + + fog_pars_fragment: [ + + "#ifdef USE_FOG", + + " uniform vec3 fogColor;", + + " #ifdef FOG_EXP2", + + " uniform float fogDensity;", + + " #else", + + " uniform float fogNear;", + " uniform float fogFar;", + + " #endif", + + "#endif" + + ].join("\n"), + + fog_fragment: [ + + "#ifdef USE_FOG", + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " float depth = gl_FragDepthEXT / gl_FragCoord.w;", + + " #else", + + " float depth = gl_FragCoord.z / gl_FragCoord.w;", + + " #endif", + + " #ifdef FOG_EXP2", + + " const float LOG2 = 1.442695;", + " float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", + " fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + + " #else", + + " float fogFactor = smoothstep( fogNear, fogFar, depth );", + + " #endif", + + " gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + + "#endif" + + ].join("\n"), + + // ENVIRONMENT MAP + + envmap_pars_fragment: [ + + "#ifdef USE_ENVMAP", + + " uniform float reflectivity;", + " uniform samplerCube envMap;", + " uniform float flipEnvMap;", + " uniform int combine;", + + " #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + + " uniform bool useRefract;", + " uniform float refractionRatio;", + + " #else", + + " varying vec3 vReflect;", + + " #endif", + + "#endif" + + ].join("\n"), + + envmap_fragment: [ + + "#ifdef USE_ENVMAP", + + " vec3 reflectVec;", + + " #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + + " vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + + // http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations + // "Transforming Normal Vectors with the Inverse Transformation" + + " vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );", + + " if ( useRefract ) {", + + " reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );", + + " } else { ", + + " reflectVec = reflect( cameraToVertex, worldNormal );", + + " }", + + " #else", + + " reflectVec = vReflect;", + + " #endif", + + " #ifdef DOUBLE_SIDED", + + " float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + " vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + " #else", + + " vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + " #endif", + + " #ifdef GAMMA_INPUT", + + " cubeColor.xyz *= cubeColor.xyz;", + + " #endif", + + " if ( combine == 1 ) {", + + " gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", + + " } else if ( combine == 2 ) {", + + " gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", + + " } else {", + + " gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", + + " }", + + "#endif" + + ].join("\n"), + + envmap_pars_vertex: [ + + "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + + " varying vec3 vReflect;", + + " uniform float refractionRatio;", + " uniform bool useRefract;", + + "#endif" + + ].join("\n"), + + worldpos_vertex : [ + + "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", + + " #ifdef USE_SKINNING", + + " vec4 worldPosition = modelMatrix * skinned;", + + " #endif", + + " #if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + " vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", + + " #endif", + + " #if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + " vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + + " #endif", + + "#endif" + + ].join("\n"), + + envmap_vertex : [ + + "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + + " vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", + " worldNormal = normalize( worldNormal );", + + " vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", + + " if ( useRefract ) {", + + " vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", + + " } else {", + + " vReflect = reflect( cameraToVertex, worldNormal );", + + " }", + + "#endif" + + ].join("\n"), + + // COLOR MAP (particles) + + map_particle_pars_fragment: [ + + "#ifdef USE_MAP", + + " uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + + map_particle_fragment: [ + + "#ifdef USE_MAP", + + " gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", + + "#endif" + + ].join("\n"), + + // COLOR MAP (triangles) + + map_pars_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + " varying vec2 vUv;", + " uniform vec4 offsetRepeat;", + + "#endif" + + ].join("\n"), + + map_pars_fragment: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + " varying vec2 vUv;", + + "#endif", + + "#ifdef USE_MAP", + + " uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + map_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + " vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", + + "#endif" + + ].join("\n"), + + map_fragment: [ + + "#ifdef USE_MAP", + + " vec4 texelColor = texture2D( map, vUv );", + + " #ifdef GAMMA_INPUT", + + " texelColor.xyz *= texelColor.xyz;", + + " #endif", + + " gl_FragColor = gl_FragColor * texelColor;", + + "#endif" + + ].join("\n"), + + // LIGHT MAP + + lightmap_pars_fragment: [ + + "#ifdef USE_LIGHTMAP", + + " varying vec2 vUv2;", + " uniform sampler2D lightMap;", + + "#endif" + + ].join("\n"), + + lightmap_pars_vertex: [ + + "#ifdef USE_LIGHTMAP", + + " varying vec2 vUv2;", + + "#endif" + + ].join("\n"), + + lightmap_fragment: [ + + "#ifdef USE_LIGHTMAP", + + " gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", + + "#endif" + + ].join("\n"), + + lightmap_vertex: [ + + "#ifdef USE_LIGHTMAP", + + " vUv2 = uv2;", + + "#endif" + + ].join("\n"), + + // BUMP MAP + + bumpmap_pars_fragment: [ + + "#ifdef USE_BUMPMAP", + + " uniform sampler2D bumpMap;", + " uniform float bumpScale;", + + // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen + // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + + // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + + " vec2 dHdxy_fwd() {", + + " vec2 dSTdx = dFdx( vUv );", + " vec2 dSTdy = dFdy( vUv );", + + " float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", + " float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", + " float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", + + " return vec2( dBx, dBy );", + + " }", + + " vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", + + " vec3 vSigmaX = dFdx( surf_pos );", + " vec3 vSigmaY = dFdy( surf_pos );", + " vec3 vN = surf_norm;", // normalized + + " vec3 R1 = cross( vSigmaY, vN );", + " vec3 R2 = cross( vN, vSigmaX );", + + " float fDet = dot( vSigmaX, R1 );", + + " vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", + " return normalize( abs( fDet ) * surf_norm - vGrad );", + + " }", + + "#endif" + + ].join("\n"), + + // NORMAL MAP + + normalmap_pars_fragment: [ + + "#ifdef USE_NORMALMAP", + + " uniform sampler2D normalMap;", + " uniform vec2 normalScale;", + + // Per-Pixel Tangent Space Normal Mapping + // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + + " vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", + + " vec3 q0 = dFdx( eye_pos.xyz );", + " vec3 q1 = dFdy( eye_pos.xyz );", + " vec2 st0 = dFdx( vUv.st );", + " vec2 st1 = dFdy( vUv.st );", + + " vec3 S = normalize( q0 * st1.t - q1 * st0.t );", + " vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", + " vec3 N = normalize( surf_norm );", + + " vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", + " mapN.xy = normalScale * mapN.xy;", + " mat3 tsn = mat3( S, T, N );", + " return normalize( tsn * mapN );", + + " }", + + "#endif" + + ].join("\n"), + + // SPECULAR MAP + + specularmap_pars_fragment: [ + + "#ifdef USE_SPECULARMAP", + + " uniform sampler2D specularMap;", + + "#endif" + + ].join("\n"), + + specularmap_fragment: [ + + "float specularStrength;", + + "#ifdef USE_SPECULARMAP", + + " vec4 texelSpecular = texture2D( specularMap, vUv );", + " specularStrength = texelSpecular.r;", + + "#else", + + " specularStrength = 1.0;", + + "#endif" + + ].join("\n"), + + // LIGHTS LAMBERT + + lights_lambert_pars_vertex: [ + + "uniform vec3 ambient;", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + " uniform vec3 wrapRGB;", + + "#endif" + + ].join("\n"), + + lights_lambert_vertex: [ + + "vLightFront = vec3( 0.0 );", + + "#ifdef DOUBLE_SIDED", + + " vLightBack = vec3( 0.0 );", + + "#endif", + + "transformedNormal = normalize( transformedNormal );", + + "#if MAX_DIR_LIGHTS > 0", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + " vec3 dirVector = normalize( lDirection.xyz );", + + " float dotProduct = dot( transformedNormal, dirVector );", + " vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + " #ifdef DOUBLE_SIDED", + + " vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + " #ifdef WRAP_AROUND", + + " vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + " #endif", + + " #endif", + + " #ifdef WRAP_AROUND", + + " vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + " directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", + + " #ifdef DOUBLE_SIDED", + + " directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", + + " #endif", + + " #endif", + + " vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", + + " #ifdef DOUBLE_SIDED", + + " vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", + + " #endif", + + "}", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + " vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + " float lDistance = 1.0;", + " if ( pointLightDistance[ i ] > 0.0 )", + " lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + + " lVector = normalize( lVector );", + " float dotProduct = dot( transformedNormal, lVector );", + + " vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + " #ifdef DOUBLE_SIDED", + + " vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + " #ifdef WRAP_AROUND", + + " vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + " #endif", + + " #endif", + + " #ifdef WRAP_AROUND", + + " vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + " pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", + + " #ifdef DOUBLE_SIDED", + + " pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", + + " #endif", + + " #endif", + + " vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", + + " #ifdef DOUBLE_SIDED", + + " vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", + + " #endif", + + " }", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + " vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", + + " if ( spotEffect > spotLightAngleCos[ i ] ) {", + + " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + " float lDistance = 1.0;", + " if ( spotLightDistance[ i ] > 0.0 )", + " lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + + " lVector = normalize( lVector );", + + " float dotProduct = dot( transformedNormal, lVector );", + " vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + " #ifdef DOUBLE_SIDED", + + " vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + " #ifdef WRAP_AROUND", + + " vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + " #endif", + + " #endif", + + " #ifdef WRAP_AROUND", + + " vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + " spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", + + " #ifdef DOUBLE_SIDED", + + " spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", + + " #endif", + + " #endif", + + " vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", + + " #ifdef DOUBLE_SIDED", + + " vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", + + " #endif", + + " }", + + " }", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + " vec3 lVector = normalize( lDirection.xyz );", + + " float dotProduct = dot( transformedNormal, lVector );", + + " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + " float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", + + " vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + " #ifdef DOUBLE_SIDED", + + " vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", + + " #endif", + + " }", + + "#endif", + + "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", + + "#ifdef DOUBLE_SIDED", + + " vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", + + "#endif" + + ].join("\n"), + + // LIGHTS PHONG + + lights_phong_pars_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + " varying vec3 vWorldPosition;", + + "#endif" + + ].join("\n"), + + + lights_phong_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + " vWorldPosition = worldPosition.xyz;", + + "#endif" + + ].join("\n"), + + lights_phong_pars_fragment: [ + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + + " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + + " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + " varying vec3 vWorldPosition;", + + "#endif", + + "#ifdef WRAP_AROUND", + + " uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;" + + ].join("\n"), + + lights_phong_fragment: [ + + "vec3 normal = normalize( vNormal );", + "vec3 viewPosition = normalize( vViewPosition );", + + "#ifdef DOUBLE_SIDED", + + " normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "#ifdef USE_NORMALMAP", + + " normal = perturbNormal2Arb( -vViewPosition, normal );", + + "#elif defined( USE_BUMPMAP )", + + " normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " vec3 pointDiffuse = vec3( 0.0 );", + " vec3 pointSpecular = vec3( 0.0 );", + + " for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + " vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + " float lDistance = 1.0;", + " if ( pointLightDistance[ i ] > 0.0 )", + " lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + + " lVector = normalize( lVector );", + + // diffuse + + " float dotProduct = dot( normal, lVector );", + + " #ifdef WRAP_AROUND", + + " float pointDiffuseWeightFull = max( dotProduct, 0.0 );", + " float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + " vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + + " #else", + + " float pointDiffuseWeight = max( dotProduct, 0.0 );", + + " #endif", + + " pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", + + // specular + + " vec3 pointHalfVector = normalize( lVector + viewPosition );", + " float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + " float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", + " pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", + + " }", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " vec3 spotDiffuse = vec3( 0.0 );", + " vec3 spotSpecular = vec3( 0.0 );", + + " for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + " vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + " float lDistance = 1.0;", + " if ( spotLightDistance[ i ] > 0.0 )", + " lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + + " lVector = normalize( lVector );", + + " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + " if ( spotEffect > spotLightAngleCos[ i ] ) {", + + " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + // diffuse + + " float dotProduct = dot( normal, lVector );", + + " #ifdef WRAP_AROUND", + + " float spotDiffuseWeightFull = max( dotProduct, 0.0 );", + " float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + " vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + " #else", + + " float spotDiffuseWeight = max( dotProduct, 0.0 );", + + " #endif", + + " spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", + + // specular + + " vec3 spotHalfVector = normalize( lVector + viewPosition );", + " float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + " float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", + " spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", + + " }", + + " }", + + "#endif", + + "#if MAX_DIR_LIGHTS > 0", + + " vec3 dirDiffuse = vec3( 0.0 );", + " vec3 dirSpecular = vec3( 0.0 );" , + + " for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + " vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + " float dotProduct = dot( normal, dirVector );", + + " #ifdef WRAP_AROUND", + + " float dirDiffuseWeightFull = max( dotProduct, 0.0 );", + " float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + " vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", + + " #else", + + " float dirDiffuseWeight = max( dotProduct, 0.0 );", + + " #endif", + + " dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", + + // specular + + " vec3 dirHalfVector = normalize( dirVector + viewPosition );", + " float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + " float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + + /* + // fresnel term from skin shader + " const float F0 = 0.128;", + + " float base = 1.0 - dot( viewPosition, dirHalfVector );", + " float exponential = pow( base, 5.0 );", + + " float fresnel = exponential + F0 * ( 1.0 - exponential );", + */ + + /* + // fresnel term from fresnel shader + " const float mFresnelBias = 0.08;", + " const float mFresnelScale = 0.3;", + " const float mFresnelPower = 5.0;", + + " float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", + */ + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );", + " dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + + " }", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " vec3 hemiDiffuse = vec3( 0.0 );", + " vec3 hemiSpecular = vec3( 0.0 );" , + + " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + " vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + " float dotProduct = dot( normal, lVector );", + " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + " vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + " hemiDiffuse += diffuse * hemiColor;", + + // specular (sky light) + + " vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + " float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + " float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + + // specular (ground light) + + " vec3 lVectorGround = -lVector;", + + " vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + " float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + " float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + + " float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );", + " vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );", + " hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + " }", + + "#endif", + + "vec3 totalDiffuse = vec3( 0.0 );", + "vec3 totalSpecular = vec3( 0.0 );", + + "#if MAX_DIR_LIGHTS > 0", + + " totalDiffuse += dirDiffuse;", + " totalSpecular += dirSpecular;", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " totalDiffuse += hemiDiffuse;", + " totalSpecular += hemiSpecular;", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " totalDiffuse += pointDiffuse;", + " totalSpecular += pointSpecular;", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " totalDiffuse += spotDiffuse;", + " totalSpecular += spotSpecular;", + + "#endif", + + "#ifdef METAL", + + " gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", + + "#else", + + " gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + + "#endif" + + ].join("\n"), + + // VERTEX COLORS + + color_pars_fragment: [ + + "#ifdef USE_COLOR", + + " varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_fragment: [ + + "#ifdef USE_COLOR", + + " gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", + + "#endif" + + ].join("\n"), + + color_pars_vertex: [ + + "#ifdef USE_COLOR", + + " varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_vertex: [ + + "#ifdef USE_COLOR", + + " #ifdef GAMMA_INPUT", + + " vColor = color * color;", + + " #else", + + " vColor = color;", + + " #endif", + + "#endif" + + ].join("\n"), + + // SKINNING + + skinning_pars_vertex: [ + + "#ifdef USE_SKINNING", + + " #ifdef BONE_TEXTURE", + + " uniform sampler2D boneTexture;", + " uniform int boneTextureWidth;", + " uniform int boneTextureHeight;", + + " mat4 getBoneMatrix( const in float i ) {", + + " float j = i * 4.0;", + " float x = mod( j, float( boneTextureWidth ) );", + " float y = floor( j / float( boneTextureWidth ) );", + + " float dx = 1.0 / float( boneTextureWidth );", + " float dy = 1.0 / float( boneTextureHeight );", + + " y = dy * ( y + 0.5 );", + + " vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", + " vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", + " vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", + " vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", + + " mat4 bone = mat4( v1, v2, v3, v4 );", + + " return bone;", + + " }", + + " #else", + + " uniform mat4 boneGlobalMatrices[ MAX_BONES ];", + + " mat4 getBoneMatrix( const in float i ) {", + + " mat4 bone = boneGlobalMatrices[ int(i) ];", + " return bone;", + + " }", + + " #endif", + + "#endif" + + ].join("\n"), + + skinbase_vertex: [ + + "#ifdef USE_SKINNING", + + " mat4 boneMatX = getBoneMatrix( skinIndex.x );", + " mat4 boneMatY = getBoneMatrix( skinIndex.y );", + " mat4 boneMatZ = getBoneMatrix( skinIndex.z );", + " mat4 boneMatW = getBoneMatrix( skinIndex.w );", + + "#endif" + + ].join("\n"), + + skinning_vertex: [ + + "#ifdef USE_SKINNING", + + " #ifdef USE_MORPHTARGETS", + + " vec4 skinVertex = vec4( morphed, 1.0 );", + + " #else", + + " vec4 skinVertex = vec4( position, 1.0 );", + + " #endif", + + " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + " skinned += boneMatY * skinVertex * skinWeight.y;", + " skinned += boneMatZ * skinVertex * skinWeight.z;", + " skinned += boneMatW * skinVertex * skinWeight.w;", + + "#endif" + + ].join("\n"), + + // MORPHING + + morphtarget_pars_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + " #ifndef USE_MORPHNORMALS", + + " uniform float morphTargetInfluences[ 8 ];", + + " #else", + + " uniform float morphTargetInfluences[ 4 ];", + + " #endif", + + "#endif" + + ].join("\n"), + + morphtarget_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + " vec3 morphed = vec3( 0.0 );", + " morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", + " morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", + " morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", + " morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", + + " #ifndef USE_MORPHNORMALS", + + " morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", + " morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", + " morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", + " morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", + + " #endif", + + " morphed += position;", + + "#endif" + + ].join("\n"), + + default_vertex : [ + + "vec4 mvPosition;", + + "#ifdef USE_SKINNING", + + " mvPosition = modelViewMatrix * skinned;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", + + " mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", + + " mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#endif", + + "gl_Position = projectionMatrix * mvPosition;" + + ].join("\n"), + + morphnormal_vertex: [ + + "#ifdef USE_MORPHNORMALS", + + " vec3 morphedNormal = vec3( 0.0 );", + + " morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", + " morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", + " morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", + " morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", + + " morphedNormal += normal;", + + "#endif" + + ].join("\n"), + + skinnormal_vertex: [ + + "#ifdef USE_SKINNING", + + " mat4 skinMatrix = skinWeight.x * boneMatX;", + " skinMatrix += skinWeight.y * boneMatY;", + " skinMatrix += skinWeight.z * boneMatZ;", + " skinMatrix += skinWeight.w * boneMatW;", + + " #ifdef USE_MORPHNORMALS", + + " vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", + + " #else", + + " vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", + + " #endif", + + "#endif" + + ].join("\n"), + + defaultnormal_vertex: [ + + "vec3 objectNormal;", + + "#ifdef USE_SKINNING", + + " objectNormal = skinnedNormal.xyz;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", + + " objectNormal = morphedNormal;", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", + + " objectNormal = normal;", + + "#endif", + + "#ifdef FLIP_SIDED", + + " objectNormal = -objectNormal;", + + "#endif", + + "vec3 transformedNormal = normalMatrix * objectNormal;" + + ].join("\n"), + + // SHADOW MAP + + // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples + // http://spidergl.org/example.php?id=6 + // http://fabiensanglard.net/shadowmapping + + shadowmap_pars_fragment: [ + + "#ifdef USE_SHADOWMAP", + + " uniform sampler2D shadowMap[ MAX_SHADOWS ];", + " uniform vec2 shadowMapSize[ MAX_SHADOWS ];", + + " uniform float shadowDarkness[ MAX_SHADOWS ];", + " uniform float shadowBias[ MAX_SHADOWS ];", + + " varying vec4 vShadowCoord[ MAX_SHADOWS ];", + + " float unpackDepth( const in vec4 rgba_depth ) {", + + " const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", + " float depth = dot( rgba_depth, bit_shift );", + " return depth;", + + " }", + + "#endif" + + ].join("\n"), + + shadowmap_fragment: [ + + "#ifdef USE_SHADOWMAP", + + " #ifdef SHADOWMAP_DEBUG", + + " vec3 frustumColors[3];", + " frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", + " frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", + " frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", + + " #endif", + + " #ifdef SHADOWMAP_CASCADE", + + " int inFrustumCount = 0;", + + " #endif", + + " float fDepth;", + " vec3 shadowColor = vec3( 1.0 );", + + " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + " vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", + + // "if ( something && something )" breaks ATI OpenGL shader compiler + // "if ( all( something, something ) )" using this instead + + " bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", + " bool inFrustum = all( inFrustumVec );", + + // don't shadow pixels outside of light frustum + // use just first frustum (for cascades) + // don't shadow pixels behind far plane of light frustum + + " #ifdef SHADOWMAP_CASCADE", + + " inFrustumCount += int( inFrustum );", + " bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", + + " #else", + + " bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", + + " #endif", + + " bool frustumTest = all( frustumTestVec );", + + " if ( frustumTest ) {", + + " shadowCoord.z += shadowBias[ i ];", + + " #if defined( SHADOWMAP_TYPE_PCF )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + " float shadow = 0.0;", + + /* + // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL + // must enroll loop manually + + " for ( float y = -1.25; y <= 1.25; y += 1.25 )", + " for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", + + " vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", + + // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup + //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", + + " float fDepth = unpackDepth( rgbaDepth );", + + " if ( fDepth < shadowCoord.z )", + " shadow += 1.0;", + + " }", + + " shadow /= 9.0;", + + */ + + " const float shadowDelta = 1.0 / 9.0;", + + " float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + " float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + " float dx0 = -1.25 * xPixelOffset;", + " float dy0 = -1.25 * yPixelOffset;", + " float dx1 = 1.25 * xPixelOffset;", + " float dy1 = 1.25 * yPixelOffset;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + " shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + " #elif defined( SHADOWMAP_TYPE_PCF_SOFT )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + " float shadow = 0.0;", + + " float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + " float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + " float dx0 = -1.0 * xPixelOffset;", + " float dy0 = -1.0 * yPixelOffset;", + " float dx1 = 1.0 * xPixelOffset;", + " float dy1 = 1.0 * yPixelOffset;", + + " mat3 shadowKernel;", + " mat3 depthKernel;", + + " depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + " depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + " depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + " depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + " depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + " depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + " depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + " depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + " depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + + " vec3 shadowZ = vec3( shadowCoord.z );", + " shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", + " shadowKernel[0] *= vec3(0.25);", + + " shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", + " shadowKernel[1] *= vec3(0.25);", + + " shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", + " shadowKernel[2] *= vec3(0.25);", + + " vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", + + " shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", + " shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", + + " vec4 shadowValues;", + " shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", + " shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", + " shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", + " shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", + + " shadow = dot( shadowValues, vec4( 1.0 ) );", + + " shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + " #else", + + " vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", + " float fDepth = unpackDepth( rgbaDepth );", + + " if ( fDepth < shadowCoord.z )", + + // spot with multiple shadows is darker + + " shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", + + // spot with multiple shadows has the same color as single shadow spot + + //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", + + " #endif", + + " }", + + + " #ifdef SHADOWMAP_DEBUG", + + " #ifdef SHADOWMAP_CASCADE", + + " if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", + + " #else", + + " if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", + + " #endif", + + " #endif", + + " }", + + " #ifdef GAMMA_OUTPUT", + + " shadowColor *= shadowColor;", + + " #endif", + + " gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", + + "#endif" + + ].join("\n"), + + shadowmap_pars_vertex: [ + + "#ifdef USE_SHADOWMAP", + + " varying vec4 vShadowCoord[ MAX_SHADOWS ];", + " uniform mat4 shadowMatrix[ MAX_SHADOWS ];", + + "#endif" + + ].join("\n"), + + shadowmap_vertex: [ + + "#ifdef USE_SHADOWMAP", + + " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + " vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + " }", + + "#endif" + + ].join("\n"), + + // ALPHATEST + + alphatest_fragment: [ + + "#ifdef ALPHATEST", + + " if ( gl_FragColor.a < ALPHATEST ) discard;", + + "#endif" + + ].join("\n"), + + // LINEAR SPACE + + linear_to_gamma_fragment: [ + + "#ifdef GAMMA_OUTPUT", + + " gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", + + "#endif" + + ].join("\n"), + + // LOGARITHMIC DEPTH BUFFER + // http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html + + // WebGL doesn't support gl_FragDepth out of the box, unless the EXT_frag_depth extension is available. On platforms + // without EXT_frag_depth, we have to fall back on linear z-buffer in the fragment shader, which means that some long + // faces close to the camera may have issues. This can be worked around by tesselating the model more finely when + // the camera is near the surface. + + logdepthbuf_pars_vertex: [ + + "#ifdef USE_LOGDEPTHBUF", + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " varying float vFragDepth;", + + " #endif", + + " uniform float logDepthBufFC;", + + "#endif", + + ].join('\n'), + + logdepthbuf_vertex: [ + + "#ifdef USE_LOGDEPTHBUF", + + " gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * logDepthBufFC;", + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " vFragDepth = 1.0 + gl_Position.w;", + + "#else", + + " gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;", + + " #endif", + + "#endif" + + ].join("\n"), + + logdepthbuf_pars_fragment: [ + + "#ifdef USE_LOGDEPTHBUF", + + " uniform float logDepthBufFC;", + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " #extension GL_EXT_frag_depth : enable", + " varying float vFragDepth;", + + " #endif", + + "#endif" + + ].join('\n'), + + logdepthbuf_fragment: [ + "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)", + + " gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;", + + "#endif" + + ].join("\n") + +}; + +/** + * Uniform Utilities + */ + +THREE.UniformsUtils = { + + merge: function ( uniforms ) { + + var u, p, tmp, merged = {}; + + for ( u = 0; u < uniforms.length; u ++ ) { + + tmp = this.clone( uniforms[ u ] ); + + for ( p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + }, + + clone: function ( uniforms_src ) { + + var u, p, parameter, parameter_src, uniforms_dst = {}; + + for ( u in uniforms_src ) { + + uniforms_dst[ u ] = {}; + + for ( p in uniforms_src[ u ] ) { + + parameter_src = uniforms_src[ u ][ p ]; + + if ( parameter_src instanceof THREE.Color || + parameter_src instanceof THREE.Vector2 || + parameter_src instanceof THREE.Vector3 || + parameter_src instanceof THREE.Vector4 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { + + uniforms_dst[ u ][ p ] = parameter_src.clone(); + + } else if ( parameter_src instanceof Array ) { + + uniforms_dst[ u ][ p ] = parameter_src.slice(); + + } else { + + uniforms_dst[ u ][ p ] = parameter_src; + + } + + } + + } + + return uniforms_dst; + + } + +}; +/** + * Uniforms library for shared webgl shaders + */ + +THREE.UniformsLib = { + + common: { + + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + + "lightMap" : { type: "t", value: null }, + "specularMap" : { type: "t", value: null }, + + "envMap" : { type: "t", value: null }, + "flipEnvMap" : { type: "f", value: -1 }, + "useRefract" : { type: "i", value: 0 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 }, + "combine" : { type: "i", value: 0 }, + + "morphTargetInfluences" : { type: "f", value: 0 } + + }, + + bump: { + + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 } + + }, + + normalmap: { + + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } + }, + + fog : { + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + lights: { + + "ambientLightColor" : { type: "fv", value: [] }, + + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, + + "hemisphereLightDirection" : { type: "fv", value: [] }, + "hemisphereLightSkyColor" : { type: "fv", value: [] }, + "hemisphereLightGroundColor" : { type: "fv", value: [] }, + + "pointLightColor" : { type: "fv", value: [] }, + "pointLightPosition" : { type: "fv", value: [] }, + "pointLightDistance" : { type: "fv1", value: [] }, + + "spotLightColor" : { type: "fv", value: [] }, + "spotLightPosition" : { type: "fv", value: [] }, + "spotLightDirection" : { type: "fv", value: [] }, + "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightAngleCos" : { type: "fv1", value: [] }, + "spotLightExponent" : { type: "fv1", value: [] } + + }, + + particle: { + + "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + "size" : { type: "f", value: 1.0 }, + "scale" : { type: "f", value: 1.0 }, + "map" : { type: "t", value: null }, + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + shadowmap: { + + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, + + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, + + "shadowMatrix" : { type: "m4v", value: [] } + + } + +}; +/** + * Webgl Shader Library for three.js + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ + + +THREE.ShaderLib = { + + 'basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + + " #ifdef USE_ENVMAP", + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + " #endif", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'lambert': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define LAMBERT", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + " varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + " varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + " #ifdef DOUBLE_SIDED", + + //"float isFront = float( gl_FrontFacing );", + //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", + + " if ( gl_FrontFacing )", + " gl_FragColor.xyz *= vLightFront;", + " else", + " gl_FragColor.xyz *= vLightBack;", + + " #else", + + " gl_FragColor.xyz *= vLightFront;", + + " #endif", + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'phong': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bump" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define PHONG", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_phong_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + " vNormal = normalize( transformedNormal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + " vViewPosition = -mvPosition.xyz;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform vec3 ambient;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_phong_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + THREE.ShaderChunk[ "lights_phong_fragment" ], + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'particle_basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "particle" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + "uniform float size;", + "uniform float scale;", + + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + " #ifdef USE_SIZEATTENUATION", + " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + " #else", + " gl_PointSize = size;", + " #endif", + + " gl_Position = projectionMatrix * mvPosition;", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 psColor;", + "uniform float opacity;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_particle_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = vec4( psColor, opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_particle_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'dashed': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + + { + "scale": { type: "f", value: 1 }, + "dashSize": { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } + + ] ), + + vertexShader: [ + + "uniform float scale;", + "attribute float lineDistance;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + " vLineDistance = scale * lineDistance;", + + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * mvPosition;", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform float dashSize;", + "uniform float totalSize;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " if ( mod( vLineDistance, totalSize ) > dashSize ) {", + + " discard;", + + " }", + + " gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'depth': { + + uniforms: { + + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " float depth = gl_FragDepthEXT / gl_FragCoord.w;", + + " #else", + + " float depth = gl_FragCoord.z / gl_FragCoord.w;", + + " #endif", + + " float color = 1.0 - smoothstep( mNear, mFar, depth );", + " gl_FragColor = vec4( vec3( color ), opacity );", + + "}" + + ].join("\n") + + }, + + 'normal': { + + uniforms: { + + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + " vNormal = normalize( normalMatrix * normal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Normal map shader + // - Blinn-Phong + // - normal + diffuse + specular + AO + displacement + reflection + shadow maps + // - point and directional lights (use with "lights: true" material option) + ------------------------------------------------------------------------- */ + + 'normalmap' : { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + + "enableAO" : { type: "i", value: 0 }, + "enableDiffuse" : { type: "i", value: 0 }, + "enableSpecular" : { type: "i", value: 0 }, + "enableReflection": { type: "i", value: 0 }, + "enableDisplacement": { type: "i", value: 0 }, + + "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture + "tDiffuse" : { type: "t", value: null }, + "tCube" : { type: "t", value: null }, + "tNormal" : { type: "t", value: null }, + "tSpecular" : { type: "t", value: null }, + "tAO" : { type: "t", value: null }, + + "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "uDisplacementBias": { type: "f", value: 0.0 }, + "uDisplacementScale": { type: "f", value: 1.0 }, + + "diffuse": { type: "c", value: new THREE.Color( 0xffffff ) }, + "specular": { type: "c", value: new THREE.Color( 0x111111 ) }, + "ambient": { type: "c", value: new THREE.Color( 0xffffff ) }, + "shininess": { type: "f", value: 30 }, + "opacity": { type: "f", value: 1 }, + + "useRefract": { type: "i", value: 0 }, + "refractionRatio": { type: "f", value: 0.98 }, + "reflectivity": { type: "f", value: 0.5 }, + + "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, + "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + + } + + ] ), + + fragmentShader: [ + + "uniform vec3 ambient;", + "uniform vec3 diffuse;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", + + "uniform bool enableDiffuse;", + "uniform bool enableSpecular;", + "uniform bool enableAO;", + "uniform bool enableReflection;", + + "uniform sampler2D tDiffuse;", + "uniform sampler2D tNormal;", + "uniform sampler2D tSpecular;", + "uniform sampler2D tAO;", + + "uniform samplerCube tCube;", + + "uniform vec2 uNormalScale;", + + "uniform bool useRefract;", + "uniform float refractionRatio;", + "uniform float reflectivity;", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + " uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + + " vec3 specularTex = vec3( 1.0 );", + + " vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", + " normalTex.xy *= uNormalScale;", + " normalTex = normalize( normalTex );", + + " if( enableDiffuse ) {", + + " #ifdef GAMMA_INPUT", + + " vec4 texelColor = texture2D( tDiffuse, vUv );", + " texelColor.xyz *= texelColor.xyz;", + + " gl_FragColor = gl_FragColor * texelColor;", + + " #else", + + " gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", + + " #endif", + + " }", + + " if( enableAO ) {", + + " #ifdef GAMMA_INPUT", + + " vec4 aoColor = texture2D( tAO, vUv );", + " aoColor.xyz *= aoColor.xyz;", + + " gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", + + " #else", + + " gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", + + " #endif", + + " }", + + " if( enableSpecular )", + " specularTex = texture2D( tSpecular, vUv ).xyz;", + + " mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", + " vec3 finalNormal = tsb * normalTex;", + + " #ifdef FLIP_SIDED", + + " finalNormal = -finalNormal;", + + " #endif", + + " vec3 normal = normalize( finalNormal );", + " vec3 viewPosition = normalize( vViewPosition );", + + // point lights + + " #if MAX_POINT_LIGHTS > 0", + + " vec3 pointDiffuse = vec3( 0.0 );", + " vec3 pointSpecular = vec3( 0.0 );", + + " for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + " vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", + + " float pointDistance = 1.0;", + " if ( pointLightDistance[ i ] > 0.0 )", + " pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", + + " pointVector = normalize( pointVector );", + + // diffuse + + " #ifdef WRAP_AROUND", + + " float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", + " float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", + + " vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + + " #else", + + " float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", + + " #endif", + + " pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;", + + // specular + + " vec3 pointHalfVector = normalize( pointVector + viewPosition );", + " float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + " float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", + " pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", + + " }", + + " #endif", + + // spot lights + + " #if MAX_SPOT_LIGHTS > 0", + + " vec3 spotDiffuse = vec3( 0.0 );", + " vec3 spotSpecular = vec3( 0.0 );", + + " for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + " vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", + + " float spotDistance = 1.0;", + " if ( spotLightDistance[ i ] > 0.0 )", + " spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", + + " spotVector = normalize( spotVector );", + + " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + " if ( spotEffect > spotLightAngleCos[ i ] ) {", + + " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + // diffuse + + " #ifdef WRAP_AROUND", + + " float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", + " float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", + + " vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + " #else", + + " float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", + + " #endif", + + " spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;", + + // specular + + " vec3 spotHalfVector = normalize( spotVector + viewPosition );", + " float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + " float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", + " spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", + + " }", + + " }", + + " #endif", + + // directional lights + + " #if MAX_DIR_LIGHTS > 0", + + " vec3 dirDiffuse = vec3( 0.0 );", + " vec3 dirSpecular = vec3( 0.0 );", + + " for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", + + " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + " vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + " #ifdef WRAP_AROUND", + + " float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", + " float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", + + " vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", + + " #else", + + " float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + + " #endif", + + " dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;", + + // specular + + " vec3 dirHalfVector = normalize( dirVector + viewPosition );", + " float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + " float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", + " dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + " }", + + " #endif", + + // hemisphere lights + + " #if MAX_HEMI_LIGHTS > 0", + + " vec3 hemiDiffuse = vec3( 0.0 );", + " vec3 hemiSpecular = vec3( 0.0 );" , + + " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + " vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + " float dotProduct = dot( normal, lVector );", + " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + " vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + " hemiDiffuse += diffuse * hemiColor;", + + // specular (sky light) + + + " vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + " float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + " float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + + // specular (ground light) + + " vec3 lVectorGround = -lVector;", + + " vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + " float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + " float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + + " float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + " vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", + " vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", + " hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + " }", + + " #endif", + + // all lights contribution summation + + " vec3 totalDiffuse = vec3( 0.0 );", + " vec3 totalSpecular = vec3( 0.0 );", + + " #if MAX_DIR_LIGHTS > 0", + + " totalDiffuse += dirDiffuse;", + " totalSpecular += dirSpecular;", + + " #endif", + + " #if MAX_HEMI_LIGHTS > 0", + + " totalDiffuse += hemiDiffuse;", + " totalSpecular += hemiSpecular;", + + " #endif", + + " #if MAX_POINT_LIGHTS > 0", + + " totalDiffuse += pointDiffuse;", + " totalSpecular += pointSpecular;", + + " #endif", + + " #if MAX_SPOT_LIGHTS > 0", + + " totalDiffuse += spotDiffuse;", + " totalSpecular += spotSpecular;", + + " #endif", + + " #ifdef METAL", + + " gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );", + + " #else", + + " gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + + " #endif", + + " if ( enableReflection ) {", + + " vec3 vReflect;", + " vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + + " if ( useRefract ) {", + + " vReflect = refract( cameraToVertex, normal, refractionRatio );", + + " } else {", + + " vReflect = reflect( cameraToVertex, normal );", + + " }", + + " vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", + + " #ifdef GAMMA_INPUT", + + " cubeColor.xyz *= cubeColor.xyz;", + + " #endif", + + " gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );", + + " }", + + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n"), + + vertexShader: [ + + "attribute vec4 tangent;", + + "uniform vec2 uOffset;", + "uniform vec2 uRepeat;", + + "uniform bool enableDisplacement;", + + "#ifdef VERTEX_TEXTURES", + + " uniform sampler2D tDisplacement;", + " uniform float uDisplacementScale;", + " uniform float uDisplacementBias;", + + "#endif", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + + // normal, tangent and binormal vectors + + " #ifdef USE_SKINNING", + + " vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + + " vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", + " vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + + " #else", + + " vNormal = normalize( normalMatrix * normal );", + " vTangent = normalize( normalMatrix * tangent.xyz );", + + " #endif", + + " vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + + " vUv = uv * uRepeat + uOffset;", + + // displacement mapping + + " vec3 displacedPosition;", + + " #ifdef VERTEX_TEXTURES", + + " if ( enableDisplacement ) {", + + " vec3 dv = texture2D( tDisplacement, uv ).xyz;", + " float df = uDisplacementScale * dv.x + uDisplacementBias;", + " displacedPosition = position + normalize( normal ) * df;", + + " } else {", + + " #ifdef USE_SKINNING", + + " vec4 skinVertex = vec4( position, 1.0 );", + + " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + " skinned += boneMatY * skinVertex * skinWeight.y;", + " skinned += boneMatZ * skinVertex * skinWeight.z;", + " skinned += boneMatW * skinVertex * skinWeight.w;", + + " displacedPosition = skinned.xyz;", + + " #else", + + " displacedPosition = position;", + + " #endif", + + " }", + + " #else", + + " #ifdef USE_SKINNING", + + " vec4 skinVertex = vec4( position, 1.0 );", + + " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + " skinned += boneMatY * skinVertex * skinWeight.y;", + " skinned += boneMatZ * skinVertex * skinWeight.z;", + " skinned += boneMatW * skinVertex * skinWeight.w;", + + " displacedPosition = skinned.xyz;", + + " #else", + + " displacedPosition = position;", + + " #endif", + + " #endif", + + // + + " vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", + " vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + + " gl_Position = projectionMatrix * mvPosition;", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + // + + " vWorldPosition = worldPosition.xyz;", + " vViewPosition = -mvPosition.xyz;", + + // shadows + + " #ifdef USE_SHADOWMAP", + + " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + " vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + " }", + + " #endif", + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ + + 'cube': { + + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: -1 } }, + + vertexShader: [ + + "varying vec3 vWorldPosition;", + + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + " vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + " vWorldPosition = worldPosition.xyz;", + + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform samplerCube tCube;", + "uniform float tFlip;", + + "varying vec3 vWorldPosition;", + + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "void main() {", + + " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + "}" + + ].join("\n") + + }, + + // Depth encoding into RGBA texture + // based on SpiderGL shadow map example + // http://spidergl.org/example.php?id=6 + // originally from + // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + // see also here: + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + + 'depthRGBA': { + + uniforms: {}, + + vertexShader: [ + + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + + "vec4 pack_depth( const in float depth ) {", + + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", + + "}", + + "void main() {", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", + + " #else", + + " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + + " #endif", + + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + + "}" + + ].join("\n") + + } + +}; + +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +THREE.WebGLRenderer = function ( parameters ) { + + console.log( 'THREE.WebGLRenderer', THREE.REVISION ); + + parameters = parameters || {}; + + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, + + _precision = parameters.precision !== undefined ? parameters.precision : 'highp', + + _buffers = {}, + + _alpha = parameters.alpha !== undefined ? parameters.alpha : false, + _depth = parameters.depth !== undefined ? parameters.depth : true, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, + + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = 0; + + // public properties + + this.domElement = _canvas; + this.context = null; + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : self.devicePixelRatio !== undefined + ? self.devicePixelRatio + : 1; + + // clearing + + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; + + // scene graph + + this.sortObjects = true; + this.autoUpdateObjects = true; + + // physically based shading + + this.gammaInput = false; + this.gammaOutput = false; + + // shadow map + + this.shadowMapEnabled = false; + this.shadowMapAutoUpdate = true; + this.shadowMapType = THREE.PCFShadowMap; + this.shadowMapCullFace = THREE.CullFaceFront; + this.shadowMapDebug = false; + this.shadowMapCascade = false; + + // morphs + + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; + + // flags + + this.autoScaleCubemaps = true; + + // custom render plugins + + this.renderPluginsPre = []; + this.renderPluginsPost = []; + + // info + + this.info = { + + memory: { + + programs: 0, + geometries: 0, + textures: 0 + + }, + + render: { + + calls: 0, + vertices: 0, + faces: 0, + points: 0 + + } + + }; + + // internal properties + + var _this = this, + + _programs = [], + + // internal state cache + + _currentProgram = null, + _currentFramebuffer = null, + _currentMaterialId = -1, + _currentGeometryGroupHash = null, + _currentCamera = null, + + _usedTextureUnits = 0, + + // GL state cache + + _oldDoubleSided = -1, + _oldFlipSided = -1, + + _oldBlending = -1, + + _oldBlendEquation = -1, + _oldBlendSrc = -1, + _oldBlendDst = -1, + + _oldDepthTest = -1, + _oldDepthWrite = -1, + + _oldPolygonOffset = null, + _oldPolygonOffsetFactor = null, + _oldPolygonOffsetUnits = null, + + _oldLineWidth = null, + + _viewportX = 0, + _viewportY = 0, + _viewportWidth = _canvas.width, + _viewportHeight = _canvas.height, + _currentWidth = 0, + _currentHeight = 0, + + _newAttributes = new Uint8Array( 16 ), + _enabledAttributes = new Uint8Array( 16 ), + + // frustum + + _frustum = new THREE.Frustum(), + + // camera matrices cache + + _projScreenMatrix = new THREE.Matrix4(), + _projScreenMatrixPS = new THREE.Matrix4(), + + _vector3 = new THREE.Vector3(), + + // light arrays cache + + _direction = new THREE.Vector3(), + + _lightsNeedUpdate = true, + + _lights = { + + ambient: [ 0, 0, 0 ], + directional: { length: 0, colors: new Array(), positions: new Array() }, + point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, + spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, + hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } + + }; + + // initialize + + var _gl; + + var _glExtensionTextureFloat; + var _glExtensionTextureFloatLinear; + var _glExtensionStandardDerivatives; + var _glExtensionTextureFilterAnisotropic; + var _glExtensionCompressedTextureS3TC; + var _glExtensionElementIndexUint; + var _glExtensionFragDepth; + + + initGL(); + + setDefaultGLState(); + + this.context = _gl; + + // GPU capabilities + + var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); + var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); + var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); + + var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; + + var _supportsVertexTextures = ( _maxVertexTextures > 0 ); + var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; + + var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; + + // + + var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); + var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); + var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); + + var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); + var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); + var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); + + var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); + var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); + var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); + + var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); + var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); + var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); + + // clamp precision to maximum available + + var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; + var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; + + if ( _precision === "highp" && ! highpAvailable ) { + + if ( mediumpAvailable ) { + + _precision = "mediump"; + console.warn( "WebGLRenderer: highp not supported, using mediump" ); + + } else { + + _precision = "lowp"; + console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); + + } + + } + + if ( _precision === "mediump" && ! mediumpAvailable ) { + + _precision = "lowp"; + console.warn( "WebGLRenderer: mediump not supported, using lowp" ); + + } + + // API + + this.getContext = function () { + + return _gl; + + }; + + this.supportsVertexTextures = function () { + + return _supportsVertexTextures; + + }; + + this.supportsFloatTextures = function () { + + return _glExtensionTextureFloat; + + }; + + this.supportsStandardDerivatives = function () { + + return _glExtensionStandardDerivatives; + + }; + + this.supportsCompressedTextureS3TC = function () { + + return _glExtensionCompressedTextureS3TC; + + }; + + this.getMaxAnisotropy = function () { + + return _maxAnisotropy; + + }; + + this.getPrecision = function () { + + return _precision; + + }; + + this.setSize = function ( width, height, updateStyle ) { + + _canvas.width = width * this.devicePixelRatio; + _canvas.height = height * this.devicePixelRatio; + + if ( this.devicePixelRatio !== 1 && 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 ) { + + _viewportX = x * this.devicePixelRatio; + _viewportY = y * this.devicePixelRatio; + + _viewportWidth = width * this.devicePixelRatio; + _viewportHeight = height * this.devicePixelRatio; + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + }; + + this.setScissor = function ( x, y, width, height ) { + + _gl.scissor( + x * this.devicePixelRatio, + y * this.devicePixelRatio, + width * this.devicePixelRatio, + height * this.devicePixelRatio + ); + + }; + + this.enableScissorTest = function ( enable ) { + + enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); + + }; + + // Clearing + + this.setClearColor = function ( color, alpha ) { + + _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + this.setClearColorHex = function ( hex, alpha ) { + + console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + this.setClearColor( hex, alpha ); + + }; + + this.getClearColor = function () { + + return _clearColor; + + }; + + this.getClearAlpha = function () { + + return _clearAlpha; + + }; + + this.clear = function ( color, depth, stencil ) { + + var bits = 0; + + if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; + if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; + + _gl.clear( bits ); + + }; + + this.clearColor = function () { + + _gl.clear( _gl.COLOR_BUFFER_BIT ); + + }; + + this.clearDepth = function () { + + _gl.clear( _gl.DEPTH_BUFFER_BIT ); + + }; + + this.clearStencil = function () { + + _gl.clear( _gl.STENCIL_BUFFER_BIT ); + + }; + + this.clearTarget = function ( renderTarget, color, depth, stencil ) { + + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); + + }; + + // Plugins + + this.addPostPlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPost.push( plugin ); + + }; + + this.addPrePlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPre.push( plugin ); + + }; + + // Rendering + + this.updateShadowMap = function ( scene, camera ) { + + _currentProgram = null; + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + _lightsNeedUpdate = true; + _oldDoubleSided = -1; + _oldFlipSided = -1; + + this.shadowMapPlugin.update( scene, camera ); + + }; + + // Internal functions + + // Buffer allocation + + function createParticleBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createLineBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + geometry.__webglLineDistanceBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createMeshBuffers ( geometryGroup ) { + + geometryGroup.__webglVertexBuffer = _gl.createBuffer(); + geometryGroup.__webglNormalBuffer = _gl.createBuffer(); + geometryGroup.__webglTangentBuffer = _gl.createBuffer(); + geometryGroup.__webglColorBuffer = _gl.createBuffer(); + geometryGroup.__webglUVBuffer = _gl.createBuffer(); + geometryGroup.__webglUV2Buffer = _gl.createBuffer(); + + geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); + geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); + + geometryGroup.__webglFaceBuffer = _gl.createBuffer(); + geometryGroup.__webglLineBuffer = _gl.createBuffer(); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__webglMorphTargetsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__webglMorphNormalsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); + + } + + } + + _this.info.memory.geometries ++; + + }; + + // Events + + var onGeometryDispose = function ( event ) { + + var geometry = event.target; + + geometry.removeEventListener( 'dispose', onGeometryDispose ); + + deallocateGeometry( geometry ); + + }; + + var onTextureDispose = function ( event ) { + + var texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + deallocateTexture( texture ); + + _this.info.memory.textures --; + + + }; + + var onRenderTargetDispose = function ( event ) { + + var renderTarget = event.target; + + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + + deallocateRenderTarget( renderTarget ); + + _this.info.memory.textures --; + + }; + + var onMaterialDispose = function ( event ) { + + var material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + deallocateMaterial( material ); + + }; + + // Buffer deallocation + + var deleteBuffers = function ( geometry ) { + + if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); + if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); + if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); + if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); + if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); + if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); + + if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); + if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); + + if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); + if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); + + if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); + // custom attributes + + if ( geometry.__webglCustomAttributesList !== undefined ) { + + for ( var id in geometry.__webglCustomAttributesList ) { + + _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); + + } + + } + + _this.info.memory.geometries --; + + }; + + var deallocateGeometry = function ( geometry ) { + + geometry.__webglInit = undefined; + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + + for ( var key in attributes ) { + + if ( attributes[ key ].buffer !== undefined ) { + + _gl.deleteBuffer( attributes[ key ].buffer ); + + } + + } + + _this.info.memory.geometries --; + + } else { + + if ( geometry.geometryGroups !== undefined ) { + + for ( var g in geometry.geometryGroups ) { + + var geometryGroup = geometry.geometryGroups[ g ]; + + if ( geometryGroup.numMorphTargets !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); + + } + + } + + if ( geometryGroup.numMorphNormals !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); + + } + + } + + deleteBuffers( geometryGroup ); + + } + + } else { + + deleteBuffers( geometry ); + + } + + } + + }; + + var deallocateTexture = function ( texture ) { + + if ( texture.image && texture.image.__webglTextureCube ) { + + // cube texture + + _gl.deleteTexture( texture.image.__webglTextureCube ); + + } else { + + // 2D texture + + if ( ! texture.__webglInit ) return; + + texture.__webglInit = false; + _gl.deleteTexture( texture.__webglTexture ); + + } + + }; + + var deallocateRenderTarget = function ( renderTarget ) { + + if ( !renderTarget || ! renderTarget.__webglTexture ) return; + + _gl.deleteTexture( renderTarget.__webglTexture ); + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + for ( var i = 0; i < 6; i ++ ) { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); + + } + + } else { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); + + } + + }; + + var deallocateMaterial = function ( material ) { + + var program = material.program; + + if ( program === undefined ) return; + + material.program = undefined; + + // only deallocate GL program if this was the last use of shared program + // assumed there is only single copy of any program in the _programs list + // (that's how it's constructed) + + var i, il, programInfo; + var deleteProgram = false; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program === program ) { + + programInfo.usedTimes --; + + if ( programInfo.usedTimes === 0 ) { + + deleteProgram = true; + + } + + break; + + } + + } + + if ( deleteProgram === true ) { + + // avoid using array.splice, this is costlier than creating new array from scratch + + var newPrograms = []; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program !== program ) { + + newPrograms.push( programInfo ); + + } + + } + + _programs = newPrograms; + + _gl.deleteProgram( program ); + + _this.info.memory.programs --; + + } + + }; + + // Buffer initialization + + function initCustomAttributes ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + var material = object.material; + + if ( material.attributes ) { + + if ( geometry.__webglCustomAttributesList === undefined ) { + + geometry.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + var attribute = material.attributes[ a ]; + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if ( attribute.type === "v2" ) size = 2; + else if ( attribute.type === "v3" ) size = 3; + else if ( attribute.type === "v4" ) size = 4; + else if ( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + attribute.needsUpdate = true; + + } + + geometry.__webglCustomAttributesList.push( attribute ); + + } + + } + + }; + + function initParticleBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + + geometry.__sortArray = []; + + geometry.__webglParticleCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initLineBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); + + geometry.__webglLineCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initMeshBuffers ( geometryGroup, object ) { + + var geometry = object.geometry, + faces3 = geometryGroup.faces3, + + nvertices = faces3.length * 3, + ntris = faces3.length * 1, + nlines = faces3.length * 3, + + material = getBufferMaterial( object, geometryGroup ), + + uvType = bufferGuessUVType( material ), + normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ); + + // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); + + geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + + if ( normalType ) { + + geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + + } + + if ( geometry.hasTangents ) { + + geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); + + } + + if ( vertexColorType ) { + + geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + + } + + if ( uvType ) { + + if ( geometry.faceVertexUvs.length > 0 ) { + + geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); + + } + + if ( geometry.faceVertexUvs.length > 1 ) { + + geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); + + } + + } + + if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { + + geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); + geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); + + } + + var UintArray = _glExtensionElementIndexUint !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 + + geometryGroup.__typeArray = UintArray; + geometryGroup.__faceArray = new UintArray( ntris * 3 ); + geometryGroup.__lineArray = new UintArray( nlines * 2 ); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__morphTargetsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__morphNormalsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + geometryGroup.__webglFaceCount = ntris * 3; + geometryGroup.__webglLineCount = nlines * 2; + + + // custom attributes + + if ( material.attributes ) { + + if ( geometryGroup.__webglCustomAttributesList === undefined ) { + + geometryGroup.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + // Do a shallow copy of the attribute object so different geometryGroup chunks use different + // attribute buffers which are correctly indexed in the setMeshBuffers function + + var originalAttribute = material.attributes[ a ]; + + var attribute = {}; + + for ( var property in originalAttribute ) { + + attribute[ property ] = originalAttribute[ property ]; + + } + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if( attribute.type === "v2" ) size = 2; + else if( attribute.type === "v3" ) size = 3; + else if( attribute.type === "v4" ) size = 4; + else if( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + originalAttribute.needsUpdate = true; + attribute.__original = originalAttribute; + + } + + geometryGroup.__webglCustomAttributesList.push( attribute ); + + } + + } + + geometryGroup.__inittedArrays = true; + + }; + + function getBufferMaterial( object, geometryGroup ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ geometryGroup.materialIndex ] + : object.material; + + }; + + function materialNeedsSmoothNormals ( material ) { + + return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + + }; + + function bufferGuessNormalType ( material ) { + + // only MeshBasicMaterial and MeshDepthMaterial don't need normals + + if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { + + return false; + + } + + if ( materialNeedsSmoothNormals( material ) ) { + + return THREE.SmoothShading; + + } else { + + return THREE.FlatShading; + + } + + }; + + function bufferGuessVertexColorType( material ) { + + if ( material.vertexColors ) { + + return material.vertexColors; + + } + + return false; + + }; + + function bufferGuessUVType( material ) { + + // material must use some texture to require uvs + + if ( material.map || + material.lightMap || + material.bumpMap || + material.normalMap || + material.specularMap || + material instanceof THREE.ShaderMaterial ) { + + return true; + + } + + return false; + + }; + + // + + function initDirectBuffers( geometry ) { + + for ( var name in geometry.attributes ) { + + var bufferType = ( name === "index" ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; + + var attribute = geometry.attributes[ name ]; + attribute.buffer = _gl.createBuffer(); + + _gl.bindBuffer( bufferType, attribute.buffer ); + _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW ); + + } + + } + + // Buffer setting + + function setParticleBuffers ( geometry, hint, object ) { + + var v, c, vertex, offset, index, color, + + vertices = geometry.vertices, + vl = vertices.length, + + colors = geometry.colors, + cl = colors.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + + sortArray = geometry.__sortArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + i, il, + a, ca, cal, value, + customAttribute; + + if ( object.sortParticles ) { + + _projScreenMatrixPS.copy( _projScreenMatrix ); + _projScreenMatrixPS.multiply( object.matrixWorld ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + _vector3.copy( vertex ); + _vector3.applyProjection( _projScreenMatrixPS ); + + sortArray[ v ] = [ _vector3.z, v ]; + + } + + sortArray.sort( numericalSort ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ sortArray[v][1] ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + for ( c = 0; c < cl; c ++ ) { + + offset = c * 3; + + color = colors[ sortArray[c][1] ]; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + customAttribute.array[ ca ] = customAttribute.value[ index ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } else { + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices") ) { + + cal = customAttribute.value.length; + + offset = 0; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } + + } + + if ( dirtyVertices || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + } + + function setLineBuffers ( geometry, hint ) { + + var v, c, d, vertex, offset, color, + + vertices = geometry.vertices, + colors = geometry.colors, + lineDistances = geometry.lineDistances, + + vl = vertices.length, + cl = colors.length, + dl = lineDistances.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + lineDistanceArray = geometry.__lineDistanceArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyLineDistances = geometry.lineDistancesNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + + i, il, + a, ca, cal, value, + customAttribute; + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( dirtyLineDistances ) { + + for ( d = 0; d < dl; d ++ ) { + + lineDistanceArray[ d ] = lineDistances[ d ]; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices" ) ) { + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + } + + function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { + + if ( ! geometryGroup.__inittedArrays ) { + + return; + + } + + var normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ), + uvType = bufferGuessUVType( material ), + + needsSmoothNormals = ( normalType === THREE.SmoothShading ); + + var f, fl, fi, face, + vertexNormals, faceNormal, normal, + vertexColors, faceColor, + vertexTangents, + uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, + c1, c2, c3, c4, + sw1, sw2, sw3, sw4, + si1, si2, si3, si4, + sa1, sa2, sa3, sa4, + sb1, sb2, sb3, sb4, + m, ml, i, il, + vn, uvi, uv2i, + vk, vkl, vka, + nka, chf, faceVertexNormals, + a, + + vertexIndex = 0, + + offset = 0, + offset_uv = 0, + offset_uv2 = 0, + offset_face = 0, + offset_normal = 0, + offset_tangent = 0, + offset_line = 0, + offset_color = 0, + offset_skin = 0, + offset_morphTarget = 0, + offset_custom = 0, + offset_customSrc = 0, + + value, + + vertexArray = geometryGroup.__vertexArray, + uvArray = geometryGroup.__uvArray, + uv2Array = geometryGroup.__uv2Array, + normalArray = geometryGroup.__normalArray, + tangentArray = geometryGroup.__tangentArray, + colorArray = geometryGroup.__colorArray, + + skinIndexArray = geometryGroup.__skinIndexArray, + skinWeightArray = geometryGroup.__skinWeightArray, + + morphTargetsArrays = geometryGroup.__morphTargetsArrays, + morphNormalsArrays = geometryGroup.__morphNormalsArrays, + + customAttributes = geometryGroup.__webglCustomAttributesList, + customAttribute, + + faceArray = geometryGroup.__faceArray, + lineArray = geometryGroup.__lineArray, + + geometry = object.geometry, // this is shared for all chunks + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyUvs = geometry.uvsNeedUpdate, + dirtyNormals = geometry.normalsNeedUpdate, + dirtyTangents = geometry.tangentsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyMorphTargets = geometry.morphTargetsNeedUpdate, + + vertices = geometry.vertices, + chunk_faces3 = geometryGroup.faces3, + obj_faces = geometry.faces, + + obj_uvs = geometry.faceVertexUvs[ 0 ], + obj_uvs2 = geometry.faceVertexUvs[ 1 ], + + obj_colors = geometry.colors, + + obj_skinIndices = geometry.skinIndices, + obj_skinWeights = geometry.skinWeights, + + morphTargets = geometry.morphTargets, + morphNormals = geometry.morphNormals; + + if ( dirtyVertices ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = vertices[ face.a ]; + v2 = vertices[ face.b ]; + v3 = vertices[ face.c ]; + + vertexArray[ offset ] = v1.x; + vertexArray[ offset + 1 ] = v1.y; + vertexArray[ offset + 2 ] = v1.z; + + vertexArray[ offset + 3 ] = v2.x; + vertexArray[ offset + 4 ] = v2.y; + vertexArray[ offset + 5 ] = v2.z; + + vertexArray[ offset + 6 ] = v3.x; + vertexArray[ offset + 7 ] = v3.y; + vertexArray[ offset + 8 ] = v3.z; + + offset += 9; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyMorphTargets ) { + + for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { + + offset_morphTarget = 0; + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + chf = chunk_faces3[ f ]; + face = obj_faces[ chf ]; + + // morph positions + + v1 = morphTargets[ vk ].vertices[ face.a ]; + v2 = morphTargets[ vk ].vertices[ face.b ]; + v3 = morphTargets[ vk ].vertices[ face.c ]; + + vka = morphTargetsArrays[ vk ]; + + vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget + 1 ] = v1.y; + vka[ offset_morphTarget + 2 ] = v1.z; + + vka[ offset_morphTarget + 3 ] = v2.x; + vka[ offset_morphTarget + 4 ] = v2.y; + vka[ offset_morphTarget + 5 ] = v2.z; + + vka[ offset_morphTarget + 6 ] = v3.x; + vka[ offset_morphTarget + 7 ] = v3.y; + vka[ offset_morphTarget + 8 ] = v3.z; + + // morph normals + + if ( material.morphNormals ) { + + if ( needsSmoothNormals ) { + + faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; + + n1 = faceVertexNormals.a; + n2 = faceVertexNormals.b; + n3 = faceVertexNormals.c; + + } else { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } + + nka = morphNormalsArrays[ vk ]; + + nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget + 1 ] = n1.y; + nka[ offset_morphTarget + 2 ] = n1.z; + + nka[ offset_morphTarget + 3 ] = n2.x; + nka[ offset_morphTarget + 4 ] = n2.y; + nka[ offset_morphTarget + 5 ] = n2.z; + + nka[ offset_morphTarget + 6 ] = n3.x; + nka[ offset_morphTarget + 7 ] = n3.y; + nka[ offset_morphTarget + 8 ] = n3.z; + + } + + // + + offset_morphTarget += 9; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); + + if ( material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); + + } + + } + + } + + if ( obj_skinWeights.length ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + // weights + + sw1 = obj_skinWeights[ face.a ]; + sw2 = obj_skinWeights[ face.b ]; + sw3 = obj_skinWeights[ face.c ]; + + skinWeightArray[ offset_skin ] = sw1.x; + skinWeightArray[ offset_skin + 1 ] = sw1.y; + skinWeightArray[ offset_skin + 2 ] = sw1.z; + skinWeightArray[ offset_skin + 3 ] = sw1.w; + + skinWeightArray[ offset_skin + 4 ] = sw2.x; + skinWeightArray[ offset_skin + 5 ] = sw2.y; + skinWeightArray[ offset_skin + 6 ] = sw2.z; + skinWeightArray[ offset_skin + 7 ] = sw2.w; + + skinWeightArray[ offset_skin + 8 ] = sw3.x; + skinWeightArray[ offset_skin + 9 ] = sw3.y; + skinWeightArray[ offset_skin + 10 ] = sw3.z; + skinWeightArray[ offset_skin + 11 ] = sw3.w; + + // indices + + si1 = obj_skinIndices[ face.a ]; + si2 = obj_skinIndices[ face.b ]; + si3 = obj_skinIndices[ face.c ]; + + skinIndexArray[ offset_skin ] = si1.x; + skinIndexArray[ offset_skin + 1 ] = si1.y; + skinIndexArray[ offset_skin + 2 ] = si1.z; + skinIndexArray[ offset_skin + 3 ] = si1.w; + + skinIndexArray[ offset_skin + 4 ] = si2.x; + skinIndexArray[ offset_skin + 5 ] = si2.y; + skinIndexArray[ offset_skin + 6 ] = si2.z; + skinIndexArray[ offset_skin + 7 ] = si2.w; + + skinIndexArray[ offset_skin + 8 ] = si3.x; + skinIndexArray[ offset_skin + 9 ] = si3.y; + skinIndexArray[ offset_skin + 10 ] = si3.z; + skinIndexArray[ offset_skin + 11 ] = si3.w; + + offset_skin += 12; + + } + + if ( offset_skin > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); + + } + + } + + if ( dirtyColors && vertexColorType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexColors = face.vertexColors; + faceColor = face.color; + + if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { + + c1 = vertexColors[ 0 ]; + c2 = vertexColors[ 1 ]; + c3 = vertexColors[ 2 ]; + + } else { + + c1 = faceColor; + c2 = faceColor; + c3 = faceColor; + + } + + colorArray[ offset_color ] = c1.r; + colorArray[ offset_color + 1 ] = c1.g; + colorArray[ offset_color + 2 ] = c1.b; + + colorArray[ offset_color + 3 ] = c2.r; + colorArray[ offset_color + 4 ] = c2.g; + colorArray[ offset_color + 5 ] = c2.b; + + colorArray[ offset_color + 6 ] = c3.r; + colorArray[ offset_color + 7 ] = c3.g; + colorArray[ offset_color + 8 ] = c3.b; + + offset_color += 9; + + } + + if ( offset_color > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + } + + if ( dirtyTangents && geometry.hasTangents ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexTangents = face.vertexTangents; + + t1 = vertexTangents[ 0 ]; + t2 = vertexTangents[ 1 ]; + t3 = vertexTangents[ 2 ]; + + tangentArray[ offset_tangent ] = t1.x; + tangentArray[ offset_tangent + 1 ] = t1.y; + tangentArray[ offset_tangent + 2 ] = t1.z; + tangentArray[ offset_tangent + 3 ] = t1.w; + + tangentArray[ offset_tangent + 4 ] = t2.x; + tangentArray[ offset_tangent + 5 ] = t2.y; + tangentArray[ offset_tangent + 6 ] = t2.z; + tangentArray[ offset_tangent + 7 ] = t2.w; + + tangentArray[ offset_tangent + 8 ] = t3.x; + tangentArray[ offset_tangent + 9 ] = t3.y; + tangentArray[ offset_tangent + 10 ] = t3.z; + tangentArray[ offset_tangent + 11 ] = t3.w; + + offset_tangent += 12; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); + + } + + if ( dirtyNormals && normalType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexNormals = face.vertexNormals; + faceNormal = face.normal; + + if ( vertexNormals.length === 3 && needsSmoothNormals ) { + + for ( i = 0; i < 3; i ++ ) { + + vn = vertexNormals[ i ]; + + normalArray[ offset_normal ] = vn.x; + normalArray[ offset_normal + 1 ] = vn.y; + normalArray[ offset_normal + 2 ] = vn.z; + + offset_normal += 3; + + } + + } else { + + for ( i = 0; i < 3; i ++ ) { + + normalArray[ offset_normal ] = faceNormal.x; + normalArray[ offset_normal + 1 ] = faceNormal.y; + normalArray[ offset_normal + 2 ] = faceNormal.z; + + offset_normal += 3; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); + + } + + if ( dirtyUvs && obj_uvs && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv = obj_uvs[ fi ]; + + if ( uv === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uvi = uv[ i ]; + + uvArray[ offset_uv ] = uvi.x; + uvArray[ offset_uv + 1 ] = uvi.y; + + offset_uv += 2; + + } + + } + + if ( offset_uv > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); + + } + + } + + if ( dirtyUvs && obj_uvs2 && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv2 = obj_uvs2[ fi ]; + + if ( uv2 === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uv2i = uv2[ i ]; + + uv2Array[ offset_uv2 ] = uv2i.x; + uv2Array[ offset_uv2 + 1 ] = uv2i.y; + + offset_uv2 += 2; + + } + + } + + if ( offset_uv2 > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); + + } + + } + + if ( dirtyElements ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face + 1 ] = vertexIndex + 1; + faceArray[ offset_face + 2 ] = vertexIndex + 2; + + offset_face += 3; + + lineArray[ offset_line ] = vertexIndex; + lineArray[ offset_line + 1 ] = vertexIndex + 1; + + lineArray[ offset_line + 2 ] = vertexIndex; + lineArray[ offset_line + 3 ] = vertexIndex + 2; + + lineArray[ offset_line + 4 ] = vertexIndex + 1; + lineArray[ offset_line + 5 ] = vertexIndex + 2; + + offset_line += 6; + + vertexIndex += 3; + + } + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! customAttribute.__original.needsUpdate ) continue; + + offset_custom = 0; + offset_customSrc = 0; + + if ( customAttribute.size === 1 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; + customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; + + offset_custom += 3; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom + 1 ] = value; + customAttribute.array[ offset_custom + 2 ] = value; + + offset_custom += 3; + + } + + } + + } else if ( customAttribute.size === 2 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + } + + } else if ( customAttribute.size === 3 ) { + + var pp; + + if ( customAttribute.type === "c" ) { + + pp = [ "r", "g", "b" ]; + + } else { + + pp = [ "x", "y", "z" ]; + + } + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + if ( dispose ) { + + delete geometryGroup.__inittedArrays; + delete geometryGroup.__colorArray; + delete geometryGroup.__normalArray; + delete geometryGroup.__tangentArray; + delete geometryGroup.__uvArray; + delete geometryGroup.__uv2Array; + delete geometryGroup.__faceArray; + delete geometryGroup.__vertexArray; + delete geometryGroup.__lineArray; + delete geometryGroup.__skinIndexArray; + delete geometryGroup.__skinWeightArray; + + } + + }; + + function setDirectBuffers( geometry, hint ) { + + var attributes = geometry.attributes; + + var attributeName, attributeItem; + + for ( attributeName in attributes ) { + + attributeItem = attributes[ attributeName ]; + + if ( attributeItem.needsUpdate ) { + + if ( attributeName === 'index' ) { + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); + + } else { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); + + } + + attributeItem.needsUpdate = false; + + } + + } + + } + + // Buffer rendering + + this.renderBufferImmediate = function ( object, program, material ) { + + initAttributes(); + + if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); + if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); + if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); + if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); + + if ( object.hasPositions ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); + enableAttribute( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); + + if ( material.shading === THREE.FlatShading ) { + + var nx, ny, nz, + nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, + normalArray, + i, il = object.count * 3; + + for( i = 0; i < il; i += 9 ) { + + normalArray = object.normalArray; + + nax = normalArray[ i ]; + nay = normalArray[ i + 1 ]; + naz = normalArray[ i + 2 ]; + + nbx = normalArray[ i + 3 ]; + nby = normalArray[ i + 4 ]; + nbz = normalArray[ i + 5 ]; + + ncx = normalArray[ i + 6 ]; + ncy = normalArray[ i + 7 ]; + ncz = normalArray[ i + 8 ]; + + nx = ( nax + nbx + ncx ) / 3; + ny = ( nay + nby + ncy ) / 3; + nz = ( naz + nbz + ncz ) / 3; + + normalArray[ i ] = nx; + normalArray[ i + 1 ] = ny; + normalArray[ i + 2 ] = nz; + + normalArray[ i + 3 ] = nx; + normalArray[ i + 4 ] = ny; + normalArray[ i + 5 ] = nz; + + normalArray[ i + 6 ] = nx; + normalArray[ i + 7 ] = ny; + normalArray[ i + 8 ] = nz; + + } + + } + + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); + enableAttribute( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasUvs && material.map ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); + enableAttribute( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); + enableAttribute( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } + + disableUnusedAttributes(); + + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + + object.count = 0; + + }; + + function setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) { + + for ( var attributeName in programAttributes ) { + + var attributePointer = programAttributes[ attributeName ]; + var attributeItem = geometryAttributes[ attributeName ]; + + if ( attributePointer >= 0 ) { + + if ( attributeItem ) { + + var attributeSize = attributeItem.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + enableAttribute( attributePointer ); + _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 + + } else if ( material.defaultAttributeValues ) { + + if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + + _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + + _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } + + } + + } + + } + + disableUnusedAttributes(); + + } + + this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { + + if ( material.visible === false ) return; + + var linewidth, a, attribute; + var attributeItem, attributeName, attributePointer, attributeSize; + + var program = setProgram( camera, lights, fog, material, object ); + + var programAttributes = program.attributes; + var geometryAttributes = geometry.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + initAttributes(); + + } + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + var index = geometryAttributes[ "index" ]; + + if ( index ) { + + // indexed triangles + + var type, size; + + if ( index.array instanceof Uint32Array ) { + + type = _gl.UNSIGNED_INT; + size = 4; + + } else { + + type = _gl.UNSIGNED_SHORT; + size = 2; + + } + + var offsets = geometry.offsets; + + if ( offsets.length === 0 ) { + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + _gl.drawElements( _gl.TRIANGLES, index.array.length, type, 0 ); + + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + _this.info.render.faces += index.array.length / 3; + + } else { + + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change + + updateBuffers = true; + + for ( var i = 0, il = offsets.length; i < il; i ++ ) { + + var startIndex = offsets[ i ].index; + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + // render indexed triangles + + _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, type, offsets[ i ].start * size ); + + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + _this.info.render.faces += offsets[ i ].count / 3; + + } + + } + + } else { + + // non-indexed triangles + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + + } + + var position = geometry.attributes[ "position" ]; + + // render non-indexed triangles + + _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 ); + + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / 3; + _this.info.render.faces += position.array.length / 9; + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + // render particles + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + + } + + var position = geometryAttributes[ "position" ]; + + // render particles + + _gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); + + _this.info.render.calls ++; + _this.info.render.points += position.array.length / 3; + + } else if ( object instanceof THREE.Line ) { + + var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + + setLineWidth( material.linewidth ); + + var index = geometryAttributes[ "index" ]; + + if ( index ) { + + // indexed lines + + var type, size; + + if ( index.array instanceof Uint32Array ){ + + type = _gl.UNSIGNED_INT; + size = 4; + + } else { + + type = _gl.UNSIGNED_SHORT; + size = 2; + + } + + var offsets = geometry.offsets; + + if ( offsets.length === 0 ) { + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + _gl.drawElements( _gl.LINES, index.array.length, type, 0 ); // 2 bytes per Uint16Array + + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + + } else { + + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change + + if ( offsets.length > 1 ) updateBuffers = true; + + for ( var i = 0, il = offsets.length; i < il; i ++ ) { + + var startIndex = offsets[ i ].index; + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + // render indexed lines + + _gl.drawElements( _gl.LINES, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array + + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + + } + + } + + } else { + + // non-indexed lines + + if ( updateBuffers ) { + + setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + + } + + var position = geometryAttributes[ "position" ]; + + _gl.drawArrays( mode, 0, position.array.length / 3 ); + + _this.info.render.calls ++; + _this.info.render.points += position.array.length / 3; + + } + + } + + }; + + this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { + + if ( material.visible === false ) return; + + var linewidth, a, attribute, i, il; + + var program = setProgram( camera, lights, fog, material, object ); + + var attributes = program.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryGroupHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryGroupHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + initAttributes(); + + } + + // vertices + + if ( !material.morphTargets && attributes.position >= 0 ) { + + if ( updateBuffers ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + } else { + + if ( object.morphTargetBase ) { + + setupMorphTargets( material, geometryGroup, object ); + + } + + } + + + if ( updateBuffers ) { + + // custom attributes + + // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers + + if ( geometryGroup.__webglCustomAttributesList ) { + + for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { + + attribute = geometryGroup.__webglCustomAttributesList[ i ]; + + if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); + enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); + + } + + } + + } + + + // colors + + if ( attributes.color >= 0 ) { + + if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); + + } + + } + + // normals + + if ( attributes.normal >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + // tangents + + if ( attributes.tangent >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // uvs + + if ( attributes.uv >= 0 ) { + + if ( object.geometry.faceVertexUvs[0] ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); + + } + + } + + if ( attributes.uv2 >= 0 ) { + + if ( object.geometry.faceVertexUvs[1] ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + enableAttribute( attributes.uv2 ); + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); + + } + + } + + if ( material.skinning && + attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + enableAttribute( attributes.skinIndex ); + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + enableAttribute( attributes.skinWeight ); + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // line distances + + if ( attributes.lineDistance >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); + enableAttribute( attributes.lineDistance ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); + + } + + } + + disableUnusedAttributes(); + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; + + // wireframe + + if ( material.wireframe ) { + + setLineWidth( material.wireframeLinewidth ); + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); + + // triangles + + } else { + + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 ); + + } + + _this.info.render.calls ++; + _this.info.render.vertices += geometryGroup.__webglFaceCount; + _this.info.render.faces += geometryGroup.__webglFaceCount / 3; + + // render lines + + } else if ( object instanceof THREE.Line ) { + + var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + + setLineWidth( material.linewidth ); + + _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); + + _this.info.render.calls ++; + + // render particles + + } else if ( object instanceof THREE.ParticleSystem ) { + + _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); + + _this.info.render.calls ++; + _this.info.render.points += geometryGroup.__webglParticleCount; + + } + + }; + + 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; + + } + + } + + function disableUnusedAttributes() { + + for ( var i = 0, l = _enabledAttributes.length; i < l; i ++ ) { + + if ( _enabledAttributes[ i ] !== _newAttributes[ i ] ) { + + _gl.disableVertexAttribArray( i ); + _enabledAttributes[ i ] = 0; + + } + + } + + } + + function setupMorphTargets ( material, geometryGroup, object ) { + + // set base + + var attributes = material.program.attributes; + + if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } else if ( attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.morphTargetForcedOrder.length ) { + + // set forced order + + var m = 0; + var order = object.morphTargetForcedOrder; + var influences = object.morphTargetInfluences; + + while ( m < material.numSupportedMorphTargets && m < order.length ) { + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; + + m ++; + } + + } else { + + // find the most influencing + + var influence, activeInfluenceIndices = []; + var influences = object.morphTargetInfluences; + var i, il = influences.length; + + for ( i = 0; i < il; i ++ ) { + + influence = influences[ i ]; + + if ( influence > 0 ) { + + activeInfluenceIndices.push( [ influence, i ] ); + + } + + } + + if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { + + activeInfluenceIndices.sort( numericalSort ); + activeInfluenceIndices.length = material.numSupportedMorphTargets; + + } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { + + activeInfluenceIndices.sort( numericalSort ); + + } else if ( activeInfluenceIndices.length === 0 ) { + + activeInfluenceIndices.push( [ 0, 0 ] ); + + }; + + var influenceIndex, m = 0; + + while ( m < material.numSupportedMorphTargets ) { + + if ( activeInfluenceIndices[ m ] ) { + + influenceIndex = activeInfluenceIndices[ m ][ 1 ]; + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; + + } else { + + /* + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + if ( material.morphNormals ) { + + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + */ + + object.__webglMorphTargetInfluences[ m ] = 0; + + } + + m ++; + + } + + } + + // load updated influences uniform + + if ( material.program.uniforms.morphTargetInfluences !== null ) { + + _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); + + } + + }; + + // Sorting + + function painterSortStable ( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + + }; + + function numericalSort ( a, b ) { + + return b[ 0 ] - a[ 0 ]; + + }; + + + // Rendering + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + if ( camera instanceof THREE.Camera === false ) { + + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + var i, il, + + webglObject, object, + renderList, + + lights = scene.__lights, + fog = scene.fog; + + // reset caching for this frame + + _currentMaterialId = -1; + _lightsNeedUpdate = true; + + // update scene graph + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // update WebGL objects + + if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); + + // custom render plugins (pre pass) + + renderPlugins( this.renderPluginsPre, scene, camera ); + + // + + _this.info.render.calls = 0; + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + _this.info.render.points = 0; + + this.setRenderTarget( renderTarget ); + + if ( this.autoClear || forceClear ) { + + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + + } + + // set matrices for regular objects (frustum culled) + + renderList = scene.__webglObjects; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + webglObject.id = i; + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + setupMatrices( object, camera ); + + unrollBufferMaterial( webglObject ); + + webglObject.render = true; + + if ( this.sortObjects === true ) { + + if ( object.renderDepth !== null ) { + + webglObject.z = object.renderDepth; + + } else { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); + + webglObject.z = _vector3.z; + + } + + } + + } + + } + + } + + if ( this.sortObjects ) { + + renderList.sort( painterSortStable ); + + } + + // set matrices for immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + setupMatrices( object, camera ); + + unrollImmediateBufferMaterial( webglObject ); + + } + + } + + if ( scene.overrideMaterial ) { + + var material = scene.overrideMaterial; + + this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + this.setDepthTest( material.depthTest ); + this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); + + } else { + + var material = null; + + // opaque pass (front-to-back order) + + this.setBlending( THREE.NoBlending ); + + renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); + + // transparent pass (back-to-front order) + + renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); + + } + + // custom render plugins (post pass) + + renderPlugins( this.renderPluginsPost, scene, camera ); + + + // Generate mipmap if we're using any kind of mipmap filtering + + if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + + updateRenderTargetMipmap( renderTarget ); + + } + + // Ensure depth buffer writing is enabled so it can be cleared on next render + + this.setDepthTest( true ); + this.setDepthWrite( true ); + + // _gl.finish(); + + }; + + function renderPlugins( plugins, scene, camera ) { + + if ( ! plugins.length ) return; + + for ( var i = 0, il = plugins.length; i < il; i ++ ) { + + // reset state for plugin (to start from clean slate) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); + + // reset state after plugin (anything could have changed) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + } + + }; + + function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, buffer, material, start, end, delta; + + if ( reverse ) { + + start = renderList.length - 1; + end = -1; + delta = -1; + + } else { + + start = 0; + end = renderList.length; + delta = 1; + } + + for ( var i = start; i !== end; i += delta ) { + + webglObject = renderList[ i ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.setMaterialFaces( material ); + + if ( buffer instanceof THREE.BufferGeometry ) { + + _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); + + } else { + + _this.renderBuffer( camera, lights, fog, material, buffer, object ); + + } + + } + + } + + }; + + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, material, program; + + for ( var i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.renderImmediateObject( camera, lights, fog, material, object ); + + } + + } + + }; + + this.renderImmediateObject = function ( camera, lights, fog, material, object ) { + + var program = setProgram( camera, lights, fog, material, object ); + + _currentGeometryGroupHash = -1; + + _this.setMaterialFaces( material ); + + if ( object.immediateRenderCallback ) { + + object.immediateRenderCallback( program, _gl, _frustum ); + + } else { + + object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); + + } + + }; + + function unrollImmediateBufferMaterial ( globject ) { + + var object = globject.object, + material = object.material; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + }; + + function unrollBufferMaterial ( globject ) { + + var object = globject.object; + var buffer = globject.buffer; + + var geometry = object.geometry; + var material = object.material; + + if ( material instanceof THREE.MeshFaceMaterial ) { + + var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; + + material = material.materials[ materialIndex ]; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } else { + + if ( material ) { + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } + + } + + }; + + // Objects refresh + + this.initWebGLObjects = function ( scene ) { + + if ( !scene.__webglObjects ) { + + scene.__webglObjects = []; + scene.__webglObjectsImmediate = []; + scene.__webglSprites = []; + scene.__webglFlares = []; + + } + + while ( scene.__objectsAdded.length ) { + + addObject( scene.__objectsAdded[ 0 ], scene ); + scene.__objectsAdded.splice( 0, 1 ); + + } + + while ( scene.__objectsRemoved.length ) { + + removeObject( scene.__objectsRemoved[ 0 ], scene ); + scene.__objectsRemoved.splice( 0, 1 ); + + } + + // update must be called after objects adding / removal + + for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { + + var object = scene.__webglObjects[ o ].object; + + // TODO: Remove this hack (WebGLRenderer refactoring) + + if ( object.__webglInit === undefined ) { + + if ( object.__webglActive !== undefined ) { + + removeObject( object, scene ); + + } + + addObject( object, scene ); + + } + + updateObject( object ); + + } + + }; + + // Objects adding + + function addObject( object, scene ) { + + var g, geometry, material, geometryGroup; + + if ( object.__webglInit === undefined ) { + + object.__webglInit = true; + + object._modelViewMatrix = new THREE.Matrix4(); + object._normalMatrix = new THREE.Matrix3(); + + geometry = object.geometry; + + if ( geometry === undefined ) { + + // ImmediateRenderObject + + } else if ( geometry.__webglInit === undefined ) { + + geometry.__webglInit = true; + geometry.addEventListener( 'dispose', onGeometryDispose ); + + if ( geometry instanceof THREE.BufferGeometry ) { + + initDirectBuffers( geometry ); + + } else if ( object instanceof THREE.Mesh ) { + + material = object.material; + + if ( geometry.geometryGroups === undefined ) { + + geometry.makeGroups( material instanceof THREE.MeshFaceMaterial, _glExtensionElementIndexUint ? 4294967296 : 65535 ); + + } + + // create separate VBOs per geometry chunk + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + // initialise VBO on the first access + + if ( ! geometryGroup.__webglVertexBuffer ) { + + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); + + geometry.verticesNeedUpdate = true; + geometry.morphTargetsNeedUpdate = true; + geometry.elementsNeedUpdate = true; + geometry.uvsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + geometry.tangentsNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + } + + } + + } else if ( object instanceof THREE.Line ) { + + if ( ! geometry.__webglVertexBuffer ) { + + createLineBuffers( geometry ); + initLineBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.lineDistancesNeedUpdate = true; + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + if ( ! geometry.__webglVertexBuffer ) { + + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + } + + } + + } + + } + + if ( object.__webglActive === undefined ) { + + if ( object instanceof THREE.Mesh ) { + + geometry = object.geometry; + + if ( geometry instanceof THREE.BufferGeometry ) { + + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( geometry instanceof THREE.Geometry ) { + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + addBuffer( scene.__webglObjects, geometryGroup, object ); + + } + + } + + } else if ( object instanceof THREE.Line || + object instanceof THREE.ParticleSystem ) { + + geometry = object.geometry; + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + addBufferImmediate( scene.__webglObjectsImmediate, object ); + + } else if ( object instanceof THREE.Sprite ) { + + scene.__webglSprites.push( object ); + + } else if ( object instanceof THREE.LensFlare ) { + + scene.__webglFlares.push( object ); + + } + + object.__webglActive = true; + + } + + }; + + function addBuffer( objlist, buffer, object ) { + + objlist.push( + { + id: null, + buffer: buffer, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); + + }; + + function addBufferImmediate( objlist, object ) { + + objlist.push( + { + id: null, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); + + }; + + // Objects updates + + function updateObject( object ) { + + var geometry = object.geometry, + geometryGroup, customAttributesDirty, material; + + if ( geometry instanceof THREE.BufferGeometry ) { + + setDirectBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } else if ( object instanceof THREE.Mesh ) { + + // check all geometry groups + + for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { + + geometryGroup = geometry.geometryGroupsList[ i ]; + + material = getBufferMaterial( object, geometryGroup ); + + if ( geometry.buffersNeedUpdate ) { + + initMeshBuffers( geometryGroup, object ); + + } + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { + + setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); + + } + + } + + geometry.verticesNeedUpdate = false; + geometry.morphTargetsNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; + + geometry.buffersNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } else if ( object instanceof THREE.Line ) { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { + + setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.lineDistancesNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + + } else if ( object instanceof THREE.ParticleSystem ) { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { + + setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } + + }; + + // Objects updates - custom attributes check + + function areCustomAttributesDirty( material ) { + + for ( var a in material.attributes ) { + + if ( material.attributes[ a ].needsUpdate ) return true; + + } + + return false; + + }; + + function clearCustomAttributes( material ) { + + for ( var a in material.attributes ) { + + material.attributes[ a ].needsUpdate = false; + + } + + }; + + // Objects removal + + function removeObject( object, scene ) { + + if ( object instanceof THREE.Mesh || + object instanceof THREE.ParticleSystem || + object instanceof THREE.Line ) { + + removeInstances( scene.__webglObjects, object ); + + } else if ( object instanceof THREE.Sprite ) { + + removeInstancesDirect( scene.__webglSprites, object ); + + } else if ( object instanceof THREE.LensFlare ) { + + removeInstancesDirect( scene.__webglFlares, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + removeInstances( scene.__webglObjectsImmediate, object ); + + } + + delete object.__webglActive; + + }; + + function removeInstances( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ].object === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + function removeInstancesDirect( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ] === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + // Materials + + this.initMaterial = function ( material, lights, fog, object ) { + + material.addEventListener( 'dispose', onMaterialDispose ); + + var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; + + if ( material instanceof THREE.MeshDepthMaterial ) { + + shaderID = 'depth'; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + shaderID = 'normal'; + + } else if ( material instanceof THREE.MeshBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + shaderID = 'lambert'; + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + shaderID = 'phong'; + + } else if ( material instanceof THREE.LineBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + shaderID = 'dashed'; + + } else if ( material instanceof THREE.ParticleSystemMaterial ) { + + shaderID = 'particle_basic'; + + } + + if ( shaderID ) { + + setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); + + } + + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) + + maxLightCount = allocateLights( lights ); + + maxShadows = allocateShadows( lights ); + + maxBones = allocateBones( object ); + + parameters = { + + precision: _precision, + supportsVertexTextures: _supportsVertexTextures, + + map: !!material.map, + envMap: !!material.envMap, + lightMap: !!material.lightMap, + bumpMap: !!material.bumpMap, + normalMap: !!material.normalMap, + specularMap: !!material.specularMap, + + vertexColors: material.vertexColors, + + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, + + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: _logarithmicDepthBuffer, + + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, + + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: this.maxMorphTargets, + maxMorphNormals: this.maxMorphNormals, + + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, + + maxShadows: maxShadows, + shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, + shadowMapType: this.shadowMapType, + shadowMapDebug: this.shadowMapDebug, + shadowMapCascade: this.shadowMapCascade, + + alphaTest: material.alphaTest, + metal: material.metal, + wrapAround: material.wrapAround, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide + + }; + + // Generate code + + var chunks = []; + + if ( shaderID ) { + + chunks.push( shaderID ); + + } else { + + chunks.push( material.fragmentShader ); + chunks.push( material.vertexShader ); + + } + + for ( var d in material.defines ) { + + chunks.push( d ); + chunks.push( material.defines[ d ] ); + + } + + for ( var p in parameters ) { + + chunks.push( p ); + chunks.push( parameters[ p ] ); + + } + + var code = chunks.join(); + + var program; + + // Check if code has been already compiled + + for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { + + var programInfo = _programs[ p ]; + + if ( programInfo.code === code ) { + + program = programInfo; + program.usedTimes ++; + + break; + + } + + } + + if ( program === undefined ) { + + program = new THREE.WebGLProgram( this, code, material, parameters ); + _programs.push( program ); + + _this.info.memory.programs = _programs.length; + + } + + material.program = program; + + var attributes = material.program.attributes; + + if ( material.morphTargets ) { + + material.numSupportedMorphTargets = 0; + + var id, base = "morphTarget"; + + for ( i = 0; i < this.maxMorphTargets; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphTargets ++; + + } + + } + + } + + if ( material.morphNormals ) { + + material.numSupportedMorphNormals = 0; + + var id, base = "morphNormal"; + + for ( i = 0; i < this.maxMorphNormals; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphNormals ++; + + } + + } + + } + + material.uniformsList = []; + + for ( u in material.uniforms ) { + + material.uniformsList.push( [ material.uniforms[ u ], u ] ); + + } + + }; + + function setMaterialShaders( material, shaders ) { + + material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); + material.vertexShader = shaders.vertexShader; + material.fragmentShader = shaders.fragmentShader; + + }; + + function setProgram( camera, lights, fog, material, object ) { + + _usedTextureUnits = 0; + + if ( material.needsUpdate ) { + + if ( material.program ) deallocateMaterial( material ); + + _this.initMaterial( material, lights, fog, object ); + material.needsUpdate = false; + + } + + if ( material.morphTargets ) { + + if ( ! object.__webglMorphTargetInfluences ) { + + object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); + + } + + } + + var refreshMaterial = false; + + var program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.uniforms; + + if ( program.id !== _currentProgram ) { + + _gl.useProgram( program.program ); + _currentProgram = program.id; + + refreshMaterial = true; + + } + + if ( material.id !== _currentMaterialId ) { + + _currentMaterialId = material.id; + refreshMaterial = true; + + } + + if ( refreshMaterial || camera !== _currentCamera ) { + + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + if ( _logarithmicDepthBuffer ) { + + _gl.uniform1f(p_uniforms.logDepthBufFC, 2.0 / (Math.log(camera.far + 1.0) / Math.LN2)); + + } + + + if ( camera !== _currentCamera ) _currentCamera = camera; + + } + + // skinning uniforms must be set even if material didn't change + // auto-setting of texture unit for bone texture must go before other textures + // not sure why, but otherwise weird things happen + + if ( material.skinning ) { + + if ( _supportsBoneTextures && object.useVertexTexture ) { + + if ( p_uniforms.boneTexture !== null ) { + + var textureUnit = getTextureUnit(); + + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.boneTexture, textureUnit ); + + } + + if ( p_uniforms.boneTextureWidth !== null ) { + + _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); + + } + + if ( p_uniforms.boneTextureHeight !== null ) { + + _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); + + } + + } else { + + if ( p_uniforms.boneGlobalMatrices !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); + + } + + } + + } + + if ( refreshMaterial ) { + + // refresh uniforms common to several materials + + if ( fog && material.fog ) { + + refreshUniformsFog( m_uniforms, fog ); + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material.lights ) { + + if ( _lightsNeedUpdate ) { + + setupLights( program, lights ); + _lightsNeedUpdate = false; + + } + + refreshUniformsLights( m_uniforms, _lights ); + + } + + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsCommon( m_uniforms, material ); + + } + + // refresh single material specific uniforms + + if ( material instanceof THREE.LineBasicMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); + + } else if ( material instanceof THREE.ParticleSystemMaterial ) { + + refreshUniformsParticle( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsPhong( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + refreshUniformsLambert( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + m_uniforms.opacity.value = material.opacity; + + } + + if ( object.receiveShadow && ! material._shadowPass ) { + + refreshUniformsShadow( m_uniforms, lights ); + + } + + // load common uniforms + + loadUniformsGeneric( program, material.uniformsList ); + + // load material specific uniforms + // (shader material also gets them for the sake of genericity) + + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material.envMap ) { + + if ( p_uniforms.cameraPosition !== null ) { + + _vector3.setFromMatrixPosition( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); + + } + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { + + if ( p_uniforms.viewMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); + + } + + } + + } + + loadUniformsMatrices( p_uniforms, object ); + + if ( p_uniforms.modelMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); + + } + + return program; + + }; + + // Uniforms (refresh uniforms objects) + + function refreshUniformsCommon ( uniforms, material ) { + + uniforms.opacity.value = material.opacity; + + if ( _this.gammaInput ) { + + uniforms.diffuse.value.copyGammaToLinear( material.color ); + + } else { + + uniforms.diffuse.value = material.color; + + } + + uniforms.map.value = material.map; + uniforms.lightMap.value = material.lightMap; + uniforms.specularMap.value = material.specularMap; + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + + var uvScaleMap; + + if ( material.map ) { + + uvScaleMap = material.map; + + } else if ( material.specularMap ) { + + uvScaleMap = material.specularMap; + + } else if ( material.normalMap ) { + + uvScaleMap = material.normalMap; + + } else if ( material.bumpMap ) { + + uvScaleMap = material.bumpMap; + + } + + if ( uvScaleMap !== undefined ) { + + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + + if ( _this.gammaInput ) { + + //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; + uniforms.reflectivity.value = material.reflectivity; + + } else { + + uniforms.reflectivity.value = material.reflectivity; + + } + + uniforms.refractionRatio.value = material.refractionRatio; + uniforms.combine.value = material.combine; + uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; + + }; + + function refreshUniformsLine ( uniforms, material ) { + + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + + }; + + function refreshUniformsDash ( uniforms, material ) { + + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; + + }; + + function refreshUniformsParticle ( uniforms, material ) { + + uniforms.psColor.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size; + uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. + + uniforms.map.value = material.map; + + }; + + function refreshUniformsFog ( uniforms, fog ) { + + uniforms.fogColor.value = fog.color; + + if ( fog instanceof THREE.Fog ) { + + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; + + } else if ( fog instanceof THREE.FogExp2 ) { + + uniforms.fogDensity.value = fog.density; + + } + + }; + + function refreshUniformsPhong ( uniforms, material ) { + + uniforms.shininess.value = material.shininess; + + if ( _this.gammaInput ) { + + uniforms.ambient.value.copyGammaToLinear( material.ambient ); + uniforms.emissive.value.copyGammaToLinear( material.emissive ); + uniforms.specular.value.copyGammaToLinear( material.specular ); + + } else { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; + + } + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsLambert ( uniforms, material ) { + + if ( _this.gammaInput ) { + + uniforms.ambient.value.copyGammaToLinear( material.ambient ); + uniforms.emissive.value.copyGammaToLinear( material.emissive ); + + } else { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + + } + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsLights ( uniforms, lights ) { + + uniforms.ambientLightColor.value = lights.ambient; + + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; + + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + + uniforms.spotLightColor.value = lights.spot.colors; + uniforms.spotLightPosition.value = lights.spot.positions; + uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDirection.value = lights.spot.directions; + uniforms.spotLightAngleCos.value = lights.spot.anglesCos; + uniforms.spotLightExponent.value = lights.spot.exponents; + + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; + + }; + + function refreshUniformsShadow ( uniforms, lights ) { + + if ( uniforms.shadowMatrix ) { + + var j = 0; + + for ( var i = 0, il = lights.length; i < il; i ++ ) { + + var light = lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { + + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; + uniforms.shadowBias.value[ j ] = light.shadowBias; + + j ++; + + } + + } + + } + + }; + + // Uniforms (load to GPU) + + function loadUniformsMatrices ( uniforms, object ) { + + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); + + if ( uniforms.normalMatrix ) { + + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); + + } + + }; + + function getTextureUnit() { + + var textureUnit = _usedTextureUnits; + + if ( textureUnit >= _maxTextures ) { + + console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + + } + + _usedTextureUnits += 1; + + return textureUnit; + + }; + + function loadUniformsGeneric ( program, uniforms ) { + + var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; + + for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { + + location = program.uniforms[ uniforms[ j ][ 1 ] ]; + if ( !location ) continue; + + uniform = uniforms[ j ][ 0 ]; + + type = uniform.type; + value = uniform.value; + + if ( type === "i" ) { // single integer + + _gl.uniform1i( location, value ); + + } else if ( type === "f" ) { // single float + + _gl.uniform1f( location, value ); + + } else if ( type === "v2" ) { // single THREE.Vector2 + + _gl.uniform2f( location, value.x, value.y ); + + } else if ( type === "v3" ) { // single THREE.Vector3 + + _gl.uniform3f( location, value.x, value.y, value.z ); + + } else if ( type === "v4" ) { // single THREE.Vector4 + + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); + + } else if ( type === "c" ) { // single THREE.Color + + _gl.uniform3f( location, value.r, value.g, value.b ); + + } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) + + _gl.uniform1iv( location, value ); + + } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) + + _gl.uniform3iv( location, value ); + + } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) + + _gl.uniform1fv( location, value ); + + } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) + + _gl.uniform3fv( location, value ); + + } else if ( type === "v2v" ) { // array of THREE.Vector2 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 2 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 2; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + + } + + _gl.uniform2fv( location, uniform._array ); + + } else if ( type === "v3v" ) { // array of THREE.Vector3 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 3 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 3; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + + } + + _gl.uniform3fv( location, uniform._array ); + + } else if ( type === "v4v" ) { // array of THREE.Vector4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 4 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 4; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + uniform._array[ offset + 3 ] = value[ i ].w; + + } + + _gl.uniform4fv( location, uniform._array ); + + } else if ( type === "m4") { // single THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 ); + + } + + value.flattenToArray( uniform._array ); + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "m4v" ) { // array of THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); + + } + + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "t" ) { // single THREE.Texture (2d or cube) + + texture = value; + textureUnit = getTextureUnit(); + + _gl.uniform1i( location, textureUnit ); + + if ( !texture ) continue; + + if ( texture.image instanceof Array && texture.image.length === 6 ) { + + setCubeTexture( texture, textureUnit ); + + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { + + setCubeTextureDynamic( texture, textureUnit ); + + } else { + + _this.setTexture( texture, textureUnit ); + + } + + } else if ( type === "tv" ) { // array of THREE.Texture (2d) + + if ( uniform._array === undefined ) { + + uniform._array = []; + + } + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + uniform._array[ i ] = getTextureUnit(); + + } + + _gl.uniform1iv( location, uniform._array ); + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; + + if ( !texture ) continue; + + _this.setTexture( texture, textureUnit ); + + } + + } else { + + console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + + } + + } + + }; + + function setupMatrices ( object, camera ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); + + }; + + // + + function setColorGamma( array, offset, color, intensitySq ) { + + array[ offset ] = color.r * color.r * intensitySq; + array[ offset + 1 ] = color.g * color.g * intensitySq; + array[ offset + 2 ] = color.b * color.b * intensitySq; + + }; + + function setColorLinear( array, offset, color, intensity ) { + + array[ offset ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; + + }; + + function setupLights ( program, lights ) { + + var l, ll, light, n, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, intensitySq, + position, + distance, + + zlights = _lights, + + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, + + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + + spotColors = zlights.spot.colors, + spotPositions = zlights.spot.positions, + spotDistances = zlights.spot.distances, + spotDirections = zlights.spot.directions, + spotAnglesCos = zlights.spot.anglesCos, + spotExponents = zlights.spot.exponents, + + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, + + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, + + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, + + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0; + + for ( l = 0, ll = lights.length; l < ll; l ++ ) { + + light = lights[ l ]; + + if ( light.onlyShadow ) continue; + + color = light.color; + intensity = light.intensity; + distance = light.distance; + + if ( light instanceof THREE.AmbientLight ) { + + if ( ! light.visible ) continue; + + if ( _this.gammaInput ) { + + r += color.r * color.r; + g += color.g * color.g; + b += color.b * color.b; + + } else { + + r += color.r; + g += color.g; + b += color.b; + + } + + } else if ( light instanceof THREE.DirectionalLight ) { + + dirCount += 1; + + if ( ! light.visible ) continue; + + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + dirOffset = dirLength * 3; + + dirPositions[ dirOffset ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; + + if ( _this.gammaInput ) { + + setColorGamma( dirColors, dirOffset, color, intensity * intensity ); + + } else { + + setColorLinear( dirColors, dirOffset, color, intensity ); + + } + + dirLength += 1; + + } else if ( light instanceof THREE.PointLight ) { + + pointCount += 1; + + if ( ! light.visible ) continue; + + pointOffset = pointLength * 3; + + if ( _this.gammaInput ) { + + setColorGamma( pointColors, pointOffset, color, intensity * intensity ); + + } else { + + setColorLinear( pointColors, pointOffset, color, intensity ); + + } + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + pointPositions[ pointOffset ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; + + pointDistances[ pointLength ] = distance; + + pointLength += 1; + + } else if ( light instanceof THREE.SpotLight ) { + + spotCount += 1; + + if ( ! light.visible ) continue; + + spotOffset = spotLength * 3; + + if ( _this.gammaInput ) { + + setColorGamma( spotColors, spotOffset, color, intensity * intensity ); + + } else { + + setColorLinear( spotColors, spotOffset, color, intensity ); + + } + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + spotPositions[ spotOffset ] = _vector3.x; + spotPositions[ spotOffset + 1 ] = _vector3.y; + spotPositions[ spotOffset + 2 ] = _vector3.z; + + spotDistances[ spotLength ] = distance; + + _direction.copy( _vector3 ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + spotDirections[ spotOffset ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; + + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + + spotLength += 1; + + } else if ( light instanceof THREE.HemisphereLight ) { + + hemiCount += 1; + + if ( ! light.visible ) continue; + + _direction.setFromMatrixPosition( light.matrixWorld ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + hemiOffset = hemiLength * 3; + + hemiPositions[ hemiOffset ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; + + skyColor = light.color; + groundColor = light.groundColor; + + if ( _this.gammaInput ) { + + intensitySq = intensity * intensity; + + setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); + setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); + + } else { + + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + + } + + hemiLength += 1; + + } + + } + + // null eventual remains from removed lights + // (this is to avoid if in shader) + + for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; + for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; + for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; + + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; + + }; + + // GL state setting + + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + + if ( cullFace === THREE.CullFaceNone ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + if ( cullFace === THREE.CullFaceBack ) { + + _gl.cullFace( _gl.BACK ); + + } else if ( cullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.FRONT_AND_BACK ); + + } + + _gl.enable( _gl.CULL_FACE ); + + } + + }; + + this.setMaterialFaces = function ( material ) { + + var doubleSided = material.side === THREE.DoubleSide; + var flipSided = material.side === THREE.BackSide; + + if ( _oldDoubleSided !== doubleSided ) { + + if ( doubleSided ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + _gl.enable( _gl.CULL_FACE ); + + } + + _oldDoubleSided = doubleSided; + + } + + if ( _oldFlipSided !== flipSided ) { + + if ( flipSided ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + _oldFlipSided = flipSided; + + } + + }; + + this.setDepthTest = function ( depthTest ) { + + if ( _oldDepthTest !== depthTest ) { + + if ( depthTest ) { + + _gl.enable( _gl.DEPTH_TEST ); + + } else { + + _gl.disable( _gl.DEPTH_TEST ); + + } + + _oldDepthTest = depthTest; + + } + + }; + + this.setDepthWrite = function ( depthWrite ) { + + if ( _oldDepthWrite !== depthWrite ) { + + _gl.depthMask( depthWrite ); + _oldDepthWrite = depthWrite; + + } + + }; + + function setLineWidth ( width ) { + + if ( width !== _oldLineWidth ) { + + _gl.lineWidth( width ); + + _oldLineWidth = width; + + } + + }; + + function setPolygonOffset ( polygonoffset, factor, units ) { + + if ( _oldPolygonOffset !== polygonoffset ) { + + if ( polygonoffset ) { + + _gl.enable( _gl.POLYGON_OFFSET_FILL ); + + } else { + + _gl.disable( _gl.POLYGON_OFFSET_FILL ); + + } + + _oldPolygonOffset = polygonoffset; + + } + + if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { + + _gl.polygonOffset( factor, units ); + + _oldPolygonOffsetFactor = factor; + _oldPolygonOffsetUnits = units; + + } + + }; + + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { + + if ( blending !== _oldBlending ) { + + if ( blending === THREE.NoBlending ) { + + _gl.disable( _gl.BLEND ); + + } else if ( blending === THREE.AdditiveBlending ) { + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); + + } else if ( blending === THREE.SubtractiveBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); + + } else if ( blending === THREE.MultiplyBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); + + } else if ( blending === THREE.CustomBlending ) { + + _gl.enable( _gl.BLEND ); + + } else { + + _gl.enable( _gl.BLEND ); + _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 ); + + } + + _oldBlending = blending; + + } + + if ( blending === THREE.CustomBlending ) { + + if ( blendEquation !== _oldBlendEquation ) { + + _gl.blendEquation( paramThreeToGL( blendEquation ) ); + + _oldBlendEquation = blendEquation; + + } + + if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { + + _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); + + _oldBlendSrc = blendSrc; + _oldBlendDst = blendDst; + + } + + } else { + + _oldBlendEquation = null; + _oldBlendSrc = null; + _oldBlendDst = null; + + } + + }; + + // Textures + + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { + + if ( isImagePowerOfTwo ) { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); + + } else { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + + } + + if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { + + if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + + _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); + texture.__oldAnisotropy = texture.anisotropy; + + } + + } + + }; + + this.setTexture = function ( texture, slot ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.__webglInit ) { + + texture.__webglInit = true; + + texture.addEventListener( 'dispose', onTextureDispose ); + + texture.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + + var image = texture.image, + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); + + var mipmap, mipmaps = texture.mipmaps; + + if ( texture instanceof THREE.DataTexture ) { + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + + } + + } else if ( texture instanceof THREE.CompressedTexture ) { + + for( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + if ( texture.format!==THREE.RGBAFormat ) { + _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + } else { + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + } + + } + + } else { // regular Texture (image, video, canvas) + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + + } + + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + } + + }; + + function clampToMaxSize ( image, maxSize ) { + + if ( image.width <= maxSize && image.height <= maxSize ) { + + return image; + + } + + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. + + var maxDimension = Math.max( image.width, image.height ); + var newWidth = Math.floor( image.width * maxSize / maxDimension ); + var newHeight = Math.floor( image.height * maxSize / maxDimension ); + + var canvas = document.createElement( 'canvas' ); + canvas.width = newWidth; + canvas.height = newHeight; + + var ctx = canvas.getContext( "2d" ); + ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); + + return canvas; + + } + + function setCubeTexture ( texture, slot ) { + + if ( texture.image.length === 6 ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.image.__webglTextureCube ) { + + texture.addEventListener( 'dispose', onTextureDispose ); + + texture.image.__webglTextureCube = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + + var isCompressed = texture instanceof THREE.CompressedTexture; + + var cubeImage = []; + + for ( var i = 0; i < 6; i ++ ) { + + if ( _this.autoScaleCubemaps && ! isCompressed ) { + + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); + + } else { + + cubeImage[ i ] = texture.image[ i ]; + + } + + } + + var image = cubeImage[ 0 ], + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + if( !isCompressed ) { + + _gl.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!==THREE.RGBAFormat ) { + + _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } else { + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + } + + } + } + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) { + + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + + } + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + } + + } + + }; + + function setCubeTextureDynamic ( texture, slot ) { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); + + }; + + // Render targets + + function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); + + }; + + function setupRenderBuffer ( renderbuffer, renderTarget ) { + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + /* For some reason this is not working. Defaulting to RGBA4. + } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + */ + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + } else { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + + } + + }; + + this.setRenderTarget = function ( renderTarget ) { + + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); + + if ( renderTarget && ! renderTarget.__webglFramebuffer ) { + + if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; + if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; + + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + + renderTarget.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + // Setup texture, create render and frame buffers + + var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), + glFormat = paramThreeToGL( renderTarget.format ), + glType = paramThreeToGL( renderTarget.type ); + + if ( isCube ) { + + renderTarget.__webglFramebuffer = []; + renderTarget.__webglRenderbuffer = []; + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + + setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); + + } + + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + + } else { + + renderTarget.__webglFramebuffer = _gl.createFramebuffer(); + + if ( renderTarget.shareDepthFrom ) { + + renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; + + } else { + + renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); + + } + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + + setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); + + if ( renderTarget.shareDepthFrom ) { + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + } + + } else { + + setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); + + } + + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + } + + // Release everything + + if ( isCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + + } + + var framebuffer, width, height, vx, vy; + + if ( renderTarget ) { + + if ( isCube ) { + + framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; + + } else { + + framebuffer = renderTarget.__webglFramebuffer; + + } + + width = renderTarget.width; + height = renderTarget.height; + + vx = 0; + vy = 0; + + } else { + + framebuffer = null; + + width = _viewportWidth; + height = _viewportHeight; + + vx = _viewportX; + vy = _viewportY; + + } + + if ( framebuffer !== _currentFramebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.viewport( vx, vy, width, height ); + + _currentFramebuffer = framebuffer; + + } + + _currentWidth = width; + _currentHeight = height; + + }; + + function updateRenderTargetMipmap ( renderTarget ) { + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_2D ); + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + }; + + // Fallback filters for non-power-of-2 textures + + function filterFallback ( f ) { + + if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { + + return _gl.NEAREST; + + } + + return _gl.LINEAR; + + }; + + // Map three.js constants to WebGL constants + + function paramThreeToGL ( p ) { + + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; + if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; + + if ( p === THREE.NearestFilter ) return _gl.NEAREST; + if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; + + if ( p === THREE.LinearFilter ) return _gl.LINEAR; + if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; + + if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; + + if ( p === THREE.ByteType ) return _gl.BYTE; + if ( p === THREE.ShortType ) return _gl.SHORT; + if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === THREE.IntType ) return _gl.INT; + if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === THREE.FloatType ) return _gl.FLOAT; + + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; + if ( p === THREE.RGBFormat ) return _gl.RGB; + if ( p === THREE.RGBAFormat ) return _gl.RGBA; + if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; + if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; + + if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; + if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; + + if ( p === THREE.ZeroFactor ) return _gl.ZERO; + if ( p === THREE.OneFactor ) return _gl.ONE; + if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; + + if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; + if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; + + if ( _glExtensionCompressedTextureS3TC !== undefined ) { + + if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } + + return 0; + + }; + + // Allocations + + function allocateBones ( object ) { + + if ( _supportsBoneTextures && object && object.useVertexTexture ) { + + return 1024; + + } else { + + // default for when object is not specified + // ( for example when prebuilding shader + // to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) + + var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + + var maxBones = nVertexMatrices; + + if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { + + maxBones = Math.min( object.bones.length, maxBones ); + + if ( maxBones < object.bones.length ) { + + console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + + } + + } + + return maxBones; + + } + + }; + + function allocateLights( lights ) { + + var dirLights = 0; + var pointLights = 0; + var spotLights = 0; + var hemiLights = 0; + + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { + + var light = lights[ l ]; + + if ( light.onlyShadow || light.visible === false ) continue; + + if ( light instanceof THREE.DirectionalLight ) dirLights ++; + if ( light instanceof THREE.PointLight ) pointLights ++; + if ( light instanceof THREE.SpotLight ) spotLights ++; + if ( light instanceof THREE.HemisphereLight ) hemiLights ++; + + } + + return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; + + }; + + function allocateShadows( lights ) { + + var maxShadows = 0; + + for ( var l = 0, ll = lights.length; l < ll; l++ ) { + + var light = lights[ l ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight ) maxShadows ++; + if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; + + } + + return maxShadows; + + }; + + // Initialization + + function initGL() { + + 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 ) { + + throw 'Error creating WebGL context.'; + + } + + } catch ( error ) { + + console.error( error ); + + } + + _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); + _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); + _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); + + _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + + _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + + _glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' ); + + + if ( _glExtensionTextureFloat === null ) { + + console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); + + } + + if ( _glExtensionStandardDerivatives === null ) { + + console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); + + } + + if ( _glExtensionTextureFilterAnisotropic === null ) { + + console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); + + } + + if ( _glExtensionCompressedTextureS3TC === null ) { + + console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); + + } + + if ( _glExtensionElementIndexUint === null ) { + + console.log( 'THREE.WebGLRenderer: elementindex as unsigned integer not supported.' ); + + } + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function() { + + return { + "rangeMin" : 1, + "rangeMax" : 1, + "precision" : 1 + }; + + } + } + + if ( _logarithmicDepthBuffer ) { + + _glExtensionFragDepth = _gl.getExtension( 'EXT_frag_depth' ); + + } + + }; + + function setDefaultGLState () { + + _gl.clearColor( 0, 0, 0, 1 ); + _gl.clearDepth( 1 ); + _gl.clearStencil( 0 ); + + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthFunc( _gl.LEQUAL ); + + _gl.frontFace( _gl.CCW ); + _gl.cullFace( _gl.BACK ); + _gl.enable( _gl.CULL_FACE ); + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + // default plugins (order is important) + + this.shadowMapPlugin = new THREE.ShadowMapPlugin(); + this.addPrePlugin( this.shadowMapPlugin ); + + this.addPostPlugin( new THREE.SpritePlugin() ); + this.addPostPlugin( new THREE.LensFlarePlugin() ); + +}; + +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.WebGLRenderTarget = function ( width, height, options ) { + + this.width = width; + this.height = height; + + options = options || {}; + + this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; + this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); + + this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; + this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; + + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + + this.generateMipmaps = true; + + this.shareDepthFrom = null; + +}; + +THREE.WebGLRenderTarget.prototype = { + + constructor: THREE.WebGLRenderTarget, + + setSize: function ( width, height ) { + + this.width = width; + this.height = height; + + }, + + clone: function () { + + var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); + + tmp.wrapS = this.wrapS; + tmp.wrapT = this.wrapT; + + tmp.magFilter = this.magFilter; + tmp.minFilter = this.minFilter; + + tmp.anisotropy = this.anisotropy; + + tmp.offset.copy( this.offset ); + tmp.repeat.copy( this.repeat ); + + tmp.format = this.format; + tmp.type = this.type; + + tmp.depthBuffer = this.depthBuffer; + tmp.stencilBuffer = this.stencilBuffer; + + tmp.generateMipmaps = this.generateMipmaps; + + tmp.shareDepthFrom = this.shareDepthFrom; + + return tmp; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); + +/** + * @author alteredq / http://alteredqualia.com + */ + +THREE.WebGLRenderTargetCube = function ( width, height, options ) { + + THREE.WebGLRenderTarget.call( this, width, height, options ); + + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + +}; + +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); + +THREE.WebGLProgram = ( function () { + + var programIdCount = 0; + + var generateDefines = function ( defines ) { + + var value, chunk, chunks = []; + + for ( var d in defines ) { + + value = defines[ d ]; + if ( value === false ) continue; + + chunk = "#define " + d + " " + value; + chunks.push( chunk ); + + } + + return chunks.join( "\n" ); + + }; + + var cacheUniformLocations = function ( gl, program, identifiers ) { + + var uniforms = {}; + + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { + + var id = identifiers[ i ]; + uniforms[ id ] = gl.getUniformLocation( program, id ); + + } + + return uniforms; + + }; + + var cacheAttributeLocations = function ( gl, program, identifiers ) { + + var attributes = {}; + + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { + + var id = identifiers[ i ]; + attributes[ id ] = gl.getAttribLocation( program, id ); + + } + + return attributes; + + }; + + return function ( renderer, code, material, parameters ) { + + var _this = renderer; + var _gl = _this.context; + + var fragmentShader = material.fragmentShader; + var vertexShader = material.vertexShader; + var uniforms = material.uniforms; + var attributes = material.attributes; + var defines = material.defines; + var index0AttributeName = material.index0AttributeName; + + if ( index0AttributeName === undefined && parameters.morphTargets === true ) { + + // programs with morphTargets displace position out of attribute 0 + + index0AttributeName = 'position'; + + } + + var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; + + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; + + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; + + } + + // console.log( "building new program " ); + + // + + var customDefines = generateDefines( defines ); + + // + + var program = _gl.createProgram(); + + var prefix_vertex, prefix_fragment; + + if ( material instanceof THREE.RawShaderMaterial ) { + + prefix_vertex = ''; + prefix_fragment = ''; + + } else { + + prefix_vertex = [ + + "precision " + parameters.precision + " float;", + "precision " + parameters.precision + " int;", + + customDefines, + + parameters.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + "#define MAX_BONES " + parameters.maxBones, + + parameters.map ? "#define USE_MAP" : "", + parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + + parameters.skinning ? "#define USE_SKINNING" : "", + parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", + + parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", + parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", + + parameters.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", + //_this._glExtensionFragDepth ? "#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;", + "attribute vec2 uv2;", + + "#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", + + "" + + ].join( '\n' ); + + prefix_fragment = [ + + "precision " + parameters.precision + " float;", + "precision " + parameters.precision + " int;", + + ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", + + customDefines, + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + + ( 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.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + + parameters.metal ? "#define METAL" : "", + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + parameters.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", + //_this._glExtensionFragDepth ? "#define USE_LOGDEPTHBUF_EXT" : "", + + "uniform mat4 viewMatrix;", + "uniform vec3 cameraPosition;", + "" + + ].join( '\n' ); + + } + + var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader ); + var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader ); + + _gl.attachShader( program, glVertexShader ); + _gl.attachShader( program, glFragmentShader ); + + if ( index0AttributeName !== undefined ) { + + // Force a particular attribute to index 0. + // because potentially expensive emulation is done by browser if attribute 0 is disabled. + // And, color, for example is often automatically bound to index 0 so disabling it + + _gl.bindAttribLocation( program, 0, index0AttributeName ); + + } + + _gl.linkProgram( program ); + + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { + + console.error( 'Could not initialise shader' ); + console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); + console.error( 'gl.getError()', _gl.getError() ); + + } + + if ( _gl.getProgramInfoLog( program ) !== '' ) { + + console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); + + } + + // clean up + + _gl.deleteShader( glVertexShader ); + _gl.deleteShader( glFragmentShader ); + + // cache uniform locations + + var identifiers = [ + + 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', + 'morphTargetInfluences' + + ]; + + if ( parameters.useVertexTexture ) { + + identifiers.push( 'boneTexture' ); + identifiers.push( 'boneTextureWidth' ); + identifiers.push( 'boneTextureHeight' ); + + } else { + + identifiers.push( 'boneGlobalMatrices' ); + + } + + if ( parameters.logarithmicDepthBuffer ) { + + identifiers.push('logDepthBufFC'); + + } + + + for ( var u in uniforms ) { + + identifiers.push( u ); + + } + + this.uniforms = cacheUniformLocations( _gl, program, identifiers ); + + // cache attributes locations + + identifiers = [ + + "position", "normal", "uv", "uv2", "tangent", "color", + "skinIndex", "skinWeight", "lineDistance" + + ]; + + for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) { + + identifiers.push( "morphTarget" + i ); + + } + + for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) { + + identifiers.push( "morphNormal" + i ); + + } + + for ( var a in attributes ) { + + identifiers.push( a ); + + } + + this.attributes = cacheAttributeLocations( _gl, program, identifiers ); + + // + + this.id = programIdCount ++; + this.code = code; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; + + return this; + + }; + +} )(); + +THREE.WebGLShader = ( function () { + + var addLineNumbers = function ( string ) { + + var lines = string.split( '\n' ); + + for ( var i = 0; i < lines.length; i ++ ) { + + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + + } + + return lines.join( '\n' ); + + }; + + return function ( 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.error( 'THREE.WebGLShader:', 'gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) ); + console.error( addLineNumbers( string ) ); + + } + + return shader; + + }; + +} )(); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableVertex = function () { + + this.position = new THREE.Vector3(); + this.positionWorld = new THREE.Vector3(); + this.positionScreen = new THREE.Vector4(); + + this.visible = true; + +}; + +THREE.RenderableVertex.prototype.copy = function ( vertex ) { + + this.positionWorld.copy( vertex.positionWorld ); + this.positionScreen.copy( vertex.positionScreen ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableFace = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + this.v3 = new THREE.RenderableVertex(); + + this.normalModel = new THREE.Vector3(); + + this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + this.vertexNormalsLength = 0; + + this.color = null; + this.material = null; + this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; + + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableObject = function () { + + this.id = 0; + + this.object = null; + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableSprite = function () { + + this.id = 0; + + this.object = null; + + this.x = 0; + this.y = 0; + this.z = 0; + + this.rotation = 0; + this.scale = new THREE.Vector2(); + + this.material = null; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableLine = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + + this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; + this.material = null; + + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.GeometryUtils = { + + // Merge two geometries or geometry and geometry from object (using object's transform) + + merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { + + var matrix, normalMatrix, + vertexOffset = geometry1.vertices.length, + uvPosition = geometry1.faceVertexUvs[ 0 ].length, + geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, + vertices1 = geometry1.vertices, + vertices2 = geometry2.vertices, + faces1 = geometry1.faces, + faces2 = geometry2.faces, + uvs1 = geometry1.faceVertexUvs[ 0 ], + uvs2 = geometry2.faceVertexUvs[ 0 ]; + + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + + if ( object2 instanceof THREE.Mesh ) { + + object2.matrixAutoUpdate && object2.updateMatrix(); + + matrix = object2.matrix; + + normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + + } + + // vertices + + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + + var vertex = vertices2[ i ]; + + var vertexCopy = vertex.clone(); + + if ( matrix ) vertexCopy.applyMatrix4( matrix ); + + vertices1.push( vertexCopy ); + + } + + // 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 THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); + + if ( normalMatrix ) { + + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + + } + + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + + normal = faceVertexNormals[ j ].clone(); + + if ( normalMatrix ) { + + 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( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + uvs1.push( uvCopy ); + + } + + }, + + // Get random point in triangle (via barycentric coordinates) + // (uniform distribution) + // http://www.cgafaq.info/wiki/Random_Point_In_Triangle + + randomPointInTriangle: function () { + + var vector = new THREE.Vector3(); + + return function ( vectorA, vectorB, vectorC ) { + + var point = new THREE.Vector3(); + + var a = THREE.Math.random16(); + var b = THREE.Math.random16(); + + if ( ( a + b ) > 1 ) { + + a = 1 - a; + b = 1 - b; + + } + + var c = 1 - a - b; + + point.copy( vectorA ); + point.multiplyScalar( a ); + + vector.copy( vectorB ); + vector.multiplyScalar( b ); + + point.add( vector ); + + vector.copy( vectorC ); + vector.multiplyScalar( c ); + + point.add( vector ); + + return point; + + }; + + }(), + + // Get random point in face (triangle / quad) + // (uniform distribution) + + randomPointInFace: function ( face, geometry, useCachedAreas ) { + + var vA, vB, vC, vD; + + vA = geometry.vertices[ face.a ]; + vB = geometry.vertices[ face.b ]; + vC = geometry.vertices[ face.c ]; + + return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); + + }, + + // Get uniformly distributed random points in mesh + // - create array with cumulative sums of face areas + // - pick random number from 0 to total area + // - find corresponding place in area array by binary search + // - get random point in face + + randomPointsInGeometry: function ( geometry, n ) { + + var face, i, + faces = geometry.faces, + vertices = geometry.vertices, + il = faces.length, + totalArea = 0, + cumulativeAreas = [], + vA, vB, vC, vD; + + // precompute face areas + + for ( i = 0; i < il; i ++ ) { + + face = faces[ i ]; + + vA = vertices[ face.a ]; + vB = vertices[ face.b ]; + vC = vertices[ face.c ]; + + face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); + + totalArea += face._area; + + cumulativeAreas[ i ] = totalArea; + + } + + // binary search cumulative areas array + + function binarySearchIndices( value ) { + + function binarySearch( start, end ) { + + // return closest larger index + // if exact number is not found + + if ( end < start ) + return start; + + var mid = start + Math.floor( ( end - start ) / 2 ); + + if ( cumulativeAreas[ mid ] > value ) { + + return binarySearch( start, mid - 1 ); + + } else if ( cumulativeAreas[ mid ] < value ) { + + return binarySearch( mid + 1, end ); + + } else { + + return mid; + + } + + } + + var result = binarySearch( 0, cumulativeAreas.length - 1 ) + return result; + + } + + // pick random face weighted by face area + + var r, index, + result = []; + + var stats = {}; + + for ( i = 0; i < n; i ++ ) { + + r = THREE.Math.random16() * totalArea; + + index = binarySearchIndices( r ); + + result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); + + if ( ! stats[ index ] ) { + + stats[ index ] = 1; + + } else { + + stats[ index ] += 1; + + } + + } + + return result; + + }, + + // Get triangle area (half of parallelogram) + // http://mathworld.wolfram.com/TriangleArea.html + + triangleArea: function () { + + var vector1 = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); + + return function ( vectorA, vectorB, vectorC ) { + + vector1.subVectors( vectorB, vectorA ); + vector2.subVectors( vectorC, vectorA ); + vector1.cross( vector2 ); + + return 0.5 * vector1.length(); + + }; + + }(), + + // Center geometry so that 0,0,0 is in center of bounding box + + center: function ( geometry ) { + + geometry.computeBoundingBox(); + + var bb = geometry.boundingBox; + + var offset = new THREE.Vector3(); + + offset.addVectors( bb.min, bb.max ); + offset.multiplyScalar( -0.5 ); + + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); + geometry.computeBoundingBox(); + + return offset; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageUtils = { + + crossOrigin: undefined, + + loadTexture: function ( url, mapping, onLoad, onError ) { + + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; + + var texture = new THREE.Texture( undefined, mapping ); + + var image = loader.load( url, function () { + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } ); + + texture.image = image; + texture.sourceFile = url; + + return texture; + + }, + + loadCompressedTexture: function ( url, mapping, onLoad, onError ) { + + var texture = new THREE.CompressedTexture(); + texture.mapping = mapping; + + var request = new XMLHttpRequest(); + + request.onload = function () { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + texture.format = dds.format; + + texture.mipmaps = dds.mipmaps; + texture.image.width = dds.width; + texture.image.height = dds.height; + + // gl.generateMipmap fails for compressed textures + // mipmaps must be embedded in the DDS file + // or texture filters must not use mipmapping + + texture.generateMipmaps = false; + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + return texture; + + }, + + loadTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.Texture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping needed for cube textures + + texture.flipY = false; + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = new Image(); + images[ i ] = cubeImage; + + cubeImage.onload = function () { + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + }; + + cubeImage.onerror = onError; + + cubeImage.crossOrigin = this.crossOrigin; + cubeImage.src = array[ i ]; + + } + + return texture; + + }, + + loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + texture.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + texture.generateMipmaps = false; + + var generateCubeFaceCallback = function ( rq, img ) { + + return function () { + + var buffer = rq.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + img.format = dds.format; + + img.mipmaps = dds.mipmaps; + img.width = dds.width; + img.height = dds.height; + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + } + + // compressed cubemap textures as 6 separate DDS files + + if ( array instanceof Array ) { + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = {}; + images[ i ] = cubeImage; + + var request = new XMLHttpRequest(); + + request.onload = generateCubeFaceCallback( request, cubeImage ); + request.onerror = onError; + + var url = array[ i ]; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + // compressed cubemap texture stored in a single DDS file + + } else { + + var url = array; + var request = new XMLHttpRequest(); + + request.onload = function( ) { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + if ( dds.isCubemap ) { + + var faces = dds.mipmaps.length / dds.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); + images[ f ].format = dds.format; + images[ f ].width = dds.width; + images[ f ].height = dds.height; + + } + + } + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + return texture; + + }, + + loadDDSTexture: function ( url, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + texture.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + texture.generateMipmaps = false; + + { + var request = new XMLHttpRequest(); + + request.onload = function( ) { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + if ( dds.isCubemap ) { + + var faces = dds.mipmaps.length / dds.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); + images[ f ].format = dds.format; + images[ f ].width = dds.width; + images[ f ].height = dds.height; + + } + + } + + + } else { + texture.image.width = dds.width; + texture.image.height = dds.height; + texture.mipmaps = dds.mipmaps; + } + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + return texture; + + }, + + parseDDS: function ( buffer, loadMipmaps ) { + + var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + + // Adapted from @toji's DDS utils + // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + + // All values and structures referenced from: + // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + + var DDS_MAGIC = 0x20534444; + + var DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000; + + var DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000; + + var DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000; + + var DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000; + + function fourCCToInt32( value ) { + + return value.charCodeAt(0) + + (value.charCodeAt(1) << 8) + + (value.charCodeAt(2) << 16) + + (value.charCodeAt(3) << 24); + + } + + function int32ToFourCC( value ) { + + return String.fromCharCode( + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff + ); + } + + function loadARGBMip( buffer, dataOffset, width, height ) { + var dataLength = width*height*4; + var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); + var byteArray = new Uint8Array( dataLength ); + var dst = 0; + var src = 0; + for ( var y = 0; y < height; y++ ) { + for ( var x = 0; x < width; x++ ) { + var b = srcBuffer[src]; src++; + var g = srcBuffer[src]; src++; + var r = srcBuffer[src]; src++; + var a = srcBuffer[src]; src++; + byteArray[dst] = r; dst++; //r + byteArray[dst] = g; dst++; //g + byteArray[dst] = b; dst++; //b + byteArray[dst] = a; dst++; //a + } + } + return byteArray; + } + + var FOURCC_DXT1 = fourCCToInt32("DXT1"); + var FOURCC_DXT3 = fourCCToInt32("DXT3"); + var FOURCC_DXT5 = fourCCToInt32("DXT5"); + + var headerLengthInt = 31; // The header length in 32 bit ints + + // Offsets into the header array + + var off_magic = 0; + + var off_size = 1; + var off_flags = 2; + var off_height = 3; + var off_width = 4; + + var off_mipmapCount = 7; + + var off_pfFlags = 20; + var off_pfFourCC = 21; + var off_RGBBitCount = 22; + var off_RBitMask = 23; + var off_GBitMask = 24; + var off_BBitMask = 25; + var off_ABitMask = 26; + + var off_caps = 27; + var off_caps2 = 28; + var off_caps3 = 29; + var off_caps4 = 30; + + // Parse header + + var header = new Int32Array( buffer, 0, headerLengthInt ); + + if ( header[ off_magic ] !== DDS_MAGIC ) { + + console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); + return dds; + + } + + if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { + + console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); + return dds; + + } + + var blockBytes; + + var fourCC = header[ off_pfFourCC ]; + + var isRGBAUncompressed = false; + + switch ( fourCC ) { + + case FOURCC_DXT1: + + blockBytes = 8; + dds.format = THREE.RGB_S3TC_DXT1_Format; + break; + + case FOURCC_DXT3: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT3_Format; + break; + + case FOURCC_DXT5: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT5_Format; + break; + + default: + + if( header[off_RGBBitCount] ==32 + && header[off_RBitMask]&0xff0000 + && header[off_GBitMask]&0xff00 + && header[off_BBitMask]&0xff + && header[off_ABitMask]&0xff000000 ) { + isRGBAUncompressed = true; + blockBytes = 64; + dds.format = THREE.RGBAFormat; + } else { + console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); + return dds; + } + } + + dds.mipmapCount = 1; + + if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { + + dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); + + } + + //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. + + dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; + + dds.width = header[ off_width ]; + dds.height = header[ off_height ]; + + var dataOffset = header[ off_size ] + 4; + + // Extract mipmaps buffers + + var width = dds.width; + var height = dds.height; + + var faces = dds.isCubemap ? 6 : 1; + + for ( var face = 0; face < faces; face ++ ) { + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + if( isRGBAUncompressed ) { + var byteArray = loadARGBMip( buffer, dataOffset, width, height ); + var dataLength = byteArray.length; + } else { + var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; + var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); + } + + var mipmap = { "data": byteArray, "width": width, "height": height }; + dds.mipmaps.push( mipmap ); + + dataOffset += dataLength; + + width = Math.max( width * 0.5, 1 ); + height = Math.max( height * 0.5, 1 ); + + } + + width = dds.width; + height = dds.height; + + } + + return dds; + + }, + + getNormalMap: function ( image, depth ) { + + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + + var cross = function ( a, b ) { + + return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; + + } + + var subtract = function ( a, b ) { + + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; + + } + + var normalize = function ( a ) { + + var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); + return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; + + } + + depth = depth | 1; + + var width = image.width; + var height = image.height; + + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0 ); + + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; + + for ( var x = 0; x < width; x ++ ) { + + for ( var y = 0; y < height; y ++ ) { + + var ly = y - 1 < 0 ? 0 : y - 1; + var uy = y + 1 > height - 1 ? height - 1 : y + 1; + var lx = x - 1 < 0 ? 0 : x - 1; + var ux = x + 1 > width - 1 ? width - 1 : x + 1; + + var points = []; + var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; + points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + + var normals = []; + var num_points = points.length; + + for ( var i = 0; i < num_points; i ++ ) { + + var v1 = points[ i ]; + var v2 = points[ ( i + 1 ) % num_points ]; + v1 = subtract( v1, origin ); + v2 = subtract( v2, origin ); + normals.push( normalize( cross( v1, v2 ) ) ); + + } + + var normal = [ 0, 0, 0 ]; + + for ( var i = 0; i < normals.length; i ++ ) { + + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; + + } + + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; + + var idx = ( y * width + x ) * 4; + + output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; + output[ idx + 3 ] = 255; + + } + + } + + context.putImageData( imageData, 0, 0 ); + + return canvas; + + }, + + generateDataTexture: function ( width, height, color ) { + + var size = width * height; + var data = new Uint8Array( 3 * size ); + + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); + + for ( var i = 0; i < size; i ++ ) { + + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; + + } + + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; + + return texture; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneUtils = { + + createMultiMaterialObject: function ( geometry, materials ) { + + var group = new THREE.Object3D(); + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + group.add( new THREE.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 THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); + + scene.remove( child ); + parent.add( child ); + + } + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For Text operations in three.js (See TextGeometry) + * + * It uses techniques used in: + * + * typeface.js and canvastext + * For converting fonts and rendering with javascript + * http://typeface.neocracy.org + * + * Triangulation ported from AS3 + * Simple Polygon Triangulation + * http://actionsnippet.com/?p=1462 + * + * A Method to triangulate shapes with holes + * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ + * + */ + +THREE.FontUtils = { + + faces : {}, + + // Just for now. face[weight][style] + + face : "helvetiker", + weight: "normal", + style : "normal", + size : 150, + divisions : 10, + + getFace : function() { + + return this.faces[ this.face ][ this.weight ][ this.style ]; + + }, + + loadFace : function( data ) { + + var family = data.familyName.toLowerCase(); + + var ThreeFont = this; + + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; + + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + return data; + + }, + + drawText : function( text ) { + + var characterPts = [], allPts = []; + + // RenderText + + var i, p, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; + + var fontPaths = []; + + for ( i = 0; i < length; i ++ ) { + + var path = new THREE.Path(); + + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; + + fontPaths.push( ret.path ); + + } + + // get the width + + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } + + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; + + //extract.paths = fontPaths; + //extract.offset = width; + + return { paths : fontPaths, offset : width }; + + }, + + + + + extractGlyphPoints : function( c, face, scale, offset, path ) { + + var pts = []; + + var i, i2, divisions, + outline, action, length, + scaleX, scaleY, + x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, + laste, + glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; + + if ( !glyph ) return; + + if ( glyph.o ) { + + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; + + scaleX = scale; + scaleY = scale; + + for ( i = 0; i < length; ) { + + action = outline[ i ++ ]; + + //console.log( action ); + + switch( action ) { + + case 'm': + + // Move To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + + path.moveTo( x, y ); + break; + + case 'l': + + // Line To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + path.lineTo(x,y); + break; + + case 'q': + + // QuadraticCurveTo + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * scaleY; + + path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } + + } + + break; + + case 'b': + + // Cubic Bezier Curve + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * -scaleY; + cpx2 = outline[ i++ ] * scaleX + offset; + cpy2 = outline[ i++ ] * -scaleY; + + path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + } + + } + + break; + + } + + } + } + + + + return { offset: glyph.ha*scale, path:path}; + } + +}; + + +THREE.FontUtils.generateShapes = function( text, parameters ) { + + // Parameters + + parameters = parameters || {}; + + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; + + var font = parameters.font !== undefined ? parameters.font : "helvetiker"; + var weight = parameters.weight !== undefined ? parameters.weight : "normal"; + var style = parameters.style !== undefined ? parameters.style : "normal"; + + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; + + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; + + // Get a Font data json object + + var data = THREE.FontUtils.drawText( text ); + + var paths = data.paths; + var shapes = []; + + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + + } + + return shapes; + +}; + + +/** + * 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( namespace ) { + + var EPSILON = 0.0000000001; + + // takes in an contour array and returns + + var process = function( 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 ( 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.log( "Warning, unable to triangulate polygon!" ); + + 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; + + }; + + // calculate area of the contour polygon + + var 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; + + }; + + var snip = function ( 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 ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) 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 >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; + + } + + return true; + + }; + + + namespace.Triangulate = process; + namespace.Triangulate.area = area; + + return namespace; + +})(THREE.FontUtils); + +// To use the typeface.js face files, hook up the API +self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; +THREE.typeface_js = self._typeface_js; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTagentAt(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.SplineCurve3 + * THREE.ClosedSplineCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ + +/************************************************************** + * Abstract Curve base class + **************************************************************/ + +THREE.Curve = function () { + +}; + +// Virtual base class method to overwrite and implement in subclasses +// - t [0 .. 1] + +THREE.Curve.prototype.getPoint = function ( t ) { + + console.log( "Warning, getPoint() not implemented!" ); + return null; + +}; + +// Get point at relative position in curve according to arc length +// - u [0 .. 1] + +THREE.Curve.prototype.getPointAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); + +}; + +// Get sequence of points using getPoint( t ) + +THREE.Curve.prototype.getPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPoint( d / divisions ) ); + + } + + return pts; + +}; + +// Get sequence of points using getPointAt( u ) + +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPointAt( d / divisions ) ); + + } + + return pts; + +}; + +// Get total curve arc length + +THREE.Curve.prototype.getLength = function () { + + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; + +}; + +// Get list of cumulative segment lengths + +THREE.Curve.prototype.getLengths = function ( divisions ) { + + if ( !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. + +}; + + +THREE.Curve.prototype.updateArcLengths = function() { + this.needsUpdate = true; + this.getLengths(); +}; + +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance + +THREE.Curve.prototype.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; + continue; + + } else if ( comparison > 0 ) { + + high = i - 1; + continue; + + } 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 interpolatation 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 + +THREE.Curve.prototype.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(); + +}; + + +THREE.Curve.prototype.getTangentAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); + +}; + + + + + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Curve.Utils = { + + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { + + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + + }, + + // Puay Bing, thanks for helping with this derivative! + + tangentCubicBezier: function (t, p0, p1, p2, p3 ) { + + return -3 * p0 * (1 - t) * (1 - t) + + 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + + 6 * t * p2 * (1-t) - 3 * t * t * p2 + + 3 * t * t * p3; + }, + + + tangentSpline: function ( t, p0, p1, p2, p3 ) { + + // To check if my formulas are correct + + var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 + var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t + var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 + var h11 = 3 * t * t - 2 * t; // t3 − t2 + + return h00 + h10 + h01 + h11; + + }, + + // Catmull-Rom + + interpolate: function( p0, p1, p2, p3, t ) { + + 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; + + } + +}; + + +// TODO: Transformation for Curves? + +/************************************************************** + * 3D Curves + **************************************************************/ + +// A Factory method for creating new curve subclasses + +THREE.Curve.create = function ( constructor, getPointFunc ) { + + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.getPoint = getPointFunc; + + return constructor; + +}; + +/** + * @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 + **************************************************************/ + +THREE.CurvePath = function () { + + this.curves = []; + this.bends = []; + + this.autoClose = false; // Automatically closes the path +}; + +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CurvePath.prototype.add = function ( curve ) { + + this.curves.push( curve ); + +}; + +THREE.CurvePath.prototype.checkConnection = function() { + // TODO + // If the ending of curve is not connected to the starting + // or the next curve, then, this is not a real path +}; + +THREE.CurvePath.prototype.closePath = function() { + // TODO Test + // and verify for vector3 (needs to implement equals) + // 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 THREE.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') + +THREE.CurvePath.prototype.getPoint = function( t ) { + + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; + + // To think about boundaries points. + + while ( i < curveLengths.length ) { + + if ( curveLengths[ i ] >= d ) { + + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; + + var u = 1 - diff / curve.getLength(); + + return curve.getPointAt( u ); + + break; + } + + i ++; + + } + + return null; + + // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; + + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; + + if ( v3 ) { + + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; + + } + + sum.add( p ); + + } + + var ret = { + + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY + + }; + + if ( v3 ) { + + ret.maxZ = maxZ; + ret.minZ = minZ; + + } + + return ret; + +}; + +/************************************************************** + * Create Geometries Helpers + **************************************************************/ + +/// Generate geometry from path points (for Line or ParticleSystem objects) + +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +// Generate geometry from equidistance sampling along the path + +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { + + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +THREE.CurvePath.prototype.createGeometry = function( points ) { + + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < points.length; i ++ ) { + + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); + + } + + return geometry; + +}; + + +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ + +// Wrap path / Bend modifiers? + +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + + this.bends.push( bendpath ); + +}; + +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { + + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { + + var oldPts = this.getSpacedPoints( segments ); + + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html + +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { + + var bounds = this.getBoundingBox(); + + var i, il, p, oldX, oldY, xNorm; + + for ( i = 0, il = oldPts.length; i < il; i ++ ) { + + p = oldPts[ i ]; + + oldX = p.x; + oldY = p.y; + + xNorm = oldX / bounds.maxX; + + // If using actual distance, for length > path, requires line extrusions + //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance + + xNorm = path.getUtoTmapping( xNorm, oldX ); + + // check for out of bounds? + + var pathPt = path.getPoint( xNorm ); + var normal = path.getTangent( xNorm ); + normal.set( -normal.y, normal.x ).multiplyScalar( oldY ); + + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; + + } + + return oldPts; + +}; + + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Gyroscope = function () { + + THREE.Object3D.call( this ); + +}; + +THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); + this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); + + this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); + + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + +}; + +THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); +THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); +THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); +THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); + + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ + +THREE.Path = function ( points ) { + + THREE.CurvePath.call(this); + + this.actions = []; + + if ( points ) { + + this.fromPoints( points ); + + } + +}; + +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); + +THREE.PathActions = { + + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve + BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve + CSPLINE_THRU: 'splineThru', // Catmull-rom spline + ARC: 'arc', // Circle + ELLIPSE: 'ellipse' +}; + +// TODO Clean up PATH API + +// Create path using straight lines to connect all points +// - vectors: array of Vector2 + +THREE.Path.prototype.fromPoints = function ( vectors ) { + + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { + + this.lineTo( vectors[ v ].x, vectors[ v ].y ); + + }; + +}; + +// startPath() endPath()? + +THREE.Path.prototype.moveTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); + +}; + +THREE.Path.prototype.lineTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); + +}; + +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCP1x, aCP1y ), + new THREE.Vector2( aCP2x, aCP2y ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { + + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; +//--- + var npts = [ new THREE.Vector2( x0, y0 ) ]; + Array.prototype.push.apply( npts, pts ); + + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + +}; + +// FUTURE: Change the API or follow canvas API? + +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absarc(aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); + }; + +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absellipse(aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var args = Array.prototype.slice.call( arguments ); + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + this.curves.push( curve ); + + var lastPoint = curve.getPoint(1); + args.push(lastPoint.x); + args.push(lastPoint.y); + + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); + + }; + +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { + + if ( ! divisions ) divisions = 40; + + var points = []; + + for ( var i = 0; i < divisions; i ++ ) { + + points.push( this.getPoint( i / divisions ) ); + + //if( !this.getPoint( i / divisions ) ) throw "DIE"; + + } + + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } + + return points; + +}; + +/* Return an array of vectors based on contour of the path */ + +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { + + if (this.useSpacedPoints) { + console.log('tata'); + return this.getSpacedPoints( divisions, closedPath ); + } + + divisions = divisions || 12; + + var points = []; + + var i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + action = item.action; + args = item.args; + + switch( action ) { + + case THREE.PathActions.MOVE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.LINE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.QUADRATIC_CURVE_TO: + + cpx = args[ 2 ]; + cpy = args[ 3 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.BEZIER_CURVE_TO: + + cpx = args[ 4 ]; + cpy = args[ 5 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.CSPLINE_THRU: + + laste = this.actions[ i - 1 ].args; + + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; + + var n = divisions * args[ 0 ].length; + + spts = spts.concat( args[ 0 ] ); + + var spline = new THREE.SplineCurve( spts ); + + for ( j = 1; j <= n; j ++ ) { + + points.push( spline.getPointAt( j / n ) ) ; + + } + + break; + + case THREE.PathActions.ARC: + + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !!args[ 5 ]; + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + case THREE.PathActions.ELLIPSE: + + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !!args[ 6 ]; + + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + } // end switch + + } + + + + // Normalize to remove the closing point by default. + var lastPoint = points[ points.length - 1]; + var EPSILON = 0.0000000001; + if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && + Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) + points.splice( points.length - 1, 1); + if ( closedPath ) { + + points.push( points[ 0 ] ); + + } + + return points; + +}; + +// Breaks path into shapes + +THREE.Path.prototype.toShapes = function( isCCW ) { + + function isPointInsidePolygon( inPt, inPolygon ) { + var EPSILON = 0.0000000001; + + 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) > 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 colinear + if ( inPt.y != edgeLowPt.y ) continue; // parallel + // egde 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 i, il, item, action, args; + + var subPaths = [], lastPath = new THREE.Path(); + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + args = item.args; + action = item.action; + + if ( action == THREE.PathActions.MOVE_TO ) { + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + lastPath = new THREE.Path(); + + } + + } + + lastPath[ action ].apply( lastPath, args ); + + } + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + + } + + // console.log(subPaths); + + if ( subPaths.length == 0 ) return []; + + var solid, tmpPath, tmpShape, shapes = []; + + if ( subPaths.length == 1) { + + tmpPath = subPaths[0]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + + } + + var holesFirst = !THREE.Shape.Utils.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 ( i = 0, il = subPaths.length; i < il; i ++ ) { + + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = THREE.Shape.Utils.isClockWise( tmpPoints ); + solid = isCCW ? !solid : solid; + + if ( solid ) { + + if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx++; + + newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; + newShapes[mainIdx].s.actions = tmpPath.actions; + 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); + + } + + } + + if ( newShapes.length > 1 ) { + var ambigious = 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 sh = newShapes[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 { + ambigious = true; + } + } + } + if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } + } + } + // console.log("ambigious: ", ambigious); + if ( toChange.length > 0 ) { + // console.log("to change: ", toChange); + if (! ambigious) newShapeHoles = betterShapeHoles; + } + } + + var tmpHoles, j, jl; + for ( i = 0, il = newShapes.length; i < il; i ++ ) { + tmpShape = newShapes[i].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[i]; + for ( 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 + * 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. + +THREE.Shape = function () { + + THREE.Path.apply( this, arguments ); + this.holes = []; + +}; + +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); + +// Convenience method to return ExtrudeGeometry + +THREE.Shape.prototype.extrude = function ( options ) { + + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; + +}; + +// Convenience method to return ShapeGeometry + +THREE.Shape.prototype.makeGeometry = function ( options ) { + + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; + +}; + +// Get points of holes + +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + +// Get points of holes (spaced by regular distance) + +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + + +// Get points of shape and holes (keypoints based on segments parameter) + +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { + + return { + + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) + + }; + +}; + +THREE.Shape.prototype.extractPoints = function ( divisions ) { + + if (this.useSpacedPoints) { + return this.extractAllSpacedPoints(divisions); + } + + return this.extractAllPoints(divisions); + +}; + +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; + +// Get points of shape and holes (spaced by regular distance) + +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + + return { + + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) + + }; + +}; + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Shape.Utils = { + + triangulateShape: function ( contour, holes ) { + + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { + // inOtherPt needs to be colinear 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 EPSILON = 0.0000000001; + + 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) > 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 colinear + if ( ( perpSeg1 != 0 ) || + ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; + + // they are collinear or degenerate + var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? + var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist 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 + + var EPSILON = 0.0000000001; + + // 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) > 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 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 = 0; 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 ); + + // 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.log( "Duplicate point", key ); + + } + + allPointsMap[ key ] = i; + + } + + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); + + var triangles = THREE.FontUtils.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 THREE.FontUtils.Triangulate.area( pts ) < 0; + + }, + + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + + // Quad Bezier Functions + + b2p0: function ( t, p ) { + + var k = 1 - t; + return k * k * p; + + }, + + b2p1: function ( t, p ) { + + return 2 * ( 1 - t ) * t * p; + + }, + + b2p2: function ( t, p ) { + + return t * t * p; + + }, + + b2: function ( t, p0, p1, p2 ) { + + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); + + }, + + // Cubic Bezier Functions + + b3p0: function ( t, p ) { + + var k = 1 - t; + return k * k * k * p; + + }, + + b3p1: function ( t, p ) { + + var k = 1 - t; + return 3 * k * k * t * p; + + }, + + b3p2: function ( t, p ) { + + var k = 1 - t; + return 3 * k * t * t * p; + + }, + + b3p3: function ( t, p ) { + + return t * t * t * p; + + }, + + b3: function ( t, p0, p1, p2, p3 ) { + + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); + + } + +}; + + +/************************************************************** + * Line + **************************************************************/ + +THREE.LineCurve = function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.LineCurve.prototype.getPoint = function ( t ) { + + 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 + +THREE.LineCurve.prototype.getPointAt = function ( u ) { + + return this.getPoint( u ); + +}; + +THREE.LineCurve.prototype.getTangent = function( t ) { + + var tangent = this.v2.clone().sub(this.v1); + + return tangent.normalize(); + +}; +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ + + +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + + +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + + return new THREE.Vector2( tx, ty ); + +}; + + +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); + + // returns unit vector + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; +/************************************************************** + * Cubic Bezier curve + **************************************************************/ + +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + +}; + +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + return new THREE.Vector2( tx, ty ); + +}; + +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; +/************************************************************** + * Spline curve + **************************************************************/ + +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { + + this.points = (points == undefined) ? [] : points; + +}; + +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.SplineCurve.prototype.getPoint = function ( t ) { + + var v = new THREE.Vector2(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + + return v; + +}; +/************************************************************** + * Ellipse curve + **************************************************************/ + +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { + + this.aX = aX; + this.aY = aY; + + this.xRadius = xRadius; + this.yRadius = yRadius; + + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; + + this.aClockwise = aClockwise; + +}; + +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.EllipseCurve.prototype.getPoint = function ( t ) { + + var angle; + var deltaAngle = this.aEndAngle - this.aStartAngle; + + if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; + if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; + + if ( this.aClockwise === true ) { + + angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + + } else { + + angle = this.aStartAngle + t * deltaAngle; + + } + + var tx = this.aX + this.xRadius * Math.cos( angle ); + var ty = this.aY + this.yRadius * Math.sin( angle ); + + return new THREE.Vector2( tx, ty ); + +}; + +/************************************************************** + * Arc curve + **************************************************************/ + +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +}; + +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +/************************************************************** + * Line3D + **************************************************************/ + +THREE.LineCurve3 = THREE.Curve.create( + + function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var r = new THREE.Vector3(); + + + r.subVectors( this.v2, this.v1 ); // diff + r.multiplyScalar( t ); + r.add( this.v1 ); + + return r; + + } + +); + +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ + +THREE.QuadraticBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ + +THREE.CubicBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); +/************************************************************** + * Spline 3D curve + **************************************************************/ + + +THREE.SplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + + var pt0 = points[ c[0] ], + pt1 = points[ c[1] ], + pt2 = points[ c[2] ], + pt3 = points[ c[3] ]; + + v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); + v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); + v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); + + return v; + + } + +); + + +// THREE.SplineCurve3.prototype.getTangent = function(t) { +// var v = new THREE.Vector3(); +// var c = []; +// var points = this.points, point, intPoint, weight; +// point = ( points.length - 1 ) * t; + +// intPoint = Math.floor( point ); +// weight = point - intPoint; + +// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; +// c[ 1 ] = intPoint; +// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; +// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + +// var pt0 = points[ c[0] ], +// pt1 = points[ c[1] ], +// pt2 = points[ c[2] ], +// pt3 = points[ c[3] ]; + +// // t = weight; +// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); +// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); +// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); + +// return v; + +// } +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ + + +THREE.ClosedSplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 0 ) * t; + // This needs to be from 0-length +1 + + intPoint = Math.floor( point ); + weight = point - intPoint; + + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; + c[ 0 ] = ( intPoint - 1 ) % points.length; + c[ 1 ] = ( intPoint ) % points.length; + c[ 2 ] = ( intPoint + 1 ) % points.length; + c[ 3 ] = ( intPoint + 2 ) % points.length; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); + + return v; + + } + +); +/** + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.AnimationHandler = ( function () { + + var playing = []; + var library = {}; + var that = {}; + + that.update = function ( deltaTimeMS ) { + + for ( var i = 0; i < playing.length; i ++ ) { + + playing[ i ].update( deltaTimeMS ); + + } + + }; + + that.addToUpdate = function ( animation ) { + + if ( playing.indexOf( animation ) === -1 ) { + + playing.push( animation ); + + } + + }; + + that.removeFromUpdate = function ( animation ) { + + var index = playing.indexOf( animation ); + + if ( index !== -1 ) { + + playing.splice( index, 1 ); + + } + + }; + + that.add = function ( data ) { + + if ( library[ data.name ] !== undefined ) { + + console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); + + } + + library[ data.name ] = data; + initData( data ); + + }; + + that.remove = function ( name ) { + + if ( library[ name ] === undefined ) { + + console.log( "THREE.AnimationHandler.add: Warning! " + name + " doesn't exists in library. Doing nothing." ); + + } + + library[ name ] = undefined; + + }; + + that.get = function ( name ) { + + if ( typeof name === "string" ) { + + if ( library[ name ] ) { + + return library[ name ]; + + } else { + + return null; + + } + + } else { + + // todo: add simple tween library + + } + + }; + + that.parse = function ( root ) { + + // setup hierarchy + + var hierarchy = []; + + if ( root instanceof THREE.SkinnedMesh ) { + + for ( var b = 0; b < root.bones.length; b++ ) { + + hierarchy.push( root.bones[ b ] ); + + } + + } else { + + parseRecurseHierarchy( root, hierarchy ); + + } + + return hierarchy; + + }; + + var parseRecurseHierarchy = function ( root, hierarchy ) { + + hierarchy.push( root ); + + for ( var c = 0; c < root.children.length; c++ ) + parseRecurseHierarchy( root.children[ c ], hierarchy ); + + } + + var initData = function ( data ) { + + if ( data.initialized === true ) + return; + + + // loop through all keys + + for ( var h = 0; h < data.hierarchy.length; h ++ ) { + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + // remove minus times + + if ( data.hierarchy[ h ].keys[ k ].time < 0 ) { + + data.hierarchy[ h ].keys[ k ].time = 0; + + } + + // create quaternions + + if ( data.hierarchy[ h ].keys[ k ].rot !== undefined && + !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { + + var quat = data.hierarchy[ h ].keys[ k ].rot; + data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat ); + + } + + } + + // prepare morph target keys + + if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { + + // get all used + + var usedMorphTargets = {}; + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; + usedMorphTargets[ morphTargetName ] = -1; + + } + + } + + data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; + + + // set all used on all frames + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + var influences = {}; + + for ( var morphTargetName in usedMorphTargets ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { + + influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; + break; + + } + + } + + if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { + + influences[ morphTargetName ] = 0; + + } + + } + + data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + + } + + } + + + // remove all keys that are on the same time + + for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { + + data.hierarchy[ h ].keys.splice( k, 1 ); + k --; + + } + + } + + + // set index + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + data.hierarchy[ h ].keys[ k ].index = k; + + } + + } + + data.initialized = true; + + }; + + + // interpolation types + + that.LINEAR = 0; + that.CATMULLROM = 1; + that.CATMULLROM_FORWARD = 2; + + return that; + +}() ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Animation = function ( root, name ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( name ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + + this.currentTime = 0; + this.timeScale = 1; + + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + + this.interpolationType = THREE.AnimationHandler.LINEAR; + +}; + +THREE.Animation.prototype.play = function ( startTime ) { + + this.currentTime = startTime !== undefined ? startTime : 0; + + if ( this.isPlaying === false ) { + + this.isPlaying = true; + + this.reset(); + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + +THREE.Animation.prototype.pause = function() { + + if ( this.isPaused === true ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +THREE.Animation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + THREE.AnimationHandler.removeFromUpdate( this ); + +}; + +THREE.Animation.prototype.reset = function () { + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var object = this.hierarchy[ h ]; + + object.matrixAutoUpdate = true; + + if ( object.animationCache === undefined ) { + + object.animationCache = {}; + object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var prevKey = object.animationCache.prevKey; + var nextKey = object.animationCache.nextKey; + + prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; + + nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); + nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); + nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); + + } + +}; + + +THREE.Animation.prototype.update = (function(){ + + var points = []; + var target = new THREE.Vector3(); + + // Catmull-Rom spline + + var interpolateCatmullRom = function ( points, scale ) { + + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; + + pa = points[ c[ 0 ] ]; + pb = points[ c[ 1 ] ]; + pc = points[ c[ 2 ] ]; + pd = points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); + v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); + v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); + + return v3; + + }; + + var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + }; + + return function ( delta ) { + if ( this.isPlaying === false ) return; + + this.currentTime += delta * this.timeScale; + + // + + var vector; + var types = [ "pos", "rot", "scl" ]; + + var duration = this.data.length; + + if ( this.loop === true && this.currentTime > duration ) { + + this.currentTime %= duration; + this.reset(); + + } else if ( this.loop === false && this.currentTime > duration ) { + + this.stop(); + return; + + } + + this.currentTime = Math.min( this.currentTime, duration ); + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache; + + // loop through pos/rot/scl + + for ( var t = 0; t < 3; t ++ ) { + + // get keys + + var type = types[ t ]; + var prevKey = animationCache.prevKey[ type ]; + var nextKey = animationCache.nextKey[ type ]; + + if ( nextKey.time <= this.currentTime ) { + + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); + + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + + } + + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; + + } + + object.matrixAutoUpdate = true; + object.matrixWorldNeedsUpdate = true; + + var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); + + var prevXYZ = prevKey[ type ]; + var nextXYZ = nextKey[ type ]; + + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; + + // interpolate + + if ( type === "pos" ) { + + vector = object.position; + + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; + points[ 1 ] = prevXYZ; + points[ 2 ] = nextXYZ; + points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; + + scale = scale * 0.33 + 0.33; + + var currentPoint = interpolateCatmullRom( points, scale ); + + vector.x = currentPoint[ 0 ]; + vector.y = currentPoint[ 1 ]; + vector.z = currentPoint[ 2 ]; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); + + target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + target.sub( vector ); + target.y = 0; + target.normalize(); + + var angle = Math.atan2( target.x, target.z ); + object.rotation.set( 0, angle, 0 ); + + } + + } + + } else if ( type === "rot" ) { + + THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); + + } else if ( type === "scl" ) { + + vector = object.scale; + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } + + } + + } + + }; + +})(); + + + + + +// Get next key with + +THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key < keys.length - 1 ? key : keys.length - 1; + + } else { + + key = key % keys.length; + + } + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ 0 ]; + +}; + +// Get previous key with + +THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key > 0 ? key : 0; + + } else { + + key = key >= 0 ? key : key + keys.length; + + } + + + for ( ; key >= 0; key -- ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author khang duong + * @author erik kitson + */ + +THREE.KeyFrameAnimation = function ( root, data ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( data ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + this.currentTime = 0; + this.timeScale = 0.001; + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + + // initialize to first keyframes + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + obj = this.hierarchy[h]; + + if ( keys.length && sids ) { + + for ( var s = 0; s < sids.length; s++ ) { + + var sid = sids[ s ], + next = this.getNextKeyWith( sid, h, 0 ); + + if ( next ) { + + next.apply( sid ); + + } + + } + + obj.matrixAutoUpdate = false; + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; + + } + + } + +}; + +// Play + +THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { + + this.currentTime = startTime !== undefined ? startTime : 0; + + if ( this.isPlaying === false ) { + + this.isPlaying = true; + + // reset key cache + + var h, hl = this.hierarchy.length, + object, + node; + + for ( h = 0; h < hl; h++ ) { + + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; + + if ( node.animationCache === undefined ) { + + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var keys = this.data.hierarchy[h].keys; + + if (keys.length) { + + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; + + this.startTime = Math.min( keys[0].time, this.startTime ); + this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); + + } + + } + + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + + +// Pause + +THREE.KeyFrameAnimation.prototype.pause = function() { + + if( this.isPaused ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +// Stop + +THREE.KeyFrameAnimation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + + THREE.AnimationHandler.removeFromUpdate( this ); + + // reset JIT matrix and remove cache + + for ( var h = 0; h < this.data.hierarchy.length; h++ ) { + + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; + + if ( node.animationCache !== undefined ) { + + var original = node.animationCache.originalMatrix; + + if( obj instanceof THREE.Bone ) { + + original.copy( obj.skinMatrix ); + obj.skinMatrix = original; + + } else { + + original.copy( obj.matrix ); + obj.matrix = original; + + } + + delete node.animationCache; + + } + + } + +}; + + +// Update + +THREE.KeyFrameAnimation.prototype.update = function ( delta ) { + + if ( this.isPlaying === false ) return; + + this.currentTime += delta * this.timeScale; + + // + + var duration = this.data.length; + + if ( this.loop === true && this.currentTime > duration ) { + + this.currentTime %= duration; + + } + + this.currentTime = Math.min( this.currentTime, duration ); + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + + var object = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; + + var keys = node.keys, + animationCache = node.animationCache; + + + if ( keys.length ) { + + var prevKey = animationCache.prevKey; + var nextKey = animationCache.nextKey; + + if ( nextKey.time <= this.currentTime ) { + + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; + + } + + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; + + } + + if ( nextKey.time >= this.currentTime ) { + + prevKey.interpolate( nextKey, this.currentTime ); + + } else { + + prevKey.interpolate( nextKey, nextKey.time ); + + } + + this.data.hierarchy[ h ].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; + + } + + } + +}; + +// Get next key with + +THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ 0 ]; + +}; + +// Get previous key with + +THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; + + for ( ; key >= 0; key-- ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ keys.length - 1 ]; + +}; + +/** + * @author mrdoob / http://mrdoob.com + */ + +THREE.MorphAnimation = function ( mesh ) { + + this.mesh = mesh; + this.frames = mesh.morphTargetInfluences.length; + this.currentTime = 0; + this.duration = 1000; + this.loop = true; + + this.isPlaying = false; + +}; + +THREE.MorphAnimation.prototype = { + + play: function () { + + this.isPlaying = true; + + }, + + pause: function () { + + this.isPlaying = false; + }, + + update: ( function () { + + var lastFrame = 0; + var currentFrame = 0; + + return function ( delta ) { + + if ( this.isPlaying === false ) return; + + this.currentTime += delta; + + if ( this.loop === true && this.currentTime > this.duration ) { + + this.currentTime %= this.duration; + + } + + this.currentTime = Math.min( this.currentTime, this.duration ); + + var interpolation = this.duration / this.frames; + var frame = Math.floor( this.currentTime / interpolation ); + + if ( frame != currentFrame ) { + + this.mesh.morphTargetInfluences[ lastFrame ] = 0; + this.mesh.morphTargetInfluences[ currentFrame ] = 1; + this.mesh.morphTargetInfluences[ frame ] = 0; + + lastFrame = currentFrame; + currentFrame = frame; + + } + + this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; + this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; + + } + + } )() + +}; + +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CubeCamera = function ( near, far, cubeResolution ) { + + THREE.Object3D.call( this ); + + var fov = 90, aspect = 1; + + var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, -1, 0 ); + cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); + + var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, -1, 0 ); + cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); + this.add( cameraNX ); + + var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); + + var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, -1 ); + cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); + this.add( cameraNY ); + + var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, -1, 0 ); + cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); + + var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, -1, 0 ); + cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); + this.add( cameraNZ ); + + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); + + this.updateCubeMap = function ( renderer, scene ) { + + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; + + renderTarget.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.generateMipmaps = generateMipmaps; + + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); + + }; + +}; + +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); + +/** + * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog + * + * A general perpose camera, for setting FOV, Lens Focal Length, + * and switching between perspective and orthographic views easily. + * Use this only if you do not wish to manage + * both a Orthographic and Perspective Camera + * + */ + + +THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { + + THREE.Camera.call( this ); + + this.fov = fov; + + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + + // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects + + this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); + this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); + + this.zoom = 1; + + this.toPerspective(); + + var aspect = width/height; + +}; + +THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.CombinedCamera.prototype.toPerspective = function () { + + // Switches to the Perspective Camera + + this.near = this.cameraP.near; + this.far = this.cameraP.far; + + this.cameraP.fov = this.fov / this.zoom ; + + this.cameraP.updateProjectionMatrix(); + + this.projectionMatrix = this.cameraP.projectionMatrix; + + this.inPerspectiveMode = true; + this.inOrthographicMode = false; + +}; + +THREE.CombinedCamera.prototype.toOrthographic = function () { + + // Switches to the Orthographic camera estimating viewport from Perspective + + var fov = this.fov; + var aspect = this.cameraP.aspect; + var near = this.cameraP.near; + var far = this.cameraP.far; + + // The size that we set is the mid plane of the viewing frustum + + var hyperfocus = ( near + far ) / 2; + + var halfHeight = Math.tan( fov / 2 ) * hyperfocus; + var planeHeight = 2 * halfHeight; + var planeWidth = planeHeight * aspect; + var halfWidth = planeWidth / 2; + + halfHeight /= this.zoom; + halfWidth /= this.zoom; + + this.cameraO.left = -halfWidth; + this.cameraO.right = halfWidth; + this.cameraO.top = halfHeight; + this.cameraO.bottom = -halfHeight; + + // this.cameraO.left = -farHalfWidth; + // this.cameraO.right = farHalfWidth; + // this.cameraO.top = farHalfHeight; + // this.cameraO.bottom = -farHalfHeight; + + // this.cameraO.left = this.left / this.zoom; + // this.cameraO.right = this.right / this.zoom; + // this.cameraO.top = this.top / this.zoom; + // this.cameraO.bottom = this.bottom / this.zoom; + + this.cameraO.updateProjectionMatrix(); + + this.near = this.cameraO.near; + this.far = this.cameraO.far; + this.projectionMatrix = this.cameraO.projectionMatrix; + + this.inPerspectiveMode = false; + this.inOrthographicMode = true; + +}; + + +THREE.CombinedCamera.prototype.setSize = function( width, height ) { + + this.cameraP.aspect = width / height; + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + +}; + + +THREE.CombinedCamera.prototype.setFov = function( fov ) { + + this.fov = fov; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +// For mantaining similar API with PerspectiveCamera + +THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toPerspective(); + this.toOrthographic(); + + } + +}; + +/* +* Uses Focal Length (in mm) to estimate and set FOV +* 35mm (fullframe) camera is used if frame size is not specified; +* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html +*/ +THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + + this.setFov( fov ); + + return fov; +}; + + +THREE.CombinedCamera.prototype.setZoom = function( zoom ) { + + this.zoom = zoom; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +THREE.CombinedCamera.prototype.toFrontView = function() { + + this.rotation.x = 0; + this.rotation.y = 0; + this.rotation.z = 0; + + // should we be modifing the matrix instead? + + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBackView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toLeftView = function() { + + this.rotation.x = 0; + this.rotation.y = - Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toRightView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toTopView = function() { + + this.rotation.x = - Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBottomView = function() { + + this.rotation.x = Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as + */ + +THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + THREE.Geometry.call( this ); + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; + + var scope = this; + + var width_half = width / 2; + var height_half = height / 2; + var depth_half = depth / 2; + + buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx + buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py + buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny + buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz + buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz + + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { + + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; + + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + + w = 'z'; + + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { + + w = 'y'; + gridY = scope.depthSegments; + + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { + + w = 'x'; + gridX = scope.depthSegments; + + } + + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); + + normal[ w ] = depth > 0 ? 1 : - 1; + + for ( iy = 0; iy < gridY1; iy ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; + + scope.vertices.push( vector ); + + } + + } + + 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; + + var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); + var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); + var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); + var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); + + var face = new THREE.Face3( a + offset, b + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + face = new THREE.Face3( b + offset, c + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + + } + + } + + this.mergeVertices(); + +}; + +THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author hughes + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { + + 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; + + // + + var elements = segments + 2; + + var indices = new Uint16Array( segments * 3 ); + var vertices = new Float32Array( elements * 3 ); + var normals = new Float32Array( elements * 3 ); + var uvs = new Float32Array( elements * 2 ); + + // center + + normals[ 2 ] = 1; + + uvs[ 0 ] = 0.5; + uvs[ 1 ] = 0.5; + + var offset = 0, offset2 = 2, offset3 = 3; + + for ( var i = 0; i <= segments; i ++ ) { + + var segment = thetaStart + i / segments * thetaLength; + + var x = radius * Math.cos( segment ); + var y = radius * Math.sin( segment ); + + vertices[ offset3 ] = x; + vertices[ offset3 + 1 ] = y; + + normals[ offset3 + 2 ] = 1; + + uvs[ offset2 ] = ( x / radius + 1 ) / 2; + uvs[ offset2 + 1 ] = ( y / radius + 1 ) / 2; + + offset2 += 2; + offset3 += 3; + + // + + indices[ offset ] = 0; + indices[ offset + 1 ] = i + 1; + indices[ offset + 2 ] = i + 2; + + offset += 3; + + } + + THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs ); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.CircleGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype ); + +// DEPRECATED + +THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { + console.warn( 'DEPRECATED: THREE.CubeGeometry is deprecated. Use THREE.BoxGeometry instead.' ); + return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); + }; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { + + THREE.Geometry.call( this ); + + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded + }; + + radiusTop = radiusTop !== undefined ? radiusTop : 20; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + height = height !== undefined ? height : 100; + + radialSegments = radialSegments || 8; + heightSegments = heightSegments || 1; + + openEnded = openEnded !== undefined ? openEnded : false; + + var heightHalf = height / 2; + + var x, y, vertices = [], uvs = []; + + for ( y = 0; y <= heightSegments; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + var v = y / heightSegments; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + + for ( x = 0; x <= radialSegments; x ++ ) { + + var u = x / radialSegments; + + var vertex = new THREE.Vector3(); + vertex.x = radius * Math.sin( u * Math.PI * 2 ); + vertex.y = - v * height + heightHalf; + vertex.z = radius * Math.cos( u * Math.PI * 2 ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; + + for ( x = 0; x < radialSegments; x ++ ) { + + if ( radiusTop !== 0 ) { + + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); + + } else { + + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); + + } + + na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); + nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); + + for ( y = 0; y < heightSegments; y ++ ) { + + var v1 = vertices[ y ][ x ]; + var v2 = vertices[ y + 1 ][ x ]; + var v3 = vertices[ y + 1 ][ x + 1 ]; + var v4 = vertices[ y ][ x + 1 ]; + + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); + + var uv1 = uvs[ y ][ x ].clone(); + var uv2 = uvs[ y + 1 ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); + var uv4 = uvs[ y ][ x + 1 ].clone(); + + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + + } + + } + + // top cap + + if ( openEnded === false && radiusTop > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); + + for ( x = 0; x < radialSegments; x ++ ) { + + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); + + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 0 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + // bottom cap + + if ( openEnded === false && radiusBottom > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); + + for ( x = 0; x < radialSegments; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 1 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + this.computeFaceNormals(); + +} + +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @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 segements 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: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) + * frames: // containing arrays of tangents, normals, binormals + * + * material: // material index for front and back faces + * extrudeMaterial: // material index for extrusion and beveled faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ + +THREE.ExtrudeGeometry = function ( shapes, options ) { + + if ( typeof( shapes ) === "undefined" ) { + shapes = []; + return; + } + + THREE.Geometry.call( this ); + + shapes = shapes instanceof Array ? shapes : [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + 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 ) ); + +}; + +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +THREE.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 ); + } +}; + +THREE.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; + + var material = options.material; + var extrudeMaterial = options.extrudeMaterial; + + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + + var shapebb = this.shapebb; + //shapebb = shape.getBoundingBox(); + + + + var splineTube, binormal, normal, position2; + if ( extrudePath ) { + + extrudePts = extrudePath.getSpacedPoints( steps ); + + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion + + // SETUP TNB variables + + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? + + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); + + } + + // Safeguards if bevels are not enabled + + if ( ! bevelEnabled ) { + + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + + } + + // Variables initalization + + var ahole, h, hl; // looping of holes + var scope = this; + var bevelPoints = []; + + var shapesOffset = this.vertices.length; + + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.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 ( THREE.Shape.Utils.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 = THREE.Shape.Utils.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.log( "die" ); + + return vec.clone().multiplyScalar( size ).add( pt ); + + } + + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length, + cont, clen = contour.length; + + + // Find directions for point movement + + var RAD_TO_DEGREES = 180 / Math.PI; + + + function getBevelVec( inPt, inPrev, inNext ) { + + var EPSILON = 0.0000000001; + var sign = THREE.Math.sign; + + // computes for inPt the corresponding point inPt' on a new contour + // shiftet 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 colinear edges + var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear + + // 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 THREE.Vector2( v_trans_x, v_trans_y ); + } else { + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + } + + } else { // handle special case of colinear edges + + var direction_eq = false; // assumes: opposite + if ( v_prev_x > EPSILON ) { + if ( v_next_x > EPSILON ) { direction_eq = true; } + } else { + if ( v_prev_x < -EPSILON ) { + if ( v_next_x < -EPSILON ) { direction_eq = true; } + } else { + if ( sign(v_prev_y) == 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 THREE.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) + + var pt_i = contour[ i ]; + var pt_j = contour[ j ]; + var pt_k = contour[ 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 * ( 1 - t ); + + //z = bevelThickness * t; + bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved + //bs = bevelSize * t ; // linear + + // 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 * ( 1 - t ); + //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); + bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; + + // contract shape + + for ( i = 0, 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, true ); + + } + + 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, false ); + + } + + } else { + + // Bottom faces + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); + + } + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); + + } + } + + } + + // 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 THREE.Vector3( x, y, z ) ); + + } + + function f3( a, b, c, isBottom ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + + // normal, color, material + scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + + var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, 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 THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); + scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); + + var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, + stepIndex, stepsLength, contourIndex1, contourIndex2 ); + + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + + } + +}; + +THREE.ExtrudeGeometry.WorldUVGenerator = { + + generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y; + + return [ + new THREE.Vector2( ax, ay ), + new THREE.Vector2( bx, by ), + new THREE.Vector2( cx, cy ) + ]; + + }, + + generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + + return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); + + }, + + generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, + indexA, indexB, indexC, indexD, stepIndex, stepsLength, + contourIndex1, contourIndex2 ) { + + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + az = geometry.vertices[ indexA ].z, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + bz = geometry.vertices[ indexB ].z, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y, + cz = geometry.vertices[ indexC ].z, + + dx = geometry.vertices[ indexD ].x, + dy = geometry.vertices[ indexD ].y, + dz = geometry.vertices[ indexD ].z; + + if ( Math.abs( ay - by ) < 0.01 ) { + return [ + new THREE.Vector2( ax, 1 - az ), + new THREE.Vector2( bx, 1 - bz ), + new THREE.Vector2( cx, 1 - cz ), + new THREE.Vector2( dx, 1 - dz ) + ]; + } else { + return [ + new THREE.Vector2( ay, 1 - az ), + new THREE.Vector2( by, 1 - bz ), + new THREE.Vector2( cy, 1 - cz ), + new THREE.Vector2( dy, 1 - dz ) + ]; + } + } +}; + +THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); + +/** + * @author jonobr1 / http://jonobr1.com + * + * Creates a one-sided polygonal geometry from a path shape. Similar to + * ExtrudeGeometry. + * + * parameters = { + * + * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. + * + * material: // material index for front and back faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ + +THREE.ShapeGeometry = function ( shapes, options ) { + + THREE.Geometry.call( this ); + + if ( shapes instanceof Array === false ) shapes = [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + this.addShapeList( shapes, options ); + + this.computeFaceNormals(); + +}; + +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * Add an array of shapes to THREE.ShapeGeometry. + */ +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { + + for ( var i = 0, l = shapes.length; i < l; i++ ) { + + this.addShape( shapes[ i ], options ); + + } + + return this; + +}; + +/** + * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. + */ +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { + + if ( options === undefined ) options = {}; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; + + var shapebb = this.shapebb; + + // + + var i, l, hole, s; + + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.isClockWise( vertices ); + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe... + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + + if ( THREE.Shape.Utils.isClockWise( hole ) ) { + + holes[ i ] = hole.reverse(); + + } + + } + + reverse = false; + + } + + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); + + // Vertices + + var contour = vertices; + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + vertices = vertices.concat( hole ); + + } + + // + + var vert, vlen = vertices.length; + var face, flen = faces.length; + var cont, clen = contour.length; + + for ( i = 0; i < vlen; i++ ) { + + vert = vertices[ i ]; + + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); + + } + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + + var a = face[ 0 ] + shapesOffset; + var b = face[ 1 ] + shapesOffset; + var c = face[ 2 ] + shapesOffset; + + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); + + } + +}; + +/** + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://exocortex.com + */ + +// 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 2*PI) range of the lathed section +// 2*pi is a closed lathe, less than 2PI is a portion. +THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { + + THREE.Geometry.call( this ); + + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; + + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; + + for ( var i = 0, il = segments; i <= il; i ++ ) { + + var phi = phiStart + i * inverseSegments * phiLength; + + var c = Math.cos( phi ), + s = Math.sin( phi ); + + for ( var j = 0, jl = points.length; j < jl; j ++ ) { + + var pt = points[ j ]; + + var vertex = new THREE.Vector3(); + + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; + + this.vertices.push( vertex ); + + } + + } + + var np = points.length; + + for ( var i = 0, il = segments; i < il; i ++ ) { + + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { + + var base = j + np * i; + var a = base; + var b = base + np; + var c = base + 1 + np; + var d = base + 1; + + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; + + this.faces.push( new THREE.Face3( a, b, d ) ); + + this.faceVertexUvs[ 0 ].push( [ + + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u0, v1 ) + + ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + + this.faceVertexUvs[ 0 ].push( [ + + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) + + ] ); + + + } + + } + + this.mergeVertices(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { + + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; + + var width_half = width / 2; + var height_half = height / 2; + + var gridX = widthSegments || 1; + var gridY = heightSegments || 1; + + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + + var segment_width = width / gridX; + var segment_height = height / gridY; + + var vertices = new Float32Array( gridX1 * gridY1 * 3 ); + var normals = new Float32Array( gridX1 * gridY1 * 3 ); + var uvs = new Float32Array( gridX1 * gridY1 * 2 ); + + var offset = 0; + var offset2 = 0; + + for ( var iy = 0; iy < gridY1; iy ++ ) { + + var y = iy * segment_height - height_half; + + for ( var ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segment_width - width_half; + + vertices[ offset ] = x; + vertices[ offset + 1 ] = - y; + + normals[ offset + 2 ] = 1; + + uvs[ offset2 ] = ix / gridX; + uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); + + offset += 3; + offset2 += 2; + + } + + } + + offset = 0; + + var indices = new ( vertices.length > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); + + for ( var iy = 0; iy < gridY; iy ++ ) { + + for ( var 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; + + indices[ offset ] = a; + indices[ offset + 1 ] = b; + indices[ offset + 2 ] = d; + + indices[ offset + 3 ] = b; + indices[ offset + 4 ] = c; + indices[ offset + 5 ] = d; + + offset += 6; + + } + + } + + THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs ); + +}; + +THREE.PlaneGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype ); + +/** + * @author Kaleb Murphy + */ + +THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + + innerRadius = innerRadius || 0; + 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( 3, phiSegments ) : 8; + + var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + + for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring + + for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + + var vertex = new THREE.Vector3(); + var segment = thetaStart + o / thetaSegments * thetaLength; + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); + } + + radius += radiusStep; + + } + + var n = new THREE.Vector3( 0, 0, 1 ); + + for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring + + var thetaSegment = i * thetaSegments; + + for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + + var segment = o + thetaSegment; + + var v1 = segment + i; + var v2 = segment + thetaSegments + i; + var v3 = segment + thetaSegments + 1 + i; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + + v1 = segment + i; + v2 = segment + thetaSegments + 1 + i; + v3 = segment + 1 + i; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + + } + } + + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + + 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 x, y, vertices = [], uvs = []; + + for ( y = 0; y <= heightSegments; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + for ( x = 0; x <= widthSegments; x ++ ) { + + var u = x / widthSegments; + var v = y / heightSegments; + + var vertex = new THREE.Vector3(); + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + for ( y = 0; y < heightSegments; y ++ ) { + + for ( x = 0; x < widthSegments; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = vertices[ y + 1 ][ x ]; + var v4 = vertices[ y + 1 ][ x + 1 ]; + + var n1 = this.vertices[ v1 ].clone().normalize(); + var n2 = this.vertices[ v2 ].clone().normalize(); + var n3 = this.vertices[ v3 ].clone().normalize(); + var n4 = this.vertices[ v4 ].clone().normalize(); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x ].clone(); + var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); + + if ( Math.abs( this.vertices[ v1 ].y ) === radius ) { + + uv1.x = ( uv1.x + uv2.x ) / 2; + this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); + + } else if ( Math.abs( this.vertices[ v3 ].y ) === radius ) { + + uv3.x = ( uv3.x + uv4.x ) / 2; + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } else { + + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + + } + + } + + } + + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For creating 3D text geometry in three.js + * + * Text = 3D Text + * + * parameters = { + * size: , // size of the text + * height: , // thickness to extrude text + * curveSegments: , // number of points on the curves + * + * font: , // font name + * weight: , // font weight (normal, bold) + * style: , // font style (normal, italics) + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into text bevel goes + * bevelSize: , // how far from text outline is bevel + * } + * + */ + +/* Usage Examples + + // TextGeometry wrapper + + var text3d = new TextGeometry( text, options ); + + // Complete manner + + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); + +*/ + + +THREE.TextGeometry = function ( text, parameters ) { + + parameters = parameters || {}; + + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); + + // 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; + + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); + +}; + +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); + +/** + * @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 + */ + +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { + + THREE.Geometry.call( this ); + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; + + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 8; + tubularSegments = tubularSegments || 6; + arc = arc || Math.PI * 2; + + var center = new THREE.Vector3(), uvs = [], normals = []; + + for ( var j = 0; j <= radialSegments; j ++ ) { + + for ( var i = 0; i <= tubularSegments; i ++ ) { + + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; + + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + + var vertex = new THREE.Vector3(); + 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 ); + + this.vertices.push( vertex ); + + uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); + + } + + } + + for ( var j = 1; j <= radialSegments; j ++ ) { + + for ( var i = 1; i <= tubularSegments; i ++ ) { + + 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; + + var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); + + face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); + + } + + } + + this.computeFaceNormals(); + +}; + +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author oosmoxiecode + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 + */ + +THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { + + THREE.Geometry.call( this ); + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + p: p, + q: q, + heightScale: heightScale + }; + + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 64; + tubularSegments = tubularSegments || 8; + p = p || 2; + q = q || 3; + heightScale = heightScale || 1; + + var grid = new Array( radialSegments ); + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); + + for ( var i = 0; i < radialSegments; ++ i ) { + + grid[ i ] = new Array( tubularSegments ); + var u = i / radialSegments * 2 * p * Math.PI; + var p1 = getPos( u, q, p, radius, heightScale ); + var p2 = getPos( u + 0.01, q, p, radius, heightScale ); + tang.subVectors( p2, p1 ); + n.addVectors( p2, p1 ); + + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); + + for ( var j = 0; j < tubularSegments; ++ j ) { + + var v = j / tubularSegments * 2 * Math.PI; + var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + var cy = tube * Math.sin( v ); + + var pos = new THREE.Vector3(); + pos.x = p1.x + cx * n.x + cy * bitan.x; + pos.y = p1.y + cx * n.y + cy * bitan.y; + pos.z = p1.z + cx * n.z + cy * bitan.z; + + grid[ i ][ j ] = this.vertices.push( pos ) - 1; + + } + + } + + for ( var i = 0; i < radialSegments; ++ i ) { + + for ( var j = 0; j < tubularSegments; ++ j ) { + + var ip = ( i + 1 ) % radialSegments; + var jp = ( j + 1 ) % tubularSegments; + + var a = grid[ i ][ j ]; + var b = grid[ ip ][ j ]; + var c = grid[ ip ][ jp ]; + var d = grid[ i ][ jp ]; + + var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); + var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); + var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); + var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); + + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + } + + this.computeFaceNormals(); + this.computeVertexNormals(); + + function getPos( u, in_q, in_p, radius, heightScale ) { + + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); + + var tx = radius * ( 2 + cs ) * 0.5 * cu; + var ty = radius * ( 2 + cs ) * su * 0.5; + var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; + + return new THREE.Vector3( tx, ty, tz ); + + } + +}; + +THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * + * Modified from the TorusKnotGeometry by @oosmoxiecode + * + * Creates a tube which extrudes along a 3d spline + * + * Uses parallel transport frames as described in + * http://www.cs.indiana.edu/pub/techreports/TR425.pdf + */ + +THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed ) { + + THREE.Geometry.call( this ); + + this.parameters = { + path: path, + segments: segments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; + + segments = segments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; + + var grid = []; + + var scope = this, + + tangent, + normal, + binormal, + + numpoints = segments + 1, + + x, y, z, + tx, ty, tz, + u, v, + + cx, cy, + pos, pos2 = new THREE.Vector3(), + i, j, + ip, jp, + a, b, c, d, + uva, uvb, uvc, uvd; + + var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), + tangents = frames.tangents, + normals = frames.normals, + binormals = frames.binormals; + + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + function vert( x, y, z ) { + + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + + } + + // consruct the grid + + for ( i = 0; i < numpoints; i++ ) { + + grid[ i ] = []; + + u = i / ( numpoints - 1 ); + + pos = path.getPointAt( u ); + + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; + + for ( j = 0; j < radialSegments; j++ ) { + + v = j / radialSegments * 2 * Math.PI; + + cx = -radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = radius * Math.sin( v ); + + pos2.copy( pos ); + pos2.x += cx * normal.x + cy * binormal.x; + pos2.y += cx * normal.y + cy * binormal.y; + pos2.z += cx * normal.z + cy * binormal.z; + + grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + + } + } + + + // construct the mesh + + for ( i = 0; i < segments; i++ ) { + + for ( j = 0; j < radialSegments; j++ ) { + + ip = ( closed ) ? (i + 1) % segments : i + 1; + jp = (j + 1) % radialSegments; + + a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = grid[ ip ][ j ]; + c = grid[ ip ][ jp ]; + d = grid[ i ][ jp ]; + + uva = new THREE.Vector2( i / segments, j / radialSegments ); + uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); + uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); + uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); + + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + } + + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + + +// For computing of Frenet frames, exposing the tangents, normals and binormals the spline +THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { + + var tangent = new THREE.Vector3(), + normal = new THREE.Vector3(), + binormal = new THREE.Vector3(), + + tangents = [], + normals = [], + binormals = [], + + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), + + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, + + tx, ty, tz, + i, u, v; + + + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + // compute the tangent vectors for each segment on the path + + for ( i = 0; i < numpoints; i++ ) { + + u = i / ( numpoints - 1 ); + + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); + + } + + initialNormal3(); + + function initialNormal1(lastBinormal) { + // fixed start binormal. Has dangers of 0 vectors + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); + normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + } + + function initialNormal2() { + + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); + + normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); + binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + + } + + function initialNormal3() { + // select an initial normal vector perpenicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component + + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + smallest = Number.MAX_VALUE; + tx = Math.abs( tangents[ 0 ].x ); + ty = Math.abs( tangents[ 0 ].y ); + tz = Math.abs( tangents[ 0 ].z ); + + if ( tx <= smallest ) { + smallest = tx; + normal.set( 1, 0, 0 ); + } + + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); + } + + if ( tz <= smallest ) { + 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 path + + for ( i = 1; i < numpoints; i++ ) { + + normals[ i ] = normals[ i-1 ].clone(); + + binormals[ i ] = binormals[ i-1 ].clone(); + + vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + + if ( vec.length() > epsilon ) { + + vec.normalize(); + + theta = Math.acos( THREE.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 ) { + + theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); + theta /= ( numpoints - 1 ); + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { + + theta = -theta; + + } + + for ( i = 1; i < numpoints; i++ ) { + + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + } +}; + +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { + + THREE.Geometry.call( this ); + + radius = radius || 1; + detail = detail || 0; + + var that = this; + + for ( var i = 0, l = vertices.length; i < l; i += 3 ) { + + prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); + + } + + var midpoints = [], p = this.vertices; + + var faces = []; + + for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { + + var v1 = p[ indices[ i ] ]; + var v2 = p[ indices[ i + 1 ] ]; + var v3 = p[ indices[ i + 2 ] ]; + + faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + + } + + var centroid = new THREE.Vector3(); + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + subdivide( faces[ i ], detail ); + + } + + + // Handle case when face straddles the seam + + for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { + + var uvs = this.faceVertexUvs[ 0 ][ i ]; + + var x0 = uvs[ 0 ].x; + var x1 = uvs[ 1 ].x; + var x2 = uvs[ 2 ].x; + + var max = Math.max( x0, Math.max( x1, x2 ) ); + var min = Math.min( x0, Math.min( x1, x2 ) ); + + if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary + + if ( x0 < 0.2 ) uvs[ 0 ].x += 1; + if ( x1 < 0.2 ) uvs[ 1 ].x += 1; + if ( x2 < 0.2 ) uvs[ 2 ].x += 1; + + } + + } + + + // Apply radius + + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + + this.vertices[ i ].multiplyScalar( radius ); + + } + + + // Merge vertices + + this.mergeVertices(); + + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + + + // Project vector onto sphere's surface + + function prepare( vector ) { + + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; + + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + + var u = azimuth( vector ) / 2 / Math.PI + 0.5; + var v = inclination( vector ) / Math.PI + 0.5; + vertex.uv = new THREE.Vector2( u, 1 - v ); + + return vertex; + + } + + + // Approximate a curved face with recursively sub-divided triangles. + + function make( v1, v2, v3 ) { + + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + that.faces.push( face ); + + centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); + + var azi = azimuth( centroid ); + + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); + + } + + + // Analytically subdivide a face to the required detail level. + + function subdivide( face, detail ) { + + var cols = Math.pow(2, detail); + var cells = Math.pow(4, detail); + var a = prepare( that.vertices[ face.a ] ); + var b = prepare( that.vertices[ face.b ] ); + var c = prepare( that.vertices[ face.c ] ); + var v = []; + + // Construct all of the vertices for this subdivision. + + for ( var i = 0 ; i <= cols; i ++ ) { + + v[ i ] = []; + + var aj = prepare( a.clone().lerp( c, i / cols ) ); + var bj = prepare( b.clone().lerp( c, i / cols ) ); + var rows = cols - i; + + for ( var j = 0; j <= rows; j ++) { + + if ( j == 0 && i == cols ) { + + v[ i ][ j ] = aj; + + } else { + + v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); + + } + + } + + } + + // Construct all of the faces. + + for ( var i = 0; i < cols ; i ++ ) { + + for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { + + var k = Math.floor( j / 2 ); + + if ( j % 2 == 0 ) { + + make( + v[ i ][ k + 1], + v[ i + 1 ][ k ], + v[ i ][ k ] + ); + + } else { + + make( + v[ i ][ k + 1 ], + v[ i + 1][ k + 1], + v[ i + 1 ][ k ] + ); + + } + + } + + } + + } + + + // 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 ) ) ); + + } + + + // Texture fixing helper. Spheres have some odd behaviours. + + function correctUV( uv, vector, azimuth ) { + + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); + return uv.clone(); + + } + + +}; + +THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.IcosahedronGeometry = function ( radius, detail ) { + + this.parameters = { + radius: radius, + detail: 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 + ]; + + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); + +}; + +THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.OctahedronGeometry = function ( radius, detail ) { + + this.parameters = { + radius: radius, + detail: 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 + ]; + + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); +}; + +THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.TetrahedronGeometry = function ( 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 + ]; + + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); + +}; + +THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author zz85 / https://github.com/zz85 + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + * + * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); + * + */ + +THREE.ParametricGeometry = function ( func, slices, stacks ) { + + THREE.Geometry.call( this ); + + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; + + var i, il, j, p; + var u, v; + + var stackCount = stacks + 1; + var sliceCount = slices + 1; + + for ( i = 0; i <= stacks; i ++ ) { + + v = i / stacks; + + for ( j = 0; j <= slices; j ++ ) { + + u = j / slices; + + p = func( u, v ); + verts.push( p ); + + } + } + + var a, b, c, d; + var uva, uvb, uvc, uvd; + + for ( i = 0; i < stacks; i ++ ) { + + for ( j = 0; j < slices; j ++ ) { + + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = (i + 1) * sliceCount + j + 1; + d = (i + 1) * sliceCount + j; + + uva = new THREE.Vector2( j / slices, i / stacks ); + uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); + uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); + uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); + + faces.push( new THREE.Face3( a, b, d ) ); + uvs.push( [ uva, uvb, uvd ] ); + + faces.push( new THREE.Face3( b, c, d ) ); + uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + + } + + // console.log(this); + + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); + + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AxisHelper = function ( size ) { + + size = size || 1; + + var geometry = new THREE.Geometry(); + + geometry.vertices.push( + new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) + ); + + geometry.colors.push( + new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), + new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), + new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) + ); + + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + +}; + +THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://github.com/zz85 + * @author bhouston / http://exocortex.com + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * hex - color in hex value + * headLength - Number + * headWidth - Number + */ + +THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) { + + // dir is assumed to be normalized + + THREE.Object3D.call( this ); + + if ( hex === undefined ) hex = 0xffff00; + if ( length === undefined ) length = 1; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; + + this.position = origin; + + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); + lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); + + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + + var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); + + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); + + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); + +}; + +THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ArrowHelper.prototype.setDirection = function () { + + var axis = new THREE.Vector3(); + var radians; + + return function ( 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 ); + + } + + }; + +}(); + +THREE.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, length, 1 ); + this.line.updateMatrix(); + + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); + +}; + +THREE.ArrowHelper.prototype.setColor = function ( hex ) { + + this.line.material.color.setHex( hex ); + this.cone.material.color.setHex( hex ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BoxHelper = function ( object ) { + + // 5____4 + // 1/___0/| + // | 6__|_7 + // 2/___3/ + + var vertices = [ + new THREE.Vector3( 1, 1, 1 ), + new THREE.Vector3( - 1, 1, 1 ), + new THREE.Vector3( - 1, - 1, 1 ), + new THREE.Vector3( 1, - 1, 1 ), + + new THREE.Vector3( 1, 1, - 1 ), + new THREE.Vector3( - 1, 1, - 1 ), + new THREE.Vector3( - 1, - 1, - 1 ), + new THREE.Vector3( 1, - 1, - 1 ) + ]; + + this.vertices = vertices; + + // TODO: Wouldn't be nice if Line had .segments? + + var geometry = new THREE.Geometry(); + geometry.vertices.push( + vertices[ 0 ], vertices[ 1 ], + vertices[ 1 ], vertices[ 2 ], + vertices[ 2 ], vertices[ 3 ], + vertices[ 3 ], vertices[ 0 ], + + vertices[ 4 ], vertices[ 5 ], + vertices[ 5 ], vertices[ 6 ], + vertices[ 6 ], vertices[ 7 ], + vertices[ 7 ], vertices[ 4 ], + + vertices[ 0 ], vertices[ 4 ], + vertices[ 1 ], vertices[ 5 ], + vertices[ 2 ], vertices[ 6 ], + vertices[ 3 ], vertices[ 7 ] + ); + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); + + if ( object !== undefined ) { + + this.update( object ); + + } + +}; + +THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.BoxHelper.prototype.update = function ( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingBox === null ) { + + geometry.computeBoundingBox(); + + } + + var min = geometry.boundingBox.min; + var max = geometry.boundingBox.max; + var vertices = this.vertices; + + vertices[ 0 ].set( max.x, max.y, max.z ); + vertices[ 1 ].set( min.x, max.y, max.z ); + vertices[ 2 ].set( min.x, min.y, max.z ); + vertices[ 3 ].set( max.x, min.y, max.z ); + vertices[ 4 ].set( max.x, max.y, min.z ); + vertices[ 5 ].set( min.x, max.y, min.z ); + vertices[ 6 ].set( min.x, min.y, min.z ); + vertices[ 7 ].set( max.x, min.y, min.z ); + + this.geometry.computeBoundingSphere(); + this.geometry.verticesNeedUpdate = true; + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +/** + * @author WestLangley / http://github.com/WestLangley + */ + +// a helper to show the world-axis-aligned bounding box for an object + +THREE.BoundingBoxHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0x888888; + + this.object = object; + + this.box = new THREE.Box3(); + + THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); + +}; + +THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.BoundingBoxHelper.prototype.update = function () { + + this.box.setFromObject( this.object ); + + this.box.size( this.scale ); + + this.box.center( this.position ); + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - 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 + */ + +THREE.CameraHelper = function ( camera ) { + + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); + + var pointMap = {}; + + // colors + + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; + + // near + + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); + + // far + + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); + + // sides + + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); + + // cone + + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); + + // up + + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); + + // target + + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); + + // cross + + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); + + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); + + function addLine( a, b, hex ) { + + addPoint( a, hex ); + addPoint( b, hex ); + + } + + function addPoint( id, hex ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( hex ) ); + + if ( pointMap[ id ] === undefined ) { + + pointMap[ id ] = []; + + } + + pointMap[ id ].push( geometry.vertices.length - 1 ); + + } + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + + this.camera = camera; + this.matrixWorld = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = pointMap; + + this.update(); + +}; + +THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.CameraHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + var camera = new THREE.Camera(); + var projector = new THREE.Projector(); + + return function () { + + var scope = this; + + 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 ); + + function setPoint( point, x, y, z ) { + + vector.set( x, y, z ); + projector.unprojectVector( vector, camera ); + + var points = scope.pointMap[ point ]; + + if ( points !== undefined ) { + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + scope.geometry.vertices[ points[ i ] ].copy( vector ); + + } + + } + + } + + this.geometry.verticesNeedUpdate = true; + + }; + +}(); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.DirectionalLightHelper = function ( light, size ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + size = size || 1; + + var geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3( - size, size, 0 ), + new THREE.Vector3( size, size, 0 ), + new THREE.Vector3( size, - size, 0 ), + new THREE.Vector3( - size, - size, 0 ), + new THREE.Vector3( - size, size, 0 ) + ); + + var material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.lightPlane = new THREE.Line( geometry, material ); + this.add( this.lightPlane ); + + geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3(), + new THREE.Vector3() + ); + + material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.targetLine = new THREE.Line( geometry, material ); + this.add( this.targetLine ); + + this.update(); + +}; + +THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.DirectionalLightHelper.prototype.dispose = function () { + + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); +}; + +THREE.DirectionalLightHelper.prototype.update = function () { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var v3 = new THREE.Vector3(); + + return function () { + + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); + + this.lightPlane.lookAt( v3 ); + this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.targetLine.geometry.vertices[ 1 ].copy( v3 ); + this.targetLine.geometry.verticesNeedUpdate = true; + this.targetLine.material.color.copy( this.lightPlane.material.color ); + + } + +}(); + + +/** + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.EdgesHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0xffffff; + + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; + + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); + + var geometry2 = object.geometry.clone(); + + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); + + var vertices = geometry2.vertices; + var faces = geometry2.faces; + var numEdges = 0; + + 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 ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; + numEdges ++; + + } else { + + hash[ key ].face2 = i; + + } + + } + + } + + geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + + var coords = geometry.attributes.position.array; + + var index = 0; + + for ( var key in hash ) { + + var h = hash[ key ]; + + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK + + var vertex = vertices[ h.vert1 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + vertex = vertices[ h.vert2 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0xffff00; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + var geometry = new THREE.Geometry(); + + var faces = this.object.geometry.faces; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.normalMatrix = new THREE.Matrix3(); + + this.update(); + +}; + +THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.FaceNormalsHelper.prototype.update = function () { + + var vertices = this.geometry.vertices; + + var object = this.object; + var objectVertices = object.geometry.vertices; + var objectFaces = object.geometry.faces; + var objectWorldMatrix = object.matrixWorld; + + object.updateMatrixWorld( true ); + + this.normalMatrix.getNormalMatrix( objectWorldMatrix ); + + for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) { + + var face = objectFaces[ i ]; + + vertices[ i2 ].copy( objectVertices[ face.a ] ) + .add( objectVertices[ face.b ] ) + .add( objectVertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( objectWorldMatrix ); + + vertices[ i2 + 1 ].copy( face.normal ) + .applyMatrix3( this.normalMatrix ) + .normalize() + .multiplyScalar( this.size ) + .add( vertices[ i2 ] ); + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + +}; + + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.GridHelper = function ( size, step ) { + + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + + this.color1 = new THREE.Color( 0x444444 ); + this.color2 = new THREE.Color( 0x888888 ); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( + new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), + new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) + ); + + var color = i === 0 ? this.color1 : this.color2; + + geometry.colors.push( color, color, color, color ); + + } + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + +}; + +THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { + + this.color1.set( colorCenterLine ); + this.color2.set( colorGrid ); + + this.geometry.colorsNeedUpdate = true; + +} + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.colors = [ new THREE.Color(), new THREE.Color() ]; + + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + for ( var i = 0, il = 8; i < il; i ++ ) { + + geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; + + } + + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); + + this.lightSphere = new THREE.Mesh( geometry, material ); + this.add( this.lightSphere ); + + this.update(); + +}; + +THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.HemisphereLightHelper.prototype.dispose = function () { + this.lightSphere.geometry.dispose(); + this.lightSphere.material.dispose(); +}; + +THREE.HemisphereLightHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + + return function () { + + this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + + this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + this.lightSphere.geometry.colorsNeedUpdate = true; + + } + +}(); + + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.PointLightHelper = function ( light, sphereSize ) { + + this.light = light; + this.light.updateMatrixWorld(); + + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + THREE.Mesh.call( this, geometry, material ); + + this.matrixWorld = 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 ); + */ + +}; + +THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.PointLightHelper.prototype.dispose = function () { + + this.geometry.dispose(); + this.material.dispose(); +}; + +THREE.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 alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.SpotLightHelper = function ( light ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); + + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + + this.cone = new THREE.Mesh( geometry, material ); + this.add( this.cone ); + + this.update(); + +}; + +THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.SpotLightHelper.prototype.dispose = function () { + this.cone.geometry.dispose(); + this.cone.material.dispose(); +}; + +THREE.SpotLightHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); + + return function () { + + var coneLength = this.light.distance ? this.light.distance : 10000; + 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 mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.VertexNormalsHelper = function ( 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 geometry = new THREE.Geometry(); + + var vertices = object.geometry.vertices; + + var faces = object.geometry.faces; + + 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 ++ ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.normalMatrix = new THREE.Matrix3(); + + this.update(); + +}; + +THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var keys = [ 'a', 'b', 'c', 'd' ]; + + this.object.updateMatrixWorld( true ); + + this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); + + var vertices = this.geometry.vertices; + + var verts = this.object.geometry.vertices; + + var faces = this.object.geometry.faces; + + var worldMatrix = this.object.matrixWorld; + + 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 vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; + + var normal = face.vertexNormals[ j ]; + + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + + v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + + v1.add( vertices[ idx ] ); + idx = idx + 1; + + vertices[ idx ].copy( v1 ); + idx = idx + 1; + + } + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + + } + +}()); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0x0000ff; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + var geometry = new THREE.Geometry(); + + var vertices = object.geometry.vertices; + + var faces = object.geometry.faces; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.update(); + +}; + +THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var keys = [ 'a', 'b', 'c', 'd' ]; + + this.object.updateMatrixWorld( true ); + + var vertices = this.geometry.vertices; + + var verts = this.object.geometry.vertices; + + var faces = this.object.geometry.faces; + + var worldMatrix = this.object.matrixWorld; + + var idx = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; + + var tangent = face.vertexTangents[ j ]; + + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + + v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); + + v1.add( vertices[ idx ] ); + idx = idx + 1; + + vertices[ idx ].copy( v1 ); + idx = idx + 1; + + } + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + + } + +}()); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.WireframeHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0xffffff; + + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; + + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); + + if ( object.geometry instanceof THREE.Geometry ) { + + var vertices = object.geometry.vertices; + var faces = object.geometry.faces; + var numEdges = 0; + + // allocate maximal size + var edges = new Uint32Array( 6 * faces.length ); + + 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 ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; + + } + + } + + } + + geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numEdges; i < l; i ++ ) { + + for ( var j = 0; j < 2; j ++ ) { + + var vertex = vertices[ edges [ 2 * i + j] ]; + + var index = 6 * i + 3 * j; + coords[ index + 0 ] = vertex.x; + coords[ index + 1 ] = vertex.y; + coords[ index + 2 ] = vertex.z; + + } + + } + + } else if ( object.geometry instanceof THREE.BufferGeometry && object.geometry.attributes.index !== undefined ) { // indexed BufferGeometry + + var vertices = object.geometry.attributes.position.array; + var indices = object.geometry.attributes.index.array; + var offsets = object.geometry.offsets; + var numEdges = 0; + + // allocate maximal size + var edges = new Uint32Array( 2 * indices.length ); + + for ( var o = 0, ol = offsets.length; o < ol; ++ o ) { + + var start = offsets[ o ].start; + var count = offsets[ o ].count; + var index = offsets[ o ].index; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + for ( var j = 0; j < 3; j ++ ) { + + edge[ 0 ] = index + indices[ i + j ]; + edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; + edge.sort( sortFunction ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; + + } + + } + + } + + } + + geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numEdges; i < l; i ++ ) { + + for ( var j = 0; j < 2; j ++ ) { + + var index = 6 * i + 3 * j; + var index2 = 3 * edges[ 2 * i + j]; + coords[ index + 0 ] = vertices[ index2 ]; + coords[ index + 1 ] = vertices[ index2 + 1 ]; + coords[ index + 2 ] = vertices[ index2 + 2 ]; + + } + + } + + } else if ( object.geometry instanceof THREE.BufferGeometry ) { // non-indexed BufferGeometry + + var vertices = object.geometry.attributes.position.array; + var numEdges = vertices.length / 3; + var numTris = numEdges / 3; + + geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numTris; i < l; i ++ ) { + + for ( var j = 0; j < 3; j ++ ) { + + var index = 18 * i + 6 * j; + + var index1 = 9 * i + 3 * j; + coords[ index + 0 ] = vertices[ index1 ]; + coords[ index + 1 ] = vertices[ index1 + 1 ]; + coords[ index + 2 ] = vertices[ index1 + 2 ]; + + var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); + coords[ index + 3 ] = vertices[ index2 ]; + coords[ index + 4 ] = vertices[ index2 + 1 ]; + coords[ index + 5 ] = vertices[ index2 + 2 ]; + + } + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ImmediateRenderObject = function () { + + THREE.Object3D.call( this ); + + this.render = function ( renderCallback ) { }; + +}; + +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlare = function ( texture, size, distance, blending, color ) { + + THREE.Object3D.call( this ); + + this.lensFlares = []; + + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; + + if( texture !== undefined ) { + + this.add( texture, size, distance, blending, color ); + + } + +}; + +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); + + +/* + * Add: adds another flare + */ + +THREE.LensFlare.prototype.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 THREE.Color( 0xffffff ); + if( blending === undefined ) blending = THREE.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 ontop z = 1 is back + scale: 1, // scale + rotation: 1, // 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. + */ + +THREE.LensFlare.prototype.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/ + */ + +THREE.MorphBlendMesh = function( geometry, material ) { + + THREE.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 ); + +}; + +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { + + var animation = { + + startFrame: start, + endFrame: 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 ); + +}; + +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { + + var pattern = /([a-z]+)(\d+)/; + + 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 ]; + var num = chunks[ 2 ]; + + 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; + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = 1; + animation.directionBackwards = false; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = -1; + animation.directionBackwards = true; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.weight = weight; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = time; + + } + +}; + +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + + var time = 0; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + time = animation.time; + + } + + return time; + +}; + +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { + + var duration = -1; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + duration = animation.duration; + + } + + return duration; + +}; + +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = 0; + animation.active = true; + + } else { + + console.warn( "animation[" + name + "] undefined" ); + + } + +}; + +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.active = false; + + } + +}; + +THREE.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.startFrame + THREE.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; + + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + + } + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlarePlugin = function () { + + var _gl, _renderer, _precision, _lensFlare = {}; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + _precision = renderer.getPrecision(); + + _lensFlare.vertices = new Float32Array( 8 + 8 ); + _lensFlare.faces = new Uint16Array( 6 ); + + var i = 0; + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; + + i = 0; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; + + // buffers + + _lensFlare.vertexBuffer = _gl.createBuffer(); + _lensFlare.elementBuffer = _gl.createBuffer(); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); + + // textures + + _lensFlare.tempTexture = _gl.createTexture(); + _lensFlare.occlusionTexture = _gl.createTexture(); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.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 ); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.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 ); + + if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { + + _lensFlare.hasVertexTexture = false; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); + + } else { + + _lensFlare.hasVertexTexture = true; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); + + } + + _lensFlare.attributes = {}; + _lensFlare.uniforms = {}; + + _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); + _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); + + _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); + _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); + _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); + _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); + _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); + _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); + _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); + _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); + + }; + + + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + * Then _lensFlare.update_lensFlares() is called to re-position and + * update transparency of flares. Then they are rendered. + * + */ + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var flares = scene.__webglFlares, + nFlares = flares.length; + + if ( ! nFlares ) return; + + var tempPosition = new THREE.Vector3(); + + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; + + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); + + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); + + var uniforms = _lensFlare.uniforms, + attributes = _lensFlare.attributes; + + // set _lensFlare program and reset blending + + _gl.useProgram( _lensFlare.program ); + + _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); + _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); + + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/unforms + + _gl.uniform1i( uniforms.occlusionMap, 0 ); + _gl.uniform1i( uniforms.map, 1 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.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, _lensFlare.elementBuffer ); + + _gl.disable( _gl.CULL_FACE ); + _gl.depthMask( false ); + + var i, j, jl, flare, sprite; + + for ( i = 0; i < nFlares; i ++ ) { + + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); + + // calc object screen position + + flare = flares[ i ]; + + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); + + // setup arrays for gl programs + + screenPosition.copy( tempPosition ) + + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + + // screen cull + + if ( _lensFlare.hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { + + // save current RGB to temp texture + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 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 ); + + _gl.disable( _gl.BLEND ); + _gl.enable( _gl.DEPTH_TEST ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // copy result to occlusionMap + + _gl.activeTexture( _gl.TEXTURE0 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + + + // restore graphics + + _gl.uniform1i( uniforms.renderType, 1 ); + _gl.disable( _gl.DEPTH_TEST ); + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.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 ); + _gl.enable( _gl.BLEND ); + + for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { + + 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 / viewportHeight; + + 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 ); + + _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + _renderer.setTexture( sprite.texture, 1 ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + } + + } + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthMask( true ); + + }; + + function createProgram ( shader, precision ) { + + var program = _gl.createProgram(); + + var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + + var prefix = "precision " + precision + " 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 alteredq / http://alteredqualia.com/ + */ + +THREE.ShadowMapPlugin = function () { + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), + + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), + + _matrixPosition = new THREE.Vector3(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + shadowMap, shadowMatrix, shadowCamera, + program, buffer, material, + webglObject, object, light, + renderList, + + lights = [], + k = 0, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _gl.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.BACK ); + + } + + _renderer.setDepthTest( true ); + + // preprocess lights + // - skip lights that are not casting shadows + // - create virtual lights for cascaded shadow maps + + for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { + + light = scene.__lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { + + for ( n = 0; n < light.shadowCascadeCount; n ++ ) { + + var virtualLight; + + if ( ! light.shadowCascadeArray[ n ] ) { + + virtualLight = createVirtualLight( light, n ); + virtualLight.originalCamera = camera; + + var gyro = new THREE.Gyroscope(); + gyro.position.copy( light.shadowCascadeOffset ); + + gyro.add( virtualLight ); + gyro.add( virtualLight.target ); + + camera.add( gyro ); + + light.shadowCascadeArray[ n ] = virtualLight; + + console.log( "Created virtualLight", virtualLight ); + + } else { + + virtualLight = light.shadowCascadeArray[ n ]; + + } + + updateVirtualLight( light, n ); + + lights[ k ] = virtualLight; + k ++; + + } + + } else { + + lights[ k ] = light; + k ++; + + } + + } + + // render depth map + + for ( i = 0, il = lights.length; i < il; i ++ ) { + + light = lights[ i ]; + + if ( ! light.shadowMap ) { + + var shadowFilter = THREE.LinearFilter; + + if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowFilter = THREE.NearestFilter; + + } + + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; + + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + + light.shadowMatrix = new THREE.Matrix4(); + + } + + if ( ! light.shadowCamera ) { + + if ( light instanceof THREE.SpotLight ) { + + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); + + } else { + + console.error( "Unsupported light type for shadow" ); + continue; + + } + + scene.add( light.shadowCamera ); + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + } + + if ( light.shadowCameraVisible && ! light.cameraHelper ) { + + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + light.shadowCamera.add( light.cameraHelper ); + + } + + if ( light.isVirtual && virtualLight.originalCamera == camera ) { + + updateShadowCamera( camera, light ); + + } + + shadowMap = light.shadowMap; + shadowMatrix = light.shadowMatrix; + shadowCamera = light.shadowCamera; + + shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); + _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _matrixPosition ); + shadowCamera.updateMatrixWorld(); + + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); + + // 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 ); + + // render shadow map + + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible && object.castShadow ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // culling is overriden globally for all objects + // while rendering depth map + + // need to deal with MeshFaceMaterial somehow + // in that case just use the first of material.materials for now + // (proper solution would require to break objects by materials + // similarly to regular rendering and then set corresponding + // depth materials per each chunk instead of just once per object) + + objectMaterial = getObjectMaterial( object ); + + useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible && object.castShadow ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.BACK ); + + } + + }; + + function createVirtualLight( light, cascade ) { + + var virtualLight = new THREE.DirectionalLight(); + + virtualLight.isVirtual = true; + + virtualLight.onlyShadow = true; + virtualLight.castShadow = true; + + virtualLight.shadowCameraNear = light.shadowCameraNear; + virtualLight.shadowCameraFar = light.shadowCameraFar; + + virtualLight.shadowCameraLeft = light.shadowCameraLeft; + virtualLight.shadowCameraRight = light.shadowCameraRight; + virtualLight.shadowCameraBottom = light.shadowCameraBottom; + virtualLight.shadowCameraTop = light.shadowCameraTop; + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; + virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; + + virtualLight.pointsWorld = []; + virtualLight.pointsFrustum = []; + + var pointsWorld = virtualLight.pointsWorld, + pointsFrustum = virtualLight.pointsFrustum; + + for ( var i = 0; i < 8; i ++ ) { + + pointsWorld[ i ] = new THREE.Vector3(); + pointsFrustum[ i ] = new THREE.Vector3(); + + } + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + pointsFrustum[ 0 ].set( -1, -1, nearZ ); + pointsFrustum[ 1 ].set( 1, -1, nearZ ); + pointsFrustum[ 2 ].set( -1, 1, nearZ ); + pointsFrustum[ 3 ].set( 1, 1, nearZ ); + + pointsFrustum[ 4 ].set( -1, -1, farZ ); + pointsFrustum[ 5 ].set( 1, -1, farZ ); + pointsFrustum[ 6 ].set( -1, 1, farZ ); + pointsFrustum[ 7 ].set( 1, 1, farZ ); + + return virtualLight; + + } + + // Synchronize virtual light with the original light + + function updateVirtualLight( light, cascade ) { + + var virtualLight = light.shadowCascadeArray[ cascade ]; + + virtualLight.position.copy( light.position ); + virtualLight.target.position.copy( light.target.position ); + virtualLight.lookAt( virtualLight.target ); + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + var pointsFrustum = virtualLight.pointsFrustum; + + pointsFrustum[ 0 ].z = nearZ; + pointsFrustum[ 1 ].z = nearZ; + pointsFrustum[ 2 ].z = nearZ; + pointsFrustum[ 3 ].z = nearZ; + + pointsFrustum[ 4 ].z = farZ; + pointsFrustum[ 5 ].z = farZ; + pointsFrustum[ 6 ].z = farZ; + pointsFrustum[ 7 ].z = farZ; + + } + + // Fit shadow camera's ortho frustum to camera frustum + + function updateShadowCamera( camera, light ) { + + var shadowCamera = light.shadowCamera, + pointsFrustum = light.pointsFrustum, + pointsWorld = light.pointsWorld; + + _min.set( Infinity, Infinity, Infinity ); + _max.set( -Infinity, -Infinity, -Infinity ); + + for ( var i = 0; i < 8; i ++ ) { + + var p = pointsWorld[ i ]; + + p.copy( pointsFrustum[ i ] ); + THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); + + p.applyMatrix4( shadowCamera.matrixWorldInverse ); + + if ( p.x < _min.x ) _min.x = p.x; + if ( p.x > _max.x ) _max.x = p.x; + + if ( p.y < _min.y ) _min.y = p.y; + if ( p.y > _max.y ) _max.y = p.y; + + if ( p.z < _min.z ) _min.z = p.z; + if ( p.z > _max.z ) _max.z = p.z; + + } + + shadowCamera.left = _min.x; + shadowCamera.right = _max.x; + shadowCamera.top = _max.y; + shadowCamera.bottom = _min.y; + + // can't really fit near/far + //shadowCamera.near = _min.z; + //shadowCamera.far = _max.z; + + shadowCamera.updateProjectionMatrix(); + + } + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use for shadow maps + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + +THREE.ShadowMapPlugin.__projector = new THREE.Projector(); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpritePlugin = function () { + + var _gl, _renderer, _texture; + + var vertices, faces, vertexBuffer, elementBuffer; + var program, attributes, uniforms; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + 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 + ] ); + + 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.createElement( 'canvas' ); + canvas.width = 8; + canvas.height = 8; + + var context = canvas.getContext( '2d' ); + context.fillStyle = '#ffffff'; + context.fillRect( 0, 0, canvas.width, canvas.height ); + + _texture = new THREE.Texture( canvas ); + _texture.needsUpdate = true; + + }; + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var sprites = scene.__webglSprites, + nSprites = sprites.length; + + if ( ! nSprites ) return; + + // setup gl + + _gl.useProgram( program ); + + _gl.enableVertexAttribArray( attributes.position ); + _gl.enableVertexAttribArray( attributes.uv ); + + _gl.disable( _gl.CULL_FACE ); + _gl.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 ); + + _gl.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 instanceof THREE.Fog ) { + + _gl.uniform1f( uniforms.fogNear, fog.near ); + _gl.uniform1f( uniforms.fogFar, fog.far ); + + _gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; + + } else if ( fog instanceof THREE.FogExp2 ) { + + _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 + + var i, sprite, material, fogType, scale = []; + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + material = sprite.material; + + if ( sprite.visible === false ) continue; + + sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + + } + + sprites.sort( painterSortStable ); + + // render all sprites + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + + if ( sprite.visible === false ) continue; + + material = sprite.material; + + _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); + + scale[ 0 ] = sprite.scale.x; + scale[ 1 ] = sprite.scale.y; + + if ( scene.fog && material.fog ) { + + fogType = sceneFogType; + + } else { + + fogType = 0; + + } + + 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 ); + + _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + _renderer.setDepthTest( material.depthTest ); + _renderer.setDepthWrite( material.depthWrite ); + + if ( material.map && material.map.image && material.map.image.width ) { + + _renderer.setTexture( material.map, 0 ); + + } else { + + _renderer.setTexture( _texture, 0 ); + + } + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + + }; + + 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;', + 'float 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.z !== b.z ) { + + return b.z - a.z; + + } else { + + return b.id - a.id; + + } + + }; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DepthPassPlugin = function () { + + this.enabled = false; + this.renderTarget = null; + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! this.enabled ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + program, buffer, material, + webglObject, object, light, + renderList, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _renderer.setDepthTest( true ); + + // update scene + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // render depth map + + _renderer.setRenderTarget( this.renderTarget ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // todo: create proper depth material for particles + + if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; + + objectMaterial = getObjectMaterial( object ); + + if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); + + useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + }; + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + + +/** + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.ShaderFlares = { + + 'lensFlareVertexTexture': { + + 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" ) + + }, + + + 'lensFlare': { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if( renderType == 2 ) {", + + "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: [ + + "precision mediump float;", + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + + "void main() {", + + // pink square + + "if( renderType == 0 ) {", + + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", + + // restore + + "} else if( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", + "visibility = ( 1.0 - visibility / 4.0 );", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + + ].join( "\n" ) + + } + +}; + +global.THREE = THREE; + diff --git a/scripts/materials.js b/scripts/materials.js index 70d30ee..8905822 100644 --- a/scripts/materials.js +++ b/scripts/materials.js @@ -1,10 +1,10 @@ elation.require(['utils.template'], function() { elation.requireCSS('engine.materials'); - elation.template.add('engine.materials.chunk', '

{chunkname}

uniforms

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}

vertex

{chunk.vertex_pars}

{chunk.vertex}

fragment

{chunk.fragment_pars}

{chunk.fragment}

'); - elation.template.add('engine.materials.chunk.uniforms', '

{chunkname}

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}
'); - elation.template.add('engine.materials.chunk.vertex', '

{chunkname}

{content}

'); - elation.template.add('engine.materials.chunk.fragment', '

{chunkname}

{content}

'); + // elation.template.add('engine.materials.chunk', '

{chunkname}

uniforms

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}

vertex

{chunk.vertex_pars}

{chunk.vertex}

fragment

{chunk.fragment_pars}

{chunk.fragment}

'); + // elation.template.add('engine.materials.chunk.uniforms', '

{chunkname}

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}
'); + // elation.template.add('engine.materials.chunk.vertex', '

{chunkname}

{content}

'); + // elation.template.add('engine.materials.chunk.fragment', '

{chunkname}

{content}

'); elation.extend("engine.materials", new function() { @@ -421,6 +421,6 @@ elation.require(['utils.template'], function() { } }); - elation.engine.materials.add('uvtest', new THREE.MeshPhongMaterial({map: elation.engine.materials.getTexture('/media/space/textures/uvtest.png', [1, 1])})); + // elation.engine.materials.add('uvtest', new THREE.MeshPhongMaterial({map: elation.engine.materials.getTexture('/media/space/textures/uvtest.png', [1, 1])})); elation.engine.materials.add('normal', new THREE.MeshNormalMaterial()); }); diff --git a/scripts/systems/networking.js b/scripts/systems/networking.js new file mode 100644 index 0000000..2a728fa --- /dev/null +++ b/scripts/systems/networking.js @@ -0,0 +1,177 @@ +elation.extend("engine.systems.networking.client", function(args) { + + if (ENV_IS_NODE) { + this.server = true; + } + else if (ENV_IS_BROWSER) { + this.client = true; + } + elation.implement(this, elation.engine.systems.system); + this.connected = false; + this.websocket = new WebSocket("ws://ec2-54-201-16-112.us-west-2.compute.amazonaws.com:8080"); + this.connection = this.websocket; + this.tagged = []; + this.toSend = []; + + this.remotePlayers = {}; + + this.websocket.onopen = function() { + this.connected = true; + console.log('networking: connected to server'); + }.bind(this); + + this.websocket.onmessage = function(ev) { + this.newMessage(JSON.parse(ev.data)); + }.bind(this); + + + this.system_attach = function(ev) { + console.log('INIT: networking'); + this.world = this.engine.systems.world; + elation.events.add(this.world, 'engine_thing_create,world_thing_add', this.handleNewThing.bind(this)); + elation.events.add(this.world, 'world_thing_remove', this.handleRemovedThing.bind(this)) + }; + + this.handleNewThing = function(ev) { + if (ev.data.thing.hasTag('networking_local_sync')) { + this.tagged.push(ev.data.thing); + console.log('networking: tagged - ', this.tagged); + if (ev.data.thing.componentname == 'engine.things.vrcadeplayer') { + // TODO: better handling of local player vs remote player + ev.data.thing.network_id = Math.floor(Math.random() * 10000); // TODO + this.addToMessages({type: 'new_player', position: ev.data.thing.properties.position.toArray(), network_id: ev.data.thing.network_id}); + elation.events.add(ev.data.thing, 'thing_change', this.handleChange.bind(this)); + } + else { + this.addToMessages({type: 'new_thing', position: ev.data.thing.properties.position.toArray()}); + } + } + }; + + + this.newMessage = function(msg) { + if (msg.type == "new_player") { + var remotePlayer = this.world.spawn('remoteplayer', 'player' + msg.network_id, {'position': msg.position, 'collidable': false}); + this.remotePlayers[msg.network_id] = remotePlayer; + } + else if (msg.type = "thing_change") { + if (this.remotePlayers[msg.network_id]) { + this.remotePlayers[msg.network_id].properties.position.set(msg.position[0], msg.position[1], msg.position[2]); + this.remotePlayers[msg.network_id].refresh(); + } + } + + }; + + this.handleChange = function(ev) { + this.addToMessages({type: 'thing_change', position: ev.target.properties.position.toArray(), network_id: ev.target.network_id}); + // console.log(ev.target.properties.position.toArray()); + }; + + this.handleRemovedThing = function(ev) { + if (this.tagged.indexOf(ev.data.thing) !== -1) { + // TODO: splice it out + } + }; + this.send = function(data) { + this.connection.send(data); + // console.log('networking: sent data:', data); + }; + + this.addToMessages = function(data) { + this.toSend.push(data); + }; + + this.sendMessages = function() { + if (this.toSend.length > 0 && this.connected) { + for (var i = 0; i < this.toSend.length; i++) { + this.send(JSON.stringify(this.toSend[i])); + } + this.toSend = []; + } + }; + + this.engine_frame = function(ev) { + this.sendMessages(); + }; + + this.engine_stop = function(ev) { + console.log('SHUTDOWN: networking'); + this.websocket.close(); + this.websocket = null; + }; +}); + +// client connection objects + +elation.extend('engine.systems.networking.client.connection', function(opts) { + // a transport-agnostic object representing the connection from the client + // to the server. + // + // should take opts for transport, server host, server port + // expose send() + // fire events on connection, disconnection, and received messages + + var socketOpts = { host: opts.host, port: opts.port }; + if (opts.transport == 'websocket') { + this.socket = new engine.systems.networking.websocket(socketOpts); + } + if (opts.transport == 'webrtc') { + this.socket = new engine.systems.networking.webrtc(socketOpts); + } + + this.send = function(data) { + this.socket.send(data); + }; + +}); + +elation.extend('engine.systems.networking.websocket', function(opts) { + this.address = 'ws://' + opts.address + opts.port; + + this.init = function() { + this.connect(); + }; + + this.connect = function() { + if (!this.websocket) { + this.websocket = new WebSocket(this.address); + elation.events.add(this.websocket, "open", elation.bind(this, this.onOpen)); + elation.events.add(this.websocket, "message", elation.bind(this, this.onMessage)); + elation.events.add(this.websocket, "close", elation.bind(this, this.onClose)); + } + }; + + this.close = function() { + if (this.websocket) { + this.websocket.close(); + this.websocket = null; + } + }; + + this.send = function(data) { + this.websocket.send(data); + }; + + this.onOpen = function(ev) { + this.connected = true; + elation.events.fire({type: 'socket_connected'}); + }; + + this.onMessage = function(ev) { + elation.events.fire({type: 'new_message', data: ev.data}); + }; + + this.onClose = function(ev) { + elation.events.fire({type: 'socket_closed'}); + this.websocket = null; + }; + +}); + +elation.extend('engine.systems.networking.webrtc', function() { + // TODO: + // take opts address and port + // expose connect(), send(data), and close(); + // fire socket_connected, new_message, socket_closed +}); diff --git a/scripts/systems/render.js b/scripts/systems/render.js index e9b6bfe..9213b91 100644 --- a/scripts/systems/render.js +++ b/scripts/systems/render.js @@ -1,5 +1,31 @@ +// [ +// "engine.external.three.three", +// "engine.external.three.stats", +// "engine.external.threex.renderstats", +// "engine.external.three.render.CSS3DRenderer", +// "engine.external.three.render.EffectComposer", +// "engine.external.three.render.RenderPass", +// "engine.external.three.render.OculusRiftEffect", +// "engine.external.three.render.OculusRenderPass", +// "engine.external.three.render.ShaderPass", +// "engine.external.three.render.MaskPass", +// "engine.external.three.render.CopyShader", +// //"engine.external.three.render.SepiaShader", +// //"engine.external.three.render.BleachBypassShader", +// //"engine.external.three.render.FilmShader", +// //"engine.external.three.render.FilmPass", +// //"engine.external.three.render.ConvolutionShader", +// "engine.external.three.render.BloomPass", +// //"engine.external.three.render.SSAOShader", +// "engine.external.three.render.FXAAShader", +// "engine.external.three.fonts.helvetiker_regular", +// //"engine.external.three.fonts.drive-thru_regular", +// "engine.materials", +// "engine.geometries", +// ] + elation.require([ - "engine.external.three.three", + "engine.external.three.nodethree", "engine.external.three.stats", "engine.external.threex.renderstats", "engine.external.three.render.CSS3DRenderer", @@ -18,7 +44,7 @@ elation.require([ "engine.external.three.render.BloomPass", //"engine.external.three.render.SSAOShader", "engine.external.three.render.FXAAShader", - "engine.external.three.fonts.helvetiker_regular", + // "engine.external.three.fonts.helvetiker_regular", //"engine.external.three.fonts.drive-thru_regular", "engine.materials", "engine.geometries", diff --git a/scripts/systems/world.js b/scripts/systems/world.js index e844173..9411133 100644 --- a/scripts/systems/world.js +++ b/scripts/systems/world.js @@ -22,11 +22,10 @@ elation.require([ this.loaded = false; this.loading = false; - - if (document.location.hash) { + if (ENV_IS_BROWSER && document.location.hash) { this.parseDocumentHash(); - } elation.events.add(window, 'popstate', elation.bind(this, this.parseDocumentHash)); + } } this.engine_start = function(ev) { @@ -139,11 +138,13 @@ elation.require([ //this.spawn("sector", "default"); this.createDefaultScene(); } - var dochash = "world.load=" + name; - if (this.engine.systems.physics.timescale == 0) { - dochash += "&world.paused=1"; + if (ENV_IS_BROWSER) { + var dochash = "world.load=" + name; + if (this.engine.systems.physics.timescale == 0) { + dochash += "&world.paused=1"; + } + document.location.hash = dochash; } - document.location.hash = dochash; } this.listLocalOverrides = function() { var overrides = []; diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 2882045..8132ffb 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -269,10 +269,12 @@ elation.component.add("engine.things.generic", function() { this.refresh(); } this.initDOM = function() { - this.objects['dom'] = this.createObjectDOM(); - elation.html.addclass(this.container, "space.thing"); - elation.html.addclass(this.container, "space.things." + this.type); - //this.updateDOM(); + if (ENV_IS_BROWSER) { + this.objects['dom'] = this.createObjectDOM(); + elation.html.addclass(this.container, "space.thing"); + elation.html.addclass(this.container, "space.things." + this.type); + //this.updateDOM(); + } } this.initPhysics = function() { if (this.properties.physical) { @@ -281,7 +283,7 @@ elation.component.add("engine.things.generic", function() { } } this.createObject3D = function() { - if (this.properties.exists === false) return; + if (this.properties.exists === false || !ENV_IS_BROWSER) return; var object = null, geometry = null, material = null; if (this.properties.render) { @@ -410,7 +412,7 @@ elation.component.add("engine.things.generic", function() { return false; } this.remove = function(thing) { - if (this.children[thing.id]) { + if (thing && this.children[thing.id]) { if (this.objects['3d'] && thing.objects['3d']) { this.objects['3d'].remove(thing.objects['3d']); } diff --git a/scripts/things/menu.js b/scripts/things/menu.js index c6b2b0c..5c02c3e 100644 --- a/scripts/things/menu.js +++ b/scripts/things/menu.js @@ -5,11 +5,13 @@ elation.require(['engine.things.generic', 'engine.things.label'], function() { items: { type: 'object' }, labelcfg: { type: 'object', default: {} } }); - this.controlstate = this.engine.systems.controls.addContext('menu', { - 'menu_up': ['keyboard_up', elation.bind(this, this.updateControls)], - 'menu_down': ['keyboard_down,gamepad_0_axis_1', elation.bind(this, this.updateControls)], - 'activate': ['keyboard_enter,gamepad_0_button_0', elation.bind(this, this.updateControls)], - }); + if (this.engine.systems.controls) { + this.controlstate = this.engine.systems.controls.addContext('menu', { + 'menu_up': ['keyboard_up', elation.bind(this, this.updateControls)], + 'menu_down': ['keyboard_down,gamepad_0_axis_1', elation.bind(this, this.updateControls)], + 'activate': ['keyboard_enter,gamepad_0_button_0', elation.bind(this, this.updateControls)], + }); + } this.selected = false; this.menuitems = []; } @@ -66,12 +68,16 @@ elation.require(['engine.things.generic', 'engine.things.label'], function() { } } this.enable = function() { - this.controlstate._reset(); - this.engine.systems.controls.activateContext('menu'); + if (this.controlstate) { + this.controlstate._reset(); + this.engine.systems.controls.activateContext('menu'); + } } this.disable = function() { - this.controlstate._reset(); - this.engine.systems.controls.deactivateContext('menu'); + if (this.controlstate) { + this.controlstate._reset(); + this.engine.systems.controls.deactivateContext('menu'); + } } this.selectfirst = function() { if (this.selected) { diff --git a/scripts/things/player.js b/scripts/things/player.js index 3c31eba..d0d20b5 100644 --- a/scripts/things/player.js +++ b/scripts/things/player.js @@ -2,29 +2,32 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' elation.component.add('engine.things.player', function() { this.targetrange = 1.8; this.postinit = function() { - this.controlstate = this.engine.systems.controls.addContext('player', { - 'move_forward': ['keyboard_w', elation.bind(this, this.updateControls)], - 'move_backward': ['keyboard_s,gamepad_0_axis_1', elation.bind(this, this.updateControls)], - 'move_left': ['keyboard_a', elation.bind(this, this.updateControls)], - 'move_right': ['keyboard_d,gamepad_0_axis_0', elation.bind(this, this.updateControls)], - 'turn_left': ['keyboard_left', elation.bind(this, this.updateControls)], - 'turn_right': ['keyboard_right,mouse_delta_x,gamepad_0_axis_2', elation.bind(this, this.updateControls)], - 'look_up': ['keyboard_up', elation.bind(this, this.updateControls)], - 'look_down': ['keyboard_down,mouse_delta_y,gamepad_0_axis_3', elation.bind(this, this.updateControls)], - 'run': ['keyboard_shift,gamepad_0_button_10', elation.bind(this, this.updateControls)], - 'crouch': ['keyboard_c', elation.bind(this, this.updateControls)], - //'jump': ['keyboard_space,gamepad_0_button_1', elation.bind(this, this.updateControls)], - 'toss_ball': ['keyboard_space,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.toss_ball)], - //'toss_cube': ['keyboard_shift_space,gamepad_0_button_1', elation.bind(this, this.toss_cube)], - 'use': ['keyboard_e,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.handleUse)], - //'toggle_gravity': ['keyboard_g', elation.bind(this, this.toggle_gravity)], - 'pointerlock': ['mouse_0', elation.bind(this, this.updateControls)], - }); - // Separate HMD context so it can remain active when player controls are disabled - this.hmdstate = this.engine.systems.controls.addContext('playerhmd', { - 'hmd': ['hmd_0', elation.bind(this, this.refresh)], - //'orientation': ['orientation', elation.bind(this, this.refresh)], - }); + if (this.engine.systems.controls) { + this.controlstate = this.engine.systems.controls.addContext('player', { + 'move_forward': ['keyboard_w', elation.bind(this, this.updateControls)], + 'move_backward': ['keyboard_s,gamepad_0_axis_1', elation.bind(this, this.updateControls)], + 'move_left': ['keyboard_a', elation.bind(this, this.updateControls)], + 'move_right': ['keyboard_d,gamepad_0_axis_0', elation.bind(this, this.updateControls)], + 'turn_left': ['keyboard_left', elation.bind(this, this.updateControls)], + 'turn_right': ['keyboard_right,mouse_delta_x,gamepad_0_axis_2', elation.bind(this, this.updateControls)], + 'look_up': ['keyboard_up', elation.bind(this, this.updateControls)], + 'look_down': ['keyboard_down,mouse_delta_y,gamepad_0_axis_3', elation.bind(this, this.updateControls)], + 'run': ['keyboard_shift,gamepad_0_button_10', elation.bind(this, this.updateControls)], + 'crouch': ['keyboard_c', elation.bind(this, this.updateControls)], + //'jump': ['keyboard_space,gamepad_0_button_1', elation.bind(this, this.updateControls)], + //'toss_ball': ['keyboard_space,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.toss_ball)], + //'toss_cube': ['keyboard_shift_space,gamepad_0_button_1', elation.bind(this, this.toss_cube)], + 'use': ['keyboard_e,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.handleUse)], + //'toggle_gravity': ['keyboard_g', elation.bind(this, this.toggle_gravity)], + 'pointerlock': ['mouse_0', elation.bind(this, this.updateControls)], + }); + // Separate HMD context so it can remain active when player controls are disabled + this.hmdstate = this.engine.systems.controls.addContext('playerhmd', { + 'hmd': ['hmd_0', elation.bind(this, this.refresh)], + }); + //this.engine.systems.controls.activateContext('player'); + this.engine.systems.controls.activateContext('playerhmd'); + } this.moveVector = new THREE.Vector3(); this.turnVector = new THREE.Euler(0, 0, 0); this.lookVector = new THREE.Euler(0, 0, 0); @@ -32,8 +35,6 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' this.runMultiplier = 2.5; this.turnSpeed = 2; this.moveFriction = 10; - //this.engine.systems.controls.activateContext('player'); - this.engine.systems.controls.activateContext('playerhmd'); this.charging = false; this.usegravity = true; @@ -55,7 +56,7 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' if (this.charging !== false) { var charge = this.getCharge(); this.strengthmeter.set(charge); - } else if (this.strengthmeter.value != 0) { + } else if (this.strengthmeter && this.strengthmeter.value != 0) { this.strengthmeter.set(0); } } @@ -132,14 +133,22 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' } this.enable = function() { //this.gravityForce.update(new THREE.Vector3(0,-9.8 * this.properties.mass,0)); - this.engine.systems.controls.activateContext('player'); - this.engine.systems.controls.enablePointerLock(true); - this.engine.systems.render.views.main.picking = false; + if (this.engine.systems.controls) { + this.engine.systems.controls.activateContext('player'); + this.engine.systems.controls.enablePointerLock(true); + } + if (this.engine.systems.render) { + this.engine.systems.render.views.main.picking = false; + } } this.disable = function() { - this.engine.systems.controls.deactivateContext('player'); - this.engine.systems.controls.enablePointerLock(false); - this.engine.systems.render.views.main.picking = true; + if (this.engine.systems.controls) { + this.engine.systems.controls.deactivateContext('player'); + this.engine.systems.controls.enablePointerLock(false); + } + if (this.engine.systems.render) { + this.engine.systems.render.views.main.picking = true; + } if (this.objects.dynamics) { this.moveForce.update(this.moveVector.set(0,0,0)); //this.gravityForce.update(new THREE.Vector3(0,0,0)); @@ -155,7 +164,7 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' this.refresh = (function() { var _dir = new THREE.Euler(); // Closure scratch variable return function() { - if (this.camera) { + if (this.camera && this.controlstate) { this.moveVector.x = (this.controlstate.move_right - this.controlstate.move_left); this.moveVector.z = -(this.controlstate.move_forward - this.controlstate.move_backward); From ec6c657ae49108e2eaf874083a58c78981cc6830 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 14 Mar 2015 04:37:38 -0400 Subject: [PATCH 02/43] fix renderer so it works in browser again --- scripts/systems/render.js | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/scripts/systems/render.js b/scripts/systems/render.js index 9213b91..e9b6bfe 100644 --- a/scripts/systems/render.js +++ b/scripts/systems/render.js @@ -1,31 +1,5 @@ -// [ -// "engine.external.three.three", -// "engine.external.three.stats", -// "engine.external.threex.renderstats", -// "engine.external.three.render.CSS3DRenderer", -// "engine.external.three.render.EffectComposer", -// "engine.external.three.render.RenderPass", -// "engine.external.three.render.OculusRiftEffect", -// "engine.external.three.render.OculusRenderPass", -// "engine.external.three.render.ShaderPass", -// "engine.external.three.render.MaskPass", -// "engine.external.three.render.CopyShader", -// //"engine.external.three.render.SepiaShader", -// //"engine.external.three.render.BleachBypassShader", -// //"engine.external.three.render.FilmShader", -// //"engine.external.three.render.FilmPass", -// //"engine.external.three.render.ConvolutionShader", -// "engine.external.three.render.BloomPass", -// //"engine.external.three.render.SSAOShader", -// "engine.external.three.render.FXAAShader", -// "engine.external.three.fonts.helvetiker_regular", -// //"engine.external.three.fonts.drive-thru_regular", -// "engine.materials", -// "engine.geometries", -// ] - elation.require([ - "engine.external.three.nodethree", + "engine.external.three.three", "engine.external.three.stats", "engine.external.threex.renderstats", "engine.external.three.render.CSS3DRenderer", @@ -44,7 +18,7 @@ elation.require([ "engine.external.three.render.BloomPass", //"engine.external.three.render.SSAOShader", "engine.external.three.render.FXAAShader", - // "engine.external.three.fonts.helvetiker_regular", + "engine.external.three.fonts.helvetiker_regular", //"engine.external.three.fonts.drive-thru_regular", "engine.materials", "engine.geometries", From 8e784042adff030697ede7708cf3e8ab0395ae71 Mon Sep 17 00:00:00 2001 From: bioid Date: Thu, 26 Mar 2015 05:10:15 -0400 Subject: [PATCH 03/43] engine working in node and browser --- scripts/engine.js | 3 +-- scripts/materials.js | 16 +++++++++------- scripts/systems/world.js | 4 ++-- scripts/things/generic.js | 10 ++++++++-- scripts/things/player.js | 2 +- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/scripts/engine.js b/scripts/engine.js index 98cd45f..0824417 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -62,7 +62,7 @@ elation.require(deps, function() { // fire engine_frame event, which kicks off processing in any active systems //console.log("=========="); elation.events.fire({type: "engine_frame", element: this, data: evdata}); - console.log('did a frame', this.systems.world.children.vrcade); + // console.log('did a frame', this.systems.world.children.vrcade); this.lastupdate = ts; } @@ -86,7 +86,6 @@ elation.require(deps, function() { } })(); this.frame = function(fn) { - var window = window || {}; this.requestAnimationFrame.call(window, fn); } diff --git a/scripts/materials.js b/scripts/materials.js index 8905822..0009ab4 100644 --- a/scripts/materials.js +++ b/scripts/materials.js @@ -1,10 +1,11 @@ elation.require(['utils.template'], function() { elation.requireCSS('engine.materials'); - - // elation.template.add('engine.materials.chunk', '

{chunkname}

uniforms

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}

vertex

{chunk.vertex_pars}

{chunk.vertex}

fragment

{chunk.fragment_pars}

{chunk.fragment}

'); - // elation.template.add('engine.materials.chunk.uniforms', '

{chunkname}

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}
'); - // elation.template.add('engine.materials.chunk.vertex', '

{chunkname}

{content}

'); - // elation.template.add('engine.materials.chunk.fragment', '

{chunkname}

{content}

'); + if (ENV_IS_BROWSER) { + elation.template.add('engine.materials.chunk', '

{chunkname}

uniforms

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}

vertex

{chunk.vertex_pars}

{chunk.vertex}

fragment

{chunk.fragment_pars}

{chunk.fragment}

'); + elation.template.add('engine.materials.chunk.uniforms', '

{chunkname}

    {#uniforms}
  • {name}

    ({type})
  • {/uniforms}
'); + elation.template.add('engine.materials.chunk.vertex', '

{chunkname}

{content}

'); + elation.template.add('engine.materials.chunk.fragment', '

{chunkname}

{content}

'); + } elation.extend("engine.materials", new function() { @@ -420,7 +421,8 @@ elation.require(['utils.template'], function() { this.changetimer = setTimeout(elation.bind(this, this.change), this.changetimeout); } }); - - // elation.engine.materials.add('uvtest', new THREE.MeshPhongMaterial({map: elation.engine.materials.getTexture('/media/space/textures/uvtest.png', [1, 1])})); + if (ENV_IS_BROWSER) { + elation.engine.materials.add('uvtest', new THREE.MeshPhongMaterial({map: elation.engine.materials.getTexture('/media/space/textures/uvtest.png', [1, 1])})); + } elation.engine.materials.add('normal', new THREE.MeshNormalMaterial()); }); diff --git a/scripts/systems/world.js b/scripts/systems/world.js index 9411133..aa98641 100644 --- a/scripts/systems/world.js +++ b/scripts/systems/world.js @@ -284,10 +284,10 @@ elation.require([ } return currentobj; } - this.serialize = function() { + this.serialize = function(serializeAll) { var ret = {}; for (var k in this.children) { - ret[k] = this.children[k].serialize(); + ret[k] = this.children[k].serialize(serializeAll); } return ret[k]; // FIXME - dumb } diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 8132ffb..708e524 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -851,7 +851,7 @@ elation.component.add("engine.things.generic", function() { console.log(thispos.toArray(), otherpos.toArray(), dir.toArray(), axis.toArray(), angle, this.properties.orientation.toArray()); } } - this.serialize = function() { + this.serialize = function(serializeAll) { var ret = { name: this.name, parentname: this.parentname, @@ -900,7 +900,13 @@ console.log(thispos.toArray(), otherpos.toArray(), dir.toArray(), axis.toArray() for (var k in this.children) { if (this.children[k].properties) { - if (this.children[k].properties.persist) { + if (!serializeAll) { + if (this.children[k].properties.persist) { + ret.things[k] = this.children[k].serialize(); + numthings++; + } + } + else { ret.things[k] = this.children[k].serialize(); numthings++; } diff --git a/scripts/things/player.js b/scripts/things/player.js index d0d20b5..a8f5c28 100644 --- a/scripts/things/player.js +++ b/scripts/things/player.js @@ -15,7 +15,7 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' 'run': ['keyboard_shift,gamepad_0_button_10', elation.bind(this, this.updateControls)], 'crouch': ['keyboard_c', elation.bind(this, this.updateControls)], //'jump': ['keyboard_space,gamepad_0_button_1', elation.bind(this, this.updateControls)], - //'toss_ball': ['keyboard_space,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.toss_ball)], + 'toss_ball': ['keyboard_space,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.toss_ball)], //'toss_cube': ['keyboard_shift_space,gamepad_0_button_1', elation.bind(this, this.toss_cube)], 'use': ['keyboard_e,gamepad_0_button_0,mouse_button_0', elation.bind(this, this.handleUse)], //'toggle_gravity': ['keyboard_g', elation.bind(this, this.toggle_gravity)], From c0a343847cdcbaeb3c60b706773897dc8bec9f3f Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Apr 2015 00:42:00 -0400 Subject: [PATCH 04/43] remove node-canvas module, add client/server systems, add remoteplayer, change helvetiker_regular to use THREE._typeface_js, minor changes to engine.js for compatibility with node: --- scripts/engine.js | 8 +- scripts/external/three/canvas/.dntrc | 19 - scripts/external/three/canvas/.gitmodules | 0 scripts/external/three/canvas/.npmignore | 6 - scripts/external/three/canvas/.travis.yml | 8 - scripts/external/three/canvas/History.md | 459 ---- scripts/external/three/canvas/Makefile | 24 - scripts/external/three/canvas/Readme.md | 336 --- scripts/external/three/canvas/binding.gyp | 172 -- scripts/external/three/canvas/build/Makefile | 337 --- .../.deps/Release/canvas-postbuild.node.d | 1 - .../build/Release/.deps/Release/canvas.node.d | 1 - .../obj.target/canvas-postbuild.node.d | 1 - .../.deps/Release/obj.target/canvas.node.d | 1 - .../Release/obj.target/canvas/src/Canvas.o.d | 299 -- .../obj.target/canvas/src/CanvasGradient.o.d | 266 -- .../obj.target/canvas/src/CanvasPattern.o.d | 266 -- .../canvas/src/CanvasRenderingContext2d.o.d | 299 -- .../obj.target/canvas/src/FontFace.o.d | 288 -- .../Release/obj.target/canvas/src/Image.o.d | 264 -- .../obj.target/canvas/src/ImageData.o.d | 266 -- .../obj.target/canvas/src/PixelArray.o.d | 265 -- .../Release/obj.target/canvas/src/color.o.d | 4 - .../Release/obj.target/canvas/src/init.o.d | 297 -- .../build/Release/canvas-postbuild.node | Bin 7470 -> 0 bytes .../three/canvas/build/Release/canvas.node | Bin 208599 -> 0 bytes .../three/canvas/build/Release/linker.lock | 0 .../Release/obj.target/canvas-postbuild.node | Bin 7470 -> 0 bytes .../build/Release/obj.target/canvas.node | Bin 208599 -> 0 bytes .../Release/obj.target/canvas/src/Canvas.o | Bin 52960 -> 0 bytes .../obj.target/canvas/src/CanvasGradient.o | Bin 18256 -> 0 bytes .../obj.target/canvas/src/CanvasPattern.o | Bin 15968 -> 0 bytes .../canvas/src/CanvasRenderingContext2d.o | Bin 135424 -> 0 bytes .../Release/obj.target/canvas/src/FontFace.o | Bin 15536 -> 0 bytes .../Release/obj.target/canvas/src/Image.o | Bin 40216 -> 0 bytes .../Release/obj.target/canvas/src/ImageData.o | Bin 17832 -> 0 bytes .../obj.target/canvas/src/PixelArray.o | Bin 17832 -> 0 bytes .../Release/obj.target/canvas/src/color.o | Bin 18256 -> 0 bytes .../Release/obj.target/canvas/src/init.o | Bin 3968 -> 0 bytes .../three/canvas/build/binding.Makefile | 6 - .../canvas/build/canvas-postbuild.target.mk | 42 - .../three/canvas/build/canvas.target.mk | 172 -- .../external/three/canvas/build/config.gypi | 116 - scripts/external/three/canvas/index.js | 1 - scripts/external/three/canvas/install | 65 - scripts/external/three/canvas/lib/bindings.js | 2 - scripts/external/three/canvas/lib/canvas.js | 222 -- .../external/three/canvas/lib/context2d.js | 386 --- scripts/external/three/canvas/lib/image.js | 60 - .../external/three/canvas/lib/jpegstream.js | 61 - .../external/three/canvas/lib/pixelarray.js | 29 - .../external/three/canvas/lib/pngstream.js | 60 - .../three/canvas/node_modules/nan/.dntrc | 30 - .../canvas/node_modules/nan/CHANGELOG.md | 248 -- .../three/canvas/node_modules/nan/LICENSE.md | 13 - .../three/canvas/node_modules/nan/README.md | 1228 --------- .../canvas/node_modules/nan/appveyor.yml | 35 - .../canvas/node_modules/nan/include_dirs.js | 1 - .../three/canvas/node_modules/nan/nan.h | 2038 -------------- .../nan/nan_implementation_12_inl.h | 253 -- .../nan/nan_implementation_pre_12_inl.h | 256 -- .../three/canvas/node_modules/nan/nan_new.h | 320 --- .../canvas/node_modules/nan/package.json | 69 - scripts/external/three/canvas/package.json | 67 - scripts/external/three/canvas/src/Canvas.cc | 575 ---- scripts/external/three/canvas/src/Canvas.h | 96 - .../three/canvas/src/CanvasGradient.cc | 121 - .../three/canvas/src/CanvasGradient.h | 28 - .../three/canvas/src/CanvasPattern.cc | 91 - .../external/three/canvas/src/CanvasPattern.h | 28 - .../canvas/src/CanvasRenderingContext2d.cc | 2403 ----------------- .../canvas/src/CanvasRenderingContext2d.h | 183 -- scripts/external/three/canvas/src/FontFace.cc | 112 - scripts/external/three/canvas/src/FontFace.h | 33 - scripts/external/three/canvas/src/Image.cc | 971 ------- scripts/external/three/canvas/src/Image.h | 108 - .../external/three/canvas/src/ImageData.cc | 69 - scripts/external/three/canvas/src/ImageData.h | 28 - .../external/three/canvas/src/JPEGStream.h | 155 -- scripts/external/three/canvas/src/PNG.h | 227 -- .../external/three/canvas/src/PixelArray.cc | 154 -- .../external/three/canvas/src/PixelArray.h | 33 - scripts/external/three/canvas/src/Point.h | 19 - scripts/external/three/canvas/src/closure.h | 65 - scripts/external/three/canvas/src/color.cc | 739 ----- scripts/external/three/canvas/src/color.h | 40 - scripts/external/three/canvas/src/init.cc | 74 - .../three/canvas/util/cairo_include.sh | 6 - .../three/canvas/util/has_cairo_freetype.sh | 13 - scripts/external/three/canvas/util/has_lib.sh | 27 - .../external/three/canvas/util/lib_lookup.sh | 6 - .../three/fonts/helvetiker_regular.js | 2 +- scripts/external/three/nodethree.js | 4 +- scripts/systems/client.js | 355 +++ scripts/systems/networking.js | 177 -- scripts/systems/server.js | 309 +++ scripts/things/generic.js | 2 +- scripts/things/remoteplayer.js | 13 + 98 files changed, 685 insertions(+), 16248 deletions(-) delete mode 100644 scripts/external/three/canvas/.dntrc delete mode 100644 scripts/external/three/canvas/.gitmodules delete mode 100644 scripts/external/three/canvas/.npmignore delete mode 100644 scripts/external/three/canvas/.travis.yml delete mode 100644 scripts/external/three/canvas/History.md delete mode 100644 scripts/external/three/canvas/Makefile delete mode 100644 scripts/external/three/canvas/Readme.md delete mode 100755 scripts/external/three/canvas/binding.gyp delete mode 100644 scripts/external/three/canvas/build/Makefile delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d delete mode 100644 scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d delete mode 100755 scripts/external/three/canvas/build/Release/canvas-postbuild.node delete mode 100755 scripts/external/three/canvas/build/Release/canvas.node delete mode 100644 scripts/external/three/canvas/build/Release/linker.lock delete mode 100755 scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node delete mode 100755 scripts/external/three/canvas/build/Release/obj.target/canvas.node delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/color.o delete mode 100644 scripts/external/three/canvas/build/Release/obj.target/canvas/src/init.o delete mode 100644 scripts/external/three/canvas/build/binding.Makefile delete mode 100644 scripts/external/three/canvas/build/canvas-postbuild.target.mk delete mode 100644 scripts/external/three/canvas/build/canvas.target.mk delete mode 100644 scripts/external/three/canvas/build/config.gypi delete mode 100644 scripts/external/three/canvas/index.js delete mode 100755 scripts/external/three/canvas/install delete mode 100644 scripts/external/three/canvas/lib/bindings.js delete mode 100644 scripts/external/three/canvas/lib/canvas.js delete mode 100644 scripts/external/three/canvas/lib/context2d.js delete mode 100644 scripts/external/three/canvas/lib/image.js delete mode 100644 scripts/external/three/canvas/lib/jpegstream.js delete mode 100644 scripts/external/three/canvas/lib/pixelarray.js delete mode 100644 scripts/external/three/canvas/lib/pngstream.js delete mode 100644 scripts/external/three/canvas/node_modules/nan/.dntrc delete mode 100644 scripts/external/three/canvas/node_modules/nan/CHANGELOG.md delete mode 100644 scripts/external/three/canvas/node_modules/nan/LICENSE.md delete mode 100644 scripts/external/three/canvas/node_modules/nan/README.md delete mode 100644 scripts/external/three/canvas/node_modules/nan/appveyor.yml delete mode 100644 scripts/external/three/canvas/node_modules/nan/include_dirs.js delete mode 100644 scripts/external/three/canvas/node_modules/nan/nan.h delete mode 100644 scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h delete mode 100644 scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h delete mode 100644 scripts/external/three/canvas/node_modules/nan/nan_new.h delete mode 100644 scripts/external/three/canvas/node_modules/nan/package.json delete mode 100644 scripts/external/three/canvas/package.json delete mode 100644 scripts/external/three/canvas/src/Canvas.cc delete mode 100644 scripts/external/three/canvas/src/Canvas.h delete mode 100644 scripts/external/three/canvas/src/CanvasGradient.cc delete mode 100644 scripts/external/three/canvas/src/CanvasGradient.h delete mode 100644 scripts/external/three/canvas/src/CanvasPattern.cc delete mode 100644 scripts/external/three/canvas/src/CanvasPattern.h delete mode 100755 scripts/external/three/canvas/src/CanvasRenderingContext2d.cc delete mode 100644 scripts/external/three/canvas/src/CanvasRenderingContext2d.h delete mode 100755 scripts/external/three/canvas/src/FontFace.cc delete mode 100644 scripts/external/three/canvas/src/FontFace.h delete mode 100644 scripts/external/three/canvas/src/Image.cc delete mode 100644 scripts/external/three/canvas/src/Image.h delete mode 100644 scripts/external/three/canvas/src/ImageData.cc delete mode 100644 scripts/external/three/canvas/src/ImageData.h delete mode 100644 scripts/external/three/canvas/src/JPEGStream.h delete mode 100644 scripts/external/three/canvas/src/PNG.h delete mode 100644 scripts/external/three/canvas/src/PixelArray.cc delete mode 100644 scripts/external/three/canvas/src/PixelArray.h delete mode 100644 scripts/external/three/canvas/src/Point.h delete mode 100644 scripts/external/three/canvas/src/closure.h delete mode 100644 scripts/external/three/canvas/src/color.cc delete mode 100644 scripts/external/three/canvas/src/color.h delete mode 100755 scripts/external/three/canvas/src/init.cc delete mode 100755 scripts/external/three/canvas/util/cairo_include.sh delete mode 100755 scripts/external/three/canvas/util/has_cairo_freetype.sh delete mode 100755 scripts/external/three/canvas/util/has_lib.sh delete mode 100755 scripts/external/three/canvas/util/lib_lookup.sh create mode 100644 scripts/systems/client.js delete mode 100644 scripts/systems/networking.js create mode 100644 scripts/systems/server.js create mode 100644 scripts/things/remoteplayer.js diff --git a/scripts/engine.js b/scripts/engine.js index 0824417..6174bc5 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -3,17 +3,17 @@ var deps = [ "engine.materials", "engine.geometries", "engine.things.generic", - "utils.math" ]; + "utils.math", +]; if (ENV_IS_BROWSER) { - deps.push("engine.external.three.three") + deps.push("engine.external.three.three"); } else if (ENV_IS_NODE) { - deps.push("engine.external.three.nodethree") + deps.push("engine.external.three.nodethree"); } - elation.require(deps, function() { elation.requireCSS('engine.engine'); diff --git a/scripts/external/three/canvas/.dntrc b/scripts/external/three/canvas/.dntrc deleted file mode 100644 index 41ef805..0000000 --- a/scripts/external/three/canvas/.dntrc +++ /dev/null @@ -1,19 +0,0 @@ -## DNT config file -## see https://github.com/rvagg/dnt - -NODE_VERSIONS="\ - master \ - v0.11.12 \ - v0.10.26 \ - v0.8.22 \ -" -OUTPUT_PREFIX="canvas-" -TEST_CMD="\ - sudo apt-get install -y libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev && \ - cd /dnt/ && \ - npm install node-gyp && \ - npm install && \ - node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild && \ - npm test; \ -" -LOG_OK_CMD="sed -r 's/^\s+[0-9]+ passing \([0-9]+ms\)$/ok/' | tail -2 | head -1" diff --git a/scripts/external/three/canvas/.gitmodules b/scripts/external/three/canvas/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/external/three/canvas/.npmignore b/scripts/external/three/canvas/.npmignore deleted file mode 100644 index e91e149..0000000 --- a/scripts/external/three/canvas/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -testing -build -benchmarks -examples -support -test diff --git a/scripts/external/three/canvas/.travis.yml b/scripts/external/three/canvas/.travis.yml deleted file mode 100644 index 7049d0c..0000000 --- a/scripts/external/three/canvas/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: node_js -node_js: - - '0.8' - - '0.10' - - '0.11' -before_install: - - sudo chown -R $USER /usr/local - - sh install diff --git a/scripts/external/three/canvas/History.md b/scripts/external/three/canvas/History.md deleted file mode 100644 index 3871d37..0000000 --- a/scripts/external/three/canvas/History.md +++ /dev/null @@ -1,459 +0,0 @@ -1.2.1 / 2015-02-10 -================== - - * Use non-cairo 1.12 API for shadow blur - -1.2.0 / 2015-01-31 -================== - - * travis: drop support for node v0.6 - * Merge pull request #507 from salzhrani/iojs - * io.js compatibility - * Merge pull request #505 from woodcoder/shadow-blur - * Fix issue with line width not being correct in stroked shadows. - * Add another shadow/transform test. - * Refactor setSourceRGBA to allow the context to be supplied. - * Simple image shadow (no blurring or handling current transforms) based on image's alpha channel. - * Test showing issue #133, that images don't have shadows. - * The +1 on the offset seems to match the browser's output better, but I can't work out why it would be needed (unless it's pixel alignment related). - * Make the shadow radius more accurately match the browser's, making use of sigma scale as used in SKIA: https://github.com/google/skia/blob/master/src/effects/SkBlurMask.cpp#L26. - * Create a new image surface to render blurred shadows to, this means that vector formats like PDF will now render blurs. - * Add recommended calls to flush and dirty buffer, as per http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-image-surface-get-data. - * Add PDF button to test page to easily generate PDF version of the test image. - * Fix to ensure shadowOffset is unaffected by the current transform. - * New test illustrating that canvas implementation doesn't translate the shadowOffset. - * Merge pull request #490 from AllYearbooks/master - * Merge pull request #501 from motiz88/hsl-color - * Code style + attribution. Also removed parseClipped() and commented out wrapInt (now wrap_int). - * Added visual tests for hsl() and hsla() color parsing. - * Fixed handling in hsl/hsla color parser. parseNumber() was erroring out on numbers with long fractional parts. - * hsl/hsla color parsing + rebeccapurple hsl() and hsla() color values are now supported, with corresponding unit tests. Also added rebeccapurple (from CSS Color Level 4) to the named color list. - * float rather than int for drawImage arguments - * with_pango to true and use fontconfig to load fonts - * Merge pull request #399 from nulltask/fix/lighten - * Merge pull request #465 from espadrine/master - * Merge pull request #470 from tonylukasavage/patch-1 - * Add one-liner MacPorts install to docs - * Offer SVG output. - * Readme update: node-gyp. - * Readme: fix subheading size - * Readme: remove Gemnasium badge, use SVG for npm badge - * Readme: add Travis-CI badge - * change operator lighter to lighten - -1.1.6 / 2014-08-01 -================== - - * export canvas.CanvasPixelArray instead of canvas.PixelArray which is undefined - * Glib version test into giflib exists test - * Giflib 5.1 - * install: use an even older version of giflib (v4.1.6) - * install: use an older version of giflib (v4.2.3) - * install: install `giflib` - * install: use more compatible sh syntax - * travis: attempt to run the ./install script before testintg - * travis: test node v0.6, v0.8, v0.10, and v0.11 - * Distinguish between 'add' and 'lighter' - -1.1.5 / 2014-06-26 -================== - - * Readme: remove Contributors section - * Readme: update copyright - * On Windows, copy required DLLs next to ".node" file (#442 @pandell) - * Duplicate "msvc_settings" for "Debug" configuration - * Remove unneeded #include - * Use float constants to prevent double->float conversion warning - * Ignore Visual C++ 2013 warnings (#441 @pandell) - * Add algorithm include to CanvasRenderingContext2d.cc for std::min (#435 @kkoopa) - * Updated NAN to 1.2.0 (#434 @kkoopa) - -1.1.4 / 2014-06-08 -================== - - * Fix compile error with Visual C++ - * Add support for the lineDash API - * Update NAN - * New V8 compatibility - * Correctly limit bounds in PutImageData to prevent segment fault - * Fix segfault when onload and onerror are not function - * Add support for Node 0.11.9 - -1.1.3 / 2014-01-08 -================== - - * Add CAIRO_FORMAT_INVALID - * Readjust the amount of allocated memory - * Fix argument index for filter parameter - * Make has_lib.sh work properly on Debian 64bit - -1.1.2 / 2013-10-31 -================== - - * NAN dep upgrade, full node@<=0.11.8 compatibility - * Use node::MakeCallback() instead of v8::Function::Call() - * Improve nan location discovery - * Fix enabling gif/jpeg options on Ubuntu 13.04 - -1.1.1 / 2013-10-09 -================== - - * add better support for outdated versions of Cairo - -1.1.0 / 2013-08-01 -================== - - * add png compression options - * add jpeg stream progressive mode option - * fix resource leaks on read errors - -1.0.4 / 2013-07-23 -================== - - * 0.11.4+ compatibility using NAN - * fix typo in context2d for imageSmoothingEnabled - -1.0.3 / 2013-06-04 -================== - - * add "nearest" and "bilinear" to patternQuality - * fix fread() retval check (items not bytes) - * removed unneeded private fields - -1.0.2 / 2013-03-22 -================== - - * add Context2d#imageSmoothingEnabled= - -1.0.1 / 2013-02-25 -================== - - * travis: test modern node versions - * change the node-gyp build to use pkg-config - -1.0.0 / 2013-01-16 -================== - - * add conditional pango font support [Julian Viereck] - * add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods - * add support for grayscale JPEGs - * fix: explicitly cast the after work callback function to "uv_after_work_cb" - * fix test server for express 3.x - * fix: call cairo_surface_finish in ~Canvas when pdf - * remove old 0.4.x binding support. Closes #197 - -0.13.1 / 2012-08-20 -================== - - * fix cases where GIF_LIB_VERSION is not defined - * fix auto-detection of optional libraries for OS X - * fix Context2d::SetFont for pango when setting normal weight/style - -0.13.0 / 2012-08-12 -================== - - * add pango support [c-spencer] - * add pango / png / jpeg gyp auto-detection [c-spencer] - * add `.gifVersion` [tootallnate] - * add `.jpegVersion` [tootallnate] - * add moar gyp stuff [tootallnate] - * remove wscript - * fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()` - -0.12.1 / 2012-06-29 -================== - - * fix jpeg malloc Image issue. Closes #160 [c-spencer] - * Improve Image mode API - * Add clearData method to handle reassignment of src, and clean up mime data memory handling. - * Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional. - * Add optional mime-data tracking to Image. - * Refactor JPEG decoding into decodeJPEGIntoSurface - -0.12.0 / 2012-05-02 -================== - - * Added `textDrawingMode` context property [c-spencer] - * Added additional TextMetrics properties [c-spencer] - -0.11.3 / 2012-04-25 -================== - - * Fixed `Image` memory leak. Closes #150 - * Fixed Context2d::hasShadow() - -0.11.2 / 2012-04-12 -================== - - * Fixed: pdf memory leak, free closure and surface in ~Canvas - -0.11.1 / 2012-04-10 -================== - - * Changed: renamed .nextPage() to .addPage() - -0.11.0 / 2012-04-10 -================== - - * Added quick PDF support - * Added `Canvas#type` getter - * Added ./examples/pdf-images.js - * Added ./examples/multiple-page-pdf.js - * Added ./examples/small-pdf.js - -0.10.3 / 2012-02-27 -================== - - * Fixed quadratic curve starting point for undefined path. Closes #155 - -0.10.2 / 2012-02-06 -================== - - * Fixed: Context2d setters with invalid values ignored - * Changed: replaced seek with `fstat()` - -0.10.1 / 2012-01-31 -================== - - * Added _/opt/local/lib_ to wscript [obarthel] - * Added bounds checking to `rgba_to_string()` [obarthel] - * Fixed cleanup in JPEG Image loading [obarthel] - * Fixed missing CSS color table values [obarthel] - -0.10.0 / 2012-01-18 -================== - - * Added `ctx.createPattern()` [slaskis] - -0.9.0 / 2012-01-13 -================== - - * Added `createJPEGStream()` [Elijah Hamovitz] - -0.8.3 / 2012-01-04 -================== - - * Added support for libjpeg62-dev or libjpeg8-dev [wwlinx] - -0.8.2 / 2011-12-14 -================== - - * Fixed two memory leaks in context2d [Tharit] - * Fixed `make test-server` - -0.8.1 / 2011-10-31 -================== - - * Added 0.5.x support [TooTallNate] - * Fixed `measureText().width`. Closes #126 - -0.8.0 / 2011-10-28 -================== - - * Added data uri support. Closes #49 - -0.7.3 / 2011-09-14 -================== - - * Added better lineTo() / moveTo() exception messages - -0.7.2 / 2011-08-30 -================== - - * Changed: prefix some private methods with _ - -0.7.1 / 2011-08-25 -================== - - * Added better image format detection - * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD - -0.7.0 / 2011-07-12 -================== - - * Added GIF support [Brian McKinney] - -0.6.0 / 2011-06-04 -================== - - * Added `Image#src=Buffer` support. Closes #91 - * Added `devDependencies` - * Added `source-atop` test - * Added _image-src.js_ example - * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()` - * Fixed v8 memory hint when resizing canvas [atomizer] - -0.5.4 / 2011-04-20 -================== - - * Added; special case of zero-width rectangle [atomizer] - * Fixed; do not clamp arguments to integer values [atomizer] - * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer] - * Fixed; `restorePath()`: clear current path before appending [atomizer] - -0.5.3 / 2011-04-11 -================== - - * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte] - -0.5.2 / 2011-04-09 -================== - - * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte] - -0.5.1 / 2011-03-16 -================== - - * Fixed (kinda) `img.src=` error handling - * Fixed; move closure.h down for malloc ref. Closes #80 - -0.5.0 / 2011-03-14 -================== - - * Added several more operators (color-dodge, color-burn, difference, etc) - * Performance; no longer re-allocating `closure->data` for each png write - * Fixed freeing of `Context2d` states - * Fixed text alignment / baseline [Olaf] - * Fixed HandleScopes [Olaf] - * Fixed small misc memory leaks - * Fixed `Buffer` usage for node 0.4.x - -0.4.3 / 2011-01-11 -================== - - * Fixed font family dereferencing. Closes #72 - * Fixed; stripping of quotes from font-family before applying - * Fixed duplicate textAlign getter - * Removed sans-serif default of _Arial_ - -0.4.2 / 2010-12-28 -================== - - * Fixed font size growing issue after successive calls. Closes #70 - -0.4.1 / 2010-12-18 -================== - - * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68 - -0.4.0 / 2010-12-12 -================== - - * Added `drawImage()` with `Canvas` instance support. Closes #67 - -0.3.3 / 2010-11-30 -================== - - * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_ - * Fixed; pre-multiply `putImageData()` components - * Fixed; `PixelArray` data is not premultiplied - -0.3.2 / 2010-11-26 -================== - - * Added --profile option to config - * Fixed `eio_custom` segfault(s). Closes #46 - * Fixed two named colors. Closes #62 [thanks noonat] - * Fixed a few warnings - * Fixed; freeing data in `Image::loadJPEG()` on failure - * Fixed; include _jpeglib_ only when __HAVE_JPEG__ - * Fixed; using `strstr()` instead of `strnstr()` - -0.3.1 / 2010-11-24 -================== - - * Fixed; `Image` loading is sync until race-condition is resolved - * Fixed; `Image::loadJPEG()` return status based on errno - -0.3.0 / 2010-11-24 -================== - - * Added arcTo(). Closes #11 - * Added c color parser, _./examples/ray.js_ is now twice as fast - * Fixed `putImageData()` bug messing up rgba channels - -0.2.1 / 2010-11-19 -================== - - * Added image _resize_ example - * Fixed canvas resizing via `{width,height}=`. Closes #57 - * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext - * Fixed async image loading (test server still messed) - -0.2.0 / 2010-11-18 -================== - - * Added jpeg `Image` support (when libjpeg is available) - * Added _hsl_ / _hsla_ color support. [Tom Carden] - -0.1.0 / 2010-11-17 -================== - - * Added `Image` - * Added `ImageData` - * Added `PixelArray` - * Added `CanvasRenderingContext2d#drawImage()` - * Added `CanvasRenderingContext2d#getImageData()` - * Added `CanvasRenderingContext2d#createImageData()` - * Added kraken blur benchmark example - * Added several new tests - * Fixed instanceof checks for many c++ methods - * Fixed test runner in firefox [Don Park] - -0.0.8 / 2010-11-12 -================== - - * Added `CanvasRenderingContext2d#drawImage()` - * Fixed `free()` call missing stdlib - * Fixed Image#{width,height} initialization to 0 - * Fixed; load image on non-LOADING state - -0.0.7 / 2010-11-12 -================== - - * Fixed _lighter_ for older versions of cairo - -0.0.6 / 2010-11-12 -================== - - * Added `Image` - * Added conditional support for cairo 1.10.0 operators - -0.0.5 / 2010-11-10 -================== - - * Added custom port support to _test/server.js_ - * Added more global composite operator support - * Added `Context2d#antialias=` - * Added _voronoi_ example - * Added -D__NDEBUG__ to default build - * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park] - * Fixed getter bug preventing patterns from being returned via `fillStyle` etc - - * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc() - * Fixed; free `Canvas::ToBuffer()` closure data - -0.0.4 / 2010-11-09 -================== - - * Bump to fix npm engine cache bug... - -0.0.3 / 2010-11-09 -================== - - * Added async `toDataURL()` support - * Added async `toBuffer()` support - * Removed buffer utils - -0.0.2 / 2010-11-08 -================== - - * Added shadow support (faster/better gaussian blur to come) - * Added node v0.3 support [Don Park] - * Added -O3 to build - * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()` - -0.0.1 / 2010-11-04 -================== - - * Initial release diff --git a/scripts/external/three/canvas/Makefile b/scripts/external/three/canvas/Makefile deleted file mode 100644 index 165474e..0000000 --- a/scripts/external/three/canvas/Makefile +++ /dev/null @@ -1,24 +0,0 @@ - -ADDON = build/Release/canvas.node -REPORTER = dot - -$(ADDON): src/*.cc - npm install - -test: $(ADDON) - @./node_modules/.bin/mocha \ - --reporter $(REPORTER) \ - --ui exports \ - --require should \ - test/*.test.js - -test-server: $(ADDON) - @node test/server.js - -benchmark: - @node benchmarks/run.js - -clean: - rm -fr build - -.PHONY: test test-server benchmark clean diff --git a/scripts/external/three/canvas/Readme.md b/scripts/external/three/canvas/Readme.md deleted file mode 100644 index 28e694f..0000000 --- a/scripts/external/three/canvas/Readme.md +++ /dev/null @@ -1,336 +0,0 @@ -node-canvas -=========== -### Canvas graphics API backed by Cairo -[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas) -[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas) - - node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org). - -## Authors - - - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia)) - - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate)) - - Rod Vagg ([rvagg](http://github.com/rvagg)) - - Juriy Zaytsev ([kangax](http://github.com/kangax)) - -## Installation - -```bash -$ npm install canvas -``` - -Unless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/LearnBoost/node-canvas/wiki/_pages). - -You can quickly install Cairo and its dependencies for OS X using the one liner below: - -```bash -$ wget https://raw.githubusercontent.com/LearnBoost/node-canvas/master/install -O - | sh -``` - -or if you use MacPorts - -```bash -sudo port install pkgconfig libpng giflib freetype libpixman cairo -``` - -## Screencasts - - - [Introduction](http://screenr.com/CTk) - -## Example - -```javascript -var Canvas = require('canvas') - , Image = Canvas.Image - , canvas = new Canvas(200,200) - , ctx = canvas.getContext('2d'); - -ctx.font = '30px Impact'; -ctx.rotate(.1); -ctx.fillText("Awesome!", 50, 100); - -var te = ctx.measureText('Awesome!'); -ctx.strokeStyle = 'rgba(0,0,0,0.5)'; -ctx.beginPath(); -ctx.lineTo(50, 102); -ctx.lineTo(50 + te.width, 102); -ctx.stroke(); - -console.log(''); -``` - -## Non-Standard API - - node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers. - -### Image#src=Buffer - - node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O. - -```javascript -fs.readFile(__dirname + '/images/squid.png', function(err, squid){ - if (err) throw err; - img = new Image; - img.src = squid; - ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4); -}); -``` - - Below is an example of a canvas drawing it-self as the source several time: - -```javascript -var img = new Image; -img.src = canvas.toBuffer(); -ctx.drawImage(img, 0, 0, 50, 50); -ctx.drawImage(img, 50, 0, 50, 50); -ctx.drawImage(img, 100, 0, 50, 50); -``` - -### Image#dataMode - -node-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs). - -When mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering. - -```javascript -var img = new Image; -img.dataMode = Image.MODE_IMAGE; // Only image data tracked -img.dataMode = Image.MODE_MIME; // Only mime data tracked -img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked -``` - -If image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF. - -### Canvas#pngStream() - - To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted. - -```javascript -var fs = require('fs') - , out = fs.createWriteStream(__dirname + '/text.png') - , stream = canvas.pngStream(); - -stream.on('data', function(chunk){ - out.write(chunk); -}); - -stream.on('end', function(){ - console.log('saved png'); -}); -``` - -Currently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`. - -### Canvas#jpegStream() and Canvas#syncJPEGStream() - -You can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with -some optional parameters; functionality is otherwise identical to -`pngStream()`. See `examples/crop.js` for an example. - -_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both -are synchronous_ - -```javascript -var stream = canvas.jpegStream({ - bufsize: 4096 // output buffer size in bytes, default: 4096 - , quality: 75 // JPEG quality (0-100) default: 75 - , progressive: false // true for progressive compression, default: false -}); -``` - -### Canvas#toBuffer() - -A call to `Canvas#toBuffer()` will return a node `Buffer` instance containing all of the PNG data. - -```javascript -canvas.toBuffer(); -``` - -### Canvas#toBuffer() async - -Optionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`. - -```javascript -canvas.toBuffer(function(err, buf){ - -}); -``` - -### Canvas#toDataURL() async - -Optionally we may pass a callback function to `Canvas#toDataURL()`, and this process will be performed asynchronously, and will `callback(err, str)`. - -```javascript -canvas.toDataURL(function(err, str){ - -}); -``` - -or specify the mime type: - -```javascript -canvas.toDataURL('image/png', function(err, str){ - -}); -``` - -### CanvasRenderingContext2d#patternQuality - -Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_. - - - fast - - good - - best - - nearest - - bilinear - -### CanvasRenderingContext2d#textDrawingMode - -Can be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill. - -Defaults to _path_. - -This property is tracked as part of the canvas state in save/restore. - -### CanvasRenderingContext2d#filter - -Like `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_. - - - fast - - good - - best - - nearest - - bilinear - -### Global Composite Operations - -In addition to those specified and commonly implemented by browsers, the following have been added: - - - multiply - - screen - - overlay - - hard-light - - soft-light - - hsl-hue - - hsl-saturation - - hsl-color - - hsl-luminosity - -## Anti-Aliasing - - Set anti-aliasing mode - - - default - - none - - gray - - subpixel - - For example: - -```javascript -ctx.antialias = 'none'; -``` - -## PDF Support - - Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating - a PDF on initialization, using the "pdf" string: - -```js -var canvas = new Canvas(200, 500, 'pdf'); -``` - - An additional method `.addPage()` is then available to create - multiple page PDFs: - -```js -ctx.font = '22px Helvetica'; -ctx.fillText('Hello World', 50, 80); -ctx.addPage(); - -ctx.font = '22px Helvetica'; -ctx.fillText('Hello World 2', 50, 80); -ctx.addPage(); - -ctx.font = '22px Helvetica'; -ctx.fillText('Hello World 3', 50, 80); -ctx.addPage(); -``` - -## SVG support - - Just like PDF support, make sure to install cairo with `--enable-svg=yes`. - You also need to tell node-canvas that it is working on SVG upon its initialization: - -```js -var canvas = new Canvas(200, 500, 'svg'); -// Use the normal primitives. -fs.writeFile('out.svg', canvas.toBuffer()); -``` - -## Benchmarks - - Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself. - -## Contribute - - Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/LearnBoost/node-canvas/issues) for existing issues. - -## Examples - - Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser. - -## Testing - -If you have not previously, init git submodules: - - $ git submodule update --init - -Build node-canvas: - - $ node-gyp rebuild - -Unit tests: - - $ make test - -Visual tests: - - $ make test-server - -## Versions - -Tested with and designed for: - - - node 0.4.2 - - cairo 1.8.6 - -For node 0.2.x `node-canvas` <= 0.4.3 may be used, -0.5.0 and above are designed for node 0.4.x only. - -## License - -(The MIT License) - -Copyright (c) 2010 LearnBoost, and contributors <dev@learnboost.com> - -Copyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com> - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/scripts/external/three/canvas/binding.gyp b/scripts/external/three/canvas/binding.gyp deleted file mode 100755 index afb7323..0000000 --- a/scripts/external/three/canvas/binding.gyp +++ /dev/null @@ -1,172 +0,0 @@ -{ - 'conditions': [ - ['OS=="win"', { - 'variables': { - 'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle - 'with_jpeg%': 'false', - 'with_gif%': 'false', - 'with_pango%': 'false', - 'with_freetype%': 'false' - } - }, { # 'OS!="win"' - 'variables': { - 'with_jpeg%': '> $(depfile) -# Add extra rules as in (2). -# We remove slashes and replace spaces with new lines; -# remove blank lines; -# delete the first line and append a colon to the remaining lines. -sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ - grep -v '^$$' |\ - sed -e 1d -e 's|$$|:|' \ - >> $(depfile) -rm $(depfile).raw -endef - -# Command definitions: -# - cmd_foo is the actual command to run; -# - quiet_cmd_foo is the brief-output summary of the command. - -quiet_cmd_cc = CC($(TOOLSET)) $@ -cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< - -quiet_cmd_cxx = CXX($(TOOLSET)) $@ -cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< - -quiet_cmd_touch = TOUCH $@ -cmd_touch = touch $@ - -quiet_cmd_copy = COPY $@ -# send stderr to /dev/null to ignore messages when linking directories. -cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") - -quiet_cmd_alink = AR($(TOOLSET)) $@ -cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) - -quiet_cmd_alink_thin = AR($(TOOLSET)) $@ -cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) - -# Due to circular dependencies between libraries :(, we wrap the -# special "figure out circular dependencies" flags around the entire -# input list during linking. -quiet_cmd_link = LINK($(TOOLSET)) $@ -cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) - -# We support two kinds of shared objects (.so): -# 1) shared_library, which is just bundling together many dependent libraries -# into a link line. -# 2) loadable_module, which is generating a module intended for dlopen(). -# -# They differ only slightly: -# In the former case, we want to package all dependent code into the .so. -# In the latter case, we want to package just the API exposed by the -# outermost module. -# This means shared_library uses --whole-archive, while loadable_module doesn't. -# (Note that --whole-archive is incompatible with the --start-group used in -# normal linking.) - -# Other shared-object link notes: -# - Set SONAME to the library filename so our binaries don't reference -# the local, absolute paths used on the link command-line. -quiet_cmd_solink = SOLINK($(TOOLSET)) $@ -cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) - -quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ -cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) - - -# Define an escape_quotes function to escape single quotes. -# This allows us to handle quotes properly as long as we always use -# use single quotes and escape_quotes. -escape_quotes = $(subst ','\'',$(1)) -# This comment is here just to include a ' to unconfuse syntax highlighting. -# Define an escape_vars function to escape '$' variable syntax. -# This allows us to read/write command lines with shell variables (e.g. -# $LD_LIBRARY_PATH), without triggering make substitution. -escape_vars = $(subst $$,$$$$,$(1)) -# Helper that expands to a shell command to echo a string exactly as it is in -# make. This uses printf instead of echo because printf's behaviour with respect -# to escape sequences is more portable than echo's across different shells -# (e.g., dash, bash). -exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' - -# Helper to compare the command we're about to run against the command -# we logged the last time we ran the command. Produces an empty -# string (false) when the commands match. -# Tricky point: Make has no string-equality test function. -# The kernel uses the following, but it seems like it would have false -# positives, where one string reordered its arguments. -# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ -# $(filter-out $(cmd_$@), $(cmd_$(1)))) -# We instead substitute each for the empty string into the other, and -# say they're equal if both substitutions produce the empty string. -# .d files contain ? instead of spaces, take that into account. -command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ - $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) - -# Helper that is non-empty when a prerequisite changes. -# Normally make does this implicitly, but we force rules to always run -# so we can check their command lines. -# $? -- new prerequisites -# $| -- order-only dependencies -prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) - -# Helper that executes all postbuilds until one fails. -define do_postbuilds - @E=0;\ - for p in $(POSTBUILDS); do\ - eval $$p;\ - E=$$?;\ - if [ $$E -ne 0 ]; then\ - break;\ - fi;\ - done;\ - if [ $$E -ne 0 ]; then\ - rm -rf "$@";\ - exit $$E;\ - fi -endef - -# do_cmd: run a command via the above cmd_foo names, if necessary. -# Should always run for a given target to handle command-line changes. -# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. -# Third argument, if non-zero, makes it do POSTBUILDS processing. -# Note: We intentionally do NOT call dirx for depfile, since it contains ? for -# spaces already and dirx strips the ? characters. -define do_cmd -$(if $(or $(command_changed),$(prereq_changed)), - @$(call exact_echo, $($(quiet)cmd_$(1))) - @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" - $(if $(findstring flock,$(word 1,$(cmd_$1))), - @$(cmd_$(1)) - @echo " $(quiet_cmd_$(1)): Finished", - @$(cmd_$(1)) - ) - @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) - @$(if $(2),$(fixup_dep)) - $(if $(and $(3), $(POSTBUILDS)), - $(call do_postbuilds) - ) -) -endef - -# Declare the "all" target first so it is the default, -# even though we don't have the deps yet. -.PHONY: all -all: - -# make looks for ways to re-generate included makefiles, but in our case, we -# don't have a direct way. Explicitly telling make that it has nothing to do -# for them makes it go faster. -%.d: ; - -# Use FORCE_DO_CMD to force a target to run. Should be coupled with -# do_cmd. -.PHONY: FORCE_DO_CMD -FORCE_DO_CMD: - -TOOLSET := target -# Suffix rules, putting all outputs into $(obj). -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) - -# Try building from generated source, too. -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) - -$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) - - -ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ - $(findstring $(join ^,$(prefix)),\ - $(join ^,canvas-postbuild.target.mk)))),) - include canvas-postbuild.target.mk -endif -ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ - $(findstring $(join ^,$(prefix)),\ - $(join ^,canvas.target.mk)))),) - include canvas.target.mk -endif - -quiet_cmd_regen_makefile = ACTION Regenerating $@ -cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/root/dev/elation/components/vrcade/node_modules/canvas/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dmodule_root_dir=/root/dev/elation/components/vrcade/node_modules/canvas" binding.gyp -Makefile: $(srcdir)/../../../../../../../usr/share/node-gyp/addon.gypi $(srcdir)/../../../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp - $(call do_cmd,regen_makefile) - -# "all" is a concatenation of the "all" targets from all the included -# sub-makefiles. This is just here to clarify. -all: - -# Add in dependency-tracking rules. $(all_deps) is the list of every single -# target in our tree. Only consider the ones with .d (dependency) info: -d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) -ifneq ($(d_files),) - include $(d_files) -endif diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d deleted file mode 100644 index 70941d7..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/canvas-postbuild.node.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/canvas-postbuild.node := ln -f "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node" 2>/dev/null || (rm -rf "Release/canvas-postbuild.node" && cp -af "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node") diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d deleted file mode 100644 index d2e1ae3..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/canvas.node.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/canvas.node := ln -f "Release/obj.target/canvas.node" "Release/canvas.node" 2>/dev/null || (rm -rf "Release/canvas.node" && cp -af "Release/obj.target/canvas.node" "Release/canvas.node") diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d deleted file mode 100644 index 5b77407..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/obj.target/canvas-postbuild.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas-postbuild.node -o Release/obj.target/canvas-postbuild.node -Wl,--start-group -Wl,--end-group diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d deleted file mode 100644 index e233682..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas.node.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/obj.target/canvas.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas.node -o Release/obj.target/canvas.node -Wl,--start-group Release/obj.target/canvas/src/Canvas.o Release/obj.target/canvas/src/CanvasGradient.o Release/obj.target/canvas/src/CanvasPattern.o Release/obj.target/canvas/src/CanvasRenderingContext2d.o Release/obj.target/canvas/src/color.o Release/obj.target/canvas/src/Image.o Release/obj.target/canvas/src/ImageData.o Release/obj.target/canvas/src/init.o Release/obj.target/canvas/src/PixelArray.o Release/obj.target/canvas/src/FontFace.o -Wl,--end-group -lpixman-1 -lcairo -lpng12 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -ljpeg -lgif diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d deleted file mode 100644 index b6763b1..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d +++ /dev/null @@ -1,299 +0,0 @@ -cmd_Release/obj.target/canvas/src/Canvas.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Canvas.o.d.raw -c -o Release/obj.target/canvas/src/Canvas.o ../src/Canvas.cc -Release/obj.target/canvas/src/Canvas.o: ../src/Canvas.cc ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/PNG.h \ - /usr/include/libpng12/png.h /usr/include/libpng12/pngconf.h \ - /usr/include/libpng12/pngconf.h ../src/closure.h \ - ../src/CanvasRenderingContext2d.h ../src/color.h ../src/CanvasGradient.h \ - /usr/include/freetype2/ft2build.h \ - /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ - /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ - /usr/include/freetype2/config/ftconfig.h \ - /usr/include/freetype2/config/ftoption.h \ - /usr/include/freetype2/config/ftstdlib.h \ - /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ - /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ - /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ - ../src/JPEGStream.h -../src/Canvas.cc: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/PNG.h: -/usr/include/libpng12/png.h: -/usr/include/libpng12/pngconf.h: -/usr/include/libpng12/pngconf.h: -../src/closure.h: -../src/CanvasRenderingContext2d.h: -../src/color.h: -../src/CanvasGradient.h: -/usr/include/freetype2/ft2build.h: -/usr/include/freetype2/config/ftheader.h: -/usr/include/cairo/cairo-ft.h: -/usr/include/cairo/cairo.h: -/usr/include/freetype2/freetype.h: -/usr/include/freetype2/config/ftconfig.h: -/usr/include/freetype2/config/ftoption.h: -/usr/include/freetype2/config/ftstdlib.h: -/usr/include/freetype2/fttypes.h: -/usr/include/freetype2/ftsystem.h: -/usr/include/freetype2/ftimage.h: -/usr/include/freetype2/fterrors.h: -/usr/include/freetype2/ftmoderr.h: -/usr/include/freetype2/fterrdef.h: -../src/JPEGStream.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d deleted file mode 100644 index 0728fe6..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d +++ /dev/null @@ -1,266 +0,0 @@ -cmd_Release/obj.target/canvas/src/CanvasGradient.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d.raw -c -o Release/obj.target/canvas/src/CanvasGradient.o ../src/CanvasGradient.cc -Release/obj.target/canvas/src/CanvasGradient.o: ../src/CanvasGradient.cc \ - ../src/color.h ../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h \ - ../src/CanvasGradient.h -../src/CanvasGradient.cc: -../src/color.h: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/CanvasGradient.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d deleted file mode 100644 index b0823a7..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d +++ /dev/null @@ -1,266 +0,0 @@ -cmd_Release/obj.target/canvas/src/CanvasPattern.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d.raw -c -o Release/obj.target/canvas/src/CanvasPattern.o ../src/CanvasPattern.cc -Release/obj.target/canvas/src/CanvasPattern.o: ../src/CanvasPattern.cc \ - ../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h \ - ../src/CanvasPattern.h -../src/CanvasPattern.cc: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/Image.h: -../src/CanvasPattern.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d deleted file mode 100644 index 807f274..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d +++ /dev/null @@ -1,299 +0,0 @@ -cmd_Release/obj.target/canvas/src/CanvasRenderingContext2d.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d.raw -c -o Release/obj.target/canvas/src/CanvasRenderingContext2d.o ../src/CanvasRenderingContext2d.cc -Release/obj.target/canvas/src/CanvasRenderingContext2d.o: \ - ../src/CanvasRenderingContext2d.cc ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Point.h \ - ../src/Image.h ../src/ImageData.h ../src/PixelArray.h \ - ../src/CanvasRenderingContext2d.h ../src/color.h ../src/CanvasGradient.h \ - /usr/include/freetype2/ft2build.h \ - /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ - /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ - /usr/include/freetype2/config/ftconfig.h \ - /usr/include/freetype2/config/ftoption.h \ - /usr/include/freetype2/config/ftstdlib.h \ - /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ - /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ - /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ - ../src/CanvasPattern.h ../src/FontFace.h -../src/CanvasRenderingContext2d.cc: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/Point.h: -../src/Image.h: -../src/ImageData.h: -../src/PixelArray.h: -../src/CanvasRenderingContext2d.h: -../src/color.h: -../src/CanvasGradient.h: -/usr/include/freetype2/ft2build.h: -/usr/include/freetype2/config/ftheader.h: -/usr/include/cairo/cairo-ft.h: -/usr/include/cairo/cairo.h: -/usr/include/freetype2/freetype.h: -/usr/include/freetype2/config/ftconfig.h: -/usr/include/freetype2/config/ftoption.h: -/usr/include/freetype2/config/ftstdlib.h: -/usr/include/freetype2/fttypes.h: -/usr/include/freetype2/ftsystem.h: -/usr/include/freetype2/ftimage.h: -/usr/include/freetype2/fterrors.h: -/usr/include/freetype2/ftmoderr.h: -/usr/include/freetype2/fterrdef.h: -../src/CanvasPattern.h: -../src/FontFace.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d deleted file mode 100644 index b8c9275..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/FontFace.o.d +++ /dev/null @@ -1,288 +0,0 @@ -cmd_Release/obj.target/canvas/src/FontFace.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/FontFace.o.d.raw -c -o Release/obj.target/canvas/src/FontFace.o ../src/FontFace.cc -Release/obj.target/canvas/src/FontFace.o: ../src/FontFace.cc \ - ../src/FontFace.h ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h \ - /usr/include/freetype2/ft2build.h \ - /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ - /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ - /usr/include/freetype2/config/ftconfig.h \ - /usr/include/freetype2/config/ftoption.h \ - /usr/include/freetype2/config/ftstdlib.h \ - /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ - /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ - /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h -../src/FontFace.cc: -../src/FontFace.h: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -/usr/include/freetype2/ft2build.h: -/usr/include/freetype2/config/ftheader.h: -/usr/include/cairo/cairo-ft.h: -/usr/include/cairo/cairo.h: -/usr/include/freetype2/freetype.h: -/usr/include/freetype2/config/ftconfig.h: -/usr/include/freetype2/config/ftoption.h: -/usr/include/freetype2/config/ftstdlib.h: -/usr/include/freetype2/fttypes.h: -/usr/include/freetype2/ftsystem.h: -/usr/include/freetype2/ftimage.h: -/usr/include/freetype2/fterrors.h: -/usr/include/freetype2/ftmoderr.h: -/usr/include/freetype2/fterrdef.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d deleted file mode 100644 index 9b27358..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d +++ /dev/null @@ -1,264 +0,0 @@ -cmd_Release/obj.target/canvas/src/Image.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Image.o.d.raw -c -o Release/obj.target/canvas/src/Image.o ../src/Image.cc -Release/obj.target/canvas/src/Image.o: ../src/Image.cc ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h -../src/Image.cc: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/Image.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d deleted file mode 100644 index 6d4bc0f..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d +++ /dev/null @@ -1,266 +0,0 @@ -cmd_Release/obj.target/canvas/src/ImageData.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/ImageData.o.d.raw -c -o Release/obj.target/canvas/src/ImageData.o ../src/ImageData.cc -Release/obj.target/canvas/src/ImageData.o: ../src/ImageData.cc \ - ../src/ImageData.h ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/PixelArray.h -../src/ImageData.cc: -../src/ImageData.h: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/PixelArray.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d deleted file mode 100644 index c6e0713..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d +++ /dev/null @@ -1,265 +0,0 @@ -cmd_Release/obj.target/canvas/src/PixelArray.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/PixelArray.o.d.raw -c -o Release/obj.target/canvas/src/PixelArray.o ../src/PixelArray.cc -Release/obj.target/canvas/src/PixelArray.o: ../src/PixelArray.cc \ - ../src/PixelArray.h ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h -../src/PixelArray.cc: -../src/PixelArray.h: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d deleted file mode 100644 index 932f09d..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d +++ /dev/null @@ -1,4 +0,0 @@ -cmd_Release/obj.target/canvas/src/color.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/color.o.d.raw -c -o Release/obj.target/canvas/src/color.o ../src/color.cc -Release/obj.target/canvas/src/color.o: ../src/color.cc ../src/color.h -../src/color.cc: -../src/color.h: diff --git a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d b/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d deleted file mode 100644 index 3c6fca7..0000000 --- a/scripts/external/three/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d +++ /dev/null @@ -1,297 +0,0 @@ -cmd_Release/obj.target/canvas/src/init.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_PANGO' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/init.o.d.raw -c -o Release/obj.target/canvas/src/init.o ../src/init.cc -Release/obj.target/canvas/src/init.o: ../src/init.cc ../src/Canvas.h \ - /usr/include/nodejs/deps/v8/include/v8.h \ - /usr/include/nodejs/deps/v8/include/v8stdint.h \ - /usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \ - /usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \ - /usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node.h \ - /usr/include/nodejs/src/node_object_wrap.h \ - /usr/include/nodejs/src/node_version.h \ - /usr/include/pango-1.0/pango/pangocairo.h \ - /usr/include/pango-1.0/pango/pango.h \ - /usr/include/pango-1.0/pango/pango-attributes.h \ - /usr/include/pango-1.0/pango/pango-font.h \ - /usr/include/pango-1.0/pango/pango-coverage.h \ - /usr/include/glib-2.0/glib.h /usr/include/glib-2.0/glib/galloca.h \ - /usr/include/glib-2.0/glib/gtypes.h \ - /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h \ - /usr/include/glib-2.0/glib/gmacros.h \ - /usr/include/glib-2.0/glib/gversionmacros.h \ - /usr/include/glib-2.0/glib/garray.h \ - /usr/include/glib-2.0/glib/gasyncqueue.h \ - /usr/include/glib-2.0/glib/gthread.h \ - /usr/include/glib-2.0/glib/gatomic.h /usr/include/glib-2.0/glib/gerror.h \ - /usr/include/glib-2.0/glib/gquark.h \ - /usr/include/glib-2.0/glib/gbacktrace.h \ - /usr/include/glib-2.0/glib/gbase64.h \ - /usr/include/glib-2.0/glib/gbitlock.h \ - /usr/include/glib-2.0/glib/gbookmarkfile.h \ - /usr/include/glib-2.0/glib/gbytes.h \ - /usr/include/glib-2.0/glib/gcharset.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/gconvert.h \ - /usr/include/glib-2.0/glib/gdataset.h /usr/include/glib-2.0/glib/gdate.h \ - /usr/include/glib-2.0/glib/gdatetime.h \ - /usr/include/glib-2.0/glib/gtimezone.h /usr/include/glib-2.0/glib/gdir.h \ - /usr/include/glib-2.0/glib/genviron.h \ - /usr/include/glib-2.0/glib/gfileutils.h \ - /usr/include/glib-2.0/glib/ggettext.h /usr/include/glib-2.0/glib/ghash.h \ - /usr/include/glib-2.0/glib/glist.h /usr/include/glib-2.0/glib/gmem.h \ - /usr/include/glib-2.0/glib/gnode.h /usr/include/glib-2.0/glib/ghmac.h \ - /usr/include/glib-2.0/glib/gchecksum.h \ - /usr/include/glib-2.0/glib/ghook.h \ - /usr/include/glib-2.0/glib/ghostutils.h \ - /usr/include/glib-2.0/glib/giochannel.h \ - /usr/include/glib-2.0/glib/gmain.h /usr/include/glib-2.0/glib/gpoll.h \ - /usr/include/glib-2.0/glib/gslist.h /usr/include/glib-2.0/glib/gstring.h \ - /usr/include/glib-2.0/glib/gunicode.h \ - /usr/include/glib-2.0/glib/gutils.h \ - /usr/include/glib-2.0/glib/gkeyfile.h \ - /usr/include/glib-2.0/glib/gmappedfile.h \ - /usr/include/glib-2.0/glib/gmarkup.h \ - /usr/include/glib-2.0/glib/gmessages.h \ - /usr/include/glib-2.0/glib/goption.h \ - /usr/include/glib-2.0/glib/gpattern.h \ - /usr/include/glib-2.0/glib/gprimes.h /usr/include/glib-2.0/glib/gqsort.h \ - /usr/include/glib-2.0/glib/gqueue.h /usr/include/glib-2.0/glib/grand.h \ - /usr/include/glib-2.0/glib/gregex.h \ - /usr/include/glib-2.0/glib/gscanner.h \ - /usr/include/glib-2.0/glib/gsequence.h \ - /usr/include/glib-2.0/glib/gshell.h /usr/include/glib-2.0/glib/gslice.h \ - /usr/include/glib-2.0/glib/gspawn.h \ - /usr/include/glib-2.0/glib/gstrfuncs.h \ - /usr/include/glib-2.0/glib/gstringchunk.h \ - /usr/include/glib-2.0/glib/gtestutils.h \ - /usr/include/glib-2.0/glib/gthreadpool.h \ - /usr/include/glib-2.0/glib/gtimer.h \ - /usr/include/glib-2.0/glib/gtrashstack.h \ - /usr/include/glib-2.0/glib/gtree.h \ - /usr/include/glib-2.0/glib/gurifuncs.h \ - /usr/include/glib-2.0/glib/gvarianttype.h \ - /usr/include/glib-2.0/glib/gvariant.h \ - /usr/include/glib-2.0/glib/gversion.h \ - /usr/include/glib-2.0/glib/deprecated/gallocator.h \ - /usr/include/glib-2.0/glib/deprecated/gcache.h \ - /usr/include/glib-2.0/glib/deprecated/gcompletion.h \ - /usr/include/glib-2.0/glib/deprecated/gmain.h \ - /usr/include/glib-2.0/glib/deprecated/grel.h \ - /usr/include/glib-2.0/glib/deprecated/gthread.h \ - /usr/include/pango-1.0/pango/pango-types.h \ - /usr/include/glib-2.0/glib-object.h \ - /usr/include/glib-2.0/gobject/gbinding.h \ - /usr/include/glib-2.0/gobject/gobject.h \ - /usr/include/glib-2.0/gobject/gtype.h \ - /usr/include/glib-2.0/gobject/gvalue.h \ - /usr/include/glib-2.0/gobject/gparam.h \ - /usr/include/glib-2.0/gobject/gclosure.h \ - /usr/include/glib-2.0/gobject/gsignal.h \ - /usr/include/glib-2.0/gobject/gmarshal.h \ - /usr/include/glib-2.0/gobject/gboxed.h \ - /usr/include/glib-2.0/gobject/glib-types.h \ - /usr/include/glib-2.0/gobject/genums.h \ - /usr/include/glib-2.0/gobject/gparamspecs.h \ - /usr/include/glib-2.0/gobject/gsourceclosure.h \ - /usr/include/glib-2.0/gobject/gtypemodule.h \ - /usr/include/glib-2.0/gobject/gtypeplugin.h \ - /usr/include/glib-2.0/gobject/gvaluearray.h \ - /usr/include/glib-2.0/gobject/gvaluetypes.h \ - /usr/include/pango-1.0/pango/pango-gravity.h \ - /usr/include/pango-1.0/pango/pango-matrix.h \ - /usr/include/pango-1.0/pango/pango-script.h \ - /usr/include/pango-1.0/pango/pango-language.h \ - /usr/include/pango-1.0/pango/pango-bidi-type.h \ - /usr/include/pango-1.0/pango/pango-break.h \ - /usr/include/pango-1.0/pango/pango-item.h \ - /usr/include/pango-1.0/pango/pango-context.h \ - /usr/include/pango-1.0/pango/pango-fontmap.h \ - /usr/include/pango-1.0/pango/pango-fontset.h \ - /usr/include/pango-1.0/pango/pango-engine.h \ - /usr/include/pango-1.0/pango/pango-glyph.h \ - /usr/include/pango-1.0/pango/pango-enum-types.h \ - /usr/include/pango-1.0/pango/pango-features.h \ - /usr/include/pango-1.0/pango/pango-glyph-item.h \ - /usr/include/pango-1.0/pango/pango-layout.h \ - /usr/include/pango-1.0/pango/pango-tabs.h \ - /usr/include/pango-1.0/pango/pango-renderer.h \ - /usr/include/pango-1.0/pango/pango-utils.h /usr/include/cairo/cairo.h \ - /usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \ - /usr/include/cairo/cairo-deprecated.h ../node_modules/nan/nan.h \ - /usr/include/nodejs/src/node_buffer.h ../node_modules/nan/nan_new.h \ - ../node_modules/nan/nan_implementation_pre_12_inl.h ../src/Image.h \ - ../src/ImageData.h ../src/PixelArray.h ../src/CanvasGradient.h \ - ../src/CanvasPattern.h ../src/CanvasRenderingContext2d.h ../src/color.h \ - /usr/include/freetype2/ft2build.h \ - /usr/include/freetype2/config/ftheader.h /usr/include/cairo/cairo-ft.h \ - /usr/include/cairo/cairo.h /usr/include/freetype2/freetype.h \ - /usr/include/freetype2/config/ftconfig.h \ - /usr/include/freetype2/config/ftoption.h \ - /usr/include/freetype2/config/ftstdlib.h \ - /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \ - /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \ - /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \ - ../src/FontFace.h -../src/init.cc: -../src/Canvas.h: -/usr/include/nodejs/deps/v8/include/v8.h: -/usr/include/nodejs/deps/v8/include/v8stdint.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/deps/uv/include/uv.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h: -/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h: -/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node.h: -/usr/include/nodejs/src/node_object_wrap.h: -/usr/include/nodejs/src/node_version.h: -/usr/include/pango-1.0/pango/pangocairo.h: -/usr/include/pango-1.0/pango/pango.h: -/usr/include/pango-1.0/pango/pango-attributes.h: -/usr/include/pango-1.0/pango/pango-font.h: -/usr/include/pango-1.0/pango/pango-coverage.h: -/usr/include/glib-2.0/glib.h: -/usr/include/glib-2.0/glib/galloca.h: -/usr/include/glib-2.0/glib/gtypes.h: -/usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h: -/usr/include/glib-2.0/glib/gmacros.h: -/usr/include/glib-2.0/glib/gversionmacros.h: -/usr/include/glib-2.0/glib/garray.h: -/usr/include/glib-2.0/glib/gasyncqueue.h: -/usr/include/glib-2.0/glib/gthread.h: -/usr/include/glib-2.0/glib/gatomic.h: -/usr/include/glib-2.0/glib/gerror.h: -/usr/include/glib-2.0/glib/gquark.h: -/usr/include/glib-2.0/glib/gbacktrace.h: -/usr/include/glib-2.0/glib/gbase64.h: -/usr/include/glib-2.0/glib/gbitlock.h: -/usr/include/glib-2.0/glib/gbookmarkfile.h: -/usr/include/glib-2.0/glib/gbytes.h: -/usr/include/glib-2.0/glib/gcharset.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/gconvert.h: -/usr/include/glib-2.0/glib/gdataset.h: -/usr/include/glib-2.0/glib/gdate.h: -/usr/include/glib-2.0/glib/gdatetime.h: -/usr/include/glib-2.0/glib/gtimezone.h: -/usr/include/glib-2.0/glib/gdir.h: -/usr/include/glib-2.0/glib/genviron.h: -/usr/include/glib-2.0/glib/gfileutils.h: -/usr/include/glib-2.0/glib/ggettext.h: -/usr/include/glib-2.0/glib/ghash.h: -/usr/include/glib-2.0/glib/glist.h: -/usr/include/glib-2.0/glib/gmem.h: -/usr/include/glib-2.0/glib/gnode.h: -/usr/include/glib-2.0/glib/ghmac.h: -/usr/include/glib-2.0/glib/gchecksum.h: -/usr/include/glib-2.0/glib/ghook.h: -/usr/include/glib-2.0/glib/ghostutils.h: -/usr/include/glib-2.0/glib/giochannel.h: -/usr/include/glib-2.0/glib/gmain.h: -/usr/include/glib-2.0/glib/gpoll.h: -/usr/include/glib-2.0/glib/gslist.h: -/usr/include/glib-2.0/glib/gstring.h: -/usr/include/glib-2.0/glib/gunicode.h: -/usr/include/glib-2.0/glib/gutils.h: -/usr/include/glib-2.0/glib/gkeyfile.h: -/usr/include/glib-2.0/glib/gmappedfile.h: -/usr/include/glib-2.0/glib/gmarkup.h: -/usr/include/glib-2.0/glib/gmessages.h: -/usr/include/glib-2.0/glib/goption.h: -/usr/include/glib-2.0/glib/gpattern.h: -/usr/include/glib-2.0/glib/gprimes.h: -/usr/include/glib-2.0/glib/gqsort.h: -/usr/include/glib-2.0/glib/gqueue.h: -/usr/include/glib-2.0/glib/grand.h: -/usr/include/glib-2.0/glib/gregex.h: -/usr/include/glib-2.0/glib/gscanner.h: -/usr/include/glib-2.0/glib/gsequence.h: -/usr/include/glib-2.0/glib/gshell.h: -/usr/include/glib-2.0/glib/gslice.h: -/usr/include/glib-2.0/glib/gspawn.h: -/usr/include/glib-2.0/glib/gstrfuncs.h: -/usr/include/glib-2.0/glib/gstringchunk.h: -/usr/include/glib-2.0/glib/gtestutils.h: -/usr/include/glib-2.0/glib/gthreadpool.h: -/usr/include/glib-2.0/glib/gtimer.h: -/usr/include/glib-2.0/glib/gtrashstack.h: -/usr/include/glib-2.0/glib/gtree.h: -/usr/include/glib-2.0/glib/gurifuncs.h: -/usr/include/glib-2.0/glib/gvarianttype.h: -/usr/include/glib-2.0/glib/gvariant.h: -/usr/include/glib-2.0/glib/gversion.h: -/usr/include/glib-2.0/glib/deprecated/gallocator.h: -/usr/include/glib-2.0/glib/deprecated/gcache.h: -/usr/include/glib-2.0/glib/deprecated/gcompletion.h: -/usr/include/glib-2.0/glib/deprecated/gmain.h: -/usr/include/glib-2.0/glib/deprecated/grel.h: -/usr/include/glib-2.0/glib/deprecated/gthread.h: -/usr/include/pango-1.0/pango/pango-types.h: -/usr/include/glib-2.0/glib-object.h: -/usr/include/glib-2.0/gobject/gbinding.h: -/usr/include/glib-2.0/gobject/gobject.h: -/usr/include/glib-2.0/gobject/gtype.h: -/usr/include/glib-2.0/gobject/gvalue.h: -/usr/include/glib-2.0/gobject/gparam.h: -/usr/include/glib-2.0/gobject/gclosure.h: -/usr/include/glib-2.0/gobject/gsignal.h: -/usr/include/glib-2.0/gobject/gmarshal.h: -/usr/include/glib-2.0/gobject/gboxed.h: -/usr/include/glib-2.0/gobject/glib-types.h: -/usr/include/glib-2.0/gobject/genums.h: -/usr/include/glib-2.0/gobject/gparamspecs.h: -/usr/include/glib-2.0/gobject/gsourceclosure.h: -/usr/include/glib-2.0/gobject/gtypemodule.h: -/usr/include/glib-2.0/gobject/gtypeplugin.h: -/usr/include/glib-2.0/gobject/gvaluearray.h: -/usr/include/glib-2.0/gobject/gvaluetypes.h: -/usr/include/pango-1.0/pango/pango-gravity.h: -/usr/include/pango-1.0/pango/pango-matrix.h: -/usr/include/pango-1.0/pango/pango-script.h: -/usr/include/pango-1.0/pango/pango-language.h: -/usr/include/pango-1.0/pango/pango-bidi-type.h: -/usr/include/pango-1.0/pango/pango-break.h: -/usr/include/pango-1.0/pango/pango-item.h: -/usr/include/pango-1.0/pango/pango-context.h: -/usr/include/pango-1.0/pango/pango-fontmap.h: -/usr/include/pango-1.0/pango/pango-fontset.h: -/usr/include/pango-1.0/pango/pango-engine.h: -/usr/include/pango-1.0/pango/pango-glyph.h: -/usr/include/pango-1.0/pango/pango-enum-types.h: -/usr/include/pango-1.0/pango/pango-features.h: -/usr/include/pango-1.0/pango/pango-glyph-item.h: -/usr/include/pango-1.0/pango/pango-layout.h: -/usr/include/pango-1.0/pango/pango-tabs.h: -/usr/include/pango-1.0/pango/pango-renderer.h: -/usr/include/pango-1.0/pango/pango-utils.h: -/usr/include/cairo/cairo.h: -/usr/include/cairo/cairo-version.h: -/usr/include/cairo/cairo-features.h: -/usr/include/cairo/cairo-deprecated.h: -../node_modules/nan/nan.h: -/usr/include/nodejs/src/node_buffer.h: -../node_modules/nan/nan_new.h: -../node_modules/nan/nan_implementation_pre_12_inl.h: -../src/Image.h: -../src/ImageData.h: -../src/PixelArray.h: -../src/CanvasGradient.h: -../src/CanvasPattern.h: -../src/CanvasRenderingContext2d.h: -../src/color.h: -/usr/include/freetype2/ft2build.h: -/usr/include/freetype2/config/ftheader.h: -/usr/include/cairo/cairo-ft.h: -/usr/include/cairo/cairo.h: -/usr/include/freetype2/freetype.h: -/usr/include/freetype2/config/ftconfig.h: -/usr/include/freetype2/config/ftoption.h: -/usr/include/freetype2/config/ftstdlib.h: -/usr/include/freetype2/fttypes.h: -/usr/include/freetype2/ftsystem.h: -/usr/include/freetype2/ftimage.h: -/usr/include/freetype2/fterrors.h: -/usr/include/freetype2/ftmoderr.h: -/usr/include/freetype2/fterrdef.h: -../src/FontFace.h: diff --git a/scripts/external/three/canvas/build/Release/canvas-postbuild.node b/scripts/external/three/canvas/build/Release/canvas-postbuild.node deleted file mode 100755 index d826d22576e464358a537f4e48a94eaaa22eb693..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7470 zcmeHMU2IfE6rOflEG@JJL<^F1qku)jwIFISskYRX3$_qT8ziy0x!t|}G5b^Y-o@6C zKvIkl(xjSb#0Ot^@xce4$!~c<11O zQ=e5m%1yBT9(s_+uaBW|K{PDsT;N59DH%z&li7HStDfu z3Q>*kqvJ~7OFUe_wxtNZt_W@y!8!ggJvyZcs23|mbA32RbzI`BM2m)V-d7fg|FE*x z>$y+bSBrUl@LJYzJejau&rW%kC9KiJs3)u;V#3XMc6NhYf^H|dL z2GgUlsF6rU9SWQX^91AjL)DKKH6MVFDZEML3pnIUbzxZ_kMZnOqw?hd&SMQUAHah{ z<$3@QrgR~I2j@|PiigK*u-$L~589iP*Q(5um7O(VVZJu&Rn9+7j^^aKsFB6bw5>5*LaleuRc#@;xd2v>0*--l`>GuKq&*I z43siZ%0MXt|Cj;nGqJCPajhy$DZWf`d`~P_GWOeRl#G4s14_pJbgh!HpXKigCg}h8 zE0bh-hIevA*mKsa%_{be*Ok87Hxs87uTi`~@$4Q~?LV<6ZB}~zCS&6LD%1Tw6XR+V z417jagg9rF9erj3BK?Ip>T zehgWk{PHsB!%G;EWIXO9JUtcvN#^k!{I)4}-hj$gnjs2stcgY)+{6UGn5 zn~w@Qq4CcE;E#C#PNxNuxLvk^KgMSpVO%%-F|WW+lP*ZAx-4W;33W4wc>zAlAdwzF z+UIkJpg-mrIOZk$bL@KjFA>HuVI9Ca1djEEOeE>~-%n`Je@+>IqkZL0XB9qy4{H9| z1xhVcSKz4m0Upu(v2KE6J%PO*e?s}={Vk|=!F7A&5A}^xf!B1rAFR_j&(iI6`55`u z1^ls&x2Qh~-Cmcc$(Qqw_S@9CM%!KbzeT?M?%|Jh4(EoLkH`bs$NPIvYaiz%m$*|z zO+L&1!XNxJX@ct4l80&K`9uio0bMXp+^)wf+%&wQY_>$~?BNxvqfww>R*;Uhs?#73(WUiyjEZy=i+sAo*xcEvK*qxf_WEI zh6If+%%^}NL?^(QCjpq^T$Oi@%=(bPu5Qtq$3ca-!AE8}#QWJYS`qd5c^_NOC+=E4 z4TU#rc)P;&{j>jnvlu7F^l3y=^i%80Iy)>QtM(AE(cSo<)y=z||T}Uk6KUiMeitr7D zD{%1;fGjJTw1#8JK|5wey=2O@?DV*xE$&#%@tmmfkPOc;O{=~nK;j0+*I{zYOF-f_);023+rK4_M__n3s J%}nlX(BIB@EUW+k diff --git a/scripts/external/three/canvas/build/Release/canvas.node b/scripts/external/three/canvas/build/Release/canvas.node deleted file mode 100755 index 3f16b28e2a8dcab9530305f576986ef5d1928cc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208599 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 #FJ7hR8XJl{oP&th=O!3UHqR#(I)mB`}axR}RN_ IMp&l*AM%-9)Bpeg diff --git a/scripts/external/three/canvas/build/Release/linker.lock b/scripts/external/three/canvas/build/Release/linker.lock deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node b/scripts/external/three/canvas/build/Release/obj.target/canvas-postbuild.node deleted file mode 100755 index d826d22576e464358a537f4e48a94eaaa22eb693..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7470 zcmeHMU2IfE6rOflEG@JJL<^F1qku)jwIFISskYRX3$_qT8ziy0x!t|}G5b^Y-o@6C zKvIkl(xjSb#0Ot^@xce4$!~c<11O zQ=e5m%1yBT9(s_+uaBW|K{PDsT;N59DH%z&li7HStDfu z3Q>*kqvJ~7OFUe_wxtNZt_W@y!8!ggJvyZcs23|mbA32RbzI`BM2m)V-d7fg|FE*x z>$y+bSBrUl@LJYzJejau&rW%kC9KiJs3)u;V#3XMc6NhYf^H|dL z2GgUlsF6rU9SWQX^91AjL)DKKH6MVFDZEML3pnIUbzxZ_kMZnOqw?hd&SMQUAHah{ z<$3@QrgR~I2j@|PiigK*u-$L~589iP*Q(5um7O(VVZJu&Rn9+7j^^aKsFB6bw5>5*LaleuRc#@;xd2v>0*--l`>GuKq&*I z43siZ%0MXt|Cj;nGqJCPajhy$DZWf`d`~P_GWOeRl#G4s14_pJbgh!HpXKigCg}h8 zE0bh-hIevA*mKsa%_{be*Ok87Hxs87uTi`~@$4Q~?LV<6ZB}~zCS&6LD%1Tw6XR+V z417jagg9rF9erj3BK?Ip>T zehgWk{PHsB!%G;EWIXO9JUtcvN#^k!{I)4}-hj$gnjs2stcgY)+{6UGn5 zn~w@Qq4CcE;E#C#PNxNuxLvk^KgMSpVO%%-F|WW+lP*ZAx-4W;33W4wc>zAlAdwzF z+UIkJpg-mrIOZk$bL@KjFA>HuVI9Ca1djEEOeE>~-%n`Je@+>IqkZL0XB9qy4{H9| z1xhVcSKz4m0Upu(v2KE6J%PO*e?s}={Vk|=!F7A&5A}^xf!B1rAFR_j&(iI6`55`u z1^ls&x2Qh~-Cmcc$(Qqw_S@9CM%!KbzeT?M?%|Jh4(EoLkH`bs$NPIvYaiz%m$*|z zO+L&1!XNxJX@ct4l80&K`9uio0bMXp+^)wf+%&wQY_>$~?BNxvqfww>R*;Uhs?#73(WUiyjEZy=i+sAo*xcEvK*qxf_WEI zh6If+%%^}NL?^(QCjpq^T$Oi@%=(bPu5Qtq$3ca-!AE8}#QWJYS`qd5c^_NOC+=E4 z4TU#rc)P;&{j>jnvlu7F^l3y=^i%80Iy)>QtM(AE(cSo<)y=z||T}Uk6KUiMeitr7D zD{%1;fGjJTw1#8JK|5wey=2O@?DV*xE$&#%@tmmfkPOc;O{=~nK;j0+*I{zYOF-f_);023+rK4_M__n3s J%}nlX(BIB@EUW+k diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas.node b/scripts/external/three/canvas/build/Release/obj.target/canvas.node deleted file mode 100755 index 3f16b28e2a8dcab9530305f576986ef5d1928cc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208599 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 #FJ7hR8XJl{oP&th=O!3UHqR#(I)mB`}axR}RN_ IMp&l*AM%-9)Bpeg diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Canvas.o deleted file mode 100644 index 4724529e8e1ba88a177354b2c32b40291a0c3807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52960 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 J6m~4h{~s4fnT7xW diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o deleted file mode 100644 index 9537a84e66e034db6757f5e77e44cef75302178c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18256 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 D_6yZQ diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o deleted file mode 100644 index f0eecca94a6bc5ab68311ba0d86e4b2d94052b0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15968 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 GzyAY>hUSL= diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o deleted file mode 100644 index 0212cebe4b9123bcac452b2ee81c5f846fb18ea2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135424 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 Neup?bIwZk={ucu&Q!oGk diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/FontFace.o deleted file mode 100644 index e47afbcaad80c18045bb39290207be805b7c025d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15536 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 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/Image.o deleted file mode 100644 index 8ec55dd7a533ebcf11f58a5b751901e2a5f5aa64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40216 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 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/ImageData.o deleted file mode 100644 index b5952e2fd0a24fbeb1e5c94ebfb60e14cf93b253..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17832 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 diff --git a/scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o b/scripts/external/three/canvas/build/Release/obj.target/canvas/src/PixelArray.o deleted file mode 100644 index 54a735d2e9a5eb869ffd7015cb1be18a864fea77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17832 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 upS?nq{DoM)N%vq!55?(A}GuVl&{kl{|Q8Iq~ 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 Y8ouA;(< - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var canvas = require('./bindings') - , Canvas = canvas.Canvas - , Image = canvas.Image - , cairoVersion = canvas.cairoVersion - , PixelArray = canvas.CanvasPixelArray - , Context2d = require('./context2d') - , PNGStream = require('./pngstream') - , JPEGStream = require('./jpegstream') - , FontFace = canvas.FontFace - , fs = require('fs') - , package = require("../package.json"); - -/** - * Export `Canvas` as the module. - */ - -var Canvas = exports = module.exports = Canvas; - -/** - * Library version. - */ - -exports.version = package.version; - -/** - * Cairo version. - */ - -exports.cairoVersion = cairoVersion; - -/** - * jpeglib version. - */ - -if (canvas.jpegVersion) { - exports.jpegVersion = canvas.jpegVersion; -} - -/** - * gif_lib version. - */ - -if (canvas.gifVersion) { - exports.gifVersion = canvas.gifVersion.replace(/[^.\d]/g, ''); -} - -/** - * Expose constructors. - */ - -exports.Context2d = Context2d; -exports.PNGStream = PNGStream; -exports.JPEGStream = JPEGStream; -exports.PixelArray = PixelArray; -exports.Image = Image; - -if (FontFace) { - function Font(name, path, idx) { - this.name = name; - this._faces = {}; - - this.addFace(path, 'normal', 'normal', idx); - }; - - Font.prototype.addFace = function(path, weight, style, idx) { - style = style || 'normal'; - weight = weight || 'normal'; - - var face = new FontFace(path, idx || 0); - this._faces[weight + '-' + style] = face; - }; - - Font.prototype.getFace = function(weightStyle) { - return this._faces[weightStyle] || this._faces['normal-normal']; - }; - - exports.Font = Font; -} - -/** - * Context2d implementation. - */ - -require('./context2d'); - -/** - * Image implementation. - */ - -require('./image'); - -/** - * PixelArray implementation. - */ - -require('./pixelarray'); - -/** - * Inspect canvas. - * - * @return {String} - * @api public - */ - -Canvas.prototype.inspect = function(){ - return '[Canvas ' + this.width + 'x' + this.height + ']'; -}; - -/** - * Get a context object. - * - * @param {String} contextId - * @return {Context2d} - * @api public - */ - -Canvas.prototype.getContext = function(contextId){ - if ('2d' == contextId) { - var ctx = this._context2d || (this._context2d = new Context2d(this)); - this.context = ctx; - ctx.canvas = this; - return ctx; - } -}; - -/** - * Create a `PNGStream` for `this` canvas. - * - * @return {PNGStream} - * @api public - */ - -Canvas.prototype.pngStream = -Canvas.prototype.createPNGStream = function(){ - return new PNGStream(this); -}; - -/** - * Create a synchronous `PNGStream` for `this` canvas. - * - * @return {PNGStream} - * @api public - */ - -Canvas.prototype.syncPNGStream = -Canvas.prototype.createSyncPNGStream = function(){ - return new PNGStream(this, true); -}; - -/** - * Create a `JPEGStream` for `this` canvas. - * - * @param {Object} options - * @return {JPEGStream} - * @api public - */ - -Canvas.prototype.jpegStream = -Canvas.prototype.createJPEGStream = function(options){ - return this.createSyncJPEGStream(options); -}; - -/** - * Create a synchronous `JPEGStream` for `this` canvas. - * - * @param {Object} options - * @return {JPEGStream} - * @api public - */ - -Canvas.prototype.syncJPEGStream = -Canvas.prototype.createSyncJPEGStream = function(options){ - options = options || {}; - return new JPEGStream(this, { - bufsize: options.bufsize || 4096 - , quality: options.quality || 75 - , progressive: options.progressive || false - }); -}; - -/** - * Return a data url. Pass a function for async support. - * - * @param {String|Function} type - * @param {Function} fn - * @return {String} - * @api public - */ - -Canvas.prototype.toDataURL = function(type, fn){ - // Default to png - type = type || 'image/png'; - - // Allow callback as first arg - if ('function' == typeof type) fn = type, type = 'image/png'; - - // Throw on non-png - if ('image/png' != type) throw new Error('currently only image/png is supported'); - - var prefix = 'data:' + type + ';base64,'; - - if (fn) { - this.toBuffer(function(err, buf){ - if (err) return fn(err); - var str = 'data:' + type - fn(null, prefix + buf.toString('base64')); - }); - } else { - return prefix + this.toBuffer().toString('base64'); - } -}; diff --git a/scripts/external/three/canvas/lib/context2d.js b/scripts/external/three/canvas/lib/context2d.js deleted file mode 100644 index 7dfbea0..0000000 --- a/scripts/external/three/canvas/lib/context2d.js +++ /dev/null @@ -1,386 +0,0 @@ -/*! - * Canvas - Context2d - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var canvas = require('./bindings') - , Context2d = canvas.CanvasRenderingContext2d - , CanvasGradient = canvas.CanvasGradient - , CanvasPattern = canvas.CanvasPattern - , ImageData = canvas.ImageData - , PixelArray = canvas.CanvasPixelArray; - -/** - * Export `Context2d` as the module. - */ - -var Context2d = exports = module.exports = Context2d; - -/** - * Cache color string RGBA values. - */ - -var cache = {}; - -/** - * Text baselines. - */ - -var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging']; - -/** - * Font RegExp helpers. - */ - -var weights = 'normal|bold|bolder|lighter|[1-9]00' - , styles = 'normal|italic|oblique' - , units = 'px|pt|pc|in|cm|mm|%' - , string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+'; - -/** - * Font parser RegExp; - */ - -var fontre = new RegExp('^ *' - + '(?:(' + weights + ') *)?' - + '(?:(' + styles + ') *)?' - + '([\\d\\.]+)(' + units + ') *' - + '((?:' + string + ')( *, *(?:' + string + '))*)' - ); - -/** - * Parse font `str`. - * - * @param {String} str - * @return {Object} - * @api private - */ - -var parseFont = exports.parseFont = function(str){ - var font = {} - , captures = fontre.exec(str); - - // Invalid - if (!captures) return; - - // Cached - if (cache[str]) return cache[str]; - - // Populate font object - font.weight = captures[1] || 'normal'; - font.style = captures[2] || 'normal'; - font.size = parseFloat(captures[3]); - font.unit = captures[4]; - font.family = captures[5].replace(/["']/g, '').split(',')[0]; - - // TODO: dpi - // TODO: remaining unit conversion - switch (font.unit) { - case 'pt': - font.size /= .75; - break; - case 'in': - font.size *= 96; - break; - case 'mm': - font.size *= 96.0 / 25.4; - break; - case 'cm': - font.size *= 96.0 / 2.54; - break; - } - - return cache[str] = font; -}; - -/** - * Enable or disable image smoothing. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('imageSmoothingEnabled', function(val){ - this._imageSmoothing = !! val; - this.patternQuality = val ? 'best' : 'fast'; -}); - -/** - * Get image smoothing value. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('imageSmoothingEnabled', function(val){ - return !! this._imageSmoothing; -}); - -/** - * Create a pattern from `Image` or `Canvas`. - * - * @param {Image|Canvas} image - * @param {String} repetition - * @return {CanvasPattern} - * @api public - */ - -Context2d.prototype.createPattern = function(image, repetition){ - // TODO Use repetition (currently always 'repeat') - return new CanvasPattern(image); -}; - -/** - * Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`. - * - * @param {Number} x0 - * @param {Number} y0 - * @param {Number} x1 - * @param {Number} y1 - * @return {CanvasGradient} - * @api public - */ - -Context2d.prototype.createLinearGradient = function(x0, y0, x1, y1){ - return new CanvasGradient(x0, y0, x1, y1); -}; - -/** - * Create a radial gradient at the given point `(x0, y0)` and `(x1, y1)` - * and radius `r0` and `r1`. - * - * @param {Number} x0 - * @param {Number} y0 - * @param {Number} r0 - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} r1 - * @return {CanvasGradient} - * @api public - */ - -Context2d.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){ - return new CanvasGradient(x0, y0, r0, x1, y1, r1); -}; - -/** - * Reset transform matrix to identity, then apply the given args. - * - * @param {...} - * @api public - */ - -Context2d.prototype.setTransform = function(){ - this.resetTransform(); - this.transform.apply(this, arguments); -}; - -/** - * Set the fill style with the given css color string. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('fillStyle', function(val){ - if (!val) return; - if ('CanvasGradient' == val.constructor.name - || 'CanvasPattern' == val.constructor.name) { - this.lastFillStyle = val; - this._setFillPattern(val); - } else if ('string' == typeof val) { - this._setFillColor(val); - } -}); - -/** - * Get previous fill style. - * - * @return {CanvasGradient|String} - * @api public - */ - -Context2d.prototype.__defineGetter__('fillStyle', function(){ - return this.lastFillStyle || this.fillColor; -}); - -/** - * Set the stroke style with the given css color string. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('strokeStyle', function(val){ - if (!val) return; - if ('CanvasGradient' == val.constructor.name - || 'CanvasPattern' == val.constructor.name) { - this.lastStrokeStyle = val; - this._setStrokePattern(val); - } else if ('string' == typeof val) { - this._setStrokeColor(val); - } -}); - -/** - * Get previous stroke style. - * - * @return {CanvasGradient|String} - * @api public - */ - -Context2d.prototype.__defineGetter__('strokeStyle', function(){ - return this.lastStrokeStyle || this.strokeColor; -}); - -/** - * Register `font` for usage. - * - * @param {Font} font - * @api public - */ - -Context2d.prototype.addFont = function(font) { - this._fonts = this._fonts || {}; - if (this._fonts[font.name]) return; - this._fonts[font.name] = font; -}; - -/** - * Set font. - * - * @see exports.parseFont() - * @api public - */ - -Context2d.prototype.__defineSetter__('font', function(val){ - if (!val) return; - if ('string' == typeof val) { - var font; - if (font = parseFont(val)) { - this.lastFontString = val; - - var fonts = this._fonts; - if (fonts && fonts[font.family]) { - var fontObj = fonts[font.family]; - var type = font.weight + '-' + font.style; - - var fontFace = fontObj.getFace(type); - this._setFontFace(fontFace, font.size); - } else { - this._setFont( - font.weight - , font.style - , font.size - , font.unit - , font.family); - } - } - } -}); - -/** - * Get the current font. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('font', function(){ - return this.lastFontString || '10px sans-serif'; -}); - -/** - * Set text baseline. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('textBaseline', function(val){ - if (!val) return; - var n = baselines.indexOf(val); - if (~n) { - this.lastBaseline = val; - this._setTextBaseline(n); - } -}); - -/** - * Get the current baseline setting. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('textBaseline', function(){ - return this.lastBaseline || 'alphabetic'; -}); - -/** - * Set text alignment. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('textAlign', function(val){ - switch (val) { - case 'center': - this._setTextAlignment(0); - this.lastTextAlignment = val; - break; - case 'left': - case 'start': - this._setTextAlignment(-1); - this.lastTextAlignment = val; - break; - case 'right': - case 'end': - this._setTextAlignment(1); - this.lastTextAlignment = val; - break; - } -}); - -/** - * Get the current font. - * - * @see exports.parseFont() - * @api public - */ - -Context2d.prototype.__defineGetter__('textAlign', function(){ - return this.lastTextAlignment || 'start'; -}); - -/** - * Get `ImageData` with the given rect. - * - * @param {Number} x - * @param {Number} y - * @param {Number} width - * @param {Number} height - * @return {ImageData} - * @api public - */ - -Context2d.prototype.getImageData = function(x, y, width, height){ - var arr = new PixelArray(this.canvas, x, y, width, height); - return new ImageData(arr); -}; - -/** - * Create `ImageData` with the given dimensions or - * `ImageData` instance for dimensions. - * - * @param {Number|ImageData} width - * @param {Number} height - * @return {ImageData} - * @api public - */ - -Context2d.prototype.createImageData = function(width, height){ - if ('ImageData' == width.constructor.name) { - height = width.height; - width = width.width; - } - return new ImageData(new PixelArray(width, height)); -}; diff --git a/scripts/external/three/canvas/lib/image.js b/scripts/external/three/canvas/lib/image.js deleted file mode 100644 index 558472b..0000000 --- a/scripts/external/three/canvas/lib/image.js +++ /dev/null @@ -1,60 +0,0 @@ - -/*! - * Canvas - Image - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var Canvas = require('./bindings') - , Image = Canvas.Image; - -/** - * Src setter. - * - * - convert data uri to `Buffer` - * - * @param {String|Buffer} val filename, buffer, data uri - * @api public - */ - -Image.prototype.__defineSetter__('src', function(val){ - if ('string' == typeof val && 0 == val.indexOf('data:')) { - val = val.slice(val.indexOf(',') + 1); - this.source = new Buffer(val, 'base64'); - } else { - this.source = val; - } -}); - -/** - * Src getter. - * - * TODO: return buffer - * - * @api public - */ - -Image.prototype.__defineGetter__('src', function(){ - return this.source; -}); - -/** - * Inspect image. - * - * TODO: indicate that the .src was a buffer, data uri etc - * - * @return {String} - * @api public - */ - -Image.prototype.inspect = function(){ - return '[Image' - + (this.complete ? ':' + this.width + 'x' + this.height : '') - + (this.src ? ' ' + this.src : '') - + (this.complete ? ' complete' : '') - + ']'; -}; diff --git a/scripts/external/three/canvas/lib/jpegstream.js b/scripts/external/three/canvas/lib/jpegstream.js deleted file mode 100644 index 1db8670..0000000 --- a/scripts/external/three/canvas/lib/jpegstream.js +++ /dev/null @@ -1,61 +0,0 @@ - -/*! - * Canvas - JPEGStream - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var Stream = require('stream').Stream; - -/** - * Initialize a `JPEGStream` with the given `canvas`. - * - * "data" events are emitted with `Buffer` chunks, once complete the - * "end" event is emitted. The following example will stream to a file - * named "./my.jpeg". - * - * var out = fs.createWriteStream(__dirname + '/my.jpeg') - * , stream = canvas.createJPEGStream(); - * - * stream.pipe(out); - * - * @param {Canvas} canvas - * @param {Boolean} sync - * @api public - */ - -var JPEGStream = module.exports = function JPEGStream(canvas, options, sync) { - var self = this - , method = sync - ? 'streamJPEGSync' - : 'streamJPEG'; - this.options = options; - this.sync = sync; - this.canvas = canvas; - this.readable = true; - // TODO: implement async - if ('streamJPEG' == method) method = 'streamJPEGSync'; - process.nextTick(function(){ - canvas[method](options.bufsize, options.quality, options.progressive, function(err, chunk, len){ - if (err) { - self.emit('error', err); - self.readable = false; - } else if (len) { - self.emit('data', chunk, len); - } else { - self.emit('end'); - self.readable = false; - } - }); - }); -}; - -/** - * Inherit from `EventEmitter`. - */ - -JPEGStream.prototype.__proto__ = Stream.prototype; diff --git a/scripts/external/three/canvas/lib/pixelarray.js b/scripts/external/three/canvas/lib/pixelarray.js deleted file mode 100644 index ff10cee..0000000 --- a/scripts/external/three/canvas/lib/pixelarray.js +++ /dev/null @@ -1,29 +0,0 @@ - -/*! - * Canvas - PixelArray - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var Canvas = require('./bindings') - , PixelArray = Canvas.CanvasPixelArray; - -/** - * Custom inspect. - */ - -PixelArray.prototype.inspect = function(){ - var buf = '[PixelArray '; - for (var i = 0, len = this.length; i < len; i += 4) { - buf += '\n ' + i + ': rgba(' - + this[i + 0] + ',' - + this[i + 1] + ',' - + this[i + 2] + ',' - + this[i + 3] + ')'; - } - return buf + '\n]'; -}; diff --git a/scripts/external/three/canvas/lib/pngstream.js b/scripts/external/three/canvas/lib/pngstream.js deleted file mode 100644 index 38e08cd..0000000 --- a/scripts/external/three/canvas/lib/pngstream.js +++ /dev/null @@ -1,60 +0,0 @@ - -/*! - * Canvas - PNGStream - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var Stream = require('stream').Stream; - -/** - * Initialize a `PNGStream` with the given `canvas`. - * - * "data" events are emitted with `Buffer` chunks, once complete the - * "end" event is emitted. The following example will stream to a file - * named "./my.png". - * - * var out = fs.createWriteStream(__dirname + '/my.png') - * , stream = canvas.createPNGStream(); - * - * stream.pipe(out); - * - * @param {Canvas} canvas - * @param {Boolean} sync - * @api public - */ - -var PNGStream = module.exports = function PNGStream(canvas, sync) { - var self = this - , method = sync - ? 'streamPNGSync' - : 'streamPNG'; - this.sync = sync; - this.canvas = canvas; - this.readable = true; - // TODO: implement async - if ('streamPNG' == method) method = 'streamPNGSync'; - process.nextTick(function(){ - canvas[method](function(err, chunk, len){ - if (err) { - self.emit('error', err); - self.readable = false; - } else if (len) { - self.emit('data', chunk, len); - } else { - self.emit('end'); - self.readable = false; - } - }); - }); -}; - -/** - * Inherit from `EventEmitter`. - */ - -PNGStream.prototype.__proto__ = Stream.prototype; \ No newline at end of file diff --git a/scripts/external/three/canvas/node_modules/nan/.dntrc b/scripts/external/three/canvas/node_modules/nan/.dntrc deleted file mode 100644 index 47971da..0000000 --- a/scripts/external/three/canvas/node_modules/nan/.dntrc +++ /dev/null @@ -1,30 +0,0 @@ -## DNT config file -## see https://github.com/rvagg/dnt - -NODE_VERSIONS="\ - master \ - v0.11.13 \ - v0.10.30 \ - v0.10.29 \ - v0.10.28 \ - v0.10.26 \ - v0.10.25 \ - v0.10.24 \ - v0.10.23 \ - v0.10.22 \ - v0.10.21 \ - v0.10.20 \ - v0.10.19 \ - v0.8.28 \ - v0.8.27 \ - v0.8.26 \ - v0.8.24 \ -" -OUTPUT_PREFIX="nan-" -TEST_CMD=" \ - cd /dnt/ && \ - npm install && \ - node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild --directory test && \ - node_modules/.bin/tap --gc test/js/*-test.js \ -" - diff --git a/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md b/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md deleted file mode 100644 index 6a0fdbe..0000000 --- a/scripts/external/three/canvas/node_modules/nan/CHANGELOG.md +++ /dev/null @@ -1,248 +0,0 @@ -# NAN ChangeLog - -**Version 1.5.2: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3** - -### 1.5.2 Jan 23 2015 - - - Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4 - - Bugfix: Readded missing String constructors 18d828f - - Bugfix: Add overload handling NanNew(..) 5ef813b - - Bugfix: Fix uv_work_cb versioning 997e4ae - - Bugfix: Add function factory and test 4eca89c - - Bugfix: Add object template factory and test cdcb951 - - Correctness: Lifted an io.js related typedef c9490be - - Correctness: Make explicit downcasts of String lengths 00074e6 - - Windows: Limit the scope of disabled warning C4530 83d7deb - - -### 1.5.1 Jan 15 2015 - - - Build: version bump - -### 1.4.3 Jan 15 2015 - - - Build: version bump - -### 1.4.2 Jan 15 2015 - - - Feature: Support io.js 0dbc5e8 - -### 1.5.0 Jan 14 2015 - - - Feature: Support io.js b003843 - - Correctness: Improved NanNew internals 9cd4f6a - - Feature: Implement progress to NanAsyncWorker 8d6a160 - -### 1.4.1 Nov 8 2014 - - - Bugfix: Handle DEBUG definition correctly - - Bugfix: Accept int as Boolean - -### 1.4.0 Nov 1 2014 - - - Feature: Added NAN_GC_CALLBACK 6a5c245 - - Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8 - - Correctness: Added constness to references in NanHasInstance 02c61cd - - Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6 - - Windoze: Shut Visual Studio up when compiling 8d558c1 - - License: Switch to plain MIT from custom hacked MIT license 11de983 - - Build: Added test target to Makefile e232e46 - - Performance: Removed superfluous scope in NanAsyncWorker f4b7821 - - Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208 - - Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450 - -### 1.3.0 Aug 2 2014 - - - Added NanNew(std::string) - - Added NanNew(std::string&) - - Added NanAsciiString helper class - - Added NanUtf8String helper class - - Added NanUcs2String helper class - - Deprecated NanRawString() - - Deprecated NanCString() - - Added NanGetIsolateData(v8::Isolate *isolate) - - Added NanMakeCallback(v8::Handle target, v8::Handle func, int argc, v8::Handle* argv) - - Added NanMakeCallback(v8::Handle target, v8::Handle symbol, int argc, v8::Handle* argv) - - Added NanMakeCallback(v8::Handle target, const char* method, int argc, v8::Handle* argv) - - Added NanSetTemplate(v8::Handle templ, v8::Handle name , v8::Handle value, v8::PropertyAttribute attributes) - - Added NanSetPrototypeTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) - - Added NanSetInstanceTemplate(v8::Local templ, const char *name, v8::Handle value) - - Added NanSetInstanceTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) - -### 1.2.0 Jun 5 2014 - - - Add NanSetPrototypeTemplate - - Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class, - introduced _NanWeakCallbackDispatcher - - Removed -Wno-unused-local-typedefs from test builds - - Made test builds Windows compatible ('Sleep()') - -### 1.1.2 May 28 2014 - - - Release to fix more stuff-ups in 1.1.1 - -### 1.1.1 May 28 2014 - - - Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0 - -### 1.1.0 May 25 2014 - - - Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead - - Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]), - (uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*, - v8::String::ExternalAsciiStringResource* - - Deprecate NanSymbol() - - Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker - -### 1.0.0 May 4 2014 - - - Heavy API changes for V8 3.25 / Node 0.11.13 - - Use cpplint.py - - Removed NanInitPersistent - - Removed NanPersistentToLocal - - Removed NanFromV8String - - Removed NanMakeWeak - - Removed NanNewLocal - - Removed NAN_WEAK_CALLBACK_OBJECT - - Removed NAN_WEAK_CALLBACK_DATA - - Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions - - Introduce NanUndefined, NanNull, NanTrue and NanFalse - - Introduce NanEscapableScope and NanEscapeScope - - Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node) - - Introduce NanMakeCallback for node::MakeCallback - - Introduce NanSetTemplate - - Introduce NanGetCurrentContext - - Introduce NanCompileScript and NanRunScript - - Introduce NanAdjustExternalMemory - - Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback - - Introduce NanGetHeapStatistics - - Rename NanAsyncWorker#SavePersistent() to SaveToPersistent() - -### 0.8.0 Jan 9 2014 - - - NanDispose -> NanDisposePersistent, deprecate NanDispose - - Extract _NAN_*_RETURN_TYPE, pull up NAN_*() - -### 0.7.1 Jan 9 2014 - - - Fixes to work against debug builds of Node - - Safer NanPersistentToLocal (avoid reinterpret_cast) - - Speed up common NanRawString case by only extracting flattened string when necessary - -### 0.7.0 Dec 17 2013 - - - New no-arg form of NanCallback() constructor. - - NanCallback#Call takes Handle rather than Local - - Removed deprecated NanCallback#Run method, use NanCallback#Call instead - - Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS - - Restore (unofficial) Node 0.6 compatibility at NanCallback#Call() - - Introduce NanRawString() for char* (or appropriate void*) from v8::String - (replacement for NanFromV8String) - - Introduce NanCString() for null-terminated char* from v8::String - -### 0.6.0 Nov 21 2013 - - - Introduce NanNewLocal(v8::Handle value) for use in place of - v8::Local::New(...) since v8 started requiring isolate in Node 0.11.9 - -### 0.5.2 Nov 16 2013 - - - Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public - -### 0.5.1 Nov 12 2013 - - - Use node::MakeCallback() instead of direct v8::Function::Call() - -### 0.5.0 Nov 11 2013 - - - Added @TooTallNate as collaborator - - New, much simpler, "include_dirs" for binding.gyp - - Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros - -### 0.4.4 Nov 2 2013 - - - Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+ - -### 0.4.3 Nov 2 2013 - - - Include node_object_wrap.h, removed from node.h for Node 0.11.8. - -### 0.4.2 Nov 2 2013 - - - Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for - Node 0.11.8 release. - -### 0.4.1 Sep 16 2013 - - - Added explicit `#include ` as it was removed from node.h for v0.11.8 - -### 0.4.0 Sep 2 2013 - - - Added NAN_INLINE and NAN_DEPRECATED and made use of them - - Added NanError, NanTypeError and NanRangeError - - Cleaned up code - -### 0.3.2 Aug 30 2013 - - - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent - in NanAsyncWorker - -### 0.3.1 Aug 20 2013 - - - fix "not all control paths return a value" compile warning on some platforms - -### 0.3.0 Aug 19 2013 - - - Made NAN work with NPM - - Lots of fixes to NanFromV8String, pulling in features from new Node core - - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API - - Added optional error number argument for NanThrowError() - - Added NanInitPersistent() - - Added NanReturnNull() and NanReturnEmptyString() - - Added NanLocker and NanUnlocker - - Added missing scopes - - Made sure to clear disposed Persistent handles - - Changed NanAsyncWorker to allocate error messages on the heap - - Changed NanThrowError(Local) to NanThrowError(Handle) - - Fixed leak in NanAsyncWorker when errmsg is used - -### 0.2.2 Aug 5 2013 - - - Fixed usage of undefined variable with node::BASE64 in NanFromV8String() - -### 0.2.1 Aug 5 2013 - - - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for - NanFromV8String() - -### 0.2.0 Aug 5 2013 - - - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR, - NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY - - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS, - _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS, - _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS, - _NAN_PROPERTY_QUERY_ARGS - - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer - - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT, - NAN_WEAK_CALLBACK_DATA, NanMakeWeak - - Renamed THROW_ERROR to _NAN_THROW_ERROR - - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*) - - Added NanBufferUse(char*, uint32_t) - - Added NanNewContextHandle(v8::ExtensionConfiguration*, - v8::Handle, v8::Handle) - - Fixed broken NanCallback#GetFunction() - - Added optional encoding and size arguments to NanFromV8String() - - Added NanGetPointerSafe() and NanSetPointerSafe() - - Added initial test suite (to be expanded) - - Allow NanUInt32OptionValue to convert any Number object - -### 0.1.0 Jul 21 2013 - - - Added `NAN_GETTER`, `NAN_SETTER` - - Added `NanThrowError` with single Local argument - - Added `NanNewBufferHandle` with single uint32_t argument - - Added `NanHasInstance(Persistent&, Handle)` - - Added `Local NanCallback#GetFunction()` - - Added `NanCallback#Call(int, Local[])` - - Deprecated `NanCallback#Run(int, Local[])` in favour of Call diff --git a/scripts/external/three/canvas/node_modules/nan/LICENSE.md b/scripts/external/three/canvas/node_modules/nan/LICENSE.md deleted file mode 100644 index 95c2eb5..0000000 --- a/scripts/external/three/canvas/node_modules/nan/LICENSE.md +++ /dev/null @@ -1,13 +0,0 @@ -The MIT License (MIT) -===================== - -Copyright (c) 2015 NAN contributors ------------------------------------ - -*NAN contributors listed at * - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/scripts/external/three/canvas/node_modules/nan/README.md b/scripts/external/three/canvas/node_modules/nan/README.md deleted file mode 100644 index f91d08b..0000000 --- a/scripts/external/three/canvas/node_modules/nan/README.md +++ /dev/null @@ -1,1228 +0,0 @@ -Native Abstractions for Node.js -=============================== - -**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.** - -***Current version: 1.5.2*** - -*(See [CHANGELOG.md](https://github.com/rvagg/nan/blob/master/CHANGELOG.md) for complete ChangeLog)* - -[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/) - -[![Build Status](https://secure.travis-ci.org/rvagg/nan.png)](http://travis-ci.org/rvagg/nan) -[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan) - -Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle. - -This project also contains some helper utilities that make addon development a bit more pleasant. - - * **[News & Updates](#news)** - * **[Usage](#usage)** - * **[Example](#example)** - * **[API](#api)** - * **[Tests](#tests)** - - -## News & Updates - -### Jan-2015: 1.5.0 release - -* Support [io.js](https://github.com/iojs/io.js) thanks to [Ben Noordhuis](bnoordhuis) -* Rewritten NanNew internals thanks to [David Siegel](agnat) -* NanAsyncWorker now supports progress reporting thanks to [Brett Lawson](brett19) - -### Aug-2014: 1.3.0 release - -* `NanCString()` and `NanRawString()` have been deprecated in favour of new NanAsciiString, NanUtf8String and NanUcs2String. These classes manage the underlying memory for you in a safer way than just handing off an allocated array. You should now `*NanAsciiString(handle)` to access the raw `char` data, you can also allocate on the heap if you need to keep a reference. -* Two more NanMakeCallback overloads have been added to for parity with Node core. -* You can now `NanNew(std::string)` (use `NanNew(std::string&)` to pass by reference) -* NanSetTemplate, NanSetPrototypeTemplate and NanSetInstanceTemplate have been added. - -### May-2014: 1.1.0 release - -* We've deprecated `NanSymbol()`, you should just use `NanNew()` now. -* `NanNull()`, `NanUndefined()`, `NanTrue()`, `NanFalse()` all return `Local`s now. -* `nan_isolate` is gone, it was intended to be internal-only but if you were using it then you should switch to `v8::Isolate::GetCurrent()`. -* `NanNew()` has received some additional overload-love so you should be able to give it many kinds of values without specifying the ``. -* Lots of small fixes and additions to expand the V8 API coverage, *use the source, Luke*. - - -### May-2014: Major changes for V8 3.25 / Node 0.11.13 - -Node 0.11.11 and 0.11.12 were both broken releases for native add-ons, you simply can't properly compile against either of them for different reasons. But we now have a 0.11.13 release that jumps a couple of versions of V8 ahead and includes some more, major (traumatic) API changes. - -Because we are now nearing Node 0.12 and estimate that the version of V8 we are using in Node 0.11.13 will be close to the API we get for 0.12, we have taken the opportunity to not only *fix* NAN for 0.11.13 but make some major changes to improve the NAN API. - -We have **removed support for Node 0.11 versions prior to 0.11.13**. As usual, our tests are run against (and pass) the last 5 versions of Node 0.8 and Node 0.10. We also include Node 0.11.13 obviously. - -The major change is something that [Benjamin Byholm](kkoopa) has put many hours in to. We now have a fantastic new `NanNew(args)` interface for creating new `Local`s, this replaces `NanNewLocal()` and much more. If you look in [./nan.h](nan.h) you'll see a large number of overloaded versions of this method. In general you should be able to `NanNew(arguments)` for any type you want to make a `Local` from. This includes `Persistent` types, so we now have a `Local NanNew(const Persistent arg)` to replace `NanPersistentToLocal()`. - -We also now have `NanUndefined()`, `NanNull()`, `NanTrue()` and `NanFalse()`. Mainly because of the new requirement for an `Isolate` argument for each of the native V8 versions of this. - -V8 has now introduced an `EscapableHandleScope` from which you `scope.Escape(Local value)` to *return* a value from a one scope to another. This replaces the standard `HandleScope` and `scope.Close(Local value)`, although `HandleScope` still exists for when you don't need to return a handle to the caller. For NAN we are exposing it as `NanEscapableScope()` and `NanEscapeScope()`, while `NanScope()` is still how you create a new scope that doesn't need to return handles. For older versions of Node/V8, it'll still map to the older `HandleScope` functionality. - -`NanFromV8String()` was deprecated and has now been removed. You should use `NanCString()` or `NanRawString()` instead. - -Because `node::MakeCallback()` now takes an `Isolate`, and because it doesn't exist in older versions of Node, we've introduced `NanMakeCallback()`. You should *always* use this when calling a JavaScript function from C++. - -There's lots more, check out the Changelog in nan.h or look through [#86](https://github.com/rvagg/nan/pull/86) for all the gory details. - -### Dec-2013: NanCString and NanRawString - -Two new functions have been introduced to replace the functionality that's been provided by `NanFromV8String` until now. NanCString has sensible defaults so it's super easy to fetch a null-terminated c-style string out of a `v8::String`. `NanFromV8String` is still around and has defaults that allow you to pass a single handle to fetch a `char*` while `NanRawString` requires a little more attention to arguments. - -### Nov-2013: Node 0.11.9+ breaking V8 change - -The version of V8 that's shipping with Node 0.11.9+ has changed the signature for new `Local`s to: `v8::Local::New(isolate, value)`, i.e. introducing the `isolate` argument and therefore breaking all new `Local` declarations for previous versions. NAN 0.6+ now includes a `NanNewLocal(value)` that can be used in place to work around this incompatibility and maintain compatibility with 0.8->0.11.9+ (minus a few early 0.11 releases). - -For example, if you wanted to return a `null` on a callback you will have to change the argument from `v8::Local::New(v8::Null())` to `NanNewLocal(v8::Null())`. - -### Nov-2013: Change to binding.gyp `"include_dirs"` for NAN - -Inclusion of NAN in a project's binding.gyp is now greatly simplified. You can now just use `" -## Usage - -Simply add **NAN** as a dependency in the *package.json* of your Node addon: - -``` bash -$ npm install --save nan -``` - -Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files: - -``` python -"include_dirs" : [ - "` when compiling your addon. - - -## Example - -See **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use. - -For a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**. - -For another example, see **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon. - -Compare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work). - -Note that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class. - -```c++ -// addon.cc -#include -#include -// ... - -using v8::FunctionTemplate; -using v8::Handle; -using v8::Object; -using v8::String; - -void InitAll(Handle exports) { - exports->Set(NanNew("calculateSync"), - NanNew(CalculateSync)->GetFunction()); - - exports->Set(NanNew("calculateAsync"), - NanNew(CalculateAsync)->GetFunction()); -} - -NODE_MODULE(addon, InitAll) -``` - -```c++ -// sync.h -#include -#include - -NAN_METHOD(CalculateSync); -``` - -```c++ -// sync.cc -#include -#include -#include "./sync.h" -// ... - -using v8::Number; - -// Simple synchronous access to the `Estimate()` function -NAN_METHOD(CalculateSync) { - NanScope(); - - // expect a number as the first argument - int points = args[0]->Uint32Value(); - double est = Estimate(points); - - NanReturnValue(NanNew(est)); -} -``` - -```c++ -// async.h -#include -#include - -NAN_METHOD(CalculateAsync); -``` - -```c++ -// async.cc -#include -#include -#include "./async.h" - -// ... - -using v8::Function; -using v8::Local; -using v8::Null; -using v8::Number; -using v8::Value; - -class PiWorker : public NanAsyncWorker { - public: - PiWorker(NanCallback *callback, int points) - : NanAsyncWorker(callback), points(points) {} - ~PiWorker() {} - - // Executed inside the worker-thread. - // It is not safe to access V8, or V8 data structures - // here, so everything we need for input and output - // should go on `this`. - void Execute () { - estimate = Estimate(points); - } - - // Executed when the async work is complete - // this function will be run inside the main event loop - // so it is safe to use V8 again - void HandleOKCallback () { - NanScope(); - - Local argv[] = { - NanNull() - , NanNew(estimate) - }; - - callback->Call(2, argv); - }; - - private: - int points; - double estimate; -}; - -// Asynchronous access to the `Estimate()` function -NAN_METHOD(CalculateAsync) { - NanScope(); - - int points = args[0]->Uint32Value(); - NanCallback *callback = new NanCallback(args[1].As()); - - NanAsyncQueueWorker(new PiWorker(callback, points)); - NanReturnUndefined(); -} -``` - - -## API - - * NAN_METHOD - * NAN_GETTER - * NAN_SETTER - * NAN_PROPERTY_GETTER - * NAN_PROPERTY_SETTER - * NAN_PROPERTY_ENUMERATOR - * NAN_PROPERTY_DELETER - * NAN_PROPERTY_QUERY - * NAN_INDEX_GETTER - * NAN_INDEX_SETTER - * NAN_INDEX_ENUMERATOR - * NAN_INDEX_DELETER - * NAN_INDEX_QUERY - * NAN_GC_CALLBACK - * NAN_WEAK_CALLBACK - * NAN_DEPRECATED - * NAN_INLINE - * NanNew - * NanUndefined - * NanNull - * NanTrue - * NanFalse - * NanReturnValue - * NanReturnUndefined - * NanReturnNull - * NanReturnEmptyString - * NanReturnThis - * NanReturnHolder - * NanScope - * NanEscapableScope - * NanEscapeScope - * NanLocker - * NanUnlocker - * NanGetInternalFieldPointer - * NanSetInternalFieldPointer - * NanObjectWrapHandle - * NanSymbol - * NanGetPointerSafe - * NanSetPointerSafe - * NanRawString - * NanCString - * NanAsciiString - * NanUtf8String - * NanUcs2String - * NanBooleanOptionValue - * NanUInt32OptionValue - * NanError, NanTypeError, NanRangeError - * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int) - * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t) - * NanBufferUse(char *, uint32_t) - * NanNewContextHandle - * NanGetCurrentContext - * NanHasInstance - * NanDisposePersistent - * NanAssignPersistent - * NanMakeWeakPersistent - * NanSetTemplate - * NanSetPrototypeTemplate - * NanSetInstanceTemplate - * NanMakeCallback - * NanCompileScript - * NanRunScript - * NanAdjustExternalMemory - * NanAddGCEpilogueCallback - * NanAddGCPrologueCallback - * NanRemoveGCEpilogueCallback - * NanRemoveGCPrologueCallback - * NanGetHeapStatistics - * NanCallback - * NanAsyncWorker - * NanAsyncQueueWorker - - -### NAN_METHOD(methodname) - -Use `NAN_METHOD` to define your V8 accessible methods: - -```c++ -// .h: -class Foo : public node::ObjectWrap { - ... - - static NAN_METHOD(Bar); - static NAN_METHOD(Baz); -} - - -// .cc: -NAN_METHOD(Foo::Bar) { - ... -} - -NAN_METHOD(Foo::Baz) { - ... -} -``` - -The reason for this macro is because of the method signature change in 0.11: - -```c++ -// 0.10 and below: -Handle name(const Arguments& args) - -// 0.11 and above -void name(const FunctionCallbackInfo& args) -``` - -The introduction of `FunctionCallbackInfo` brings additional complications: - - -### NAN_GETTER(methodname) - -Use `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`. - - -### NAN_SETTER(methodname) - -Use `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with. - - -### NAN_PROPERTY_GETTER(cbname) -Use `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`. - - -### NAN_PROPERTY_SETTER(cbname) -Use `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with. - - -### NAN_PROPERTY_ENUMERATOR(cbname) -Use `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`. - - -### NAN_PROPERTY_DELETER(cbname) -Use `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`. - - -### NAN_PROPERTY_QUERY(cbname) -Use `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`. - - -### NAN_INDEX_GETTER(cbname) -Use `NAN_INDEX_GETTER` to declare your V8 accessible index getters. You get a `uint32_t` `index` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_GETTER`. - - -### NAN_INDEX_SETTER(cbname) -Use `NAN_INDEX_SETTER` to declare your V8 accessible index setters. Same as `NAN_INDEX_GETTER` but you also get a `Local` `value` object to work with. - - -### NAN_INDEX_ENUMERATOR(cbname) -Use `NAN_INDEX_ENUMERATOR` to declare your V8 accessible index enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_INDEX_GETTER` call. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_ENUMERATOR`. - - -### NAN_INDEX_DELETER(cbname) -Use `NAN_INDEX_DELETER` to declare your V8 accessible index deleters. Same as `NAN_INDEX_GETTER`. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_DELETER`. - - -### NAN_INDEX_QUERY(cbname) -Use `NAN_INDEX_QUERY` to declare your V8 accessible index queries. Same as `NAN_INDEX_GETTER`. - -You can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_QUERY`. - - -### NAN_GC_CALLBACK(cbname) -Use `NAN_GC_CALLBACK` to declare your callbacks for `NanAddGCEpilogueCallback` and `NanAddGCPrologueCallback`. You get arguments `GCType type` and `GCCallbackFlags flags`. - -```c++ -static Persistent callback; - -NAN_GC_CALLBACK(gcPrologueCallback) { - Local argv[] = {NanNew("prologue")}; - NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(callback), 1, argv); -} - -NAN_METHOD(Hook) { - NanScope(); - NanAssignPersistent(callback, args[0].As()); - NanAddGCPrologueCallback(gcPrologueCallback); - NanReturnValue(args.Holder()); -} -``` - - -### NAN_WEAK_CALLBACK(cbname) - -Use `NAN_WEAK_CALLBACK` to define your V8 WeakReference callbacks. There is an argument object `const _NanWeakCallbackData &data` allowing access to the weak object and the supplied parameter through its `GetValue` and `GetParameter` methods. You can even access the weak callback info object through the `GetCallbackInfo()`method, but you probably should not. `Revive()` keeps the weak object alive until the next GC round. - -```c++ -NAN_WEAK_CALLBACK(weakCallback) { - int *parameter = data.GetParameter(); - NanMakeCallback(NanGetCurrentContext()->Global(), data.GetValue(), 0, NULL); - if ((*parameter)++ == 0) { - data.Revive(); - } else { - delete parameter; - } -} -``` - - -### NAN_DEPRECATED -Declares a function as deprecated. - -```c++ -static NAN_DEPRECATED NAN_METHOD(foo) { - ... -} -``` - - -### NAN_INLINE -Inlines a function. - -```c++ -NAN_INLINE int foo(int bar) { - ... -} -``` - - -### Local<T> NanNew<T>( ... ) - -Use `NanNew` to construct almost all v8 objects (bound `Script`s are constructed with `NanCompileScript(Handle)`) and make new local handles. - -```c++ -Local s = NanNew("value"); - -... - -Persistent o; - -... - -Local lo = NanNew(o); - -``` - - -### Local<Primitive> NanUndefined() - -Use instead of `Undefined()` - - -### Local<Primitive> NanNull() - -Use instead of `Null()` - - -### Local<Boolean> NanTrue() - -Use instead of `True()` - - -### Local<Boolean> NanFalse() - -Use instead of `False()` - - -### NanReturnValue(Handle<Value>) - -Use `NanReturnValue` when you want to return a value from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Bar) { - ... - - NanReturnValue(NanNew("FooBar!")); -} -``` - -No `return` statement required. - - -### NanReturnUndefined() - -Use `NanReturnUndefined` when you don't want to return anything from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Baz) { - ... - - NanReturnUndefined(); -} -``` - - -### NanReturnNull() - -Use `NanReturnNull` when you want to return `Null` from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Baz) { - ... - - NanReturnNull(); -} -``` - - -### NanReturnEmptyString() - -Use `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Baz) { - ... - - NanReturnEmptyString(); -} -``` - - -### NanReturnThis() - -Use `NanReturnThis` when you want to return `This` from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Baz) { - ... - - NanReturnThis(); -} -``` - - -### NanReturnHolder() - -Use `NanReturnHolder` when you want to return `Holder` from your V8 accessible method: - -```c++ -NAN_METHOD(Foo::Baz) { - ... - - NanReturnHolder(); -} -``` - - -### NanScope() - -The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope` when you do not wish to return handles (`Handle` or `Local`) to the surrounding scope (or in functions directly exposed to V8, as they do not return values in the normal sense): - -```c++ -NAN_METHOD(Foo::Bar) { - NanScope(); - - NanReturnValue(NanNew("FooBar!")); -} -``` - -This method is not directly exposed to V8, nor does it return a handle, so it uses an unescapable scope: - -```c++ -bool Foo::Bar() { - NanScope(); - - Local val = NanFalse(); - ... - return val->Value(); -} -``` - - -### NanEscapableScope() - -The separation of handle scopes into escapable and inescapable scopes makes `NanEscapableScope()` necessary, use it in place of `HandleScope scope` when you later wish to return a handle (`Handle` or `Local`) from the scope, this is for internal functions not directly exposed to V8: - -```c++ -Handle Foo::Bar() { - NanEscapableScope(); - - return NanEscapeScope(NanNew("FooBar!")); -} -``` - - -### Local<T> NanEscapeScope(Handle<T> value); -Use together with `NanEscapableScope` to escape the scope. Corresponds to `HandleScope::Close` or `EscapableHandleScope::Escape`. - - -### NanLocker() - -The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`: - -```c++ -NAN_METHOD(Foo::Bar) { - NanLocker(); - ... - NanUnlocker(); -} -``` - - -### NanUnlocker() - -The introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`: - -```c++ -NAN_METHOD(Foo::Bar) { - NanLocker(); - ... - NanUnlocker(); -} -``` - - -### void * NanGetInternalFieldPointer(Handle<Object>, int) - -Gets a pointer to the internal field with at `index` from a V8 `Object` handle. - -```c++ -Local obj; -... -NanGetInternalFieldPointer(obj, 0); -``` - -### void NanSetInternalFieldPointer(Handle<Object>, int, void *) - -Sets the value of the internal field at `index` on a V8 `Object` handle. - -```c++ -static Persistent dataWrapperCtor; -... -Local wrapper = NanNew(dataWrapperCtor)->NewInstance(); -NanSetInternalFieldPointer(wrapper, 0, this); -``` - - -### Local<Object> NanObjectWrapHandle(Object) - -When you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`: - -```c++ -NanObjectWrapHandle(iterator)->Get(NanNew("end")) -``` - - -### ~~Local<String> NanSymbol(const char *)~~ - -Deprecated. Use `NanNew` instead. -~~Use to create string symbol objects (i.e. `v8::String::NewSymbol(x)`), for getting and setting object properties, or names of objects.~~ - -```c++ -bool foo = false; -if (obj->Has(NanNew("foo"))) - foo = optionsObj->Get(NanNew("foo"))->BooleanValue() -``` - - -### Type NanGetPointerSafe(Type *[, Type]) - -A helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to. - -```c++ -char *plugh(uint32_t *optional) { - char res[] = "xyzzy"; - uint32_t param = NanGetPointerSafe(optional, 0x1337); - switch (param) { - ... - } - NanSetPointerSafe(optional, 0xDEADBEEF); -} -``` - - -### bool NanSetPointerSafe(Type *, Type) - -A helper for setting optional argument pointers. If the pointer is `NULL`, the function simply returns `false`. Otherwise, the value is assigned to the variable the pointer points to. - -```c++ -const char *plugh(size_t *outputsize) { - char res[] = "xyzzy"; - if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) { - ... - } - - ... -} -``` - - -### ~~void* NanRawString(Handle<Value>, enum Nan::Encoding, size_t *, void *, size_t, int)~~ - -Deprecated. Use something else. - -~~When you want to convert a V8 `String` to a `char*` buffer, use `NanRawString`. You have to supply an encoding as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows setting `String::WriteOptions`. -Just remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~ - -```c++ -size_t count; -void* decoded = NanRawString(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED); -... -delete[] reinterpret_cast(decoded); -``` - - -### ~~char* NanCString(Handle<Value>, size_t *[, char *, size_t, int])~~ - -Deprecated. Use `String::Utf8Value` or `NanUtf8String` instead. - -~~When you want to convert a V8 `String` to a null-terminated C `char*` use `NanCString`. The resulting `char*` will be UTF-8-encoded, and you need to supply a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `v8::String::NO_OPTIONS`. -Just remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~ - -```c++ -size_t count; -char* name = NanCString(args[0], &count); -... -delete[] name; -``` - - -### NanAsciiString - -Contrary to the name, this is not actually an ASCII string, it is a one-byte string with no particular encoding. Do not use unless you actually need this incorrect legacy behavior. Consider fixing your broken code instead. If you actually have a proper ASCII-string, use UTF-8, which is a proper superset of ASCII. -Convert a `String` to zero-terminated, sort-of Ascii-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. - -```c++ -NAN_METHOD(foo) { - NanScope(); - NanReturnValue(NanNew(*NanAsciiString(arg[0]))); -} -``` - -####*WRONG*: -the buffer `str` points to has been freed when `baz` was destroyed: -```c++ -static char *str; - -NAN_METHOD(bar) { - NanScope(); - NanAsciiString baz(arg[0]); - - str = *baz; - NanReturnUndefined(); // baz goes out of scope, freeing str -} - -... - -printf(str); // use-after-free error -``` - -####*RIGHT*: -```c++ -static NanAsciiString *str; - -NAN_METHOD(bar) { - NanScope(); - str = new NanAsciiString(arg[0]); - NanReturnUndefined(); -} - -... - -printf(**str); -``` - - -### NanUtf8String - -Equivalent to `String::Utf8Value`, it only exists for the sake of completeness. -Convert a `String` to zero-terminated, Utf8-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. - -```c++ -NAN_METHOD(foo) { - NanScope(); - NanReturnValue(NanNew(*NanUtf8String(arg[0]))); -} -``` - -####*WRONG*: -the buffer `str` points to has been freed when `baz` was destroyed: -```c++ -static char *str; - -NAN_METHOD(bar) { - NanScope(); - NanUtf8String baz(arg[0]); - - str = *baz; - NanReturnUndefined(); // baz goes out of scope, freeing str -} - -... - -printf(str); // use-after-free error -``` - -####*RIGHT*: -```c++ -static NanUtf8String *str; - -NAN_METHOD(bar) { - NanScope(); - str = new NanUtf8String(arg[0]); - NanReturnUndefined(); -} - -... - -printf(**str); -``` - - - -### NanUcs2String - -Equivalent to `String::Value`, it only exists for the sake of completeness. -Convert a `String` to zero-terminated, Ucs2-encoded `uint16_t *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around. - -```c++ -NAN_METHOD(foo) { - NanScope(); - NanReturnValue(NanNew(*NanUcs2String(arg[0]))); -} -``` - -####*WRONG*: -the buffer `str` points to has been freed when `baz` was destroyed: -```c++ -static char *str; - -NAN_METHOD(bar) { - NanScope(); - NanUcs2String baz(arg[0]); - - str = *baz; - NanReturnUndefined(); // baz goes out of scope, freeing str -} - -... - -printf(str); // use-after-free error -``` - -####*RIGHT*: -```c++ -static NanUcs2String *str; - -NAN_METHOD(bar) { - NanScope(); - str = new NanUcs2String(arg[0]); - NanReturnUndefined(); -} - -... - -printf(**str); -``` - - -### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool]) - -When you have an "options" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`. - -The optional last parameter is the *default* value, which is `false` if left off: - -```c++ -// `foo` is false unless the user supplies a truthy value for it -bool foo = NanBooleanOptionValue(optionsObj, NanNew("foo")); -// `bar` is true unless the user supplies a falsy value for it -bool bar = NanBooleanOptionValueDefTrue(optionsObj, NanNew("bar"), true); -``` - - -### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t) - -Similar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer. - -Requires all 3 arguments as a default is not optional: - -```c++ -uint32_t count = NanUInt32OptionValue(optionsObj, NanNew("count"), 1024); -``` - - -### NanError(message), NanTypeError(message), NanRangeError(message) - -For making `Error`, `TypeError` and `RangeError` objects. - -```c++ -Local res = NanError("you must supply a callback argument"); -``` - - -### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int) - -For throwing `Error`, `TypeError` and `RangeError` objects. - -```c++ -NanThrowError("you must supply a callback argument"); -``` - -Can also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`. - - -### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t) - -The `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation: - -```c++ -NanNewBufferHandle((char*)value.data(), value.size()); -``` - -Can also be used to initialize a `Buffer` with just a `size` argument. - -Can also be supplied with a `NanFreeCallback` and a hint for the garbage collector. - - -### Local<Object> NanBufferUse(char*, uint32_t) - -`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data. -While it was possible to get around this, it required a shim by passing a -callback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove -needing to use this shim. - -`NanBufferUse` uses the `char*` passed as the backing data, and will free the -memory automatically when the weak callback is called. Keep this in mind, as -careless use can lead to "double free or corruption" and other cryptic failures. - - -### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>) - -Can be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for. - - -### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>]) -Creates a new `Local` handle. - -```c++ -Local ftmpl = NanNew(); -Local otmpl = ftmpl->InstanceTemplate(); -Local ctx = NanNewContextHandle(NULL, otmpl); -``` - - -### Local<Context> NanGetCurrentContext() - -Gets the current context. - -```c++ -Local ctx = NanGetCurrentContext(); -``` - - -### void NanDisposePersistent(Persistent<T> &) - -Use `NanDisposePersistent` to dispose a `Persistent` handle. - -```c++ -NanDisposePersistent(persistentHandle); -``` - - -### NanAssignPersistent(handle, object) - -Use `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier. - -In general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`: - -```c++ -Persistent persistentHandle; - -... - -Local obj = NanNew(); -obj->Set(NanNew("key"), keyHandle); // where keyHandle might be a Local -NanAssignPersistent(persistentHandle, obj) -``` - - -### _NanWeakCallbackInfo<T, P>* NanMakeWeakPersistent(Handle<T>, P*, _NanWeakCallbackInfo<T, P>::Callback) - -Creates a weak persistent handle with the supplied parameter and `NAN_WEAK_CALLBACK`. - -```c++ -NAN_WEAK_CALLBACK(weakCallback) { - -... - -} - -Local func; - -... - -int *parameter = new int(0); -NanMakeWeakPersistent(func, parameter, &weakCallback); -``` - - -### NanSetTemplate(templ, name, value [, attributes]) - -Use to add properties on object and function templates. - - -### NanSetPrototypeTemplate(templ, name, value [, attributes]) - -Use to add prototype properties on function templates. - - -### NanSetInstanceTemplate(templ, name, value [, attributes]) - -Use to add instance properties on function templates. - - -### NanMakeCallback(target, func, argc, argv) - -Use instead of `node::MakeCallback` to call javascript functions. This (or `NanCallback`) is the only proper way of calling functions. You must _*never, ever*_ directly use `Function::Call`, it will lead to run-time failures. - - -### NanCompileScript(Handle s [, const ScriptOrigin& origin]) - -Use to create new scripts bound to the current context. - - -### NanRunScript(script) - -Use to run both bound and unbound scripts. - - -### NanAdjustExternalMemory(int change_in_bytes) - -Simply does `AdjustAmountOfExternalAllocatedMemory`, note that the argument and returned value have type `int`. - - -### NanAddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll) - -Simply does `AddGCEpilogueCallback` - - -### NanAddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll) - -Simply does `AddGCPrologueCallback` - - -### NanRemoveGCEpilogueCallback(GCEpilogueCallback callback) - -Simply does `RemoveGCEpilogueCallback` - - -### NanRemoveGCPrologueCallback(GCPrologueCallback callback) - -Simply does `RemoveGCPrologueCallback` - - -### NanGetHeapStatistics(HeapStatistics *heap_statistics) - -Simply does `GetHeapStatistics` - - -### NanCallback - -Because of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Handle` is annoyingly tricky. `NanCallback` makes it easier by taking your handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`. - -```c++ -Local callbackHandle = args[0].As(); -NanCallback *callback = new NanCallback(callbackHandle); -// pass `callback` around and it's safe from GC until you: -delete callback; -``` - -You can execute the callback like so: - -```c++ -// no arguments: -callback->Call(0, NULL); - -// an error argument: -Handle argv[] = { - NanError(NanNew("fail!")) -}; -callback->Call(1, argv); - -// a success argument: -Handle argv[] = { - NanNull(), - NanNew("w00t!") -}; -callback->Call(2, argv); -``` - -`NanCallback` also has a `Local GetFunction()` method that you can use -to fetch a local handle to the underlying callback function, as well as a -`void SetFunction(Handle)` for setting the callback on the -`NanCallback`. You can check if a `NanCallback` is empty with the `bool IsEmpty()` method. Additionally a generic constructor is available for using -`NanCallback` without performing heap allocations. - - -### NanAsyncWorker - -`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress. - -See a rough outline of the implementation: - -```c++ -class NanAsyncWorker { -public: - NanAsyncWorker (NanCallback *callback); - - // Clean up persistent handles and delete the *callback - virtual ~NanAsyncWorker (); - - // Check the `ErrorMessage()` and call HandleOKCallback() - // or HandleErrorCallback depending on whether it has been set or not - virtual void WorkComplete (); - - // You must implement this to do some async work. If there is an - // error then use `SetErrorMessage()` to set an error message and the callback will - // be passed that string in an Error object - virtual void Execute (); - - // Save a V8 object in a Persistent handle to protect it from GC - void SaveToPersistent(const char *key, Local &obj); - - // Fetch a stored V8 object (don't call from within `Execute()`) - Local GetFromPersistent(const char *key); - - // Get the error message (or NULL) - const char *ErrorMessage(); - - // Set an error message - void SetErrorMessage(const char *msg); - -protected: - // Default implementation calls the callback function with no arguments. - // Override this to return meaningful data - virtual void HandleOKCallback (); - - // Default implementation calls the callback function with an Error object - // wrapping the `errmsg` string - virtual void HandleErrorCallback (); -}; -``` - - -### NanAsyncQueueWorker(NanAsyncWorker *) - -`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`. - - -### Tests - -To run the NAN tests do: - -``` sh -npm install -npm run-script rebuild-tests -npm test -``` - -Or just: - -``` sh -npm install -make test -``` - -### Contributors - -NAN is only possible due to the excellent work of the following contributors: - - - - - - - - - -
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnat-
- -Licence & copyright ------------------------ - -Copyright (c) 2015 NAN contributors (listed above). - -Native Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/scripts/external/three/canvas/node_modules/nan/appveyor.yml b/scripts/external/three/canvas/node_modules/nan/appveyor.yml deleted file mode 100644 index 8a331b4..0000000 --- a/scripts/external/three/canvas/node_modules/nan/appveyor.yml +++ /dev/null @@ -1,35 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml - -# Test against these versions of Node.js. -environment: - matrix: - # node.js - - nodejs_version: "0.8" - - nodejs_version: "0.10" - - nodejs_version: "0.11" - # io.js - - nodejs_version: "1.0" - -# Install scripts. (runs after repo cloning) -install: - # Get the latest stable version of Node 0.STABLE.latest - - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) - - IF NOT %nodejs_version% == 1.0 npm -g install npm - - IF NOT %nodejs_version% == 1.0 set PATH=%APPDATA%\npm;%PATH% - # Typical npm stuff. - - npm install - - npm run rebuild-tests - -# Post-install test scripts. -test_script: - # Output useful info for debugging. - - node --version - - npm --version - # run tests - - npm test - -# Don't actually build. -build: off - -# Set build version format here instead of in the admin panel. -version: "{build}" diff --git a/scripts/external/three/canvas/node_modules/nan/include_dirs.js b/scripts/external/three/canvas/node_modules/nan/include_dirs.js deleted file mode 100644 index 4f1dfb4..0000000 --- a/scripts/external/three/canvas/node_modules/nan/include_dirs.js +++ /dev/null @@ -1 +0,0 @@ -console.log(require('path').relative('.', __dirname)); diff --git a/scripts/external/three/canvas/node_modules/nan/nan.h b/scripts/external/three/canvas/node_modules/nan/nan.h deleted file mode 100644 index 531b3ac..0000000 --- a/scripts/external/three/canvas/node_modules/nan/nan.h +++ /dev/null @@ -1,2038 +0,0 @@ -/********************************************************************* - * NAN - Native Abstractions for Node.js - * - * Copyright (c) 2015 NAN contributors: - * - Rod Vagg - * - Benjamin Byholm - * - Trevor Norris - * - Nathan Rajlich - * - Brett Lawson - * - Ben Noordhuis - * - David Siegel - * - * MIT License - * - * Version 1.5.2: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3 - * - * See https://github.com/rvagg/nan for the latest update to this file - **********************************************************************************/ - -#ifndef NAN_H_ -#define NAN_H_ - -#include -#include -#include -#include -#include -#include -#include -#if defined(_MSC_VER) -# pragma warning( disable : 4530 ) -# include -# pragma warning( default : 4530 ) -#else -# include -#endif - -#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) -# define NAN_INLINE inline __attribute__((always_inline)) -#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) -# define NAN_INLINE __forceinline -#else -# define NAN_INLINE inline -#endif - -#if defined(__GNUC__) && \ - !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) -# define NAN_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) && \ - !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) -# define NAN_DEPRECATED __declspec(deprecated) -#else -# define NAN_DEPRECATED -#endif - -#if (NODE_MODULE_VERSION < 12) -typedef v8::InvocationCallback NanFunctionCallback; -typedef v8::Script NanUnboundScript; -typedef v8::Script NanBoundScript; -#else -typedef v8::FunctionCallback NanFunctionCallback; -typedef v8::UnboundScript NanUnboundScript; -typedef v8::Script NanBoundScript; -#endif - -#if (NODE_MODULE_VERSION < 42) -typedef v8::String::ExternalAsciiStringResource - NanExternalOneByteStringResource; -#else // io.js v1.0.0 -typedef v8::String::ExternalOneByteStringResource - NanExternalOneByteStringResource; -#endif - -#include "nan_new.h" // NOLINT(build/include) - -// uv helpers -#ifdef UV_VERSION_MAJOR -#ifndef UV_VERSION_PATCH -#define UV_VERSION_PATCH 0 -#endif -#define NAUV_UVVERSION ((UV_VERSION_MAJOR << 16) | \ - (UV_VERSION_MINOR << 8) | \ - (UV_VERSION_PATCH)) -#else -#define NAUV_UVVERSION 0x000b00 -#endif - - -#if NAUV_UVVERSION < 0x000b17 -#define NAUV_WORK_CB(func) \ - void func(uv_async_t *async, int) -#else -#define NAUV_WORK_CB(func) \ - void func(uv_async_t *async) -#endif - -// some generic helpers - -template NAN_INLINE bool NanSetPointerSafe( - T *var - , T val -) { - if (var) { - *var = val; - return true; - } else { - return false; - } -} - -template NAN_INLINE T NanGetPointerSafe( - T *var - , T fallback = reinterpret_cast(0) -) { - if (var) { - return *var; - } else { - return fallback; - } -} - -NAN_INLINE bool NanBooleanOptionValue( - v8::Local optionsObj - , v8::Handle opt, bool def -) { - if (def) { - return optionsObj.IsEmpty() - || !optionsObj->Has(opt) - || optionsObj->Get(opt)->BooleanValue(); - } else { - return !optionsObj.IsEmpty() - && optionsObj->Has(opt) - && optionsObj->Get(opt)->BooleanValue(); - } -} - -NAN_INLINE bool NanBooleanOptionValue( - v8::Local optionsObj - , v8::Handle opt -) { - return NanBooleanOptionValue(optionsObj, opt, false); -} - -NAN_INLINE uint32_t NanUInt32OptionValue( - v8::Local optionsObj - , v8::Handle opt - , uint32_t def -) { - return !optionsObj.IsEmpty() - && optionsObj->Has(opt) - && optionsObj->Get(opt)->IsNumber() - ? optionsObj->Get(opt)->Uint32Value() - : def; -} - -template -v8::Local NanNew(v8::Handle); - -template -NAN_INLINE v8::Local _NanEnsureLocal(v8::Handle val) { - return NanNew(val); -} - -template -NAN_INLINE v8::Local _NanEnsureLocal(v8::Local val) { - return val; -} - -#if (NODE_MODULE_VERSION > 0x000B) -// Node 0.11+ (0.11.12 and below won't compile with these) - -# define _NAN_METHOD_ARGS_TYPE const v8::FunctionCallbackInfo& -# define _NAN_METHOD_ARGS _NAN_METHOD_ARGS_TYPE args -# define _NAN_METHOD_RETURN_TYPE void - -# define _NAN_GETTER_ARGS_TYPE const v8::PropertyCallbackInfo& -# define _NAN_GETTER_ARGS _NAN_GETTER_ARGS_TYPE args -# define _NAN_GETTER_RETURN_TYPE void - -# define _NAN_SETTER_ARGS_TYPE const v8::PropertyCallbackInfo& -# define _NAN_SETTER_ARGS _NAN_SETTER_ARGS_TYPE args -# define _NAN_SETTER_RETURN_TYPE void - -# define _NAN_PROPERTY_GETTER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_PROPERTY_GETTER_ARGS _NAN_PROPERTY_GETTER_ARGS_TYPE args -# define _NAN_PROPERTY_GETTER_RETURN_TYPE void - -# define _NAN_PROPERTY_SETTER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_PROPERTY_SETTER_ARGS _NAN_PROPERTY_SETTER_ARGS_TYPE args -# define _NAN_PROPERTY_SETTER_RETURN_TYPE void - -# define _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_PROPERTY_ENUMERATOR_ARGS _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE args -# define _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE void - -# define _NAN_PROPERTY_DELETER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_PROPERTY_DELETER_ARGS \ - _NAN_PROPERTY_DELETER_ARGS_TYPE args -# define _NAN_PROPERTY_DELETER_RETURN_TYPE void - -# define _NAN_PROPERTY_QUERY_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_PROPERTY_QUERY_ARGS _NAN_PROPERTY_QUERY_ARGS_TYPE args -# define _NAN_PROPERTY_QUERY_RETURN_TYPE void - -# define _NAN_INDEX_GETTER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_INDEX_GETTER_ARGS _NAN_INDEX_GETTER_ARGS_TYPE args -# define _NAN_INDEX_GETTER_RETURN_TYPE void - -# define _NAN_INDEX_SETTER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_INDEX_SETTER_ARGS _NAN_INDEX_SETTER_ARGS_TYPE args -# define _NAN_INDEX_SETTER_RETURN_TYPE void - -# define _NAN_INDEX_ENUMERATOR_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_INDEX_ENUMERATOR_ARGS _NAN_INDEX_ENUMERATOR_ARGS_TYPE args -# define _NAN_INDEX_ENUMERATOR_RETURN_TYPE void - -# define _NAN_INDEX_DELETER_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_INDEX_DELETER_ARGS _NAN_INDEX_DELETER_ARGS_TYPE args -# define _NAN_INDEX_DELETER_RETURN_TYPE void - -# define _NAN_INDEX_QUERY_ARGS_TYPE \ - const v8::PropertyCallbackInfo& -# define _NAN_INDEX_QUERY_ARGS _NAN_INDEX_QUERY_ARGS_TYPE args -# define _NAN_INDEX_QUERY_RETURN_TYPE void - -# define NanScope() v8::HandleScope scope(v8::Isolate::GetCurrent()) -# define NanEscapableScope() \ - v8::EscapableHandleScope scope(v8::Isolate::GetCurrent()) - -# define NanEscapeScope(val) scope.Escape(_NanEnsureLocal(val)) -# define NanLocker() v8::Locker locker(v8::Isolate::GetCurrent()) -# define NanUnlocker() v8::Unlocker unlocker(v8::Isolate::GetCurrent()) -# define NanReturnValue(value) return args.GetReturnValue().Set(value) -# define NanReturnUndefined() return -# define NanReturnHolder() NanReturnValue(args.Holder()) -# define NanReturnThis() NanReturnValue(args.This()) -# define NanReturnNull() return args.GetReturnValue().SetNull() -# define NanReturnEmptyString() return args.GetReturnValue().SetEmptyString() - -# define NanObjectWrapHandle(obj) obj->handle() - - NAN_INLINE v8::Local NanUndefined() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::Undefined(v8::Isolate::GetCurrent()))); - } - - NAN_INLINE v8::Local NanNull() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::Null(v8::Isolate::GetCurrent()))); - } - - NAN_INLINE v8::Local NanTrue() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::True(v8::Isolate::GetCurrent()))); - } - - NAN_INLINE v8::Local NanFalse() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::False(v8::Isolate::GetCurrent()))); - } - - NAN_INLINE int NanAdjustExternalMemory(int bc) { - return static_cast( - v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(bc)); - } - - NAN_INLINE void NanSetTemplate( - v8::Handle templ - , const char *name - , v8::Handle value) { - templ->Set(v8::Isolate::GetCurrent(), name, value); - } - - NAN_INLINE void NanSetTemplate( - v8::Handle templ - , v8::Handle name - , v8::Handle value - , v8::PropertyAttribute attributes) { - templ->Set(name, value, attributes); - } - - NAN_INLINE v8::Local NanGetCurrentContext() { - return v8::Isolate::GetCurrent()->GetCurrentContext(); - } - - NAN_INLINE void* NanGetInternalFieldPointer( - v8::Handle object - , int index) { - return object->GetAlignedPointerFromInternalField(index); - } - - NAN_INLINE void NanSetInternalFieldPointer( - v8::Handle object - , int index - , void* value) { - object->SetAlignedPointerInInternalField(index, value); - } - -# define NAN_GC_CALLBACK(name) \ - void name(v8::Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags) - - NAN_INLINE void NanAddGCEpilogueCallback( - v8::Isolate::GCEpilogueCallback callback - , v8::GCType gc_type_filter = v8::kGCTypeAll) { - v8::Isolate::GetCurrent()->AddGCEpilogueCallback(callback, gc_type_filter); - } - - NAN_INLINE void NanRemoveGCEpilogueCallback( - v8::Isolate::GCEpilogueCallback callback) { - v8::Isolate::GetCurrent()->RemoveGCEpilogueCallback(callback); - } - - NAN_INLINE void NanAddGCPrologueCallback( - v8::Isolate::GCPrologueCallback callback - , v8::GCType gc_type_filter = v8::kGCTypeAll) { - v8::Isolate::GetCurrent()->AddGCPrologueCallback(callback, gc_type_filter); - } - - NAN_INLINE void NanRemoveGCPrologueCallback( - v8::Isolate::GCPrologueCallback callback) { - v8::Isolate::GetCurrent()->RemoveGCPrologueCallback(callback); - } - - NAN_INLINE void NanGetHeapStatistics( - v8::HeapStatistics *heap_statistics) { - v8::Isolate::GetCurrent()->GetHeapStatistics(heap_statistics); - } - - NAN_DEPRECATED NAN_INLINE v8::Local NanSymbol( - const char* data, int length = -1) { - return NanNew(data, length); - } - - template - NAN_INLINE void NanAssignPersistent( - v8::Persistent& handle - , v8::Handle obj) { - handle.Reset(v8::Isolate::GetCurrent(), obj); - } - - template - NAN_INLINE void NanAssignPersistent( - v8::Persistent& handle - , const v8::Persistent& obj) { - handle.Reset(v8::Isolate::GetCurrent(), obj); - } - - template - class _NanWeakCallbackData; - - template - struct _NanWeakCallbackInfo { - typedef void (*Callback)(const _NanWeakCallbackData& data); - NAN_INLINE _NanWeakCallbackInfo(v8::Handle handle, P* param, Callback cb) - : parameter(param), callback(cb) { - NanAssignPersistent(persistent, handle); - } - - NAN_INLINE ~_NanWeakCallbackInfo() { - persistent.Reset(); - } - - P* const parameter; - Callback const callback; - v8::Persistent persistent; - }; - - template - class _NanWeakCallbackData { - public: - NAN_INLINE _NanWeakCallbackData(_NanWeakCallbackInfo *info) - : info_(info) { } - - NAN_INLINE v8::Local GetValue() const { - return NanNew(info_->persistent); - } - - NAN_INLINE P* GetParameter() const { return info_->parameter; } - - NAN_INLINE bool IsNearDeath() const { - return info_->persistent.IsNearDeath(); - } - - NAN_INLINE void Revive() const; - - NAN_INLINE _NanWeakCallbackInfo* GetCallbackInfo() const { - return info_; - } - - NAN_DEPRECATED NAN_INLINE void Dispose() const { - } - - private: - _NanWeakCallbackInfo* info_; - }; - - template - static void _NanWeakCallbackDispatcher( - const v8::WeakCallbackData > &data) { - _NanWeakCallbackInfo *info = data.GetParameter(); - _NanWeakCallbackData wcbd(info); - info->callback(wcbd); - if (wcbd.IsNearDeath()) { - delete wcbd.GetCallbackInfo(); - } - } - - template - NAN_INLINE void _NanWeakCallbackData::Revive() const { - info_->persistent.SetWeak(info_, &_NanWeakCallbackDispatcher); - } - -template -NAN_INLINE _NanWeakCallbackInfo* NanMakeWeakPersistent( - v8::Handle handle - , P* parameter - , typename _NanWeakCallbackInfo::Callback callback) { - _NanWeakCallbackInfo *cbinfo = - new _NanWeakCallbackInfo(handle, parameter, callback); - cbinfo->persistent.SetWeak(cbinfo, &_NanWeakCallbackDispatcher); - return cbinfo; -} - -# define NAN_WEAK_CALLBACK(name) \ - template \ - static void name(const _NanWeakCallbackData &data) - -# define _NAN_ERROR(fun, errmsg) fun(NanNew(errmsg)) - -# define _NAN_THROW_ERROR(fun, errmsg) \ - do { \ - NanScope(); \ - v8::Isolate::GetCurrent()->ThrowException(_NAN_ERROR(fun, errmsg)); \ - } while (0); - - NAN_INLINE v8::Local NanError(const char* errmsg) { - return _NAN_ERROR(v8::Exception::Error, errmsg); - } - - NAN_INLINE void NanThrowError(const char* errmsg) { - _NAN_THROW_ERROR(v8::Exception::Error, errmsg); - } - - NAN_INLINE void NanThrowError(v8::Handle error) { - NanScope(); - v8::Isolate::GetCurrent()->ThrowException(error); - } - - NAN_INLINE v8::Local NanError( - const char *msg - , const int errorNumber - ) { - v8::Local err = v8::Exception::Error(NanNew(msg)); - v8::Local obj = err.As(); - obj->Set(NanNew("code"), NanNew(errorNumber)); - return err; - } - - NAN_INLINE void NanThrowError( - const char *msg - , const int errorNumber - ) { - NanThrowError(NanError(msg, errorNumber)); - } - - NAN_INLINE v8::Local NanTypeError(const char* errmsg) { - return _NAN_ERROR(v8::Exception::TypeError, errmsg); - } - - NAN_INLINE void NanThrowTypeError(const char* errmsg) { - _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); - } - - NAN_INLINE v8::Local NanRangeError(const char* errmsg) { - return _NAN_ERROR(v8::Exception::RangeError, errmsg); - } - - NAN_INLINE void NanThrowRangeError(const char* errmsg) { - _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); - } - - template NAN_INLINE void NanDisposePersistent( - v8::Persistent &handle - ) { - handle.Reset(); - } - - NAN_INLINE v8::Local NanNewBufferHandle ( - char *data - , size_t length - , node::smalloc::FreeCallback callback - , void *hint - ) { - return node::Buffer::New( - v8::Isolate::GetCurrent(), data, length, callback, hint); - } - - NAN_INLINE v8::Local NanNewBufferHandle ( - const char *data - , uint32_t size - ) { - return node::Buffer::New(v8::Isolate::GetCurrent(), data, size); - } - - NAN_INLINE v8::Local NanNewBufferHandle (uint32_t size) { - return node::Buffer::New(v8::Isolate::GetCurrent(), size); - } - - NAN_INLINE v8::Local NanBufferUse( - char* data - , uint32_t size - ) { - return node::Buffer::Use(v8::Isolate::GetCurrent(), data, size); - } - - NAN_INLINE bool NanHasInstance( - const v8::Persistent& function_template - , v8::Handle value - ) { - return NanNew(function_template)->HasInstance(value); - } - - NAN_INLINE v8::Local NanNewContextHandle( - v8::ExtensionConfiguration* extensions = NULL - , v8::Handle tmpl = v8::Handle() - , v8::Handle obj = v8::Handle() - ) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - return v8::Local::New( - isolate - , v8::Context::New(isolate, extensions, tmpl, obj) - ); - } - - NAN_INLINE v8::Local NanCompileScript( - v8::Local s - , const v8::ScriptOrigin& origin - ) { - v8::ScriptCompiler::Source source(s, origin); - return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); - } - - NAN_INLINE v8::Local NanCompileScript( - v8::Local s - ) { - v8::ScriptCompiler::Source source(s); - return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); - } - - NAN_INLINE v8::Local NanRunScript( - v8::Handle script - ) { - return script->BindToCurrentContext()->Run(); - } - - NAN_INLINE v8::Local NanRunScript( - v8::Handle script - ) { - return script->Run(); - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , v8::Handle func - , int argc - , v8::Handle* argv) { - return NanNew(node::MakeCallback( - v8::Isolate::GetCurrent(), target, func, argc, argv)); - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , v8::Handle symbol - , int argc - , v8::Handle* argv) { - return NanNew(node::MakeCallback( - v8::Isolate::GetCurrent(), target, symbol, argc, argv)); - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , const char* method - , int argc - , v8::Handle* argv) { - return NanNew(node::MakeCallback( - v8::Isolate::GetCurrent(), target, method, argc, argv)); - } - - template - NAN_INLINE void NanSetIsolateData( - v8::Isolate *isolate - , T *data - ) { - isolate->SetData(0, data); - } - - template - NAN_INLINE T *NanGetIsolateData( - v8::Isolate *isolate - ) { - return static_cast(isolate->GetData(0)); - } - - class NanAsciiString { - public: - NAN_INLINE explicit NanAsciiString(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Length(); - buf = new char[size + 1]; - size = toStr->WriteOneByte(reinterpret_cast(buf)); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - - NAN_INLINE char* operator*() { return buf; } - NAN_INLINE const char* operator*() const { return buf; } - - NAN_INLINE ~NanAsciiString() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanAsciiString(const NanAsciiString&); - void operator=(const NanAsciiString&); - - char *buf; - int size; - }; - - class NanUtf8String { - public: - NAN_INLINE explicit NanUtf8String(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Utf8Length(); - buf = new char[size + 1]; - toStr->WriteUtf8(buf); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - NAN_INLINE char* operator*() { return buf; } - NAN_INLINE const char* operator*() const { return buf; } - - NAN_INLINE ~NanUtf8String() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanUtf8String(const NanUtf8String&); - void operator=(const NanUtf8String&); - - char *buf; - int size; - }; - - class NanUcs2String { - public: - NAN_INLINE explicit NanUcs2String(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Length(); - buf = new uint16_t[size + 1]; - toStr->Write(buf); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - NAN_INLINE uint16_t* operator*() { return buf; } - NAN_INLINE const uint16_t* operator*() const { return buf; } - - NAN_INLINE ~NanUcs2String() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanUcs2String(const NanUcs2String&); - void operator=(const NanUcs2String&); - - uint16_t *buf; - int size; - }; - -#else -// Node 0.8 and 0.10 - -# define _NAN_METHOD_ARGS_TYPE const v8::Arguments& -# define _NAN_METHOD_ARGS _NAN_METHOD_ARGS_TYPE args -# define _NAN_METHOD_RETURN_TYPE v8::Handle - -# define _NAN_GETTER_ARGS_TYPE const v8::AccessorInfo & -# define _NAN_GETTER_ARGS _NAN_GETTER_ARGS_TYPE args -# define _NAN_GETTER_RETURN_TYPE v8::Handle - -# define _NAN_SETTER_ARGS_TYPE const v8::AccessorInfo & -# define _NAN_SETTER_ARGS _NAN_SETTER_ARGS_TYPE args -# define _NAN_SETTER_RETURN_TYPE void - -# define _NAN_PROPERTY_GETTER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_PROPERTY_GETTER_ARGS _NAN_PROPERTY_GETTER_ARGS_TYPE args -# define _NAN_PROPERTY_GETTER_RETURN_TYPE v8::Handle - -# define _NAN_PROPERTY_SETTER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_PROPERTY_SETTER_ARGS _NAN_PROPERTY_SETTER_ARGS_TYPE args -# define _NAN_PROPERTY_SETTER_RETURN_TYPE v8::Handle - -# define _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_PROPERTY_ENUMERATOR_ARGS _NAN_PROPERTY_ENUMERATOR_ARGS_TYPE args -# define _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE v8::Handle - -# define _NAN_PROPERTY_DELETER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_PROPERTY_DELETER_ARGS _NAN_PROPERTY_DELETER_ARGS_TYPE args -# define _NAN_PROPERTY_DELETER_RETURN_TYPE v8::Handle - -# define _NAN_PROPERTY_QUERY_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_PROPERTY_QUERY_ARGS _NAN_PROPERTY_QUERY_ARGS_TYPE args -# define _NAN_PROPERTY_QUERY_RETURN_TYPE v8::Handle - -# define _NAN_INDEX_GETTER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_INDEX_GETTER_ARGS _NAN_INDEX_GETTER_ARGS_TYPE args -# define _NAN_INDEX_GETTER_RETURN_TYPE v8::Handle - -# define _NAN_INDEX_SETTER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_INDEX_SETTER_ARGS _NAN_INDEX_SETTER_ARGS_TYPE args -# define _NAN_INDEX_SETTER_RETURN_TYPE v8::Handle - -# define _NAN_INDEX_ENUMERATOR_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_INDEX_ENUMERATOR_ARGS _NAN_INDEX_ENUMERATOR_ARGS_TYPE args -# define _NAN_INDEX_ENUMERATOR_RETURN_TYPE v8::Handle - -# define _NAN_INDEX_DELETER_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_INDEX_DELETER_ARGS _NAN_INDEX_DELETER_ARGS_TYPE args -# define _NAN_INDEX_DELETER_RETURN_TYPE v8::Handle - -# define _NAN_INDEX_QUERY_ARGS_TYPE const v8::AccessorInfo& -# define _NAN_INDEX_QUERY_ARGS _NAN_INDEX_QUERY_ARGS_TYPE args -# define _NAN_INDEX_QUERY_RETURN_TYPE v8::Handle - - NAN_DEPRECATED NAN_INLINE v8::Local NanSymbol( - const char* data, int length = -1) { - return v8::String::NewSymbol(data, length); - } - -# define NanScope() v8::HandleScope scope -# define NanEscapableScope() v8::HandleScope scope -# define NanEscapeScope(val) scope.Close(val) -# define NanLocker() v8::Locker locker -# define NanUnlocker() v8::Unlocker unlocker -# define NanReturnValue(value) return scope.Close(value) -# define NanReturnHolder() NanReturnValue(args.Holder()) -# define NanReturnThis() NanReturnValue(args.This()) -# define NanReturnUndefined() return v8::Undefined() -# define NanReturnNull() return v8::Null() -# define NanReturnEmptyString() return v8::String::Empty() -# define NanObjectWrapHandle(obj) v8::Local::New(obj->handle_) - - NAN_INLINE v8::Local NanUndefined() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::Undefined())); - } - - NAN_INLINE v8::Local NanNull() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::Null())); - } - - NAN_INLINE v8::Local NanTrue() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::True())); - } - - NAN_INLINE v8::Local NanFalse() { - NanEscapableScope(); - return NanEscapeScope(NanNew(v8::False())); - } - - NAN_INLINE int NanAdjustExternalMemory(int bc) { - return static_cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(bc)); - } - - NAN_INLINE void NanSetTemplate( - v8::Handle templ - , const char *name - , v8::Handle value) { - templ->Set(name, value); - } - - NAN_INLINE void NanSetTemplate( - v8::Handle templ - , v8::Handle name - , v8::Handle value - , v8::PropertyAttribute attributes) { - templ->Set(name, value, attributes); - } - - NAN_INLINE v8::Local NanGetCurrentContext() { - return v8::Context::GetCurrent(); - } - - NAN_INLINE void* NanGetInternalFieldPointer( - v8::Handle object - , int index) { - return object->GetPointerFromInternalField(index); - } - - NAN_INLINE void NanSetInternalFieldPointer( - v8::Handle object - , int index - , void* value) { - object->SetPointerInInternalField(index, value); - } - -# define NAN_GC_CALLBACK(name) \ - void name(v8::GCType type, v8::GCCallbackFlags flags) - - NAN_INLINE void NanAddGCEpilogueCallback( - v8::GCEpilogueCallback callback - , v8::GCType gc_type_filter = v8::kGCTypeAll) { - v8::V8::AddGCEpilogueCallback(callback, gc_type_filter); - } - NAN_INLINE void NanRemoveGCEpilogueCallback( - v8::GCEpilogueCallback callback) { - v8::V8::RemoveGCEpilogueCallback(callback); - } - NAN_INLINE void NanAddGCPrologueCallback( - v8::GCPrologueCallback callback - , v8::GCType gc_type_filter = v8::kGCTypeAll) { - v8::V8::AddGCPrologueCallback(callback, gc_type_filter); - } - NAN_INLINE void NanRemoveGCPrologueCallback( - v8::GCPrologueCallback callback) { - v8::V8::RemoveGCPrologueCallback(callback); - } - NAN_INLINE void NanGetHeapStatistics( - v8::HeapStatistics *heap_statistics) { - v8::V8::GetHeapStatistics(heap_statistics); - } - - template - NAN_INLINE void NanAssignPersistent( - v8::Persistent& handle - , v8::Handle obj) { - handle.Dispose(); - handle = v8::Persistent::New(obj); - } - - template - class _NanWeakCallbackData; - - template - struct _NanWeakCallbackInfo { - typedef void (*Callback)(const _NanWeakCallbackData &data); - NAN_INLINE _NanWeakCallbackInfo(v8::Handle handle, P* param, Callback cb) - : parameter(param) - , callback(cb) - , persistent(v8::Persistent::New(handle)) { } - - NAN_INLINE ~_NanWeakCallbackInfo() { - persistent.Dispose(); - persistent.Clear(); - } - - P* const parameter; - Callback const callback; - v8::Persistent persistent; - }; - - template - class _NanWeakCallbackData { - public: - NAN_INLINE _NanWeakCallbackData(_NanWeakCallbackInfo *info) - : info_(info) { } - - NAN_INLINE v8::Local GetValue() const { - return NanNew(info_->persistent); - } - - NAN_INLINE P* GetParameter() const { return info_->parameter; } - - NAN_INLINE bool IsNearDeath() const { - return info_->persistent.IsNearDeath(); - } - - NAN_INLINE void Revive() const; - - NAN_INLINE _NanWeakCallbackInfo* GetCallbackInfo() const { - return info_; - } - - NAN_DEPRECATED NAN_INLINE void Dispose() const { - } - - private: - _NanWeakCallbackInfo* info_; - }; - - template - static void _NanWeakPersistentDispatcher( - v8::Persistent object, void *data) { - _NanWeakCallbackInfo* info = - static_cast<_NanWeakCallbackInfo*>(data); - _NanWeakCallbackData wcbd(info); - info->callback(wcbd); - if (wcbd.IsNearDeath()) { - delete wcbd.GetCallbackInfo(); - } - } - - template - NAN_INLINE void _NanWeakCallbackData::Revive() const { - info_->persistent.MakeWeak( - info_ - , &_NanWeakPersistentDispatcher); - } - - template - NAN_INLINE _NanWeakCallbackInfo* NanMakeWeakPersistent( - v8::Handle handle - , P* parameter - , typename _NanWeakCallbackInfo::Callback callback) { - _NanWeakCallbackInfo *cbinfo = - new _NanWeakCallbackInfo(handle, parameter, callback); - cbinfo->persistent.MakeWeak( - cbinfo - , &_NanWeakPersistentDispatcher); - return cbinfo; - } - -# define NAN_WEAK_CALLBACK(name) \ - template \ - static void name(const _NanWeakCallbackData &data) - -# define _NAN_ERROR(fun, errmsg) \ - fun(v8::String::New(errmsg)) - -# define _NAN_THROW_ERROR(fun, errmsg) \ - do { \ - NanScope(); \ - return v8::Local::New( \ - v8::ThrowException(_NAN_ERROR(fun, errmsg))); \ - } while (0); - - NAN_INLINE v8::Local NanError(const char* errmsg) { - return _NAN_ERROR(v8::Exception::Error, errmsg); - } - - NAN_INLINE v8::Local NanThrowError(const char* errmsg) { - _NAN_THROW_ERROR(v8::Exception::Error, errmsg); - } - - NAN_INLINE v8::Local NanThrowError( - v8::Handle error - ) { - NanScope(); - return v8::Local::New(v8::ThrowException(error)); - } - - NAN_INLINE v8::Local NanError( - const char *msg - , const int errorNumber - ) { - v8::Local err = v8::Exception::Error(v8::String::New(msg)); - v8::Local obj = err.As(); - obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber)); - return err; - } - - NAN_INLINE v8::Local NanThrowError( - const char *msg - , const int errorNumber - ) { - return NanThrowError(NanError(msg, errorNumber)); - } - - NAN_INLINE v8::Local NanTypeError(const char* errmsg) { - return _NAN_ERROR(v8::Exception::TypeError, errmsg); - } - - NAN_INLINE v8::Local NanThrowTypeError( - const char* errmsg - ) { - _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg); - } - - NAN_INLINE v8::Local NanRangeError( - const char* errmsg - ) { - return _NAN_ERROR(v8::Exception::RangeError, errmsg); - } - - NAN_INLINE v8::Local NanThrowRangeError( - const char* errmsg - ) { - _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg); - } - - template - NAN_INLINE void NanDisposePersistent( - v8::Persistent &handle) { // NOLINT(runtime/references) - handle.Dispose(); - handle.Clear(); - } - - NAN_INLINE v8::Local NanNewBufferHandle ( - char *data - , size_t length - , node::Buffer::free_callback callback - , void *hint - ) { - return NanNew( - node::Buffer::New(data, length, callback, hint)->handle_); - } - - NAN_INLINE v8::Local NanNewBufferHandle ( - const char *data - , uint32_t size - ) { -#if NODE_MODULE_VERSION >= 0x000B - return NanNew(node::Buffer::New(data, size)->handle_); -#else - return NanNew( - node::Buffer::New(const_cast(data), size)->handle_); -#endif - } - - NAN_INLINE v8::Local NanNewBufferHandle (uint32_t size) { - return NanNew(node::Buffer::New(size)->handle_); - } - - NAN_INLINE void FreeData(char *data, void *hint) { - delete[] data; - } - - NAN_INLINE v8::Local NanBufferUse( - char* data - , uint32_t size - ) { - return NanNew( - node::Buffer::New(data, size, FreeData, NULL)->handle_); - } - - NAN_INLINE bool NanHasInstance( - const v8::Persistent& function_template - , v8::Handle value - ) { - return function_template->HasInstance(value); - } - - NAN_INLINE v8::Local NanNewContextHandle( - v8::ExtensionConfiguration* extensions = NULL - , v8::Handle tmpl = v8::Handle() - , v8::Handle obj = v8::Handle() - ) { - v8::Persistent ctx = v8::Context::New(extensions, tmpl, obj); - v8::Local lctx = NanNew(ctx); - ctx.Dispose(); - return lctx; - } - - NAN_INLINE v8::Local NanCompileScript( - v8::Local s - , const v8::ScriptOrigin& origin - ) { - return v8::Script::Compile(s, const_cast(&origin)); - } - - NAN_INLINE v8::Local NanCompileScript( - v8::Local s - ) { - return v8::Script::Compile(s); - } - - NAN_INLINE v8::Local NanRunScript(v8::Handle script) { - return script->Run(); - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , v8::Handle func - , int argc - , v8::Handle* argv) { -# if NODE_VERSION_AT_LEAST(0, 8, 0) - return NanNew(node::MakeCallback(target, func, argc, argv)); -# else - v8::TryCatch try_catch; - v8::Local result = func->Call(target, argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - return result; -# endif - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , v8::Handle symbol - , int argc - , v8::Handle* argv) { -# if NODE_VERSION_AT_LEAST(0, 8, 0) - return NanNew(node::MakeCallback(target, symbol, argc, argv)); -# else - v8::Local callback = target->Get(symbol).As(); - return NanMakeCallback(target, callback, argc, argv); -# endif - } - - NAN_INLINE v8::Local NanMakeCallback( - v8::Handle target - , const char* method - , int argc - , v8::Handle* argv) { -# if NODE_VERSION_AT_LEAST(0, 8, 0) - return NanNew(node::MakeCallback(target, method, argc, argv)); -# else - return NanMakeCallback(target, NanNew(method), argc, argv); -# endif - } - - template - NAN_INLINE void NanSetIsolateData( - v8::Isolate *isolate - , T *data - ) { - isolate->SetData(data); - } - - template - NAN_INLINE T *NanGetIsolateData( - v8::Isolate *isolate - ) { - return static_cast(isolate->GetData()); - } - - class NanAsciiString { - public: - NAN_INLINE explicit NanAsciiString(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Length(); - buf = new char[size + 1]; - size = toStr->WriteAscii(buf); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - - NAN_INLINE char* operator*() { return buf; } - NAN_INLINE const char* operator*() const { return buf; } - - NAN_INLINE ~NanAsciiString() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanAsciiString(const NanAsciiString&); - void operator=(const NanAsciiString&); - - char *buf; - int size; - }; - - class NanUtf8String { - public: - NAN_INLINE explicit NanUtf8String(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Utf8Length(); - buf = new char[size + 1]; - toStr->WriteUtf8(buf); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - NAN_INLINE char* operator*() { return buf; } - NAN_INLINE const char* operator*() const { return buf; } - - NAN_INLINE ~NanUtf8String() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanUtf8String(const NanUtf8String&); - void operator=(const NanUtf8String&); - - char *buf; - int size; - }; - - class NanUcs2String { - public: - NAN_INLINE explicit NanUcs2String(v8::Handle from) { - v8::Local toStr = from->ToString(); - size = toStr->Length(); - buf = new uint16_t[size + 1]; - toStr->Write(buf); - } - - NAN_DEPRECATED NAN_INLINE int Size() const { - return size; - } - - NAN_INLINE int length() const { - return size; - } - - NAN_INLINE uint16_t* operator*() { return buf; } - NAN_INLINE const uint16_t* operator*() const { return buf; } - - NAN_INLINE ~NanUcs2String() { - delete[] buf; - } - - private: - // disallow copying and assigning - NanUcs2String(const NanUcs2String&); - void operator=(const NanUcs2String&); - - uint16_t *buf; - int size; - }; - -#endif // NODE_MODULE_VERSION - -typedef void (*NanFreeCallback)(char *data, void *hint); - -#define NAN_METHOD(name) _NAN_METHOD_RETURN_TYPE name(_NAN_METHOD_ARGS) -#define NAN_GETTER(name) \ - _NAN_GETTER_RETURN_TYPE name( \ - v8::Local property \ - , _NAN_GETTER_ARGS) -#define NAN_SETTER(name) \ - _NAN_SETTER_RETURN_TYPE name( \ - v8::Local property \ - , v8::Local value \ - , _NAN_SETTER_ARGS) -#define NAN_PROPERTY_GETTER(name) \ - _NAN_PROPERTY_GETTER_RETURN_TYPE name( \ - v8::Local property \ - , _NAN_PROPERTY_GETTER_ARGS) -#define NAN_PROPERTY_SETTER(name) \ - _NAN_PROPERTY_SETTER_RETURN_TYPE name( \ - v8::Local property \ - , v8::Local value \ - , _NAN_PROPERTY_SETTER_ARGS) -#define NAN_PROPERTY_ENUMERATOR(name) \ - _NAN_PROPERTY_ENUMERATOR_RETURN_TYPE name(_NAN_PROPERTY_ENUMERATOR_ARGS) -#define NAN_PROPERTY_DELETER(name) \ - _NAN_PROPERTY_DELETER_RETURN_TYPE name( \ - v8::Local property \ - , _NAN_PROPERTY_DELETER_ARGS) -#define NAN_PROPERTY_QUERY(name) \ - _NAN_PROPERTY_QUERY_RETURN_TYPE name( \ - v8::Local property \ - , _NAN_PROPERTY_QUERY_ARGS) -# define NAN_INDEX_GETTER(name) \ - _NAN_INDEX_GETTER_RETURN_TYPE name(uint32_t index, _NAN_INDEX_GETTER_ARGS) -#define NAN_INDEX_SETTER(name) \ - _NAN_INDEX_SETTER_RETURN_TYPE name( \ - uint32_t index \ - , v8::Local value \ - , _NAN_INDEX_SETTER_ARGS) -#define NAN_INDEX_ENUMERATOR(name) \ - _NAN_INDEX_ENUMERATOR_RETURN_TYPE name(_NAN_INDEX_ENUMERATOR_ARGS) -#define NAN_INDEX_DELETER(name) \ - _NAN_INDEX_DELETER_RETURN_TYPE name( \ - uint32_t index \ - , _NAN_INDEX_DELETER_ARGS) -#define NAN_INDEX_QUERY(name) \ - _NAN_INDEX_QUERY_RETURN_TYPE name(uint32_t index, _NAN_INDEX_QUERY_ARGS) - -class NanCallback { - public: - NanCallback() { - NanScope(); - v8::Local obj = NanNew(); - NanAssignPersistent(handle, obj); - } - - explicit NanCallback(const v8::Handle &fn) { - NanScope(); - v8::Local obj = NanNew(); - NanAssignPersistent(handle, obj); - SetFunction(fn); - } - - ~NanCallback() { - if (handle.IsEmpty()) return; - NanDisposePersistent(handle); - } - - NAN_INLINE void SetFunction(const v8::Handle &fn) { - NanScope(); - NanNew(handle)->Set(kCallbackIndex, fn); - } - - NAN_INLINE v8::Local GetFunction() const { - NanEscapableScope(); - return NanEscapeScope(NanNew(handle)->Get(kCallbackIndex) - .As()); - } - - NAN_INLINE bool IsEmpty() const { - NanScope(); - return NanNew(handle)->Get(kCallbackIndex)->IsUndefined(); - } - - v8::Handle Call(int argc, v8::Handle argv[]) const { - NanEscapableScope(); -#if (NODE_MODULE_VERSION > 0x000B) // 0.11.12+ - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Local callback = NanNew(handle)-> - Get(kCallbackIndex).As(); - return NanEscapeScope(node::MakeCallback( - isolate - , isolate->GetCurrentContext()->Global() - , callback - , argc - , argv - )); -#else -#if NODE_VERSION_AT_LEAST(0, 8, 0) - v8::Local callback = handle-> - Get(kCallbackIndex).As(); - return NanEscapeScope(node::MakeCallback( - v8::Context::GetCurrent()->Global() - , callback - , argc - , argv - )); -#else - v8::Local callback = handle-> - Get(kCallbackIndex).As(); - return NanEscapeScope(NanMakeCallback( - v8::Context::GetCurrent()->Global(), callback, argc, argv)); -#endif -#endif - } - - private: - v8::Persistent handle; - static const uint32_t kCallbackIndex = 0; -}; - -/* abstract */ class NanAsyncWorker { - public: - explicit NanAsyncWorker(NanCallback *callback_) - : callback(callback_), errmsg_(NULL) { - request.data = this; - - NanScope(); - v8::Local obj = NanNew(); - NanAssignPersistent(persistentHandle, obj); - } - - virtual ~NanAsyncWorker() { - NanScope(); - - if (!persistentHandle.IsEmpty()) - NanDisposePersistent(persistentHandle); - if (callback) - delete callback; - if (errmsg_) - delete[] errmsg_; - } - - virtual void WorkComplete() { - NanScope(); - - if (errmsg_ == NULL) - HandleOKCallback(); - else - HandleErrorCallback(); - delete callback; - callback = NULL; - } - - NAN_INLINE void SaveToPersistent( - const char *key, const v8::Local &obj) { - v8::Local handle = NanNew(persistentHandle); - handle->Set(NanNew(key), obj); - } - - v8::Local GetFromPersistent(const char *key) const { - NanEscapableScope(); - v8::Local handle = NanNew(persistentHandle); - return NanEscapeScope(handle->Get(NanNew(key)).As()); - } - - virtual void Execute() = 0; - - uv_work_t request; - - virtual void Destroy() { - delete this; - } - - protected: - v8::Persistent persistentHandle; - NanCallback *callback; - - virtual void HandleOKCallback() { - callback->Call(0, NULL); - } - - virtual void HandleErrorCallback() { - NanScope(); - - v8::Local argv[] = { - v8::Exception::Error(NanNew(ErrorMessage())) - }; - callback->Call(1, argv); - } - - void SetErrorMessage(const char *msg) { - if (errmsg_) { - delete[] errmsg_; - } - - size_t size = strlen(msg) + 1; - errmsg_ = new char[size]; - memcpy(errmsg_, msg, size); - } - - const char* ErrorMessage() const { - return errmsg_; - } - - private: - char *errmsg_; -}; - -/* abstract */ class NanAsyncProgressWorker : public NanAsyncWorker { - public: - explicit NanAsyncProgressWorker(NanCallback *callback_) - : NanAsyncWorker(callback_), asyncdata_(NULL), asyncsize_(0) { - async = new uv_async_t; - uv_async_init( - uv_default_loop() - , async - , AsyncProgress_ - ); - async->data = this; - - uv_mutex_init(&async_lock); - } - - virtual ~NanAsyncProgressWorker() { - uv_mutex_destroy(&async_lock); - - if (asyncdata_) { - delete[] asyncdata_; - } - } - - void WorkProgress() { - uv_mutex_lock(&async_lock); - char *data = asyncdata_; - size_t size = asyncsize_; - asyncdata_ = NULL; - uv_mutex_unlock(&async_lock); - - // Dont send progress events after we've already completed. - if (callback) { - HandleProgressCallback(data, size); - } - delete[] data; - } - - class ExecutionProgress { - friend class NanAsyncProgressWorker; - public: - // You could do fancy generics with templates here. - void Send(const char* data, size_t size) const { - that_->SendProgress_(data, size); - } - - private: - explicit ExecutionProgress(NanAsyncProgressWorker* that) : that_(that) {} - // Prohibit copying and assignment. - ExecutionProgress(const ExecutionProgress&); - void operator=(const ExecutionProgress&); - #if __cplusplus >= 201103L - // Prohibit C++11 move semantics. - ExecutionProgress(ExecutionProgress&&) = delete; - void operator=(ExecutionProgress&&) = delete; - #endif - NanAsyncProgressWorker* const that_; - }; - - virtual void Execute(const ExecutionProgress& progress) = 0; - virtual void HandleProgressCallback(const char *data, size_t size) = 0; - - virtual void Destroy() { - uv_close(reinterpret_cast(async), AsyncClose_); - } - - private: - void Execute() /*final override*/ { - ExecutionProgress progress(this); - Execute(progress); - } - - void SendProgress_(const char *data, size_t size) { - char *new_data = new char[size]; - memcpy(new_data, data, size); - - uv_mutex_lock(&async_lock); - char *old_data = asyncdata_; - asyncdata_ = new_data; - asyncsize_ = size; - uv_mutex_unlock(&async_lock); - - if (old_data) { - delete[] old_data; - } - uv_async_send(async); - } - - NAN_INLINE static NAUV_WORK_CB(AsyncProgress_) { - NanAsyncProgressWorker *worker = - static_cast(async->data); - worker->WorkProgress(); - } - - NAN_INLINE static void AsyncClose_(uv_handle_t* handle) { - NanAsyncProgressWorker *worker = - static_cast(handle->data); - delete reinterpret_cast(handle); - delete worker; - } - - uv_async_t *async; - uv_mutex_t async_lock; - char *asyncdata_; - size_t asyncsize_; -}; - -NAN_INLINE void NanAsyncExecute (uv_work_t* req) { - NanAsyncWorker *worker = static_cast(req->data); - worker->Execute(); -} - -NAN_INLINE void NanAsyncExecuteComplete (uv_work_t* req) { - NanAsyncWorker* worker = static_cast(req->data); - worker->WorkComplete(); - worker->Destroy(); -} - -NAN_INLINE void NanAsyncQueueWorker (NanAsyncWorker* worker) { - uv_queue_work( - uv_default_loop() - , &worker->request - , NanAsyncExecute - , (uv_after_work_cb)NanAsyncExecuteComplete - ); -} - -//// Base 64 //// - -#define _nan_base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4) - -// Doesn't check for padding at the end. Can be 1-2 bytes over. -NAN_INLINE size_t _nan_base64_decoded_size_fast(size_t size) { - size_t remainder = size % 4; - - size = (size / 4) * 3; - if (remainder) { - if (size == 0 && remainder == 1) { - // special case: 1-byte input cannot be decoded - size = 0; - } else { - // non-padded input, add 1 or 2 extra bytes - size += 1 + (remainder == 3); - } - } - - return size; -} - -template -NAN_INLINE size_t _nan_base64_decoded_size( - const T* src - , size_t size -) { - if (size == 0) - return 0; - - if (src[size - 1] == '=') - size--; - if (size > 0 && src[size - 1] == '=') - size--; - - return _nan_base64_decoded_size_fast(size); -} - -// supports regular and URL-safe base64 -static const int _nan_unbase64_table[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1 - , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - , -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63 - , 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1 - , -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - , 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63 - , -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 - , 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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, -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, -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, -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, -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 -}; - -#define _nan_unbase64(x) _nan_unbase64_table[(uint8_t)(x)] - -template static size_t _nan_base64_decode( - char* buf - , size_t len - , const T* src - , const size_t srcLen -) { - char* dst = buf; - char* dstEnd = buf + len; - const T* srcEnd = src + srcLen; - - while (src < srcEnd && dst < dstEnd) { - ptrdiff_t remaining = srcEnd - src; - char a, b, c, d; - - while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; - if (remaining == 0 || *src == '=') break; - a = _nan_unbase64(*src++); - - while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; - if (remaining <= 1 || *src == '=') break; - b = _nan_unbase64(*src++); - - *dst++ = (a << 2) | ((b & 0x30) >> 4); - if (dst == dstEnd) break; - - while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; - if (remaining <= 2 || *src == '=') break; - c = _nan_unbase64(*src++); - - *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); - if (dst == dstEnd) break; - - while (_nan_unbase64(*src) < 0 && src < srcEnd) src++, remaining--; - if (remaining <= 3 || *src == '=') break; - d = _nan_unbase64(*src++); - - *dst++ = ((c & 0x03) << 6) | (d & 0x3F); - } - - return dst - buf; -} - -//// HEX //// - -template unsigned _nan_hex2bin(T c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); - if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); - return static_cast(-1); -} - -template static size_t _nan_hex_decode( - char* buf - , size_t len - , const T* src - , const size_t srcLen -) { - size_t i; - for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { - unsigned a = _nan_hex2bin(src[i * 2 + 0]); - unsigned b = _nan_hex2bin(src[i * 2 + 1]); - if (!~a || !~b) return i; - buf[i] = a * 16 + b; - } - - return i; -} - -namespace NanIntern { - -inline -NanExternalOneByteStringResource const* -GetExternalResource(v8::Local str) { -#if NODE_MODULE_VERSION < 42 - return str->GetExternalAsciiStringResource(); -#else // io.js v1.0.0 - return str->GetExternalOneByteStringResource(); -#endif -} - -inline -bool -IsExternal(v8::Local str) { -#if NODE_MODULE_VERSION < 42 - return str->IsExternalAscii(); -#else // io.js v1.0.0 - return str->IsExternalOneByte(); -#endif -} - -} // end of namespace NanIntern - -static bool _NanGetExternalParts( - v8::Handle val - , const char** data - , size_t* len -) { - if (node::Buffer::HasInstance(val)) { - *data = node::Buffer::Data(val.As()); - *len = node::Buffer::Length(val.As()); - return true; - } - - assert(val->IsString()); - v8::Local str = NanNew(val.As()); - - if (NanIntern::IsExternal(str)) { - const NanExternalOneByteStringResource* ext; - ext = NanIntern::GetExternalResource(str); - *data = ext->data(); - *len = ext->length(); - return true; - } - - if (str->IsExternal()) { - const v8::String::ExternalStringResource* ext; - ext = str->GetExternalStringResource(); - *data = reinterpret_cast(ext->data()); - *len = ext->length(); - return true; - } - - return false; -} - -namespace Nan { - enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER}; -} - -/* NAN_DEPRECATED */ NAN_INLINE void* _NanRawString( - v8::Handle from - , enum Nan::Encoding encoding - , size_t *datalen - , void *buf - , size_t buflen - , int flags -) { - NanScope(); - - size_t sz_; - size_t term_len = !(flags & v8::String::NO_NULL_TERMINATION); - char *data = NULL; - size_t len; - bool is_extern = _NanGetExternalParts( - from - , const_cast(&data) - , &len); - - if (is_extern && !term_len) { - NanSetPointerSafe(datalen, len); - return data; - } - - v8::Local toStr = from->ToString(); - - char *to = static_cast(buf); - - switch (encoding) { - case Nan::ASCII: -#if NODE_MODULE_VERSION < 0x000C - sz_ = toStr->Length(); - if (to == NULL) { - to = new char[sz_ + term_len]; - } else { - assert(buflen >= sz_ + term_len && "too small buffer"); - } - NanSetPointerSafe( - datalen - , toStr->WriteAscii(to, 0, static_cast(sz_ + term_len), flags)); - return to; -#endif - case Nan::BINARY: - case Nan::BUFFER: - sz_ = toStr->Length(); - if (to == NULL) { - to = new char[sz_ + term_len]; - } else { - assert(buflen >= sz_ + term_len && "too small buffer"); - } -#if NODE_MODULE_VERSION < 0x000C - { - uint16_t* twobytebuf = new uint16_t[sz_ + term_len]; - - size_t somelen = toStr->Write(twobytebuf, 0, - static_cast(sz_ + term_len), flags); - - for (size_t i = 0; i < sz_ + term_len && i < somelen + term_len; i++) { - unsigned char *b = reinterpret_cast(&twobytebuf[i]); - to[i] = *b; - } - - NanSetPointerSafe(datalen, somelen); - - delete[] twobytebuf; - return to; - } -#else - NanSetPointerSafe( - datalen, - toStr->WriteOneByte( - reinterpret_cast(to) - , 0 - , static_cast(sz_ + term_len) - , flags)); - return to; -#endif - case Nan::UTF8: - sz_ = toStr->Utf8Length(); - if (to == NULL) { - to = new char[sz_ + term_len]; - } else { - assert(buflen >= sz_ + term_len && "too small buffer"); - } - NanSetPointerSafe( - datalen - , toStr->WriteUtf8(to, static_cast(sz_ + term_len) - , NULL, flags) - - term_len); - return to; - case Nan::BASE64: - { - v8::String::Value value(toStr); - sz_ = _nan_base64_decoded_size(*value, value.length()); - if (to == NULL) { - to = new char[sz_ + term_len]; - } else { - assert(buflen >= sz_ + term_len); - } - NanSetPointerSafe( - datalen - , _nan_base64_decode(to, sz_, *value, value.length())); - if (term_len) { - to[sz_] = '\0'; - } - return to; - } - case Nan::UCS2: - { - sz_ = toStr->Length(); - if (to == NULL) { - to = new char[(sz_ + term_len) * 2]; - } else { - assert(buflen >= (sz_ + term_len) * 2 && "too small buffer"); - } - - int bc = 2 * toStr->Write( - reinterpret_cast(to) - , 0 - , static_cast(sz_ + term_len) - , flags); - NanSetPointerSafe(datalen, bc); - return to; - } - case Nan::HEX: - { - v8::String::Value value(toStr); - sz_ = value.length(); - assert(!(sz_ & 1) && "bad hex data"); - if (to == NULL) { - to = new char[sz_ / 2 + term_len]; - } else { - assert(buflen >= sz_ / 2 + term_len && "too small buffer"); - } - NanSetPointerSafe( - datalen - , _nan_hex_decode(to, sz_ / 2, *value, value.length())); - } - if (term_len) { - to[sz_ / 2] = '\0'; - } - return to; - default: - assert(0 && "unknown encoding"); - } - return to; -} - -NAN_DEPRECATED NAN_INLINE void* NanRawString( - v8::Handle from - , enum Nan::Encoding encoding - , size_t *datalen - , void *buf - , size_t buflen - , int flags -) { - return _NanRawString(from, encoding, datalen, buf, buflen, flags); -} - - -NAN_DEPRECATED NAN_INLINE char* NanCString( - v8::Handle from - , size_t *datalen - , char *buf = NULL - , size_t buflen = 0 - , int flags = v8::String::NO_OPTIONS -) { - return static_cast( - _NanRawString(from, Nan::UTF8, datalen, buf, buflen, flags) - ); -} - -NAN_INLINE void NanSetPrototypeTemplate( - v8::Local templ - , const char *name - , v8::Handle value -) { - NanSetTemplate(templ->PrototypeTemplate(), name, value); -} - -NAN_INLINE void NanSetPrototypeTemplate( - v8::Local templ - , v8::Handle name - , v8::Handle value - , v8::PropertyAttribute attributes -) { - NanSetTemplate(templ->PrototypeTemplate(), name, value, attributes); -} - -NAN_INLINE void NanSetInstanceTemplate( - v8::Local templ - , const char *name - , v8::Handle value -) { - NanSetTemplate(templ->InstanceTemplate(), name, value); -} - -NAN_INLINE void NanSetInstanceTemplate( - v8::Local templ - , v8::Handle name - , v8::Handle value - , v8::PropertyAttribute attributes -) { - NanSetTemplate(templ->InstanceTemplate(), name, value, attributes); -} - -//=== Export ================================================================== - -inline -void -NanExport(v8::Handle target, const char * name, - NanFunctionCallback f) { - target->Set(NanNew(name), - NanNew(f)->GetFunction()); -} - -//=== Tap Reverse Binding ===================================================== - -struct NanTap { - explicit NanTap(v8::Handle t) : t_() { - NanAssignPersistent(t_, t->ToObject()); - } - - ~NanTap() { NanDisposePersistent(t_); } // not sure if neccessary - - inline void plan(int i) { - v8::Handle arg = NanNew(i); - NanMakeCallback(NanNew(t_), "plan", 1, &arg); - } - - inline void ok(bool isOk, const char * msg = NULL) { - v8::Handle args[2]; - args[0] = NanNew(isOk); - if (msg) args[1] = NanNew(msg); - NanMakeCallback(NanNew(t_), "ok", msg ? 2 : 1, args); - } - - private: - v8::Persistent t_; -}; - -#define NAN_STRINGIZE2(x) #x -#define NAN_STRINGIZE(x) NAN_STRINGIZE2(x) -#define NAN_TEST_EXPRESSION(expression) \ - ( expression ), __FILE__ ":" NAN_STRINGIZE(__LINE__) ": " #expression - -#define return_NanValue(v) NanReturnValue(v) -#define return_NanUndefined() NanReturnUndefined() -#define NAN_EXPORT(target, function) NanExport(target, #function, function) - -#endif // NAN_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h b/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h deleted file mode 100644 index 5f0bff0..0000000 --- a/scripts/external/three/canvas/node_modules/nan/nan_implementation_12_inl.h +++ /dev/null @@ -1,253 +0,0 @@ -/********************************************************************* - * NAN - Native Abstractions for Node.js - * - * Copyright (c) 2015 NAN contributors - * - * MIT License - ********************************************************************/ - -#ifndef NAN_IMPLEMENTATION_12_INL_H_ -#define NAN_IMPLEMENTATION_12_INL_H_ -//============================================================================== -// node v0.11 implementation -//============================================================================== - -#if defined(_MSC_VER) -# pragma warning( disable : 4530 ) -# include -# pragma warning( default : 4530 ) -#else -# include -#endif - -namespace NanIntern { - -//=== Array ==================================================================== - -Factory::return_t -Factory::New() { - return v8::Array::New(v8::Isolate::GetCurrent()); -} - -Factory::return_t -Factory::New(int length) { - return v8::Array::New(v8::Isolate::GetCurrent(), length); -} - -//=== Boolean ================================================================== - -Factory::return_t -Factory::New(bool value) { - return v8::Boolean::New(v8::Isolate::GetCurrent(), value); -} - -//=== Boolean Object =========================================================== - -Factory::return_t -Factory::New(bool value) { - return v8::BooleanObject::New(value).As(); -} - -//=== Date ===================================================================== - -Factory::return_t -Factory::New(double value) { - return v8::Date::New(v8::Isolate::GetCurrent(), value).As(); -} - -//=== External ================================================================= - -Factory::return_t -Factory::New(void * value) { - return v8::External::New(v8::Isolate::GetCurrent(), value); -} - -//=== Function ================================================================= - -Factory::return_t -Factory::New( NanFunctionCallback callback - , v8::Handle data) { - return v8::Function::New( v8::Isolate::GetCurrent() - , callback - , data); -} - -//=== Function Template ======================================================== - -Factory::return_t -Factory::New( NanFunctionCallback callback - , v8::Handle data - , v8::Handle signature) { - return v8::FunctionTemplate::New( v8::Isolate::GetCurrent() - , callback - , data - , signature); -} - -//=== Number =================================================================== - -Factory::return_t -Factory::New(double value) { - return v8::Number::New(v8::Isolate::GetCurrent(), value); -} - -//=== Number Object ============================================================ - -Factory::return_t -Factory::New(double value) { - return v8::NumberObject::New( v8::Isolate::GetCurrent() - , value).As(); -} - -//=== Integer, Int32 and Uint32 ================================================ - -template -typename IntegerFactory::return_t -IntegerFactory::New(int32_t value) { - return To(T::New(v8::Isolate::GetCurrent(), value)); -} - -template -typename IntegerFactory::return_t -IntegerFactory::New(uint32_t value) { - return To(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); -} - -Factory::return_t -Factory::New(int32_t value) { - return To( - v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); -} - -Factory::return_t -Factory::New(uint32_t value) { - return To( - v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); -} - -//=== Object =================================================================== - -Factory::return_t -Factory::New() { - return v8::Object::New(v8::Isolate::GetCurrent()); -} - -//=== Object Template ========================================================== - -Factory::return_t -Factory::New() { - return v8::ObjectTemplate::New(v8::Isolate::GetCurrent()); -} - -//=== RegExp =================================================================== - -Factory::return_t -Factory::New( - v8::Handle pattern - , v8::RegExp::Flags flags) { - return v8::RegExp::New(pattern, flags); -} - -//=== Script =================================================================== - -Factory::return_t -Factory::New( v8::Local source) { - v8::ScriptCompiler::Source src(source); - return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); -} - -Factory::return_t -Factory::New( v8::Local source - , v8::ScriptOrigin const& origin) { - v8::ScriptCompiler::Source src(source, origin); - return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); -} - -//=== Signature ================================================================ - -Factory::return_t -Factory::New( Factory::FTH receiver - , int argc - , Factory::FTH argv[]) { - return v8::Signature::New(v8::Isolate::GetCurrent(), receiver, argc, argv); -} - -//=== String =================================================================== - -Factory::return_t -Factory::New() { - return v8::String::Empty(v8::Isolate::GetCurrent()); -} - -Factory::return_t -Factory::New(const char * value, int length) { - return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value, - v8::String::kNormalString, length); -} - -Factory::return_t -Factory::New(std::string const& value) { - assert(value.size() <= INT_MAX && "string too long"); - return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), - value.data(), v8::String::kNormalString, static_cast(value.size())); -} - -Factory::return_t -Factory::New(const uint8_t * value, int length) { - return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value, - v8::String::kNormalString, length); -} - -Factory::return_t -Factory::New(const uint16_t * value, int length) { - return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value, - v8::String::kNormalString, length); -} - -Factory::return_t -Factory::New(v8::String::ExternalStringResource * value) { - return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); -} - -Factory::return_t -Factory::New(NanExternalOneByteStringResource * value) { - return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); -} - -//=== String Object ============================================================ - -Factory::return_t -Factory::New(v8::Handle value) { - return v8::StringObject::New(value).As(); -} - -//=== Unbound Script =========================================================== - -Factory::return_t -Factory::New(v8::Local source) { - v8::ScriptCompiler::Source src(source); - return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); -} - -Factory::return_t -Factory::New( v8::Local source - , v8::ScriptOrigin const& origin) { - v8::ScriptCompiler::Source src(source, origin); - return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); -} - -} // end of namespace NanIntern - -//=== Presistents and Handles ================================================== - -template -inline v8::Local NanNew(v8::Handle h) { - return v8::Local::New(v8::Isolate::GetCurrent(), h); -} - -template -inline v8::Local NanNew(v8::Persistent const& p) { - return v8::Local::New(v8::Isolate::GetCurrent(), p); -} - -#endif // NAN_IMPLEMENTATION_12_INL_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h b/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h deleted file mode 100644 index 4c4ae11..0000000 --- a/scripts/external/three/canvas/node_modules/nan/nan_implementation_pre_12_inl.h +++ /dev/null @@ -1,256 +0,0 @@ -/********************************************************************* - * NAN - Native Abstractions for Node.js - * - * Copyright (c) 2015 NAN contributors - * - * MIT License - ********************************************************************/ - -#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_ -#define NAN_IMPLEMENTATION_PRE_12_INL_H_ - -#include - -#if defined(_MSC_VER) -# pragma warning( disable : 4530 ) -# include -# include -# pragma warning( default : 4530 ) -#else -# include -# include -#endif - -//============================================================================== -// node v0.10 implementation -//============================================================================== - -namespace NanIntern { - -//=== Array ==================================================================== - -Factory::return_t -Factory::New() { - return v8::Array::New(); -} - -Factory::return_t -Factory::New(int length) { - return v8::Array::New(length); -} - -//=== Boolean ================================================================== - -Factory::return_t -Factory::New(bool value) { - return v8::Boolean::New(value)->ToBoolean(); -} - -//=== Boolean Object =========================================================== - -Factory::return_t -Factory::New(bool value) { - return v8::BooleanObject::New(value).As(); -} - -//=== Date ===================================================================== - -Factory::return_t -Factory::New(double value) { - return v8::Date::New(value).As(); -} - -//=== External ================================================================= - -Factory::return_t -Factory::New(void * value) { - return v8::External::New(value); -} - -//=== Function ================================================================= - -Factory::return_t -Factory::New( NanFunctionCallback callback - , v8::Handle data) { - return Factory::New( callback - , data - , v8::Handle() - )->GetFunction(); -} - - -//=== FunctionTemplate ========================================================= - -Factory::return_t -Factory::New( NanFunctionCallback callback - , v8::Handle data - , v8::Handle signature) { - // Note(agnat): Emulate length argument here. Unfortunately, I couldn't find - // a way. Have at it though... - return v8::FunctionTemplate::New( callback - , data - , signature); -} - -//=== Number =================================================================== - -Factory::return_t -Factory::New(double value) { - return v8::Number::New(value); -} - -//=== Number Object ============================================================ - -Factory::return_t -Factory::New(double value) { - return v8::NumberObject::New(value).As(); -} - -//=== Integer, Int32 and Uint32 ================================================ - -template -typename IntegerFactory::return_t -IntegerFactory::New(int32_t value) { - return To(T::New(value)); -} - -template -typename IntegerFactory::return_t -IntegerFactory::New(uint32_t value) { - return To(T::NewFromUnsigned(value)); -} - -Factory::return_t -Factory::New(int32_t value) { - return To(v8::Uint32::NewFromUnsigned(value)); -} - -Factory::return_t -Factory::New(uint32_t value) { - return To(v8::Uint32::NewFromUnsigned(value)); -} - - -//=== Object =================================================================== - -Factory::return_t -Factory::New() { - return v8::Object::New(); -} - -//=== Object Template ========================================================== - -Factory::return_t -Factory::New() { - return v8::ObjectTemplate::New(); -} - -//=== RegExp =================================================================== - -Factory::return_t -Factory::New( - v8::Handle pattern - , v8::RegExp::Flags flags) { - return v8::RegExp::New(pattern, flags); -} - -//=== Script =================================================================== - -Factory::return_t -Factory::New( v8::Local source) { - return v8::Script::New(source); -} -Factory::return_t -Factory::New( v8::Local source - , v8::ScriptOrigin const& origin) { - return v8::Script::New(source, const_cast(&origin)); -} - -//=== Signature ================================================================ - -Factory::return_t -Factory::New( Factory::FTH receiver - , int argc - , Factory::FTH argv[]) { - return v8::Signature::New(receiver, argc, argv); -} - -//=== String =================================================================== - -Factory::return_t -Factory::New() { - return v8::String::Empty(); -} - -Factory::return_t -Factory::New(const char * value, int length) { - return v8::String::New(value, length); -} - -Factory::return_t -Factory::New(std::string const& value) { - assert(value.size() <= INT_MAX && "string too long"); - return v8::String::New( value.data(), static_cast(value.size())); -} - -inline -void -widenString(std::vector *ws, const uint8_t *s, int l = -1) { - size_t len = static_cast(l); - if (l < 0) { - len = strlen(reinterpret_cast(s)); - } - assert(len <= INT_MAX && "string too long"); - ws->resize(len); - std::copy(s, s + len, ws->begin()); -} - -Factory::return_t -Factory::New(const uint16_t * value, int length) { - return v8::String::New(value, length); -} - -Factory::return_t -Factory::New(const uint8_t * value, int length) { - std::vector wideString; - widenString(&wideString, value, length); - if (wideString.size() == 0) { - return v8::String::Empty(); - } else { - return v8::String::New(&wideString.front() - , static_cast(wideString.size())); - } -} - -Factory::return_t -Factory::New(v8::String::ExternalStringResource * value) { - return v8::String::NewExternal(value); -} - -Factory::return_t -Factory::New(v8::String::ExternalAsciiStringResource * value) { - return v8::String::NewExternal(value); -} - -//=== String Object ============================================================ - -Factory::return_t -Factory::New(v8::Handle value) { - return v8::StringObject::New(value).As(); -} - -} // end of namespace NanIntern - -//=== Presistents and Handles ================================================== - -template -inline v8::Local NanNew(v8::Handle h) { - return v8::Local::New(h); -} - -template -inline v8::Local NanNew(v8::Persistent const& p) { - return v8::Local::New(p); -} - -#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/nan_new.h b/scripts/external/three/canvas/node_modules/nan/nan_new.h deleted file mode 100644 index 7058d12..0000000 --- a/scripts/external/three/canvas/node_modules/nan/nan_new.h +++ /dev/null @@ -1,320 +0,0 @@ -/********************************************************************* - * NAN - Native Abstractions for Node.js - * - * Copyright (c) 2015 NAN contributors - * - * MIT License - ********************************************************************/ - -#ifndef NAN_NEW_H_ -#define NAN_NEW_H_ - -#if defined(_MSC_VER) -# pragma warning( disable : 4530 ) -# include -# pragma warning( default : 4530 ) -#else -# include -#endif - -namespace NanIntern { // scnr - -// TODO(agnat): Generalize -template v8::Local To(v8::Handle i); - -template <> -inline -v8::Local -To(v8::Handle i) { return i->ToInteger(); } - -template <> -inline -v8::Local -To(v8::Handle i) { return i->ToInt32(); } - -template <> -inline -v8::Local -To(v8::Handle i) { return i->ToUint32(); } - -template struct FactoryBase { typedef v8::Local return_t; }; - -template struct Factory; - -template <> -struct Factory : FactoryBase { - static inline return_t New(); - static inline return_t New(int length); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(bool value); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(bool value); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(double value); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(void *value); -}; - -template <> -struct Factory : FactoryBase { - static inline - return_t - New( NanFunctionCallback callback - , v8::Handle data = v8::Handle()); -}; - -template <> -struct Factory : FactoryBase { - static inline - return_t - New( NanFunctionCallback callback = NULL - , v8::Handle data = v8::Handle() - , v8::Handle signature = v8::Handle()); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(double value); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(double value); -}; - -template -struct IntegerFactory : FactoryBase { - typedef typename FactoryBase::return_t return_t; - static inline return_t New(int32_t value); - static inline return_t New(uint32_t value); -}; - -template <> -struct Factory : IntegerFactory {}; - -template <> -struct Factory : IntegerFactory {}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(int32_t value); - static inline return_t New(uint32_t value); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New( - v8::Handle pattern, v8::RegExp::Flags flags); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New( v8::Local source); - static inline return_t New( v8::Local source - , v8::ScriptOrigin const& origin); -}; - -template <> -struct Factory : FactoryBase { - typedef v8::Handle FTH; - static inline - return_t - New( FTH receiver = FTH(), int argc = 0, FTH argv[] = NULL ); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(); - static inline return_t New(const char *value, int length = -1); - static inline return_t New(const uint16_t *value, int length = -1); - static inline return_t New(std::string const& value); - - static inline return_t New(v8::String::ExternalStringResource * value); - static inline return_t New(NanExternalOneByteStringResource * value); - - // TODO(agnat): Deprecate. - static inline return_t New(const uint8_t * value, int length = -1); -}; - -template <> -struct Factory : FactoryBase { - static inline return_t New(v8::Handle value); -}; - -} // end of namespace NanIntern - -#if (NODE_MODULE_VERSION >= 12) - -namespace NanIntern { - -template <> -struct Factory : FactoryBase { - static inline return_t New( v8::Local source); - static inline return_t New( v8::Local source - , v8::ScriptOrigin const& origin); -}; - -} // end of namespace NanIntern - -# include "nan_implementation_12_inl.h" - -#else // NODE_MODULE_VERSION >= 12 - -# include "nan_implementation_pre_12_inl.h" - -#endif - -//=== API ====================================================================== - -template -typename NanIntern::Factory::return_t -NanNew() { - return NanIntern::Factory::New(); -} - -template -typename NanIntern::Factory::return_t -NanNew(A0 arg0) { - return NanIntern::Factory::New(arg0); -} - -template -typename NanIntern::Factory::return_t -NanNew(A0 arg0, A1 arg1) { - return NanIntern::Factory::New(arg0, arg1); -} - -template -typename NanIntern::Factory::return_t -NanNew(A0 arg0, A1 arg1, A2 arg2) { - return NanIntern::Factory::New(arg0, arg1, arg2); -} - -template -typename NanIntern::Factory::return_t -NanNew(A0 arg0, A1 arg1, A2 arg2, A3 arg3) { - return NanIntern::Factory::New(arg0, arg1, arg2, arg3); -} - -// Note(agnat): When passing overloaded function pointers to template functions -// as generic arguments the compiler needs help in picking the right overload. -// These two functions handle NanNew and NanNew with -// all argument variations. - -// v8::Function and v8::FunctionTemplate with one or two arguments -template -typename NanIntern::Factory::return_t -NanNew( NanFunctionCallback callback - , v8::Handle data = v8::Handle()) { - return NanIntern::Factory::New(callback, data); -} - -// v8::Function and v8::FunctionTemplate with three arguments -template -typename NanIntern::Factory::return_t -NanNew( NanFunctionCallback callback - , v8::Handle data = v8::Handle() - , A2 a2 = A2()) { - return NanIntern::Factory::New(callback, data, a2); -} - -// Convenience - -template inline v8::Local NanNew(v8::Handle h); -template inline v8::Local NanNew(v8::Persistent const& p); - -inline -NanIntern::Factory::return_t -NanNew(bool value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(int32_t value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(uint32_t value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(double value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(std::string const& value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(const char * value, int length) { - return NanNew(value, length); -} - -inline -NanIntern::Factory::return_t -NanNew(const char * value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(const uint8_t * value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(const uint16_t * value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(v8::String::ExternalStringResource * value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(NanExternalOneByteStringResource * value) { - return NanNew(value); -} - -inline -NanIntern::Factory::return_t -NanNew(v8::Handle pattern, v8::RegExp::Flags flags) { - return NanNew(pattern, flags); -} - -#endif // NAN_NEW_H_ diff --git a/scripts/external/three/canvas/node_modules/nan/package.json b/scripts/external/three/canvas/node_modules/nan/package.json deleted file mode 100644 index 3d51cc5..0000000 --- a/scripts/external/three/canvas/node_modules/nan/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "nan", - "version": "1.5.3", - "description": "Native Abstractions for Node.js: C++ header for Node 0.8->0.12 compatibility", - "main": "include_dirs.js", - "repository": { - "type": "git", - "url": "git://github.com/rvagg/nan.git" - }, - "scripts": { - "test": "tap --gc test/js/*-test.js", - "rebuild-tests": "node-gyp rebuild --directory test" - }, - "contributors": [ - { - "name": "Rod Vagg", - "email": "r@va.gg", - "url": "https://github.com/rvagg" - }, - { - "name": "Benjamin Byholm", - "email": "bbyholm@abo.fi", - "url": "https://github.com/kkoopa/" - }, - { - "name": "Trevor Norris", - "email": "trev.norris@gmail.com", - "url": "https://github.com/trevnorris" - }, - { - "name": "Nathan Rajlich", - "email": "nathan@tootallnate.net", - "url": "https://github.com/TooTallNate" - }, - { - "name": "Brett Lawson", - "email": "brett19@gmail.com", - "url": "https://github.com/brett19" - }, - { - "name": "Ben Noordhuis", - "email": "info@bnoordhuis.nl", - "url": "https://github.com/bnoordhuis" - }, - { - "name": "David Siegel", - "email": "david@artcom.de", - "url": "https://github.com/agnat" - } - ], - "devDependencies": { - "bindings": "~1.2.1", - "node-gyp": "~1.0.2", - "tap": "~0.5.0", - "xtend": "~4.0.0" - }, - "license": "MIT", - "readme": "Native Abstractions for Node.js\n===============================\n\n**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10 and 0.11, and eventually 0.12.**\n\n***Current version: 1.5.2***\n\n*(See [CHANGELOG.md](https://github.com/rvagg/nan/blob/master/CHANGELOG.md) for complete ChangeLog)*\n\n[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/)\n\n[![Build Status](https://secure.travis-ci.org/rvagg/nan.png)](http://travis-ci.org/rvagg/nan)\n[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan)\n\nThanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.11/0.12, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle.\n\nThis project also contains some helper utilities that make addon development a bit more pleasant.\n\n * **[News & Updates](#news)**\n * **[Usage](#usage)**\n * **[Example](#example)**\n * **[API](#api)**\n * **[Tests](#tests)**\n\n\n## News & Updates\n\n### Jan-2015: 1.5.0 release\n\n* Support [io.js](https://github.com/iojs/io.js) thanks to [Ben Noordhuis](bnoordhuis)\n* Rewritten NanNew internals thanks to [David Siegel](agnat)\n* NanAsyncWorker now supports progress reporting thanks to [Brett Lawson](brett19)\n\n### Aug-2014: 1.3.0 release\n\n* `NanCString()` and `NanRawString()` have been deprecated in favour of new NanAsciiString, NanUtf8String and NanUcs2String. These classes manage the underlying memory for you in a safer way than just handing off an allocated array. You should now `*NanAsciiString(handle)` to access the raw `char` data, you can also allocate on the heap if you need to keep a reference.\n* Two more NanMakeCallback overloads have been added to for parity with Node core.\n* You can now `NanNew(std::string)` (use `NanNew(std::string&)` to pass by reference)\n* NanSetTemplate, NanSetPrototypeTemplate and NanSetInstanceTemplate have been added.\n\n### May-2014: 1.1.0 release\n\n* We've deprecated `NanSymbol()`, you should just use `NanNew()` now.\n* `NanNull()`, `NanUndefined()`, `NanTrue()`, `NanFalse()` all return `Local`s now.\n* `nan_isolate` is gone, it was intended to be internal-only but if you were using it then you should switch to `v8::Isolate::GetCurrent()`.\n* `NanNew()` has received some additional overload-love so you should be able to give it many kinds of values without specifying the ``.\n* Lots of small fixes and additions to expand the V8 API coverage, *use the source, Luke*.\n\n\n### May-2014: Major changes for V8 3.25 / Node 0.11.13\n\nNode 0.11.11 and 0.11.12 were both broken releases for native add-ons, you simply can't properly compile against either of them for different reasons. But we now have a 0.11.13 release that jumps a couple of versions of V8 ahead and includes some more, major (traumatic) API changes.\n\nBecause we are now nearing Node 0.12 and estimate that the version of V8 we are using in Node 0.11.13 will be close to the API we get for 0.12, we have taken the opportunity to not only *fix* NAN for 0.11.13 but make some major changes to improve the NAN API.\n\nWe have **removed support for Node 0.11 versions prior to 0.11.13**. As usual, our tests are run against (and pass) the last 5 versions of Node 0.8 and Node 0.10. We also include Node 0.11.13 obviously.\n\nThe major change is something that [Benjamin Byholm](kkoopa) has put many hours in to. We now have a fantastic new `NanNew(args)` interface for creating new `Local`s, this replaces `NanNewLocal()` and much more. If you look in [./nan.h](nan.h) you'll see a large number of overloaded versions of this method. In general you should be able to `NanNew(arguments)` for any type you want to make a `Local` from. This includes `Persistent` types, so we now have a `Local NanNew(const Persistent arg)` to replace `NanPersistentToLocal()`.\n\nWe also now have `NanUndefined()`, `NanNull()`, `NanTrue()` and `NanFalse()`. Mainly because of the new requirement for an `Isolate` argument for each of the native V8 versions of this.\n\nV8 has now introduced an `EscapableHandleScope` from which you `scope.Escape(Local value)` to *return* a value from a one scope to another. This replaces the standard `HandleScope` and `scope.Close(Local value)`, although `HandleScope` still exists for when you don't need to return a handle to the caller. For NAN we are exposing it as `NanEscapableScope()` and `NanEscapeScope()`, while `NanScope()` is still how you create a new scope that doesn't need to return handles. For older versions of Node/V8, it'll still map to the older `HandleScope` functionality.\n\n`NanFromV8String()` was deprecated and has now been removed. You should use `NanCString()` or `NanRawString()` instead.\n\nBecause `node::MakeCallback()` now takes an `Isolate`, and because it doesn't exist in older versions of Node, we've introduced `NanMakeCallback()`. You should *always* use this when calling a JavaScript function from C++.\n\nThere's lots more, check out the Changelog in nan.h or look through [#86](https://github.com/rvagg/nan/pull/86) for all the gory details.\n\n### Dec-2013: NanCString and NanRawString\n\nTwo new functions have been introduced to replace the functionality that's been provided by `NanFromV8String` until now. NanCString has sensible defaults so it's super easy to fetch a null-terminated c-style string out of a `v8::String`. `NanFromV8String` is still around and has defaults that allow you to pass a single handle to fetch a `char*` while `NanRawString` requires a little more attention to arguments.\n\n### Nov-2013: Node 0.11.9+ breaking V8 change\n\nThe version of V8 that's shipping with Node 0.11.9+ has changed the signature for new `Local`s to: `v8::Local::New(isolate, value)`, i.e. introducing the `isolate` argument and therefore breaking all new `Local` declarations for previous versions. NAN 0.6+ now includes a `NanNewLocal(value)` that can be used in place to work around this incompatibility and maintain compatibility with 0.8->0.11.9+ (minus a few early 0.11 releases).\n\nFor example, if you wanted to return a `null` on a callback you will have to change the argument from `v8::Local::New(v8::Null())` to `NanNewLocal(v8::Null())`.\n\n### Nov-2013: Change to binding.gyp `\"include_dirs\"` for NAN\n\nInclusion of NAN in a project's binding.gyp is now greatly simplified. You can now just use `\"\n## Usage\n\nSimply add **NAN** as a dependency in the *package.json* of your Node addon:\n\n``` bash\n$ npm install --save nan\n```\n\nPull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files:\n\n``` python\n\"include_dirs\" : [\n \"` when compiling your addon.\n\n\n## Example\n\nSee **[LevelDOWN](https://github.com/rvagg/node-leveldown/pull/48)** for a full example of **NAN** in use.\n\nFor a simpler example, see the **[async pi estimation example](https://github.com/rvagg/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**.\n\nFor another example, see **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon.\n\nCompare to the current 0.10 version of this example, found in the [node-addon-examples](https://github.com/rvagg/node-addon-examples/tree/master/9_async_work) repository and also a 0.11 version of the same found [here](https://github.com/kkoopa/node-addon-examples/tree/5c01f58fc993377a567812597e54a83af69686d7/9_async_work).\n\nNote that there is no embedded version sniffing going on here and also the async work is made much simpler, see below for details on the `NanAsyncWorker` class.\n\n```c++\n// addon.cc\n#include \n#include \n// ...\n\nusing v8::FunctionTemplate;\nusing v8::Handle;\nusing v8::Object;\nusing v8::String;\n\nvoid InitAll(Handle exports) {\n exports->Set(NanNew(\"calculateSync\"),\n NanNew(CalculateSync)->GetFunction());\n\n exports->Set(NanNew(\"calculateAsync\"),\n NanNew(CalculateAsync)->GetFunction());\n}\n\nNODE_MODULE(addon, InitAll)\n```\n\n```c++\n// sync.h\n#include \n#include \n\nNAN_METHOD(CalculateSync);\n```\n\n```c++\n// sync.cc\n#include \n#include \n#include \"./sync.h\"\n// ...\n\nusing v8::Number;\n\n// Simple synchronous access to the `Estimate()` function\nNAN_METHOD(CalculateSync) {\n NanScope();\n\n // expect a number as the first argument\n int points = args[0]->Uint32Value();\n double est = Estimate(points);\n\n NanReturnValue(NanNew(est));\n}\n```\n\n```c++\n// async.h\n#include \n#include \n\nNAN_METHOD(CalculateAsync);\n```\n\n```c++\n// async.cc\n#include \n#include \n#include \"./async.h\"\n\n// ...\n\nusing v8::Function;\nusing v8::Local;\nusing v8::Null;\nusing v8::Number;\nusing v8::Value;\n\nclass PiWorker : public NanAsyncWorker {\n public:\n PiWorker(NanCallback *callback, int points)\n : NanAsyncWorker(callback), points(points) {}\n ~PiWorker() {}\n\n // Executed inside the worker-thread.\n // It is not safe to access V8, or V8 data structures\n // here, so everything we need for input and output\n // should go on `this`.\n void Execute () {\n estimate = Estimate(points);\n }\n\n // Executed when the async work is complete\n // this function will be run inside the main event loop\n // so it is safe to use V8 again\n void HandleOKCallback () {\n NanScope();\n\n Local argv[] = {\n NanNull()\n , NanNew(estimate)\n };\n\n callback->Call(2, argv);\n };\n\n private:\n int points;\n double estimate;\n};\n\n// Asynchronous access to the `Estimate()` function\nNAN_METHOD(CalculateAsync) {\n NanScope();\n\n int points = args[0]->Uint32Value();\n NanCallback *callback = new NanCallback(args[1].As());\n\n NanAsyncQueueWorker(new PiWorker(callback, points));\n NanReturnUndefined();\n}\n```\n\n\n## API\n\n * NAN_METHOD\n * NAN_GETTER\n * NAN_SETTER\n * NAN_PROPERTY_GETTER\n * NAN_PROPERTY_SETTER\n * NAN_PROPERTY_ENUMERATOR\n * NAN_PROPERTY_DELETER\n * NAN_PROPERTY_QUERY\n * NAN_INDEX_GETTER\n * NAN_INDEX_SETTER\n * NAN_INDEX_ENUMERATOR\n * NAN_INDEX_DELETER\n * NAN_INDEX_QUERY\n * NAN_GC_CALLBACK\n * NAN_WEAK_CALLBACK\n * NAN_DEPRECATED\n * NAN_INLINE\n * NanNew\n * NanUndefined\n * NanNull\n * NanTrue\n * NanFalse\n * NanReturnValue\n * NanReturnUndefined\n * NanReturnNull\n * NanReturnEmptyString\n * NanReturnThis\n * NanReturnHolder\n * NanScope\n * NanEscapableScope\n * NanEscapeScope\n * NanLocker\n * NanUnlocker\n * NanGetInternalFieldPointer\n * NanSetInternalFieldPointer\n * NanObjectWrapHandle\n * NanSymbol\n * NanGetPointerSafe\n * NanSetPointerSafe\n * NanRawString\n * NanCString\n * NanAsciiString\n * NanUtf8String\n * NanUcs2String\n * NanBooleanOptionValue\n * NanUInt32OptionValue\n * NanError, NanTypeError, NanRangeError\n * NanThrowError, NanThrowTypeError, NanThrowRangeError, NanThrowError(Handle), NanThrowError(Handle, int)\n * NanNewBufferHandle(char *, size_t, FreeCallback, void *), NanNewBufferHandle(char *, uint32_t), NanNewBufferHandle(uint32_t)\n * NanBufferUse(char *, uint32_t)\n * NanNewContextHandle\n * NanGetCurrentContext\n * NanHasInstance\n * NanDisposePersistent\n * NanAssignPersistent\n * NanMakeWeakPersistent\n * NanSetTemplate\n * NanSetPrototypeTemplate\n * NanSetInstanceTemplate\n * NanMakeCallback\n * NanCompileScript\n * NanRunScript\n * NanAdjustExternalMemory\n * NanAddGCEpilogueCallback\n * NanAddGCPrologueCallback\n * NanRemoveGCEpilogueCallback\n * NanRemoveGCPrologueCallback\n * NanGetHeapStatistics\n * NanCallback\n * NanAsyncWorker\n * NanAsyncQueueWorker\n\n\n### NAN_METHOD(methodname)\n\nUse `NAN_METHOD` to define your V8 accessible methods:\n\n```c++\n// .h:\nclass Foo : public node::ObjectWrap {\n ...\n\n static NAN_METHOD(Bar);\n static NAN_METHOD(Baz);\n}\n\n\n// .cc:\nNAN_METHOD(Foo::Bar) {\n ...\n}\n\nNAN_METHOD(Foo::Baz) {\n ...\n}\n```\n\nThe reason for this macro is because of the method signature change in 0.11:\n\n```c++\n// 0.10 and below:\nHandle name(const Arguments& args)\n\n// 0.11 and above\nvoid name(const FunctionCallbackInfo& args)\n```\n\nThe introduction of `FunctionCallbackInfo` brings additional complications:\n\n\n### NAN_GETTER(methodname)\n\nUse `NAN_GETTER` to declare your V8 accessible getters. You get a `Local` `property` and an appropriately typed `args` object that can act like the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_GETTER`.\n\n\n### NAN_SETTER(methodname)\n\nUse `NAN_SETTER` to declare your V8 accessible setters. Same as `NAN_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_PROPERTY_GETTER(cbname)\nUse `NAN_PROPERTY_GETTER` to declare your V8 accessible property getters. You get a `Local` `property` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_GETTER`.\n\n\n### NAN_PROPERTY_SETTER(cbname)\nUse `NAN_PROPERTY_SETTER` to declare your V8 accessible property setters. Same as `NAN_PROPERTY_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_PROPERTY_ENUMERATOR(cbname)\nUse `NAN_PROPERTY_ENUMERATOR` to declare your V8 accessible property enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_PROPERTY_GETTER` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_ENUMERATOR`.\n\n\n### NAN_PROPERTY_DELETER(cbname)\nUse `NAN_PROPERTY_DELETER` to declare your V8 accessible property deleters. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_DELETER`.\n\n\n### NAN_PROPERTY_QUERY(cbname)\nUse `NAN_PROPERTY_QUERY` to declare your V8 accessible property queries. Same as `NAN_PROPERTY_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_PROPERTY_QUERY`.\n\n\n### NAN_INDEX_GETTER(cbname)\nUse `NAN_INDEX_GETTER` to declare your V8 accessible index getters. You get a `uint32_t` `index` and an appropriately typed `args` object that can act similar to the `args` argument to a `NAN_METHOD` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_GETTER`.\n\n\n### NAN_INDEX_SETTER(cbname)\nUse `NAN_INDEX_SETTER` to declare your V8 accessible index setters. Same as `NAN_INDEX_GETTER` but you also get a `Local` `value` object to work with.\n\n\n### NAN_INDEX_ENUMERATOR(cbname)\nUse `NAN_INDEX_ENUMERATOR` to declare your V8 accessible index enumerators. You get an appropriately typed `args` object like the `args` argument to a `NAN_INDEX_GETTER` call.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_ENUMERATOR`.\n\n\n### NAN_INDEX_DELETER(cbname)\nUse `NAN_INDEX_DELETER` to declare your V8 accessible index deleters. Same as `NAN_INDEX_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_DELETER`.\n\n\n### NAN_INDEX_QUERY(cbname)\nUse `NAN_INDEX_QUERY` to declare your V8 accessible index queries. Same as `NAN_INDEX_GETTER`.\n\nYou can use `NanReturnNull()`, `NanReturnEmptyString()`, `NanReturnUndefined()` and `NanReturnValue()` in a `NAN_INDEX_QUERY`.\n\n\n### NAN_GC_CALLBACK(cbname)\nUse `NAN_GC_CALLBACK` to declare your callbacks for `NanAddGCEpilogueCallback` and `NanAddGCPrologueCallback`. You get arguments `GCType type` and `GCCallbackFlags flags`.\n\n```c++\nstatic Persistent callback;\n\nNAN_GC_CALLBACK(gcPrologueCallback) {\n Local argv[] = {NanNew(\"prologue\")};\n NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(callback), 1, argv);\n}\n\nNAN_METHOD(Hook) {\n NanScope();\n NanAssignPersistent(callback, args[0].As());\n NanAddGCPrologueCallback(gcPrologueCallback);\n NanReturnValue(args.Holder());\n}\n```\n\n\n### NAN_WEAK_CALLBACK(cbname)\n\nUse `NAN_WEAK_CALLBACK` to define your V8 WeakReference callbacks. There is an argument object `const _NanWeakCallbackData &data` allowing access to the weak object and the supplied parameter through its `GetValue` and `GetParameter` methods. You can even access the weak callback info object through the `GetCallbackInfo()`method, but you probably should not. `Revive()` keeps the weak object alive until the next GC round.\n\n```c++\nNAN_WEAK_CALLBACK(weakCallback) {\n int *parameter = data.GetParameter();\n NanMakeCallback(NanGetCurrentContext()->Global(), data.GetValue(), 0, NULL);\n if ((*parameter)++ == 0) {\n data.Revive();\n } else {\n delete parameter;\n }\n}\n```\n\n\n### NAN_DEPRECATED\nDeclares a function as deprecated.\n\n```c++\nstatic NAN_DEPRECATED NAN_METHOD(foo) {\n ...\n}\n```\n\n\n### NAN_INLINE\nInlines a function.\n\n```c++\nNAN_INLINE int foo(int bar) {\n ...\n}\n```\n\n\n### Local<T> NanNew<T>( ... )\n\nUse `NanNew` to construct almost all v8 objects (bound `Script`s are constructed with `NanCompileScript(Handle)`) and make new local handles.\n\n```c++\nLocal s = NanNew(\"value\");\n\n...\n\nPersistent o;\n\n...\n\nLocal lo = NanNew(o);\n\n```\n\n\n### Local<Primitive> NanUndefined()\n\nUse instead of `Undefined()`\n\n\n### Local<Primitive> NanNull()\n\nUse instead of `Null()`\n\n\n### Local<Boolean> NanTrue()\n\nUse instead of `True()`\n\n\n### Local<Boolean> NanFalse()\n\nUse instead of `False()`\n\n\n### NanReturnValue(Handle<Value>)\n\nUse `NanReturnValue` when you want to return a value from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n ...\n\n NanReturnValue(NanNew(\"FooBar!\"));\n}\n```\n\nNo `return` statement required.\n\n\n### NanReturnUndefined()\n\nUse `NanReturnUndefined` when you don't want to return anything from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnUndefined();\n}\n```\n\n\n### NanReturnNull()\n\nUse `NanReturnNull` when you want to return `Null` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnNull();\n}\n```\n\n\n### NanReturnEmptyString()\n\nUse `NanReturnEmptyString` when you want to return an empty `String` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnEmptyString();\n}\n```\n\n\n### NanReturnThis()\n\nUse `NanReturnThis` when you want to return `This` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnThis();\n}\n```\n\n\n### NanReturnHolder()\n\nUse `NanReturnHolder` when you want to return `Holder` from your V8 accessible method:\n\n```c++\nNAN_METHOD(Foo::Baz) {\n ...\n\n NanReturnHolder();\n}\n```\n\n\n### NanScope()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanScope()` necessary, use it in place of `HandleScope scope` when you do not wish to return handles (`Handle` or `Local`) to the surrounding scope (or in functions directly exposed to V8, as they do not return values in the normal sense):\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanScope();\n\n NanReturnValue(NanNew(\"FooBar!\"));\n}\n```\n\nThis method is not directly exposed to V8, nor does it return a handle, so it uses an unescapable scope:\n\n```c++\nbool Foo::Bar() {\n NanScope();\n\n Local val = NanFalse();\n ...\n return val->Value();\n}\n```\n\n\n### NanEscapableScope()\n\nThe separation of handle scopes into escapable and inescapable scopes makes `NanEscapableScope()` necessary, use it in place of `HandleScope scope` when you later wish to return a handle (`Handle` or `Local`) from the scope, this is for internal functions not directly exposed to V8:\n\n```c++\nHandle Foo::Bar() {\n NanEscapableScope();\n\n return NanEscapeScope(NanNew(\"FooBar!\"));\n}\n```\n\n\n### Local<T> NanEscapeScope(Handle<T> value);\nUse together with `NanEscapableScope` to escape the scope. Corresponds to `HandleScope::Close` or `EscapableHandleScope::Escape`.\n\n\n### NanLocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanLocker()` necessary, use it in place of `Locker locker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### NanUnlocker()\n\nThe introduction of `isolate` references for many V8 calls in Node 0.11 makes `NanUnlocker()` necessary, use it in place of `Unlocker unlocker`:\n\n```c++\nNAN_METHOD(Foo::Bar) {\n NanLocker();\n ...\n NanUnlocker();\n}\n```\n\n\n### void * NanGetInternalFieldPointer(Handle<Object>, int)\n\nGets a pointer to the internal field with at `index` from a V8 `Object` handle.\n\n```c++\nLocal obj;\n...\nNanGetInternalFieldPointer(obj, 0);\n```\n\n### void NanSetInternalFieldPointer(Handle<Object>, int, void *)\n\nSets the value of the internal field at `index` on a V8 `Object` handle.\n\n```c++\nstatic Persistent dataWrapperCtor;\n...\nLocal wrapper = NanNew(dataWrapperCtor)->NewInstance();\nNanSetInternalFieldPointer(wrapper, 0, this);\n```\n\n\n### Local<Object> NanObjectWrapHandle(Object)\n\nWhen you want to fetch the V8 object handle from a native object you've wrapped with Node's `ObjectWrap`, you should use `NanObjectWrapHandle`:\n\n```c++\nNanObjectWrapHandle(iterator)->Get(NanNew(\"end\"))\n```\n\n\n### ~~Local<String> NanSymbol(const char *)~~\n\nDeprecated. Use `NanNew` instead.\n~~Use to create string symbol objects (i.e. `v8::String::NewSymbol(x)`), for getting and setting object properties, or names of objects.~~\n\n```c++\nbool foo = false;\nif (obj->Has(NanNew(\"foo\")))\n foo = optionsObj->Get(NanNew(\"foo\"))->BooleanValue()\n```\n\n\n### Type NanGetPointerSafe(Type *[, Type])\n\nA helper for getting values from optional pointers. If the pointer is `NULL`, the function returns the optional default value, which defaults to `0`. Otherwise, the function returns the value the pointer points to.\n\n```c++\nchar *plugh(uint32_t *optional) {\n char res[] = \"xyzzy\";\n uint32_t param = NanGetPointerSafe(optional, 0x1337);\n switch (param) {\n ...\n }\n NanSetPointerSafe(optional, 0xDEADBEEF);\n} \n```\n\n\n### bool NanSetPointerSafe(Type *, Type)\n\nA helper for setting optional argument pointers. If the pointer is `NULL`, the function simply returns `false`. Otherwise, the value is assigned to the variable the pointer points to.\n\n```c++\nconst char *plugh(size_t *outputsize) {\n char res[] = \"xyzzy\";\n if !(NanSetPointerSafe(outputsize, strlen(res) + 1)) {\n ...\n }\n\n ...\n}\n```\n\n\n### ~~void* NanRawString(Handle<Value>, enum Nan::Encoding, size_t *, void *, size_t, int)~~\n\nDeprecated. Use something else.\n\n~~When you want to convert a V8 `String` to a `char*` buffer, use `NanRawString`. You have to supply an encoding as well as a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows setting `String::WriteOptions`.\nJust remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~\n\n```c++\nsize_t count;\nvoid* decoded = NanRawString(args[1], Nan::BASE64, &count, NULL, 0, String::HINT_MANY_WRITES_EXPECTED);\n...\ndelete[] reinterpret_cast(decoded);\n```\n\n\n### ~~char* NanCString(Handle<Value>, size_t *[, char *, size_t, int])~~\n\nDeprecated. Use `String::Utf8Value` or `NanUtf8String` instead.\n\n~~When you want to convert a V8 `String` to a null-terminated C `char*` use `NanCString`. The resulting `char*` will be UTF-8-encoded, and you need to supply a pointer to a variable that will be assigned the number of bytes in the returned string. It is also possible to supply a buffer and its length to the function in order not to have a new buffer allocated. The final argument allows optionally setting `String::WriteOptions`, which default to `v8::String::NO_OPTIONS`.\nJust remember that you'll end up with an object that you'll need to `delete[]` at some point unless you supply your own buffer:~~\n\n```c++\nsize_t count;\nchar* name = NanCString(args[0], &count);\n...\ndelete[] name;\n```\n\n\n### NanAsciiString\n\nContrary to the name, this is not actually an ASCII string, it is a one-byte string with no particular encoding. Do not use unless you actually need this incorrect legacy behavior. Consider fixing your broken code instead. If you actually have a proper ASCII-string, use UTF-8, which is a proper superset of ASCII.\nConvert a `String` to zero-terminated, sort-of Ascii-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanAsciiString(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanAsciiString baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanAsciiString *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanAsciiString(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n### NanUtf8String\n\nEquivalent to `String::Utf8Value`, it only exists for the sake of completeness.\nConvert a `String` to zero-terminated, Utf8-encoded `char *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanUtf8String(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanUtf8String baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanUtf8String *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanUtf8String(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n\n### NanUcs2String\n\nEquivalent to `String::Value`, it only exists for the sake of completeness.\nConvert a `String` to zero-terminated, Ucs2-encoded `uint16_t *`. The underlying buffer is freed when the owner object goes out of scope, so make a copy or heap allocation if you need it to stick around.\n\n```c++\nNAN_METHOD(foo) {\n NanScope();\n NanReturnValue(NanNew(*NanUcs2String(arg[0])));\n}\n```\n\n####*WRONG*:\nthe buffer `str` points to has been freed when `baz` was destroyed:\n```c++\nstatic char *str;\n\nNAN_METHOD(bar) {\n NanScope();\n NanUcs2String baz(arg[0]);\n\n str = *baz;\n NanReturnUndefined(); // baz goes out of scope, freeing str\n}\n\n...\n\nprintf(str); // use-after-free error\n```\n\n####*RIGHT*:\n```c++\nstatic NanUcs2String *str;\n\nNAN_METHOD(bar) {\n NanScope();\n str = new NanUcs2String(arg[0]);\n NanReturnUndefined();\n}\n\n...\n\nprintf(**str);\n```\n\n\n### bool NanBooleanOptionValue(Handle<Value>, Handle<String>[, bool])\n\nWhen you have an \"options\" object that you need to fetch properties from, boolean options can be fetched with this pair. They check first if the object exists (`IsEmpty`), then if the object has the given property (`Has`) then they get and convert/coerce the property to a `bool`.\n\nThe optional last parameter is the *default* value, which is `false` if left off:\n\n```c++\n// `foo` is false unless the user supplies a truthy value for it\nbool foo = NanBooleanOptionValue(optionsObj, NanNew(\"foo\"));\n// `bar` is true unless the user supplies a falsy value for it\nbool bar = NanBooleanOptionValueDefTrue(optionsObj, NanNew(\"bar\"), true);\n```\n\n\n### uint32_t NanUInt32OptionValue(Handle<Value>, Handle<String>, uint32_t)\n\nSimilar to `NanBooleanOptionValue`, use `NanUInt32OptionValue` to fetch an integer option from your options object. Can be any kind of JavaScript `Number` and it will be coerced to an unsigned 32-bit integer.\n\nRequires all 3 arguments as a default is not optional:\n\n```c++\nuint32_t count = NanUInt32OptionValue(optionsObj, NanNew(\"count\"), 1024);\n```\n\n\n### NanError(message), NanTypeError(message), NanRangeError(message)\n\nFor making `Error`, `TypeError` and `RangeError` objects.\n\n```c++\nLocal res = NanError(\"you must supply a callback argument\");\n```\n\n\n### NanThrowError(message), NanThrowTypeError(message), NanThrowRangeError(message), NanThrowError(Local<Value>), NanThrowError(Local<Value>, int)\n\nFor throwing `Error`, `TypeError` and `RangeError` objects.\n\n```c++\nNanThrowError(\"you must supply a callback argument\");\n```\n\nCan also handle any custom object you may want to throw. If used with the error code argument, it will add the supplied error code to the error object as a property called `code`.\n\n\n### Local<Object> NanNewBufferHandle(char *, uint32_t), Local<Object> NanNewBufferHandle(uint32_t)\n\nThe `Buffer` API has changed a little in Node 0.11, this helper provides consistent access to `Buffer` creation:\n\n```c++\nNanNewBufferHandle((char*)value.data(), value.size());\n```\n\nCan also be used to initialize a `Buffer` with just a `size` argument.\n\nCan also be supplied with a `NanFreeCallback` and a hint for the garbage collector.\n\n\n### Local<Object> NanBufferUse(char*, uint32_t)\n\n`Buffer::New(char*, uint32_t)` prior to 0.11 would make a copy of the data.\nWhile it was possible to get around this, it required a shim by passing a\ncallback. So the new API `Buffer::Use(char*, uint32_t)` was introduced to remove\nneeding to use this shim.\n\n`NanBufferUse` uses the `char*` passed as the backing data, and will free the\nmemory automatically when the weak callback is called. Keep this in mind, as\ncareless use can lead to \"double free or corruption\" and other cryptic failures.\n\n\n### bool NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)\n\nCan be used to check the type of an object to determine it is of a particular class you have already defined and have a `Persistent` handle for.\n\n\n### Local<Context> NanNewContextHandle([ExtensionConfiguration*, Handle<ObjectTemplate>, Handle<Value>])\nCreates a new `Local` handle.\n\n```c++\nLocal ftmpl = NanNew();\nLocal otmpl = ftmpl->InstanceTemplate();\nLocal ctx = NanNewContextHandle(NULL, otmpl);\n```\n\n\n### Local<Context> NanGetCurrentContext()\n\nGets the current context.\n\n```c++\nLocal ctx = NanGetCurrentContext();\n```\n\n\n### void NanDisposePersistent(Persistent<T> &)\n\nUse `NanDisposePersistent` to dispose a `Persistent` handle.\n\n```c++\nNanDisposePersistent(persistentHandle);\n```\n\n\n### NanAssignPersistent(handle, object)\n\nUse `NanAssignPersistent` to assign a non-`Persistent` handle to a `Persistent` one. You can no longer just declare a `Persistent` handle and assign directly to it later, you have to `Reset` it in Node 0.11, so this makes it easier.\n\nIn general it is now better to place anything you want to protect from V8's garbage collector as properties of a generic `Object` and then assign that to a `Persistent`. This works in older versions of Node also if you use `NanAssignPersistent`:\n\n```c++\nPersistent persistentHandle;\n\n...\n\nLocal obj = NanNew();\nobj->Set(NanNew(\"key\"), keyHandle); // where keyHandle might be a Local\nNanAssignPersistent(persistentHandle, obj)\n```\n\n\n### _NanWeakCallbackInfo<T, P>* NanMakeWeakPersistent(Handle<T>, P*, _NanWeakCallbackInfo<T, P>::Callback)\n\nCreates a weak persistent handle with the supplied parameter and `NAN_WEAK_CALLBACK`.\n\n```c++\nNAN_WEAK_CALLBACK(weakCallback) {\n\n...\n\n}\n\nLocal func;\n\n...\n\nint *parameter = new int(0);\nNanMakeWeakPersistent(func, parameter, &weakCallback);\n```\n\n\n### NanSetTemplate(templ, name, value [, attributes])\n\nUse to add properties on object and function templates.\n\n\n### NanSetPrototypeTemplate(templ, name, value [, attributes])\n\nUse to add prototype properties on function templates.\n\n\n### NanSetInstanceTemplate(templ, name, value [, attributes])\n\nUse to add instance properties on function templates.\n\n\n### NanMakeCallback(target, func, argc, argv)\n\nUse instead of `node::MakeCallback` to call javascript functions. This (or `NanCallback`) is the only proper way of calling functions. You must _*never, ever*_ directly use `Function::Call`, it will lead to run-time failures.\n\n\n### NanCompileScript(Handle s [, const ScriptOrigin& origin])\n\nUse to create new scripts bound to the current context.\n\n\n### NanRunScript(script)\n\nUse to run both bound and unbound scripts.\n\n\n### NanAdjustExternalMemory(int change_in_bytes)\n\nSimply does `AdjustAmountOfExternalAllocatedMemory`, note that the argument and returned value have type `int`.\n\n\n### NanAddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll)\n\nSimply does `AddGCEpilogueCallback`\n\n\n### NanAddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll)\n\nSimply does `AddGCPrologueCallback`\n\n\n### NanRemoveGCEpilogueCallback(GCEpilogueCallback callback)\n\nSimply does `RemoveGCEpilogueCallback`\n\n\n### NanRemoveGCPrologueCallback(GCPrologueCallback callback)\n\nSimply does `RemoveGCPrologueCallback`\n\n\n### NanGetHeapStatistics(HeapStatistics *heap_statistics)\n\nSimply does `GetHeapStatistics`\n\n\n### NanCallback\n\nBecause of the difficulties imposed by the changes to `Persistent` handles in V8 in Node 0.11, creating `Persistent` versions of your `Handle` is annoyingly tricky. `NanCallback` makes it easier by taking your handle, making it persistent until the `NanCallback` is deleted and even providing a handy `Call()` method to fetch and execute the callback `Function`.\n\n```c++\nLocal callbackHandle = args[0].As();\nNanCallback *callback = new NanCallback(callbackHandle);\n// pass `callback` around and it's safe from GC until you:\ndelete callback;\n```\n\nYou can execute the callback like so:\n\n```c++\n// no arguments:\ncallback->Call(0, NULL);\n\n// an error argument:\nHandle argv[] = {\n NanError(NanNew(\"fail!\"))\n};\ncallback->Call(1, argv);\n\n// a success argument:\nHandle argv[] = {\n NanNull(),\n NanNew(\"w00t!\")\n};\ncallback->Call(2, argv);\n```\n\n`NanCallback` also has a `Local GetFunction()` method that you can use\nto fetch a local handle to the underlying callback function, as well as a\n`void SetFunction(Handle)` for setting the callback on the\n`NanCallback`. You can check if a `NanCallback` is empty with the `bool IsEmpty()` method. Additionally a generic constructor is available for using\n`NanCallback` without performing heap allocations.\n\n\n### NanAsyncWorker\n\n`NanAsyncWorker` is an abstract class that you can subclass to have much of the annoying async queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the async work is in progress.\n\nSee a rough outline of the implementation:\n\n```c++\nclass NanAsyncWorker {\npublic:\n NanAsyncWorker (NanCallback *callback);\n\n // Clean up persistent handles and delete the *callback\n virtual ~NanAsyncWorker ();\n\n // Check the `ErrorMessage()` and call HandleOKCallback()\n // or HandleErrorCallback depending on whether it has been set or not\n virtual void WorkComplete ();\n\n // You must implement this to do some async work. If there is an\n // error then use `SetErrorMessage()` to set an error message and the callback will\n // be passed that string in an Error object\n virtual void Execute ();\n\n // Save a V8 object in a Persistent handle to protect it from GC\n void SaveToPersistent(const char *key, Local &obj);\n\n // Fetch a stored V8 object (don't call from within `Execute()`)\n Local GetFromPersistent(const char *key);\n\n // Get the error message (or NULL)\n const char *ErrorMessage();\n\n // Set an error message\n void SetErrorMessage(const char *msg);\n\nprotected:\n // Default implementation calls the callback function with no arguments.\n // Override this to return meaningful data\n virtual void HandleOKCallback ();\n\n // Default implementation calls the callback function with an Error object\n // wrapping the `errmsg` string\n virtual void HandleErrorCallback ();\n};\n```\n\n\n### NanAsyncQueueWorker(NanAsyncWorker *)\n\n`NanAsyncQueueWorker` will run a `NanAsyncWorker` asynchronously via libuv. Both the *execute* and *after_work* steps are taken care of for you—most of the logic for this is embedded in `NanAsyncWorker`.\n\n\n### Tests\n\nTo run the NAN tests do:\n\n``` sh\nnpm install\nnpm run-script rebuild-tests\nnpm test\n```\n\nOr just:\n\n``` sh\nnpm install\nmake test\n```\n\n### Contributors\n\nNAN is only possible due to the excellent work of the following contributors:\n\n\n\n\n\n\n\n\n\n
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnat-
\n\nLicence & copyright\n-----------------------\n\nCopyright (c) 2015 NAN contributors (listed above).\n\nNative Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/rvagg/nan/issues" - }, - "_id": "nan@1.5.3", - "dist": { - "shasum": "f07ee4ad6ab18083cf8c826542ff391387cf5215" - }, - "_from": "nan@~1.5.1", - "_resolved": "https://registry.npmjs.org/nan/-/nan-1.5.3.tgz" -} diff --git a/scripts/external/three/canvas/package.json b/scripts/external/three/canvas/package.json deleted file mode 100644 index 33b3b4f..0000000 --- a/scripts/external/three/canvas/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "canvas", - "description": "Canvas graphics API backed by Cairo", - "version": "1.2.1", - "author": { - "name": "TJ Holowaychuk", - "email": "tj@learnboost.com" - }, - "contributors": [ - { - "name": "Nathan Rajlich", - "email": "nathan@tootallnate.net" - }, - { - "name": "Rod Vagg", - "email": "r@va.gg" - }, - { - "name": "Juriy Zaytsev", - "email": "kangax@gmail.com" - } - ], - "keywords": [ - "canvas", - "graphic", - "graphics", - "pixman", - "cairo", - "image", - "images", - "pdf" - ], - "homepage": "https://github.com/learnboost/node-canvas", - "repository": { - "type": "git", - "url": "git://github.com/learnboost/node-canvas" - }, - "scripts": { - "test": "make test", - "install": "node-gyp rebuild" - }, - "dependencies": { - "nan": "~1.5.1" - }, - "devDependencies": { - "express": "3.0", - "jade": "0.28.1", - "mocha": "*", - "should": "*" - }, - "engines": { - "node": ">= 0.6.0" - }, - "main": "./lib/canvas.js", - "gypfile": true, - "readme": "node-canvas\n===========\n### Canvas graphics API backed by Cairo\n[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas)\n[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas)\n\n node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org).\n\n## Authors\n\n - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))\n - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate))\n - Rod Vagg ([rvagg](http://github.com/rvagg))\n - Juriy Zaytsev ([kangax](http://github.com/kangax))\n\n## Installation\n\n```bash\n$ npm install canvas\n```\n\nUnless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/LearnBoost/node-canvas/wiki/_pages).\n\nYou can quickly install Cairo and its dependencies for OS X using the one liner below:\n\n```bash\n$ wget https://raw.githubusercontent.com/LearnBoost/node-canvas/master/install -O - | sh\n```\n\nor if you use MacPorts\n\n```bash\nsudo port install pkgconfig libpng giflib freetype libpixman cairo\n```\n\n## Screencasts\n\n - [Introduction](http://screenr.com/CTk)\n\n## Example\n\n```javascript\nvar Canvas = require('canvas')\n , Image = Canvas.Image\n , canvas = new Canvas(200,200)\n , ctx = canvas.getContext('2d');\n\nctx.font = '30px Impact';\nctx.rotate(.1);\nctx.fillText(\"Awesome!\", 50, 100);\n\nvar te = ctx.measureText('Awesome!');\nctx.strokeStyle = 'rgba(0,0,0,0.5)';\nctx.beginPath();\nctx.lineTo(50, 102);\nctx.lineTo(50 + te.width, 102);\nctx.stroke();\n\nconsole.log('');\n```\n\n## Non-Standard API\n\n node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers.\n\n### Image#src=Buffer\n\n node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O.\n\n```javascript\nfs.readFile(__dirname + '/images/squid.png', function(err, squid){\n if (err) throw err;\n img = new Image;\n img.src = squid;\n ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4);\n});\n```\n\n Below is an example of a canvas drawing it-self as the source several time:\n\n```javascript\nvar img = new Image;\nimg.src = canvas.toBuffer();\nctx.drawImage(img, 0, 0, 50, 50);\nctx.drawImage(img, 50, 0, 50, 50);\nctx.drawImage(img, 100, 0, 50, 50);\n```\n\n### Image#dataMode\n\nnode-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs).\n\nWhen mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering.\n\n```javascript\nvar img = new Image;\nimg.dataMode = Image.MODE_IMAGE; // Only image data tracked\nimg.dataMode = Image.MODE_MIME; // Only mime data tracked\nimg.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked\n```\n\nIf image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.\n\n### Canvas#pngStream()\n\n To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted.\n\n```javascript\nvar fs = require('fs')\n , out = fs.createWriteStream(__dirname + '/text.png')\n , stream = canvas.pngStream();\n\nstream.on('data', function(chunk){\n out.write(chunk);\n});\n\nstream.on('end', function(){\n console.log('saved png');\n});\n```\n\nCurrently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`.\n\n### Canvas#jpegStream() and Canvas#syncJPEGStream()\n\nYou can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with\nsome optional parameters; functionality is otherwise identical to\n`pngStream()`. See `examples/crop.js` for an example.\n\n_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both\nare synchronous_\n\n```javascript\nvar stream = canvas.jpegStream({\n bufsize: 4096 // output buffer size in bytes, default: 4096\n , quality: 75 // JPEG quality (0-100) default: 75\n , progressive: false // true for progressive compression, default: false\n});\n```\n\n### Canvas#toBuffer()\n\nA call to `Canvas#toBuffer()` will return a node `Buffer` instance containing all of the PNG data.\n\n```javascript\ncanvas.toBuffer();\n```\n\n### Canvas#toBuffer() async\n\nOptionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`.\n\n```javascript\ncanvas.toBuffer(function(err, buf){\n\n});\n```\n\n### Canvas#toDataURL() async\n\nOptionally we may pass a callback function to `Canvas#toDataURL()`, and this process will be performed asynchronously, and will `callback(err, str)`.\n\n```javascript\ncanvas.toDataURL(function(err, str){\n\n});\n```\n\nor specify the mime type:\n\n```javascript\ncanvas.toDataURL('image/png', function(err, str){\n\n});\n```\n\n### CanvasRenderingContext2d#patternQuality\n\nGiven one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.\n\n - fast\n - good\n - best\n - nearest\n - bilinear\n\n### CanvasRenderingContext2d#textDrawingMode\n\nCan be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill.\n\nDefaults to _path_.\n\nThis property is tracked as part of the canvas state in save/restore.\n\n### CanvasRenderingContext2d#filter\n\nLike `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_.\n\n - fast\n - good\n - best\n - nearest\n - bilinear\n\n### Global Composite Operations\n\nIn addition to those specified and commonly implemented by browsers, the following have been added:\n\n - multiply\n - screen\n - overlay\n - hard-light\n - soft-light\n - hsl-hue\n - hsl-saturation\n - hsl-color\n - hsl-luminosity\n\n## Anti-Aliasing\n\n Set anti-aliasing mode\n\n - default\n - none\n - gray\n - subpixel\n\n For example:\n\n```javascript\nctx.antialias = 'none';\n```\n\n## PDF Support\n\n Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating\n a PDF on initialization, using the \"pdf\" string:\n\n```js\nvar canvas = new Canvas(200, 500, 'pdf');\n```\n\n An additional method `.addPage()` is then available to create\n multiple page PDFs:\n\n```js\nctx.font = '22px Helvetica';\nctx.fillText('Hello World', 50, 80);\nctx.addPage();\n\nctx.font = '22px Helvetica';\nctx.fillText('Hello World 2', 50, 80);\nctx.addPage();\n\nctx.font = '22px Helvetica';\nctx.fillText('Hello World 3', 50, 80);\nctx.addPage();\n```\n\n## SVG support\n\n Just like PDF support, make sure to install cairo with `--enable-svg=yes`.\n You also need to tell node-canvas that it is working on SVG upon its initialization:\n\n```js\nvar canvas = new Canvas(200, 500, 'svg');\n// Use the normal primitives.\nfs.writeFile('out.svg', canvas.toBuffer());\n```\n\n## Benchmarks\n\n Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself.\n\n## Contribute\n\n Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/LearnBoost/node-canvas/issues) for existing issues.\n\n## Examples\n\n Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser.\n\n## Testing\n\nIf you have not previously, init git submodules:\n\n $ git submodule update --init\n\nBuild node-canvas:\n\n $ node-gyp rebuild\n\nUnit tests:\n\n $ make test\n\nVisual tests:\n\n $ make test-server\n\n## Versions\n\nTested with and designed for:\n\n - node 0.4.2\n - cairo 1.8.6\n\nFor node 0.2.x `node-canvas` <= 0.4.3 may be used,\n0.5.0 and above are designed for node 0.4.x only.\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2010 LearnBoost, and contributors <dev@learnboost.com>\n\nCopyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", - "readmeFilename": "Readme.md", - "bugs": { - "url": "https://github.com/learnboost/node-canvas/issues" - }, - "_id": "canvas@1.2.1", - "dist": { - "shasum": "fed6cff0dc4d978badbf71bb8f9077b617450bc8" - }, - "_from": "canvas@", - "_resolved": "https://registry.npmjs.org/canvas/-/canvas-1.2.1.tgz" -} diff --git a/scripts/external/three/canvas/src/Canvas.cc b/scripts/external/three/canvas/src/Canvas.cc deleted file mode 100644 index 93f0329..0000000 --- a/scripts/external/three/canvas/src/Canvas.cc +++ /dev/null @@ -1,575 +0,0 @@ -// -// Canvas.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "Canvas.h" -#include "PNG.h" -#include "CanvasRenderingContext2d.h" -#include -#include -#include -#include -#include -#include -#include -#include "closure.h" - -#ifdef HAVE_JPEG -#include "JPEGStream.h" -#endif - -Persistent Canvas::constructor; - -/* - * Initialize Canvas. - */ - -void -Canvas::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(Canvas::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("Canvas")); - - // Prototype - Local proto = ctor->PrototypeTemplate(); - NODE_SET_PROTOTYPE_METHOD(ctor, "toBuffer", ToBuffer); - NODE_SET_PROTOTYPE_METHOD(ctor, "streamPNGSync", StreamPNGSync); -#ifdef HAVE_JPEG - NODE_SET_PROTOTYPE_METHOD(ctor, "streamJPEGSync", StreamJPEGSync); -#endif - proto->SetAccessor(NanNew("type"), GetType); - proto->SetAccessor(NanNew("width"), GetWidth, SetWidth); - proto->SetAccessor(NanNew("height"), GetHeight, SetHeight); - - NanSetTemplate(proto, "PNG_NO_FILTERS", NanNew(PNG_NO_FILTERS)); - NanSetTemplate(proto, "PNG_FILTER_NONE", NanNew(PNG_FILTER_NONE)); - NanSetTemplate(proto, "PNG_FILTER_SUB", NanNew(PNG_FILTER_SUB)); - NanSetTemplate(proto, "PNG_FILTER_UP", NanNew(PNG_FILTER_UP)); - NanSetTemplate(proto, "PNG_FILTER_AVG", NanNew(PNG_FILTER_AVG)); - NanSetTemplate(proto, "PNG_FILTER_PAETH", NanNew(PNG_FILTER_PAETH)); - NanSetTemplate(proto, "PNG_ALL_FILTERS", NanNew(PNG_ALL_FILTERS)); - - target->Set(NanNew("Canvas"), ctor->GetFunction()); -} - -/* - * Initialize a Canvas with the given width and height. - */ - -NAN_METHOD(Canvas::New) { - NanScope(); - int width = 0, height = 0; - canvas_type_t type = CANVAS_TYPE_IMAGE; - if (args[0]->IsNumber()) width = args[0]->Uint32Value(); - if (args[1]->IsNumber()) height = args[1]->Uint32Value(); - if (args[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(args[2])) - ? CANVAS_TYPE_PDF - : !strcmp("svg", *String::Utf8Value(args[2])) - ? CANVAS_TYPE_SVG - : CANVAS_TYPE_IMAGE; - Canvas *canvas = new Canvas(width, height, type); - canvas->Wrap(args.This()); - NanReturnValue(args.This()); -} - -/* - * Get type string. - */ - -NAN_GETTER(Canvas::GetType) { - NanScope(); - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image")); -} - -/* - * Get width. - */ - -NAN_GETTER(Canvas::GetWidth) { - NanScope(); - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(canvas->width)); -} - -/* - * Set width. - */ - -NAN_SETTER(Canvas::SetWidth) { - NanScope(); - if (value->IsNumber()) { - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - canvas->width = value->Uint32Value(); - canvas->resurface(args.This()); - } -} - -/* - * Get height. - */ - -NAN_GETTER(Canvas::GetHeight) { - NanScope(); - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(canvas->height)); -} - -/* - * Set height. - */ - -NAN_SETTER(Canvas::SetHeight) { - NanScope(); - if (value->IsNumber()) { - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - canvas->height = value->Uint32Value(); - canvas->resurface(args.This()); - } -} - -/* - * Canvas::ToBuffer callback. - */ - -static cairo_status_t -toBuffer(void *c, const uint8_t *data, unsigned len) { - closure_t *closure = (closure_t *) c; - - if (closure->len + len > closure->max_len) { - uint8_t *data; - unsigned max = closure->max_len; - - do { - max *= 2; - } while (closure->len + len > max); - - data = (uint8_t *) realloc(closure->data, max); - if (!data) return CAIRO_STATUS_NO_MEMORY; - closure->data = data; - closure->max_len = max; - } - - memcpy(closure->data + closure->len, data, len); - closure->len += len; - - return CAIRO_STATUS_SUCCESS; -} - -/* - * EIO toBuffer callback. - */ - -#if NODE_VERSION_AT_LEAST(0, 6, 0) -void -Canvas::ToBufferAsync(uv_work_t *req) { -#elif NODE_VERSION_AT_LEAST(0, 5, 4) -void -Canvas::EIO_ToBuffer(eio_req *req) { -#else -int -Canvas::EIO_ToBuffer(eio_req *req) { -#endif - closure_t *closure = (closure_t *) req->data; - - closure->status = canvas_write_to_png_stream( - closure->canvas->surface() - , toBuffer - , closure); - -#if !NODE_VERSION_AT_LEAST(0, 5, 4) - return 0; -#endif -} - -/* - * EIO after toBuffer callback. - */ - -#if NODE_VERSION_AT_LEAST(0, 6, 0) -void -Canvas::ToBufferAsyncAfter(uv_work_t *req) { -#else -int -Canvas::EIO_AfterToBuffer(eio_req *req) { -#endif - - NanScope(); - closure_t *closure = (closure_t *) req->data; -#if NODE_VERSION_AT_LEAST(0, 6, 0) - delete req; -#else - ev_unref(EV_DEFAULT_UC); -#endif - - if (closure->status) { - Local argv[1] = { Canvas::Error(closure->status) }; - closure->pfn->Call(1, argv); - } else { - Local buf = NanNewBufferHandle((char*)closure->data, closure->len); - memcpy(Buffer::Data(buf), closure->data, closure->len); - Local argv[2] = { NanNew(NanNull()), buf }; - closure->pfn->Call(2, argv); - } - - closure->canvas->Unref(); - delete closure->pfn; - closure_destroy(closure); - free(closure); - -#if !NODE_VERSION_AT_LEAST(0, 6, 0) - return 0; -#endif -} - -/* - * Convert PNG data to a node::Buffer, async when a - * callback function is passed. - */ - -NAN_METHOD(Canvas::ToBuffer) { - NanScope(); - cairo_status_t status; - uint32_t compression_level = 6; - uint32_t filter = PNG_ALL_FILTERS; - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - - // TODO: async / move this out - if (canvas->isPDF() || canvas->isSVG()) { - cairo_surface_finish(canvas->surface()); - closure_t *closure = (closure_t *) canvas->closure(); - - Local buf = NanNewBufferHandle((char*) closure->data, closure->len); - NanReturnValue(buf); - } - - if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { - if (!args[1]->StrictEquals(NanUndefined())) { - bool good = true; - if (args[1]->IsNumber()) { - compression_level = args[1]->Uint32Value(); - } else if (args[1]->IsString()) { - if (args[1]->StrictEquals(NanNew("0"))) { - compression_level = 0; - } else { - uint32_t tmp = args[1]->Uint32Value(); - if (tmp == 0) { - good = false; - } else { - compression_level = tmp; - } - } - } else { - good = false; - } - - if (good) { - if (compression_level > 9) { - return NanThrowRangeError("Allowed compression levels lie in the range [0, 9]."); - } - } else { - return NanThrowTypeError("Compression level must be a number."); - } - } - - if (!args[2]->StrictEquals(NanUndefined())) { - if (args[2]->IsUint32()) { - filter = args[2]->Uint32Value(); - } else { - return NanThrowTypeError("Invalid filter value."); - } - } - } - - // Async - if (args[0]->IsFunction()) { - closure_t *closure = (closure_t *) malloc(sizeof(closure_t)); - status = closure_init(closure, canvas, compression_level, filter); - - // ensure closure is ok - if (status) { - closure_destroy(closure); - free(closure); - return NanThrowError(Canvas::Error(status)); - } - - // TODO: only one callback fn in closure - canvas->Ref(); - closure->pfn = new NanCallback(args[0].As()); - -#if NODE_VERSION_AT_LEAST(0, 6, 0) - uv_work_t* req = new uv_work_t; - req->data = closure; - uv_queue_work(uv_default_loop(), req, ToBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter); -#else - eio_custom(EIO_ToBuffer, EIO_PRI_DEFAULT, EIO_AfterToBuffer, closure); - ev_ref(EV_DEFAULT_UC); -#endif - - NanReturnUndefined(); - // Sync - } else { - closure_t closure; - status = closure_init(&closure, canvas, compression_level, filter); - - // ensure closure is ok - if (status) { - closure_destroy(&closure); - return NanThrowError(Canvas::Error(status)); - } - - TryCatch try_catch; - status = canvas_write_to_png_stream(canvas->surface(), toBuffer, &closure); - - if (try_catch.HasCaught()) { - closure_destroy(&closure); - NanReturnValue(try_catch.ReThrow()); - } else if (status) { - closure_destroy(&closure); - return NanThrowError(Canvas::Error(status)); - } else { - Local buf = NanNewBufferHandle((char *)closure.data, closure.len); - closure_destroy(&closure); - NanReturnValue(buf); - } - } -} - -/* - * Canvas::StreamPNG callback. - */ - -static cairo_status_t -streamPNG(void *c, const uint8_t *data, unsigned len) { - NanScope(); - closure_t *closure = (closure_t *) c; - Local buf = NanNewBufferHandle((char *)data, len); - Local argv[3] = { - NanNew(NanNull()) - , buf - , NanNew(len) }; - NanMakeCallback(NanGetCurrentContext()->Global(), closure->fn, 3, argv); - return CAIRO_STATUS_SUCCESS; -} - -/* - * Stream PNG data synchronously. - */ - -NAN_METHOD(Canvas::StreamPNGSync) { - NanScope(); - uint32_t compression_level = 6; - uint32_t filter = PNG_ALL_FILTERS; - // TODO: async as well - if (!args[0]->IsFunction()) - return NanThrowTypeError("callback function required"); - - if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { - if (!args[1]->StrictEquals(NanUndefined())) { - bool good = true; - if (args[1]->IsNumber()) { - compression_level = args[1]->Uint32Value(); - } else if (args[1]->IsString()) { - if (args[1]->StrictEquals(NanNew("0"))) { - compression_level = 0; - } else { - uint32_t tmp = args[1]->Uint32Value(); - if (tmp == 0) { - good = false; - } else { - compression_level = tmp; - } - } - } else { - good = false; - } - - if (good) { - if (compression_level > 9) { - return NanThrowRangeError("Allowed compression levels lie in the range [0, 9]."); - } - } else { - return NanThrowTypeError("Compression level must be a number."); - } - } - - if (!args[2]->StrictEquals(NanUndefined())) { - if (args[2]->IsUint32()) { - filter = args[1]->Uint32Value(); - } else { - return NanThrowTypeError("Invalid filter value."); - } - } - } - - - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - closure_t closure; - closure.fn = Handle::Cast(args[0]); - closure.compression_level = compression_level; - closure.filter = filter; - - TryCatch try_catch; - - cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure); - - if (try_catch.HasCaught()) { - NanReturnValue(try_catch.ReThrow()); - } else if (status) { - Local argv[1] = { Canvas::Error(status) }; - NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); - } else { - Local argv[3] = { - NanNew(NanNull()) - , NanNew(NanNull()) - , NanNew(0) }; - NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); - } - NanReturnUndefined(); -} - -/* - * Stream JPEG data synchronously. - */ - -#ifdef HAVE_JPEG - -NAN_METHOD(Canvas::StreamJPEGSync) { - NanScope(); - // TODO: async as well - if (!args[0]->IsNumber()) - return NanThrowTypeError("buffer size required"); - if (!args[1]->IsNumber()) - return NanThrowTypeError("quality setting required"); - if (!args[2]->IsBoolean()) - return NanThrowTypeError("progressive setting required"); - if (!args[3]->IsFunction()) - return NanThrowTypeError("callback function required"); - - Canvas *canvas = ObjectWrap::Unwrap(args.This()); - closure_t closure; - closure.fn = Handle::Cast(args[3]); - - TryCatch try_catch; - write_to_jpeg_stream(canvas->surface(), args[0]->NumberValue(), args[1]->NumberValue(), args[2]->BooleanValue(), &closure); - - if (try_catch.HasCaught()) - NanReturnValue(try_catch.ReThrow()); - NanReturnUndefined(); -} - -#endif - -/* - * Initialize cairo surface. - */ - -Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { - type = t; - width = w; - height = h; - _surface = NULL; - _closure = NULL; - - if (CANVAS_TYPE_PDF == t) { - _closure = malloc(sizeof(closure_t)); - assert(_closure); - cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); - assert(status == CAIRO_STATUS_SUCCESS); - _surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h); - } else if (CANVAS_TYPE_SVG == t) { - _closure = malloc(sizeof(closure_t)); - assert(_closure); - cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); - assert(status == CAIRO_STATUS_SUCCESS); - _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h); - } else { - _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); - assert(_surface); - NanAdjustExternalMemory(4 * w * h); - } -} - -/* - * Destroy cairo surface. - */ - -Canvas::~Canvas() { - switch (type) { - case CANVAS_TYPE_PDF: - case CANVAS_TYPE_SVG: - cairo_surface_finish(_surface); - closure_destroy((closure_t *) _closure); - free(_closure); - cairo_surface_destroy(_surface); - break; - case CANVAS_TYPE_IMAGE: - cairo_surface_destroy(_surface); - NanAdjustExternalMemory(-4 * width * height); - break; - } -} - -/* - * Re-alloc the surface, destroying the previous. - */ - -void -Canvas::resurface(Handle canvas) { - NanScope(); - Handle context; - switch (type) { - case CANVAS_TYPE_PDF: - cairo_pdf_surface_set_size(_surface, width, height); - break; - case CANVAS_TYPE_SVG: - // Re-surface - cairo_surface_finish(_surface); - closure_destroy((closure_t *) _closure); - cairo_surface_destroy(_surface); - closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); - _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height); - - // Reset context - context = canvas->Get(NanNew("context")); - if (!context->IsUndefined()) { - Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); - cairo_t *prev = context2d->context(); - context2d->setContext(cairo_create(surface())); - cairo_destroy(prev); - } - break; - case CANVAS_TYPE_IMAGE: - // Re-surface - int old_width = cairo_image_surface_get_width(_surface); - int old_height = cairo_image_surface_get_height(_surface); - cairo_surface_destroy(_surface); - _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - NanAdjustExternalMemory(4 * (width * height - old_width * old_height)); - - // Reset context - context = canvas->Get(NanNew("context")); - if (!context->IsUndefined()) { - Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); - cairo_t *prev = context2d->context(); - context2d->setContext(cairo_create(surface())); - cairo_destroy(prev); - } - break; - } -} - -/* - * Construct an Error from the given cairo status. - */ - -Local -Canvas::Error(cairo_status_t status) { - return Exception::Error(NanNew(cairo_status_to_string(status))); -} diff --git a/scripts/external/three/canvas/src/Canvas.h b/scripts/external/three/canvas/src/Canvas.h deleted file mode 100644 index 90ef1e5..0000000 --- a/scripts/external/three/canvas/src/Canvas.h +++ /dev/null @@ -1,96 +0,0 @@ - -// -// Canvas.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_CANVAS_H__ -#define __NODE_CANVAS_H__ - -#include -#include -#include -#include - -#if HAVE_PANGO -#include -#else -#include -#endif - -#include - -using namespace v8; -using namespace node; - -/* - * Maxmimum states per context. - * TODO: remove/resize - */ - -#ifndef CANVAS_MAX_STATES -#define CANVAS_MAX_STATES 64 -#endif - -/* - * Canvas types. - */ - -typedef enum { - CANVAS_TYPE_IMAGE, - CANVAS_TYPE_PDF, - CANVAS_TYPE_SVG -} canvas_type_t; - -/* - * Canvas. - */ - -class Canvas: public node::ObjectWrap { - public: - int width; - int height; - canvas_type_t type; - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_METHOD(ToBuffer); - static NAN_GETTER(GetType); - static NAN_GETTER(GetWidth); - static NAN_GETTER(GetHeight); - static NAN_SETTER(SetWidth); - static NAN_SETTER(SetHeight); - static NAN_METHOD(StreamPNGSync); - static NAN_METHOD(StreamJPEGSync); - static Local Error(cairo_status_t status); -#if NODE_VERSION_AT_LEAST(0, 6, 0) - static void ToBufferAsync(uv_work_t *req); - static void ToBufferAsyncAfter(uv_work_t *req); -#else - static -#if NODE_VERSION_AT_LEAST(0, 5, 4) - void -#else - int -#endif - EIO_ToBuffer(eio_req *req); - static int EIO_AfterToBuffer(eio_req *req); -#endif - - inline bool isPDF(){ return CANVAS_TYPE_PDF == type; } - inline bool isSVG(){ return CANVAS_TYPE_SVG == type; } - inline cairo_surface_t *surface(){ return _surface; } - inline void *closure(){ return _closure; } - inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } - inline int stride(){ return cairo_image_surface_get_stride(_surface); } - Canvas(int width, int height, canvas_type_t type); - void resurface(Handle canvas); - - private: - ~Canvas(); - cairo_surface_t *_surface; - void *_closure; -}; - -#endif diff --git a/scripts/external/three/canvas/src/CanvasGradient.cc b/scripts/external/three/canvas/src/CanvasGradient.cc deleted file mode 100644 index 9e41c58..0000000 --- a/scripts/external/three/canvas/src/CanvasGradient.cc +++ /dev/null @@ -1,121 +0,0 @@ - -// -// Gradient.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "color.h" -#include "Canvas.h" -#include "CanvasGradient.h" - -Persistent Gradient::constructor; - -/* - * Initialize CanvasGradient. - */ - -void -Gradient::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(Gradient::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("CanvasGradient")); - - // Prototype - NODE_SET_PROTOTYPE_METHOD(ctor, "addColorStop", AddColorStop); - target->Set(NanNew("CanvasGradient"), ctor->GetFunction()); -} - -/* - * Initialize a new CanvasGradient. - */ - -NAN_METHOD(Gradient::New) { - NanScope(); - - // Linear - if (4 == args.Length()) { - Gradient *grad = new Gradient( - args[0]->NumberValue() - , args[1]->NumberValue() - , args[2]->NumberValue() - , args[3]->NumberValue()); - grad->Wrap(args.This()); - NanReturnValue(args.This()); - } - - // Radial - if (6 == args.Length()) { - Gradient *grad = new Gradient( - args[0]->NumberValue() - , args[1]->NumberValue() - , args[2]->NumberValue() - , args[3]->NumberValue() - , args[4]->NumberValue() - , args[5]->NumberValue()); - grad->Wrap(args.This()); - NanReturnValue(args.This()); - } - - return NanThrowTypeError("invalid arguments"); -} - -/* - * Add color stop. - */ - -NAN_METHOD(Gradient::AddColorStop) { - NanScope(); - if (!args[0]->IsNumber()) - return NanThrowTypeError("offset required"); - if (!args[1]->IsString()) - return NanThrowTypeError("color string required"); - - Gradient *grad = ObjectWrap::Unwrap(args.This()); - short ok; - String::Utf8Value str(args[1]); - uint32_t rgba = rgba_from_string(*str, &ok); - - if (ok) { - rgba_t color = rgba_create(rgba); - cairo_pattern_add_color_stop_rgba( - grad->pattern() - , args[0]->NumberValue() - , color.r - , color.g - , color.b - , color.a); - } else { - return NanThrowTypeError("parse color failed"); - } - - NanReturnUndefined(); -} - -/* - * Initialize linear gradient. - */ - -Gradient::Gradient(double x0, double y0, double x1, double y1) { - _pattern = cairo_pattern_create_linear(x0, y0, x1, y1); -} - -/* - * Initialize radial gradient. - */ - -Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) { - _pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1); -} - -/* - * Destroy the pattern. - */ - -Gradient::~Gradient() { - cairo_pattern_destroy(_pattern); -} diff --git a/scripts/external/three/canvas/src/CanvasGradient.h b/scripts/external/three/canvas/src/CanvasGradient.h deleted file mode 100644 index bcc531a..0000000 --- a/scripts/external/three/canvas/src/CanvasGradient.h +++ /dev/null @@ -1,28 +0,0 @@ - -// -// CanvasGradient.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_GRADIENT_H__ -#define __NODE_GRADIENT_H__ - -#include "Canvas.h" - -class Gradient: public node::ObjectWrap { - public: - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_METHOD(AddColorStop); - Gradient(double x0, double y0, double x1, double y1); - Gradient(double x0, double y0, double r0, double x1, double y1, double r1); - inline cairo_pattern_t *pattern(){ return _pattern; } - - private: - ~Gradient(); - cairo_pattern_t *_pattern; -}; - -#endif diff --git a/scripts/external/three/canvas/src/CanvasPattern.cc b/scripts/external/three/canvas/src/CanvasPattern.cc deleted file mode 100644 index 38c86d7..0000000 --- a/scripts/external/three/canvas/src/CanvasPattern.cc +++ /dev/null @@ -1,91 +0,0 @@ - -// -// Pattern.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "Canvas.h" -#include "Image.h" -#include "CanvasPattern.h" - -Persistent Pattern::constructor; - -/* - * Initialize CanvasPattern. - */ - -void -Pattern::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(Pattern::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("CanvasPattern")); - - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("CanvasPattern")); - - // Prototype - target->Set(NanNew("CanvasPattern"), ctor->GetFunction()); -} - -/* - * Initialize a new CanvasPattern. - */ - -NAN_METHOD(Pattern::New) { - NanScope(); - - int w = 0 - , h = 0; - cairo_surface_t *surface; - - Local obj = args[0]->ToObject(); - - // Image - if (NanHasInstance(Image::constructor, obj)) { - Image *img = ObjectWrap::Unwrap(obj); - if (!img->isComplete()) { - return NanThrowError("Image given has not completed loading"); - } - w = img->width; - h = img->height; - surface = img->surface(); - - // Canvas - } else if (NanHasInstance(Canvas::constructor, obj)) { - Canvas *canvas = ObjectWrap::Unwrap(obj); - w = canvas->width; - h = canvas->height; - surface = canvas->surface(); - - // Invalid - } else { - return NanThrowTypeError("Image or Canvas expected"); - } - - Pattern *pattern = new Pattern(surface,w,h); - pattern->Wrap(args.This()); - NanReturnValue(args.This()); -} - - -/* - * Initialize linear gradient. - */ - -Pattern::Pattern(cairo_surface_t *surface, int w, int h): - _width(w), _height(h) { - _pattern = cairo_pattern_create_for_surface(surface); -} - -/* - * Destroy the pattern. - */ - -Pattern::~Pattern() { - cairo_pattern_destroy(_pattern); -} diff --git a/scripts/external/three/canvas/src/CanvasPattern.h b/scripts/external/three/canvas/src/CanvasPattern.h deleted file mode 100644 index ea3faeb..0000000 --- a/scripts/external/three/canvas/src/CanvasPattern.h +++ /dev/null @@ -1,28 +0,0 @@ - -// -// CanvasPattern.h -// -// Copyright (c) 2011 LearnBoost -// - -#ifndef __NODE_PATTERN_H__ -#define __NODE_PATTERN_H__ - -#include "Canvas.h" - -class Pattern: public node::ObjectWrap { - public: - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - Pattern(cairo_surface_t *surface, int w, int h); - inline cairo_pattern_t *pattern(){ return _pattern; } - - private: - ~Pattern(); - int _width, _height; - // TODO REPEAT/REPEAT_X/REPEAT_Y - cairo_pattern_t *_pattern; -}; - -#endif diff --git a/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc b/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc deleted file mode 100755 index 74b5924..0000000 --- a/scripts/external/three/canvas/src/CanvasRenderingContext2d.cc +++ /dev/null @@ -1,2403 +0,0 @@ - -// -// CanvasRenderingContext2d.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include -#include -#include -#include -#include -#include "Canvas.h" -#include "Point.h" -#include "Image.h" -#include "ImageData.h" -#include "CanvasRenderingContext2d.h" -#include "CanvasGradient.h" -#include "CanvasPattern.h" - -#ifdef HAVE_FREETYPE -#include "FontFace.h" -#endif - -// Windows doesn't support the C99 names for these -#ifndef isnan -#define isnan(x) _isnan(x) -#define isinf(x) (!_finite(x)) -#endif - -Persistent Context2d::constructor; - -/* - * Rectangle arg assertions. - */ - -#define RECT_ARGS \ - if (!args[0]->IsNumber() \ - ||!args[1]->IsNumber() \ - ||!args[2]->IsNumber() \ - ||!args[3]->IsNumber()) NanReturnUndefined(); \ - double x = args[0]->NumberValue(); \ - double y = args[1]->NumberValue(); \ - double width = args[2]->NumberValue(); \ - double height = args[3]->NumberValue(); - -/* - * Text baselines. - */ - -enum { - TEXT_BASELINE_ALPHABETIC - , TEXT_BASELINE_TOP - , TEXT_BASELINE_BOTTOM - , TEXT_BASELINE_MIDDLE - , TEXT_BASELINE_IDEOGRAPHIC - , TEXT_BASELINE_HANGING -}; - -#if HAVE_PANGO - -/* - * State helper function - */ - -void state_assign_fontFamily(canvas_state_t *state, const char *str) { - free(state->fontFamily); - state->fontFamily = strndup(str, 100); -} - - -/* - * Simple helper macro for a rather verbose function call. - */ - -#define PANGO_LAYOUT_GET_METRICS(LAYOUT) pango_context_get_metrics( \ - pango_layout_get_context(LAYOUT), \ - pango_layout_get_font_description(LAYOUT), \ - pango_context_get_language(pango_layout_get_context(LAYOUT))) - -#endif - -/* - * Initialize Context2d. - */ - -void -Context2d::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(Context2d::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("CanvasRenderingContext2d")); - - // Prototype - Local proto = ctor->PrototypeTemplate(); - NODE_SET_PROTOTYPE_METHOD(ctor, "drawImage", DrawImage); - NODE_SET_PROTOTYPE_METHOD(ctor, "putImageData", PutImageData); - NODE_SET_PROTOTYPE_METHOD(ctor, "addPage", AddPage); - NODE_SET_PROTOTYPE_METHOD(ctor, "save", Save); - NODE_SET_PROTOTYPE_METHOD(ctor, "restore", Restore); - NODE_SET_PROTOTYPE_METHOD(ctor, "rotate", Rotate); - NODE_SET_PROTOTYPE_METHOD(ctor, "translate", Translate); - NODE_SET_PROTOTYPE_METHOD(ctor, "transform", Transform); - NODE_SET_PROTOTYPE_METHOD(ctor, "resetTransform", ResetTransform); - NODE_SET_PROTOTYPE_METHOD(ctor, "isPointInPath", IsPointInPath); - NODE_SET_PROTOTYPE_METHOD(ctor, "scale", Scale); - NODE_SET_PROTOTYPE_METHOD(ctor, "clip", Clip); - NODE_SET_PROTOTYPE_METHOD(ctor, "fill", Fill); - NODE_SET_PROTOTYPE_METHOD(ctor, "stroke", Stroke); - NODE_SET_PROTOTYPE_METHOD(ctor, "fillText", FillText); - NODE_SET_PROTOTYPE_METHOD(ctor, "strokeText", StrokeText); - NODE_SET_PROTOTYPE_METHOD(ctor, "fillRect", FillRect); - NODE_SET_PROTOTYPE_METHOD(ctor, "strokeRect", StrokeRect); - NODE_SET_PROTOTYPE_METHOD(ctor, "clearRect", ClearRect); - NODE_SET_PROTOTYPE_METHOD(ctor, "rect", Rect); - NODE_SET_PROTOTYPE_METHOD(ctor, "measureText", MeasureText); - NODE_SET_PROTOTYPE_METHOD(ctor, "moveTo", MoveTo); - NODE_SET_PROTOTYPE_METHOD(ctor, "lineTo", LineTo); - NODE_SET_PROTOTYPE_METHOD(ctor, "bezierCurveTo", BezierCurveTo); - NODE_SET_PROTOTYPE_METHOD(ctor, "quadraticCurveTo", QuadraticCurveTo); - NODE_SET_PROTOTYPE_METHOD(ctor, "beginPath", BeginPath); - NODE_SET_PROTOTYPE_METHOD(ctor, "closePath", ClosePath); - NODE_SET_PROTOTYPE_METHOD(ctor, "arc", Arc); - NODE_SET_PROTOTYPE_METHOD(ctor, "arcTo", ArcTo); - NODE_SET_PROTOTYPE_METHOD(ctor, "setLineDash", SetLineDash); - NODE_SET_PROTOTYPE_METHOD(ctor, "getLineDash", GetLineDash); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setFont", SetFont); -#ifdef HAVE_FREETYPE - NODE_SET_PROTOTYPE_METHOD(ctor, "_setFontFace", SetFontFace); -#endif - NODE_SET_PROTOTYPE_METHOD(ctor, "_setFillColor", SetFillColor); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setStrokeColor", SetStrokeColor); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setFillPattern", SetFillPattern); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setStrokePattern", SetStrokePattern); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextBaseline", SetTextBaseline); - NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextAlignment", SetTextAlignment); - proto->SetAccessor(NanNew("patternQuality"), GetPatternQuality, SetPatternQuality); - proto->SetAccessor(NanNew("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); - proto->SetAccessor(NanNew("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); - proto->SetAccessor(NanNew("shadowColor"), GetShadowColor, SetShadowColor); - proto->SetAccessor(NanNew("fillColor"), GetFillColor); - proto->SetAccessor(NanNew("strokeColor"), GetStrokeColor); - proto->SetAccessor(NanNew("miterLimit"), GetMiterLimit, SetMiterLimit); - proto->SetAccessor(NanNew("lineWidth"), GetLineWidth, SetLineWidth); - proto->SetAccessor(NanNew("lineCap"), GetLineCap, SetLineCap); - proto->SetAccessor(NanNew("lineJoin"), GetLineJoin, SetLineJoin); - proto->SetAccessor(NanNew("lineDashOffset"), GetLineDashOffset, SetLineDashOffset); - proto->SetAccessor(NanNew("shadowOffsetX"), GetShadowOffsetX, SetShadowOffsetX); - proto->SetAccessor(NanNew("shadowOffsetY"), GetShadowOffsetY, SetShadowOffsetY); - proto->SetAccessor(NanNew("shadowBlur"), GetShadowBlur, SetShadowBlur); - proto->SetAccessor(NanNew("antialias"), GetAntiAlias, SetAntiAlias); - proto->SetAccessor(NanNew("textDrawingMode"), GetTextDrawingMode, SetTextDrawingMode); - proto->SetAccessor(NanNew("filter"), GetFilter, SetFilter); - target->Set(NanNew("CanvasRenderingContext2d"), ctor->GetFunction()); -} - -/* - * Create a cairo context. - */ - -Context2d::Context2d(Canvas *canvas) { - _canvas = canvas; - _context = cairo_create(canvas->surface()); -#if HAVE_PANGO - _layout = pango_cairo_create_layout(_context); -#endif - cairo_set_line_width(_context, 1); - state = states[stateno = 0] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); - state->shadowBlur = 0; - state->shadowOffsetX = state->shadowOffsetY = 0; - state->globalAlpha = 1; - state->textAlignment = -1; - state->fillPattern = state->strokePattern = NULL; - state->fillGradient = state->strokeGradient = NULL; - state->textBaseline = TEXT_BASELINE_ALPHABETIC; - rgba_t transparent = { 0,0,0,1 }; - rgba_t transparent_black = { 0,0,0,0 }; - state->fill = transparent; - state->stroke = transparent; - state->shadow = transparent_black; - state->patternQuality = CAIRO_FILTER_GOOD; - state->textDrawingMode = TEXT_DRAW_PATHS; -#if HAVE_PANGO - state->fontWeight = PANGO_WEIGHT_NORMAL; - state->fontStyle = PANGO_STYLE_NORMAL; - state->fontSize = 10; - state->fontFamily = NULL; - state_assign_fontFamily(state, "sans serif"); - setFontFromState(); -#endif -} - -/* - * Destroy cairo context. - */ - -Context2d::~Context2d() { - while(stateno >= 0) { -#if HAVE_PANGO - free(states[stateno]->fontFamily); -#endif - free(states[stateno--]); - } -#if HAVE_PANGO - g_object_unref(_layout); -#endif - cairo_destroy(_context); -} - -/* - * Save cairo / canvas state. - */ - -void -Context2d::save() { - cairo_save(_context); - saveState(); -} - -/* - * Restore cairo / canvas state. - */ - -void -Context2d::restore() { - cairo_restore(_context); - restoreState(); -} - -/* - * Save the current state. - */ - -void -Context2d::saveState() { - if (stateno == CANVAS_MAX_STATES) return; - states[++stateno] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); - memcpy(states[stateno], state, sizeof(canvas_state_t)); -#if HAVE_PANGO - states[stateno]->fontFamily = strndup(state->fontFamily, 100); -#endif - state = states[stateno]; -} - -/* - * Restore state. - */ - -void -Context2d::restoreState() { - if (0 == stateno) return; - // Olaf (2011-02-21): Free old state data -#if HAVE_PANGO - free(states[stateno]->fontFamily); -#endif - free(states[stateno]); - states[stateno] = NULL; - state = states[--stateno]; -#if HAVE_PANGO - setFontFromState(); -#endif -} - -/* - * Save flat path. - */ - -void -Context2d::savePath() { - _path = cairo_copy_path_flat(_context); - cairo_new_path(_context); -} - -/* - * Restore flat path. - */ - -void -Context2d::restorePath() { - cairo_new_path(_context); - cairo_append_path(_context, _path); - cairo_path_destroy(_path); -} - -/* - * Fill and apply shadow. - */ - -void -Context2d::fill(bool preserve) { - if (state->fillPattern) { - cairo_set_source(_context, state->fillPattern); - cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT); - // TODO repeat/repeat-x/repeat-y - } else if (state->fillGradient) { - cairo_pattern_set_filter(state->fillGradient, state->patternQuality); - cairo_set_source(_context, state->fillGradient); - } else { - setSourceRGBA(state->fill); - } - - if (preserve) { - hasShadow() - ? shadow(cairo_fill_preserve) - : cairo_fill_preserve(_context); - } else { - hasShadow() - ? shadow(cairo_fill) - : cairo_fill(_context); - } -} - -/* - * Stroke and apply shadow. - */ - -void -Context2d::stroke(bool preserve) { - if (state->strokePattern) { - cairo_set_source(_context, state->strokePattern); - cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT); - } else if (state->strokeGradient) { - cairo_pattern_set_filter(state->strokeGradient, state->patternQuality); - cairo_set_source(_context, state->strokeGradient); - } else { - setSourceRGBA(state->stroke); - } - - if (preserve) { - hasShadow() - ? shadow(cairo_stroke_preserve) - : cairo_stroke_preserve(_context); - } else { - hasShadow() - ? shadow(cairo_stroke) - : cairo_stroke(_context); - } -} - -/* - * Apply shadow with the given draw fn. - */ - -void -Context2d::shadow(void (fn)(cairo_t *cr)) { - cairo_path_t *path = cairo_copy_path_flat(_context); - cairo_save(_context); - - // shadowOffset is unaffected by current transform - cairo_matrix_t path_matrix; - cairo_get_matrix(_context, &path_matrix); - cairo_identity_matrix(_context); - - // Apply shadow - cairo_push_group(_context); - - // No need to invoke blur if shadowBlur is 0 - if (state->shadowBlur) { - // find out extent of path - double x1, y1, x2, y2; - if (fn == cairo_fill || fn == cairo_fill_preserve) { - cairo_fill_extents(_context, &x1, &y1, &x2, &y2); - } else { - cairo_stroke_extents(_context, &x1, &y1, &x2, &y2); - } - - // create new image surface that size + padding for blurring - double dx = x2-x1, dy = y2-y1; - cairo_user_to_device_distance(_context, &dx, &dy); - int pad = state->shadowBlur * 2; - cairo_surface_t *surface = cairo_get_group_target(_context); - cairo_surface_t *shadow_surface = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, - dx + 2 * pad, - dy + 2 * pad); - cairo_t *shadow_context = cairo_create(shadow_surface); - - // transform path to the right place - cairo_translate(shadow_context, pad-x1, pad-y1); - cairo_transform(shadow_context, &path_matrix); - - // draw the path and blur - cairo_set_line_width(shadow_context, cairo_get_line_width(_context)); - cairo_new_path(shadow_context); - cairo_append_path(shadow_context, path); - setSourceRGBA(shadow_context, state->shadow); - fn(shadow_context); - blur(shadow_surface, state->shadowBlur); - - // paint to original context - cairo_set_source_surface(_context, shadow_surface, - x1 - pad + state->shadowOffsetX + 1, - y1 - pad + state->shadowOffsetY + 1); - cairo_paint(_context); - cairo_destroy(shadow_context); - cairo_surface_destroy(shadow_surface); - } else { - // Offset first, then apply path's transform - cairo_translate( - _context - , state->shadowOffsetX - , state->shadowOffsetY); - cairo_transform(_context, &path_matrix); - - // Apply shadow - cairo_new_path(_context); - cairo_append_path(_context, path); - setSourceRGBA(state->shadow); - - fn(_context); - } - - // Paint the shadow - cairo_pop_group_to_source(_context); - cairo_paint(_context); - - // Restore state - cairo_restore(_context); - cairo_new_path(_context); - cairo_append_path(_context, path); - fn(_context); - - cairo_path_destroy(path); -} - -/* - * Set source RGBA for the current context - */ - -void -Context2d::setSourceRGBA(rgba_t color) { - setSourceRGBA(_context, color); -} - -/* - * Set source RGBA - */ - -void -Context2d::setSourceRGBA(cairo_t *ctx, rgba_t color) { - cairo_set_source_rgba( - ctx - , color.r - , color.g - , color.b - , color.a * state->globalAlpha); -} - -/* - * Check if the context has a drawable shadow. - */ - -bool -Context2d::hasShadow() { - return state->shadow.a - && (state->shadowBlur || state->shadowOffsetX || state->shadowOffsetY); -} - -/* - * Blur the given surface with the given radius. - */ - -void -Context2d::blur(cairo_surface_t *surface, int radius) { - // Steve Hanov, 2009 - // Released into the public domain. - radius = radius * 0.57735f + 0.5f; - // get width, height - int width = cairo_image_surface_get_width( surface ); - int height = cairo_image_surface_get_height( surface ); - unsigned* precalc = - (unsigned*)malloc(width*height*sizeof(unsigned)); - cairo_surface_flush( surface ); - unsigned char* src = cairo_image_surface_get_data( surface ); - double mul=1.f/((radius*2)*(radius*2)); - int channel; - - // The number of times to perform the averaging. According to wikipedia, - // three iterations is good enough to pass for a gaussian. - const int MAX_ITERATIONS = 3; - int iteration; - - for ( iteration = 0; iteration < MAX_ITERATIONS; iteration++ ) { - for( channel = 0; channel < 4; channel++ ) { - int x,y; - - // precomputation step. - unsigned char* pix = src; - unsigned* pre = precalc; - - pix += channel; - for (y=0;y0) tot+=pre[-1]; - if (y>0) tot+=pre[-width]; - if (x>0 && y>0) tot-=pre[-width-1]; - *pre++=tot; - pix += 4; - } - } - - // blur step. - pix = src + (int)radius * width * 4 + (int)radius * 4 + channel; - for (y=radius;y= width ? width - 1 : x + radius; - int b = y + radius >= height ? height - 1 : y + radius; - int tot = precalc[r+b*width] + precalc[l+t*width] - - precalc[l+b*width] - precalc[r+t*width]; - *pix=(unsigned char)(tot*mul); - pix += 4; - } - pix += (int)radius * 2 * 4; - } - } - } - - cairo_surface_mark_dirty(surface); - free(precalc); -} - -/* - * Initialize a new Context2d with the given canvas. - */ - -NAN_METHOD(Context2d::New) { - NanScope(); - Local obj = args[0]->ToObject(); - if (!NanHasInstance(Canvas::constructor, obj)) - return NanThrowTypeError("Canvas expected"); - Canvas *canvas = ObjectWrap::Unwrap(obj); - Context2d *context = new Context2d(canvas); - context->Wrap(args.This()); - NanReturnValue(args.This()); -} - -/* - * Create a new page. - */ - -NAN_METHOD(Context2d::AddPage) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - if (!context->canvas()->isPDF()) { - return NanThrowError("only PDF canvases support .nextPage()"); - } - cairo_show_page(context->context()); - NanReturnUndefined(); -} - -/* - * Put image data. - * - * - imageData, dx, dy - * - imageData, dx, dy, sx, sy, sw, sh - * - */ - -NAN_METHOD(Context2d::PutImageData) { - NanScope(); - - Local obj = args[0]->ToObject(); - if (!NanHasInstance(ImageData::constructor, obj)) - return NanThrowTypeError("ImageData expected"); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - ImageData *imageData = ObjectWrap::Unwrap(obj); - PixelArray *arr = imageData->pixelArray(); - - uint8_t *src = arr->data(); - uint8_t *dst = context->canvas()->data(); - - int srcStride = arr->stride() - , dstStride = context->canvas()->stride(); - - int sx = 0 - , sy = 0 - , sw = 0 - , sh = 0 - , dx = args[1]->Int32Value() - , dy = args[2]->Int32Value() - , rows - , cols; - - switch (args.Length()) { - // imageData, dx, dy - case 3: - cols = std::min(arr->width(), context->canvas()->width - dx); - rows = std::min(arr->height(), context->canvas()->height - dy); - break; - // imageData, dx, dy, sx, sy, sw, sh - case 7: - sx = args[3]->Int32Value(); - sy = args[4]->Int32Value(); - sw = args[5]->Int32Value(); - sh = args[6]->Int32Value(); - if (sx < 0) sw += sx, sx = 0; - if (sy < 0) sh += sy, sy = 0; - if (sx + sw > arr->width()) sw = arr->width() - sx; - if (sy + sh > arr->height()) sh = arr->height() - sy; - dx += sx; - dy += sy; - cols = std::min(sw, context->canvas()->width - dx); - rows = std::min(sh, context->canvas()->height - dy); - break; - default: - return NanThrowError("invalid arguments"); - } - - if (cols <= 0 || rows <= 0) NanReturnUndefined(); - - uint8_t *srcRows = src + sy * srcStride + sx * 4; - for (int y = 0; y < rows; ++y) { - uint32_t *row = (uint32_t *)(dst + dstStride * (y + dy)); - for (int x = 0; x < cols; ++x) { - int bx = x * 4; - uint32_t *pixel = row + x + dx; - - // RGBA - uint8_t a = srcRows[bx + 3]; - uint8_t r = srcRows[bx + 0]; - uint8_t g = srcRows[bx + 1]; - uint8_t b = srcRows[bx + 2]; - float alpha = (float) a / 255; - - // ARGB - *pixel = a << 24 - | (int)((float) r * alpha) << 16 - | (int)((float) g * alpha) << 8 - | (int)((float) b * alpha); - } - srcRows += srcStride; - } - - cairo_surface_mark_dirty_rectangle( - context->canvas()->surface() - , dx - , dy - , cols - , rows); - - NanReturnUndefined(); -} - -/* - * Draw image src image to the destination (context). - * - * - dx, dy - * - dx, dy, dw, dh - * - sx, sy, sw, sh, dx, dy, dw, dh - * - */ - -NAN_METHOD(Context2d::DrawImage) { - NanScope(); - - if (args.Length() < 3) - return NanThrowTypeError("invalid arguments"); - - float sx = 0 - , sy = 0 - , sw = 0 - , sh = 0 - , dx, dy, dw, dh; - - cairo_surface_t *surface; - - Local obj = args[0]->ToObject(); - - // Image - if (NanHasInstance(Image::constructor, obj)) { - Image *img = ObjectWrap::Unwrap(obj); - if (!img->isComplete()) { - return NanThrowError("Image given has not completed loading"); - } - sw = img->width; - sh = img->height; - surface = img->surface(); - - // Canvas - } else if (NanHasInstance(Canvas::constructor, obj)) { - Canvas *canvas = ObjectWrap::Unwrap(obj); - sw = canvas->width; - sh = canvas->height; - surface = canvas->surface(); - - // Invalid - } else { - return NanThrowTypeError("Image or Canvas expected"); - } - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - // Arguments - switch (args.Length()) { - // img, sx, sy, sw, sh, dx, dy, dw, dh - case 9: - sx = args[1]->NumberValue(); - sy = args[2]->NumberValue(); - sw = args[3]->NumberValue(); - sh = args[4]->NumberValue(); - dx = args[5]->NumberValue(); - dy = args[6]->NumberValue(); - dw = args[7]->NumberValue(); - dh = args[8]->NumberValue(); - break; - // img, dx, dy, dw, dh - case 5: - dx = args[1]->NumberValue(); - dy = args[2]->NumberValue(); - dw = args[3]->NumberValue(); - dh = args[4]->NumberValue(); - break; - // img, dx, dy - case 3: - dx = args[1]->NumberValue(); - dy = args[2]->NumberValue(); - dw = sw; - dh = sh; - break; - default: - return NanThrowTypeError("invalid arguments"); - } - - // Start draw - cairo_save(ctx); - - // Scale src - if (dw != sw || dh != sh) { - float fx = (float) dw / sw; - float fy = (float) dh / sh; - cairo_scale(ctx, fx, fy); - dx /= fx; - dy /= fy; - } - - if (context->hasShadow()) { - context->setSourceRGBA(context->state->shadow); - cairo_mask_surface(ctx, surface, - dx - sx + context->state->shadowOffsetX, - dy - sy + context->state->shadowOffsetY); - } - - context->savePath(); - cairo_rectangle(ctx, dx, dy, dw, dh); - cairo_clip(ctx); - context->restorePath(); - - // Paint - cairo_set_source_surface(ctx, surface, dx - sx, dy - sy); - cairo_pattern_set_filter(cairo_get_source(ctx), context->state->patternQuality); - cairo_paint_with_alpha(ctx, context->state->globalAlpha); - - cairo_restore(ctx); - - NanReturnUndefined(); -} - -/* - * Get global alpha. - */ - -NAN_GETTER(Context2d::GetGlobalAlpha) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(context->state->globalAlpha)); -} - -/* - * Set global alpha. - */ - -NAN_SETTER(Context2d::SetGlobalAlpha) { - double n = value->NumberValue(); - if (n >= 0 && n <= 1) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->globalAlpha = n; - } -} - -/* - * Get global composite operation. - */ - -NAN_GETTER(Context2d::GetGlobalCompositeOperation) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - const char *op = "source-over"; - switch (cairo_get_operator(ctx)) { - case CAIRO_OPERATOR_ATOP: op = "source-atop"; break; - case CAIRO_OPERATOR_IN: op = "source-in"; break; - case CAIRO_OPERATOR_OUT: op = "source-out"; break; - case CAIRO_OPERATOR_XOR: op = "xor"; break; - case CAIRO_OPERATOR_DEST_ATOP: op = "destination-atop"; break; - case CAIRO_OPERATOR_DEST_IN: op = "destination-in"; break; - case CAIRO_OPERATOR_DEST_OUT: op = "destination-out"; break; - case CAIRO_OPERATOR_DEST_OVER: op = "destination-over"; break; - case CAIRO_OPERATOR_CLEAR: op = "clear"; break; - case CAIRO_OPERATOR_SOURCE: op = "source"; break; - case CAIRO_OPERATOR_DEST: op = "dest"; break; - case CAIRO_OPERATOR_OVER: op = "over"; break; - case CAIRO_OPERATOR_SATURATE: op = "saturate"; break; - // Non-standard - // supported by resent versions of cairo -#if CAIRO_VERSION_MINOR >= 10 - case CAIRO_OPERATOR_LIGHTEN: op = "lighten"; break; - case CAIRO_OPERATOR_ADD: op = "add"; break; - case CAIRO_OPERATOR_DARKEN: op = "darker"; break; - case CAIRO_OPERATOR_MULTIPLY: op = "multiply"; break; - case CAIRO_OPERATOR_SCREEN: op = "screen"; break; - case CAIRO_OPERATOR_OVERLAY: op = "overlay"; break; - case CAIRO_OPERATOR_HARD_LIGHT: op = "hard-light"; break; - case CAIRO_OPERATOR_SOFT_LIGHT: op = "soft-light"; break; - case CAIRO_OPERATOR_HSL_HUE: op = "hsl-hue"; break; - case CAIRO_OPERATOR_HSL_SATURATION: op = "hsl-saturation"; break; - case CAIRO_OPERATOR_HSL_COLOR: op = "hsl-color"; break; - case CAIRO_OPERATOR_HSL_LUMINOSITY: op = "hsl-luminosity"; break; - case CAIRO_OPERATOR_COLOR_DODGE: op = "color-dodge"; break; - case CAIRO_OPERATOR_COLOR_BURN: op = "color-burn"; break; - case CAIRO_OPERATOR_DIFFERENCE: op = "difference"; break; - case CAIRO_OPERATOR_EXCLUSION: op = "exclusion"; break; -#else - case CAIRO_OPERATOR_ADD: op = "lighter"; break; -#endif - } - - NanReturnValue(NanNew(op)); -} - -/* - * Set pattern quality. - */ - -NAN_SETTER(Context2d::SetPatternQuality) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - String::Utf8Value quality(value->ToString()); - if (0 == strcmp("fast", *quality)) { - context->state->patternQuality = CAIRO_FILTER_FAST; - } else if (0 == strcmp("good", *quality)) { - context->state->patternQuality = CAIRO_FILTER_GOOD; - } else if (0 == strcmp("best", *quality)) { - context->state->patternQuality = CAIRO_FILTER_BEST; - } else if (0 == strcmp("nearest", *quality)) { - context->state->patternQuality = CAIRO_FILTER_NEAREST; - } else if (0 == strcmp("bilinear", *quality)) { - context->state->patternQuality = CAIRO_FILTER_BILINEAR; - } -} - -/* - * Get pattern quality. - */ - -NAN_GETTER(Context2d::GetPatternQuality) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *quality; - switch (context->state->patternQuality) { - case CAIRO_FILTER_FAST: quality = "fast"; break; - case CAIRO_FILTER_BEST: quality = "best"; break; - case CAIRO_FILTER_NEAREST: quality = "nearest"; break; - case CAIRO_FILTER_BILINEAR: quality = "bilinear"; break; - default: quality = "good"; - } - NanReturnValue(NanNew(quality)); -} - -/* - * Set global composite operation. - */ - -NAN_SETTER(Context2d::SetGlobalCompositeOperation) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - String::Utf8Value type(value->ToString()); - if (0 == strcmp("xor", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_XOR); - } else if (0 == strcmp("source-atop", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_ATOP); - } else if (0 == strcmp("source-in", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_IN); - } else if (0 == strcmp("source-out", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_OUT); - } else if (0 == strcmp("destination-atop", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_ATOP); - } else if (0 == strcmp("destination-in", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_IN); - } else if (0 == strcmp("destination-out", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_OUT); - } else if (0 == strcmp("destination-over", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DEST_OVER); - } else if (0 == strcmp("clear", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); - } else if (0 == strcmp("source", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); - } else if (0 == strcmp("dest", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DEST); - } else if (0 == strcmp("saturate", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_SATURATE); - } else if (0 == strcmp("over", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); - // Non-standard - // supported by resent versions of cairo -#if CAIRO_VERSION_MINOR >= 10 - } else if (0 == strcmp("add", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_ADD); - } else if (0 == strcmp("lighten", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_LIGHTEN); - } else if (0 == strcmp("darker", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DARKEN); - } else if (0 == strcmp("multiply", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_MULTIPLY); - } else if (0 == strcmp("screen", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_SCREEN); - } else if (0 == strcmp("overlay", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_OVERLAY); - } else if (0 == strcmp("hard-light", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_HARD_LIGHT); - } else if (0 == strcmp("soft-light", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_SOFT_LIGHT); - } else if (0 == strcmp("hsl-hue", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_HUE); - } else if (0 == strcmp("hsl-saturation", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_SATURATION); - } else if (0 == strcmp("hsl-color", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_COLOR); - } else if (0 == strcmp("hsl-luminosity", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_HSL_LUMINOSITY); - } else if (0 == strcmp("color-dodge", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_COLOR_DODGE); - } else if (0 == strcmp("color-burn", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_COLOR_BURN); - } else if (0 == strcmp("difference", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_DIFFERENCE); - } else if (0 == strcmp("exclusion", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_EXCLUSION); -#endif - } else if (0 == strcmp("lighter", *type)) { - cairo_set_operator(ctx, CAIRO_OPERATOR_ADD); - } else { - cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); - } -} - -/* - * Get shadow offset x. - */ - -NAN_GETTER(Context2d::GetShadowOffsetX) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(context->state->shadowOffsetX)); -} - -/* - * Set shadow offset x. - */ - -NAN_SETTER(Context2d::SetShadowOffsetX) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->shadowOffsetX = value->NumberValue(); -} - -/* - * Get shadow offset y. - */ - -NAN_GETTER(Context2d::GetShadowOffsetY) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(context->state->shadowOffsetY)); -} - -/* - * Set shadow offset y. - */ - -NAN_SETTER(Context2d::SetShadowOffsetY) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->shadowOffsetY = value->NumberValue(); -} - -/* - * Get shadow blur. - */ - -NAN_GETTER(Context2d::GetShadowBlur) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(context->state->shadowBlur)); -} - -/* - * Set shadow blur. - */ - -NAN_SETTER(Context2d::SetShadowBlur) { - int n = value->NumberValue(); - if (n >= 0) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->shadowBlur = n; - } -} - -/* - * Get current antialiasing setting. - */ - -NAN_GETTER(Context2d::GetAntiAlias) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *aa; - switch (cairo_get_antialias(context->context())) { - case CAIRO_ANTIALIAS_NONE: aa = "none"; break; - case CAIRO_ANTIALIAS_GRAY: aa = "gray"; break; - case CAIRO_ANTIALIAS_SUBPIXEL: aa = "subpixel"; break; - default: aa = "default"; - } - NanReturnValue(NanNew(aa)); -} - -/* - * Set antialiasing. - */ - -NAN_SETTER(Context2d::SetAntiAlias) { - String::Utf8Value str(value->ToString()); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - cairo_antialias_t a; - if (0 == strcmp("none", *str)) { - a = CAIRO_ANTIALIAS_NONE; - } else if (0 == strcmp("default", *str)) { - a = CAIRO_ANTIALIAS_DEFAULT; - } else if (0 == strcmp("gray", *str)) { - a = CAIRO_ANTIALIAS_GRAY; - } else if (0 == strcmp("subpixel", *str)) { - a = CAIRO_ANTIALIAS_SUBPIXEL; - } else { - a = cairo_get_antialias(ctx); - } - cairo_set_antialias(ctx, a); -} - -/* - * Get text drawing mode. - */ - -NAN_GETTER(Context2d::GetTextDrawingMode) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *mode; - if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { - mode = "path"; - } else if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { - mode = "glyph"; - } else { - mode = "unknown"; - } - NanReturnValue(NanNew(mode)); -} - -/* - * Set text drawing mode. - */ - -NAN_SETTER(Context2d::SetTextDrawingMode) { - String::Utf8Value str(value->ToString()); - Context2d *context = ObjectWrap::Unwrap(args.This()); - if (0 == strcmp("path", *str)) { - context->state->textDrawingMode = TEXT_DRAW_PATHS; - } else if (0 == strcmp("glyph", *str)) { - context->state->textDrawingMode = TEXT_DRAW_GLYPHS; - } -} - -/* - * Get filter. - */ - -NAN_GETTER(Context2d::GetFilter) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *filter; - switch (cairo_pattern_get_filter(cairo_get_source(context->context()))) { - case CAIRO_FILTER_FAST: filter = "fast"; break; - case CAIRO_FILTER_BEST: filter = "best"; break; - case CAIRO_FILTER_NEAREST: filter = "nearest"; break; - case CAIRO_FILTER_BILINEAR: filter = "bilinear"; break; - default: filter = "good"; - } - NanReturnValue(NanNew(filter)); -} - -/* - * Set filter. - */ - -NAN_SETTER(Context2d::SetFilter) { - String::Utf8Value str(value->ToString()); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_filter_t filter; - if (0 == strcmp("fast", *str)) { - filter = CAIRO_FILTER_FAST; - } else if (0 == strcmp("best", *str)) { - filter = CAIRO_FILTER_BEST; - } else if (0 == strcmp("nearest", *str)) { - filter = CAIRO_FILTER_NEAREST; - } else if (0 == strcmp("bilinear", *str)) { - filter = CAIRO_FILTER_BILINEAR; - } else { - filter = CAIRO_FILTER_GOOD; - } - cairo_pattern_set_filter(cairo_get_source(context->context()), filter); -} - -/* - * Get miter limit. - */ - -NAN_GETTER(Context2d::GetMiterLimit) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(cairo_get_miter_limit(context->context()))); -} - -/* - * Set miter limit. - */ - -NAN_SETTER(Context2d::SetMiterLimit) { - double n = value->NumberValue(); - if (n > 0) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_set_miter_limit(context->context(), n); - } -} - -/* - * Get line width. - */ - -NAN_GETTER(Context2d::GetLineWidth) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(cairo_get_line_width(context->context()))); -} - -/* - * Set line width. - */ - -NAN_SETTER(Context2d::SetLineWidth) { - double n = value->NumberValue(); - if (n > 0) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_set_line_width(context->context(), n); - } -} - -/* - * Get line join. - */ - -NAN_GETTER(Context2d::GetLineJoin) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *join; - switch (cairo_get_line_join(context->context())) { - case CAIRO_LINE_JOIN_BEVEL: join = "bevel"; break; - case CAIRO_LINE_JOIN_ROUND: join = "round"; break; - default: join = "miter"; - } - NanReturnValue(NanNew(join)); -} - -/* - * Set line join. - */ - -NAN_SETTER(Context2d::SetLineJoin) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - String::Utf8Value type(value->ToString()); - if (0 == strcmp("round", *type)) { - cairo_set_line_join(ctx, CAIRO_LINE_JOIN_ROUND); - } else if (0 == strcmp("bevel", *type)) { - cairo_set_line_join(ctx, CAIRO_LINE_JOIN_BEVEL); - } else { - cairo_set_line_join(ctx, CAIRO_LINE_JOIN_MITER); - } -} - -/* - * Get line cap. - */ - -NAN_GETTER(Context2d::GetLineCap) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - const char *cap; - switch (cairo_get_line_cap(context->context())) { - case CAIRO_LINE_CAP_ROUND: cap = "round"; break; - case CAIRO_LINE_CAP_SQUARE: cap = "square"; break; - default: cap = "butt"; - } - NanReturnValue(NanNew(cap)); -} - -/* - * Set line cap. - */ - -NAN_SETTER(Context2d::SetLineCap) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - String::Utf8Value type(value->ToString()); - if (0 == strcmp("round", *type)) { - cairo_set_line_cap(ctx, CAIRO_LINE_CAP_ROUND); - } else if (0 == strcmp("square", *type)) { - cairo_set_line_cap(ctx, CAIRO_LINE_CAP_SQUARE); - } else { - cairo_set_line_cap(ctx, CAIRO_LINE_CAP_BUTT); - } -} - -/* - * Check if the given point is within the current path. - */ - -NAN_METHOD(Context2d::IsPointInPath) { - NanScope(); - if (args[0]->IsNumber() && args[1]->IsNumber()) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - double x = args[0]->NumberValue() - , y = args[1]->NumberValue(); - NanReturnValue(NanNew(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y))); - } - NanReturnValue(NanFalse()); -} - -/* - * Set fill pattern, useV internally for fillStyle= - */ - -NAN_METHOD(Context2d::SetFillPattern) { - NanScope(); - - Local obj = args[0]->ToObject(); - if (NanHasInstance(Gradient::constructor, obj)){ - Context2d *context = ObjectWrap::Unwrap(args.This()); - Gradient *grad = ObjectWrap::Unwrap(obj); - context->state->fillGradient = grad->pattern(); - } else if(NanHasInstance(Pattern::constructor, obj)){ - Context2d *context = ObjectWrap::Unwrap(args.This()); - Pattern *pattern = ObjectWrap::Unwrap(obj); - context->state->fillPattern = pattern->pattern(); - } else { - return NanThrowTypeError("Gradient or Pattern expected"); - } - NanReturnUndefined(); -} - -/* - * Set stroke pattern, used internally for strokeStyle= - */ - -NAN_METHOD(Context2d::SetStrokePattern) { - NanScope(); - - Local obj = args[0]->ToObject(); - if (NanHasInstance(Gradient::constructor, obj)){ - Context2d *context = ObjectWrap::Unwrap(args.This()); - Gradient *grad = ObjectWrap::Unwrap(obj); - context->state->strokeGradient = grad->pattern(); - } else if(NanHasInstance(Pattern::constructor, obj)){ - Context2d *context = ObjectWrap::Unwrap(args.This()); - Pattern *pattern = ObjectWrap::Unwrap(obj); - context->state->strokePattern = pattern->pattern(); - } else { - return NanThrowTypeError("Gradient or Pattern expected"); - } - - NanReturnUndefined(); -} - -/* - * Set shadow color. - */ - -NAN_SETTER(Context2d::SetShadowColor) { - short ok; - String::Utf8Value str(value->ToString()); - uint32_t rgba = rgba_from_string(*str, &ok); - if (ok) { - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->shadow = rgba_create(rgba); - } -} - -/* - * Get shadow color. - */ - -NAN_GETTER(Context2d::GetShadowColor) { - NanScope(); - char buf[64]; - Context2d *context = ObjectWrap::Unwrap(args.This()); - rgba_to_string(context->state->shadow, buf, sizeof(buf)); - NanReturnValue(NanNew(buf)); -} - -/* - * Set fill color, used internally for fillStyle= - */ - -NAN_METHOD(Context2d::SetFillColor) { - NanScope(); - short ok; - if (!args[0]->IsString()) NanReturnUndefined(); - String::Utf8Value str(args[0]); - uint32_t rgba = rgba_from_string(*str, &ok); - if (!ok) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->fillPattern = context->state->fillGradient = NULL; - context->state->fill = rgba_create(rgba); - NanReturnUndefined(); -} - -/* - * Get fill color. - */ - -NAN_GETTER(Context2d::GetFillColor) { - NanScope(); - char buf[64]; - Context2d *context = ObjectWrap::Unwrap(args.This()); - rgba_to_string(context->state->fill, buf, sizeof(buf)); - NanReturnValue(NanNew(buf)); -} - -/* - * Set stroke color, used internally for strokeStyle= - */ - -NAN_METHOD(Context2d::SetStrokeColor) { - NanScope(); - short ok; - if (!args[0]->IsString()) NanReturnUndefined(); - String::Utf8Value str(args[0]); - uint32_t rgba = rgba_from_string(*str, &ok); - if (!ok) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->strokePattern = context->state->strokeGradient = NULL; - context->state->stroke = rgba_create(rgba); - NanReturnUndefined(); -} - -/* - * Get stroke color. - */ - -NAN_GETTER(Context2d::GetStrokeColor) { - NanScope(); - char buf[64]; - Context2d *context = ObjectWrap::Unwrap(args.This()); - rgba_to_string(context->state->stroke, buf, sizeof(buf)); - NanReturnValue(NanNew(buf)); -} - -/* - * Bezier curve. - */ - -NAN_METHOD(Context2d::BezierCurveTo) { - NanScope(); - - if (!args[0]->IsNumber() - ||!args[1]->IsNumber() - ||!args[2]->IsNumber() - ||!args[3]->IsNumber() - ||!args[4]->IsNumber() - ||!args[5]->IsNumber()) NanReturnUndefined(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_curve_to(context->context() - , args[0]->NumberValue() - , args[1]->NumberValue() - , args[2]->NumberValue() - , args[3]->NumberValue() - , args[4]->NumberValue() - , args[5]->NumberValue()); - - NanReturnUndefined(); -} - -/* - * Quadratic curve approximation from libsvg-cairo. - */ - -NAN_METHOD(Context2d::QuadraticCurveTo) { - NanScope(); - - if (!args[0]->IsNumber() - ||!args[1]->IsNumber() - ||!args[2]->IsNumber() - ||!args[3]->IsNumber()) NanReturnUndefined(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - double x, y - , x1 = args[0]->NumberValue() - , y1 = args[1]->NumberValue() - , x2 = args[2]->NumberValue() - , y2 = args[3]->NumberValue(); - - cairo_get_current_point(ctx, &x, &y); - - if (0 == x && 0 == y) { - x = x1; - y = y1; - } - - cairo_curve_to(ctx - , x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y) - , x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2) - , x2 - , y2); - - NanReturnUndefined(); -} - -/* - * Save state. - */ - -NAN_METHOD(Context2d::Save) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->save(); - NanReturnUndefined(); -} - -/* - * Restore state. - */ - -NAN_METHOD(Context2d::Restore) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->restore(); - NanReturnUndefined(); -} - -/* - * Creates a new subpath. - */ - -NAN_METHOD(Context2d::BeginPath) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_new_path(context->context()); - NanReturnUndefined(); -} - -/* - * Marks the subpath as closed. - */ - -NAN_METHOD(Context2d::ClosePath) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_close_path(context->context()); - NanReturnUndefined(); -} - -/* - * Rotate transformation. - */ - -NAN_METHOD(Context2d::Rotate) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_rotate(context->context() - , args[0]->IsNumber() ? args[0]->NumberValue() : 0); - NanReturnUndefined(); -} - -/* - * Modify the CTM. - */ - -NAN_METHOD(Context2d::Transform) { - NanScope(); - - cairo_matrix_t matrix; - cairo_matrix_init(&matrix - , args[0]->IsNumber() ? args[0]->NumberValue() : 0 - , args[1]->IsNumber() ? args[1]->NumberValue() : 0 - , args[2]->IsNumber() ? args[2]->NumberValue() : 0 - , args[3]->IsNumber() ? args[3]->NumberValue() : 0 - , args[4]->IsNumber() ? args[4]->NumberValue() : 0 - , args[5]->IsNumber() ? args[5]->NumberValue() : 0); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_transform(context->context(), &matrix); - - NanReturnUndefined(); -} - -/* - * Reset the CTM, used internally by setTransform(). - */ - -NAN_METHOD(Context2d::ResetTransform) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_identity_matrix(context->context()); - NanReturnUndefined(); -} - -/* - * Translate transformation. - */ - -NAN_METHOD(Context2d::Translate) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_translate(context->context() - , args[0]->IsNumber() ? args[0]->NumberValue() : 0 - , args[1]->IsNumber() ? args[1]->NumberValue() : 0); - NanReturnUndefined(); -} - -/* - * Scale transformation. - */ - -NAN_METHOD(Context2d::Scale) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_scale(context->context() - , args[0]->IsNumber() ? args[0]->NumberValue() : 0 - , args[1]->IsNumber() ? args[1]->NumberValue() : 0); - NanReturnUndefined(); -} - -/* - * Use path as clipping region. - */ - -NAN_METHOD(Context2d::Clip) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - cairo_clip_preserve(ctx); - NanReturnUndefined(); -} - -/* - * Fill the path. - */ - -NAN_METHOD(Context2d::Fill) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->fill(true); - NanReturnUndefined(); -} - -/* - * Stroke the path. - */ - -NAN_METHOD(Context2d::Stroke) { - NanScope(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->stroke(true); - NanReturnUndefined(); -} - -/* - * Fill text at (x, y). - */ - -NAN_METHOD(Context2d::FillText) { - NanScope(); - - if (!args[1]->IsNumber() - || !args[2]->IsNumber()) NanReturnUndefined(); - - String::Utf8Value str(args[0]->ToString()); - double x = args[1]->NumberValue(); - double y = args[2]->NumberValue(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - - context->savePath(); - if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { - context->fill(); - context->setTextPath(*str, x, y); - } else if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { - context->setTextPath(*str, x, y); - context->fill(); - } - context->restorePath(); - - NanReturnUndefined(); -} - -/* - * Stroke text at (x ,y). - */ - -NAN_METHOD(Context2d::StrokeText) { - NanScope(); - - if (!args[1]->IsNumber() - || !args[2]->IsNumber()) NanReturnUndefined(); - - String::Utf8Value str(args[0]->ToString()); - double x = args[1]->NumberValue(); - double y = args[2]->NumberValue(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - - context->savePath(); - if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { - context->stroke(); - context->setTextPath(*str, x, y); - } else if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { - context->setTextPath(*str, x, y); - context->stroke(); - } - context->restorePath(); - - NanReturnUndefined(); -} - -/* - * Set text path for the given string at (x, y). - */ - -void -Context2d::setTextPath(const char *str, double x, double y) { -#if HAVE_PANGO - - PangoRectangle ink_rect, logical_rect; - PangoFontMetrics *metrics = NULL; - - pango_layout_set_text(_layout, str, -1); - pango_cairo_update_layout(_context, _layout); - - switch (state->textAlignment) { - // center - case 0: - pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect); - x -= logical_rect.width / 2; - break; - // right - case 1: - pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect); - x -= logical_rect.width; - break; - } - - switch (state->textBaseline) { - case TEXT_BASELINE_ALPHABETIC: - metrics = PANGO_LAYOUT_GET_METRICS(_layout); - y -= pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - break; - case TEXT_BASELINE_MIDDLE: - metrics = PANGO_LAYOUT_GET_METRICS(_layout); - y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE); - break; - case TEXT_BASELINE_BOTTOM: - metrics = PANGO_LAYOUT_GET_METRICS(_layout); - y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; - break; - } - - if (metrics) pango_font_metrics_unref(metrics); - - cairo_move_to(_context, x, y); - if (state->textDrawingMode == TEXT_DRAW_PATHS) { - pango_cairo_layout_path(_context, _layout); - } else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { - pango_cairo_show_layout(_context, _layout); - } - -#else - - cairo_text_extents_t te; - cairo_font_extents_t fe; - - // Alignment - switch (state->textAlignment) { - // center - case 0: - // Olaf (2011-02-19): te.x_bearing does not concern the alignment - cairo_text_extents(_context, str, &te); - x -= te.width / 2; - break; - // right - case 1: - // Olaf (2011-02-19): te.x_bearing does not concern the alignment - cairo_text_extents(_context, str, &te); - x -= te.width; - break; - } - - // Baseline approx - switch (state->textBaseline) { - case TEXT_BASELINE_TOP: - case TEXT_BASELINE_HANGING: - // Olaf (2011-02-26): fe.ascent approximates the distance between - // the top of the em square and the alphabetic baseline - cairo_font_extents(_context, &fe); - y += fe.ascent; - break; - case TEXT_BASELINE_MIDDLE: - // Olaf (2011-02-26): fe.ascent approximates the distance between - // the top of the em square and the alphabetic baseline - cairo_font_extents(_context, &fe); - y += (fe.ascent - fe.descent)/2; - break; - case TEXT_BASELINE_BOTTOM: - // Olaf (2011-02-26): we need to know the distance between the alphabetic - // baseline and the bottom of the em square - cairo_font_extents(_context, &fe); - y -= fe.descent; - break; - } - - cairo_move_to(_context, x, y); - if (state->textDrawingMode == TEXT_DRAW_PATHS) { - cairo_text_path(_context, str); - } else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { - cairo_show_text(_context, str); - } - -#endif -} - -/* - * Adds a point to the current subpath. - */ - -NAN_METHOD(Context2d::LineTo) { - NanScope(); - - if (!args[0]->IsNumber()) - return NanThrowTypeError("lineTo() x must be a number"); - if (!args[1]->IsNumber()) - return NanThrowTypeError("lineTo() y must be a number"); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_line_to(context->context() - , args[0]->NumberValue() - , args[1]->NumberValue()); - - NanReturnUndefined(); -} - -/* - * Creates a new subpath at the given point. - */ - -NAN_METHOD(Context2d::MoveTo) { - NanScope(); - - if (!args[0]->IsNumber()) - return NanThrowTypeError("moveTo() x must be a number"); - if (!args[1]->IsNumber()) - return NanThrowTypeError("moveTo() y must be a number"); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_move_to(context->context() - , args[0]->NumberValue() - , args[1]->NumberValue()); - - NanReturnUndefined(); -} - -/* - * Set font face. - */ - -#ifdef HAVE_FREETYPE -NAN_METHOD(Context2d::SetFontFace) { - NanScope(); - - // Ignore invalid args - if (!args[0]->IsObject() - || !args[1]->IsNumber()) - return NanThrowTypeError("Expected object and number"); - - Local obj = args[0]->ToObject(); - - if (!NanHasInstance(FontFace::constructor, obj)) - return NanThrowTypeError("FontFace expected"); - - FontFace *face = ObjectWrap::Unwrap(obj); - double size = args[1]->NumberValue(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - cairo_set_font_size(ctx, size); - cairo_set_font_face(ctx, face->cairoFace()); - - NanReturnUndefined(); -} -#endif - -/* - * Set font: - * - weight - * - style - * - size - * - unit - * - family - */ - -NAN_METHOD(Context2d::SetFont) { - NanScope(); - - // Ignore invalid args - if (!args[0]->IsString() - || !args[1]->IsString() - || !args[2]->IsNumber() - || !args[3]->IsString() - || !args[4]->IsString()) NanReturnUndefined(); - - String::Utf8Value weight(args[0]); - String::Utf8Value style(args[1]); - double size = args[2]->NumberValue(); - String::Utf8Value unit(args[3]); - String::Utf8Value family(args[4]); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - -#if HAVE_PANGO - - if (strlen(*family) > 0) state_assign_fontFamily(context->state, *family); - - if (size > 0) context->state->fontSize = size; - - PangoStyle s = PANGO_STYLE_NORMAL; - if (strlen(*style) > 0) { - if (0 == strcmp("italic", *style)) { - s = PANGO_STYLE_ITALIC; - } else if (0 == strcmp("oblique", *style)) { - s = PANGO_STYLE_OBLIQUE; - } - } - context->state->fontStyle = s; - - PangoWeight w = PANGO_WEIGHT_NORMAL; - if (strlen(*weight) > 0) { - if (0 == strcmp("bold", *weight)) { - w = PANGO_WEIGHT_BOLD; - } else if (0 == strcmp("200", *weight)) { - w = PANGO_WEIGHT_ULTRALIGHT; - } else if (0 == strcmp("300", *weight)) { - w = PANGO_WEIGHT_LIGHT; - } else if (0 == strcmp("400", *weight)) { - w = PANGO_WEIGHT_NORMAL; - } else if (0 == strcmp("500", *weight)) { - w = PANGO_WEIGHT_MEDIUM; - } else if (0 == strcmp("600", *weight)) { - w = PANGO_WEIGHT_SEMIBOLD; - } else if (0 == strcmp("700", *weight)) { - w = PANGO_WEIGHT_BOLD; - } else if (0 == strcmp("800", *weight)) { - w = PANGO_WEIGHT_ULTRABOLD; - } else if (0 == strcmp("900", *weight)) { - w = PANGO_WEIGHT_HEAVY; - } - } - context->state->fontWeight = w; - - context->setFontFromState(); - -#else - - cairo_t *ctx = context->context(); - - // Size - cairo_set_font_size(ctx, size); - - // Style - cairo_font_slant_t s = CAIRO_FONT_SLANT_NORMAL; - if (0 == strcmp("italic", *style)) { - s = CAIRO_FONT_SLANT_ITALIC; - } else if (0 == strcmp("oblique", *style)) { - s = CAIRO_FONT_SLANT_OBLIQUE; - } - - // Weight - cairo_font_weight_t w = CAIRO_FONT_WEIGHT_NORMAL; - if (0 == strcmp("bold", *weight)) { - w = CAIRO_FONT_WEIGHT_BOLD; - } - - cairo_select_font_face(ctx, *family, s, w); - -#endif - - NanReturnUndefined(); -} - -#if HAVE_PANGO - -/* - * Sets PangoLayout options from the current font state - */ - -void -Context2d::setFontFromState() { - PangoFontDescription *fd = pango_font_description_new(); - - pango_font_description_set_family(fd, state->fontFamily); - pango_font_description_set_absolute_size(fd, state->fontSize * PANGO_SCALE); - pango_font_description_set_style(fd, state->fontStyle); - pango_font_description_set_weight(fd, state->fontWeight); - - pango_layout_set_font_description(_layout, fd); - pango_font_description_free(fd); -} - -#endif - -/* - * Return the given text extents. - * TODO: Support for: - * hangingBaseline, ideographicBaseline, - * fontBoundingBoxAscent, fontBoundingBoxDescent - */ - -NAN_METHOD(Context2d::MeasureText) { - NanScope(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - String::Utf8Value str(args[0]->ToString()); - Local obj = NanNew(); - -#if HAVE_PANGO - - PangoRectangle ink_rect, logical_rect; - PangoFontMetrics *metrics; - PangoLayout *layout = context->layout(); - - pango_layout_set_text(layout, *str, -1); - pango_cairo_update_layout(ctx, layout); - - pango_layout_get_pixel_extents(layout, &ink_rect, &logical_rect); - metrics = PANGO_LAYOUT_GET_METRICS(layout); - - double x_offset; - switch (context->state->textAlignment) { - case 0: // center - x_offset = logical_rect.width / 2; - break; - case 1: // right - x_offset = logical_rect.width; - break; - default: // left - x_offset = 0.0; - } - - double y_offset; - switch (context->state->textBaseline) { - case TEXT_BASELINE_ALPHABETIC: - y_offset = -pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - break; - case TEXT_BASELINE_MIDDLE: - y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE); - break; - case TEXT_BASELINE_BOTTOM: - y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; - break; - default: - y_offset = 0.0; - } - - obj->Set(NanNew("width"), NanNew(logical_rect.width)); - obj->Set(NanNew("actualBoundingBoxLeft"), - NanNew(x_offset - PANGO_LBEARING(logical_rect))); - obj->Set(NanNew("actualBoundingBoxRight"), - NanNew(x_offset + PANGO_RBEARING(logical_rect))); - obj->Set(NanNew("actualBoundingBoxAscent"), - NanNew(-(y_offset+ink_rect.y))); - obj->Set(NanNew("actualBoundingBoxDescent"), - NanNew((PANGO_DESCENT(ink_rect) + y_offset))); - obj->Set(NanNew("emHeightAscent"), - NanNew(PANGO_ASCENT(logical_rect) - y_offset)); - obj->Set(NanNew("emHeightDescent"), - NanNew(PANGO_DESCENT(logical_rect) + y_offset)); - obj->Set(NanNew("alphabeticBaseline"), - NanNew((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) - + y_offset)); - - pango_font_metrics_unref(metrics); - -#else - - cairo_text_extents_t te; - cairo_font_extents_t fe; - - cairo_text_extents(ctx, *str, &te); - cairo_font_extents(ctx, &fe); - - double x_offset; - switch (context->state->textAlignment) { - case 0: // center - x_offset = te.width / 2; - break; - case 1: // right - x_offset = te.width; - break; - default: // left - x_offset = 0.0; - } - - double y_offset; - switch (context->state->textBaseline) { - case TEXT_BASELINE_TOP: - case TEXT_BASELINE_HANGING: - y_offset = fe.ascent; - break; - case TEXT_BASELINE_MIDDLE: - y_offset = (fe.ascent - fe.descent)/2; - break; - case TEXT_BASELINE_BOTTOM: - y_offset = -fe.descent; - break; - default: - y_offset = 0.0; - } - - obj->Set(NanNew("width"), NanNew(te.x_advance)); - obj->Set(NanNew("actualBoundingBoxLeft"), - NanNew(x_offset - te.x_bearing)); - obj->Set(NanNew("actualBoundingBoxRight"), - NanNew((te.x_bearing + te.width) - x_offset)); - obj->Set(NanNew("actualBoundingBoxAscent"), - NanNew(-(te.y_bearing + y_offset))); - obj->Set(NanNew("actualBoundingBoxDescent"), - NanNew(te.height + te.y_bearing + y_offset)); - obj->Set(NanNew("emHeightAscent"), NanNew(fe.ascent - y_offset)); - obj->Set(NanNew("emHeightDescent"), NanNew(fe.descent + y_offset)); - obj->Set(NanNew("alphabeticBaseline"), NanNew(y_offset)); - -#endif - - NanReturnValue(obj); -} - -/* - * Set text baseline. - */ - -NAN_METHOD(Context2d::SetTextBaseline) { - NanScope(); - - if (!args[0]->IsInt32()) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->textBaseline = args[0]->Int32Value(); - - NanReturnUndefined(); -} - -/* - * Set text alignment. -1 0 1 - */ - -NAN_METHOD(Context2d::SetTextAlignment) { - NanScope(); - - if (!args[0]->IsInt32()) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->textAlignment = args[0]->Int32Value(); - - NanReturnUndefined(); -} - -/* - * Set line dash - * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash - */ -NAN_METHOD(Context2d::SetLineDash) { - NanScope(); - - if (!args[0]->IsArray()) NanReturnUndefined(); - Handle dash = Handle::Cast(args[0]); - uint32_t dashes = dash->Length() & 1 ? dash->Length() * 2 : dash->Length(); - - std::vector a(dashes); - for (uint32_t i=0; i d = dash->Get(i % dash->Length()); - if (!d->IsNumber()) NanReturnUndefined(); - a[i] = d->NumberValue(); - if (a[i] < 0 || isnan(a[i]) || isinf(a[i])) NanReturnUndefined(); - } - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - double offset; - cairo_get_dash(ctx, NULL, &offset); - cairo_set_dash(ctx, a.data(), dashes, offset); - NanReturnUndefined(); -} - -/* - * Get line dash - * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash - */ -NAN_METHOD(Context2d::GetLineDash) { - NanScope(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - int dashes = cairo_get_dash_count(ctx); - std::vector a(dashes); - cairo_get_dash(ctx, a.data(), NULL); - - Local dash = NanNew(dashes); - for (int i=0; iSet(NanNew(i), NanNew(a[i])); - - NanReturnValue(dash); -} - -/* - * Set line dash offset - * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash - */ -NAN_SETTER(Context2d::SetLineDashOffset) { - NanScope(); - - double offset = value->NumberValue(); - if (isnan(offset) || isinf(offset)) return; - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - int dashes = cairo_get_dash_count(ctx); - std::vector a(dashes); - cairo_get_dash(ctx, a.data(), NULL); - cairo_set_dash(ctx, a.data(), dashes, offset); -} - -/* - * Get line dash offset - * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash - */ -NAN_GETTER(Context2d::GetLineDashOffset) { - NanScope(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - double offset; - cairo_get_dash(ctx, NULL, &offset); - - NanReturnValue(NanNew(offset)); -} - -/* - * Fill the rectangle defined by x, y, width and height. - */ - -NAN_METHOD(Context2d::FillRect) { - NanScope(); - RECT_ARGS; - if (0 == width || 0 == height) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - context->savePath(); - cairo_rectangle(ctx, x, y, width, height); - context->fill(); - context->restorePath(); - NanReturnUndefined(); -} - -/* - * Stroke the rectangle defined by x, y, width and height. - */ - -NAN_METHOD(Context2d::StrokeRect) { - NanScope(); - RECT_ARGS; - if (0 == width && 0 == height) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - context->savePath(); - cairo_rectangle(ctx, x, y, width, height); - context->stroke(); - context->restorePath(); - NanReturnUndefined(); -} - -/* - * Clears all pixels defined by x, y, width and height. - */ - -NAN_METHOD(Context2d::ClearRect) { - NanScope(); - RECT_ARGS; - if (0 == width || 0 == height) NanReturnUndefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - cairo_save(ctx); - context->savePath(); - cairo_rectangle(ctx, x, y, width, height); - cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); - cairo_fill(ctx); - context->restorePath(); - cairo_restore(ctx); - NanReturnUndefined(); -} - -/* - * Adds a rectangle subpath. - */ - -NAN_METHOD(Context2d::Rect) { - NanScope(); - RECT_ARGS; - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - if (width == 0) { - cairo_move_to(ctx, x, y); - cairo_line_to(ctx, x, y + height); - } else if (height == 0) { - cairo_move_to(ctx, x, y); - cairo_line_to(ctx, x + width, y); - } else { - cairo_rectangle(ctx, x, y, width, height); - } - NanReturnUndefined(); -} - -/* - * Adds an arc at x, y with the given radis and start/end angles. - */ - -NAN_METHOD(Context2d::Arc) { - NanScope(); - - if (!args[0]->IsNumber() - || !args[1]->IsNumber() - || !args[2]->IsNumber() - || !args[3]->IsNumber() - || !args[4]->IsNumber()) NanReturnUndefined(); - - bool anticlockwise = args[5]->BooleanValue(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - if (anticlockwise && M_PI * 2 != args[4]->NumberValue()) { - cairo_arc_negative(ctx - , args[0]->NumberValue() - , args[1]->NumberValue() - , args[2]->NumberValue() - , args[3]->NumberValue() - , args[4]->NumberValue()); - } else { - cairo_arc(ctx - , args[0]->NumberValue() - , args[1]->NumberValue() - , args[2]->NumberValue() - , args[3]->NumberValue() - , args[4]->NumberValue()); - } - - NanReturnUndefined(); -} - -/* - * Adds an arcTo point (x0,y0) to (x1,y1) with the given radius. - * - * Implementation influenced by WebKit. - */ - -NAN_METHOD(Context2d::ArcTo) { - NanScope(); - - if (!args[0]->IsNumber() - || !args[1]->IsNumber() - || !args[2]->IsNumber() - || !args[3]->IsNumber() - || !args[4]->IsNumber()) NanReturnUndefined(); - - Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_t *ctx = context->context(); - - // Current path point - double x, y; - cairo_get_current_point(ctx, &x, &y); - Point p0(x, y); - - // Point (x0,y0) - Point p1(args[0]->NumberValue(), args[1]->NumberValue()); - - // Point (x1,y1) - Point p2(args[2]->NumberValue(), args[3]->NumberValue()); - - float radius = args[4]->NumberValue(); - - if ((p1.x == p0.x && p1.y == p0.y) - || (p1.x == p2.x && p1.y == p2.y) - || radius == 0.f) { - cairo_line_to(ctx, p1.x, p1.y); - NanReturnUndefined(); - } - - Point p1p0((p0.x - p1.x),(p0.y - p1.y)); - Point p1p2((p2.x - p1.x),(p2.y - p1.y)); - float p1p0_length = sqrtf(p1p0.x * p1p0.x + p1p0.y * p1p0.y); - float p1p2_length = sqrtf(p1p2.x * p1p2.x + p1p2.y * p1p2.y); - - double cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length); - // all points on a line logic - if (-1 == cos_phi) { - cairo_line_to(ctx, p1.x, p1.y); - NanReturnUndefined(); - } - - if (1 == cos_phi) { - // add infinite far away point - unsigned int max_length = 65535; - double factor_max = max_length / p1p0_length; - Point ep((p0.x + factor_max * p1p0.x), (p0.y + factor_max * p1p0.y)); - cairo_line_to(ctx, ep.x, ep.y); - NanReturnUndefined(); - } - - float tangent = radius / tan(acos(cos_phi) / 2); - float factor_p1p0 = tangent / p1p0_length; - Point t_p1p0((p1.x + factor_p1p0 * p1p0.x), (p1.y + factor_p1p0 * p1p0.y)); - - Point orth_p1p0(p1p0.y, -p1p0.x); - float orth_p1p0_length = sqrt(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y); - float factor_ra = radius / orth_p1p0_length; - - double cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length); - if (cos_alpha < 0.f) - orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y); - - Point p((t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y)); - - orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y); - float sa = acos(orth_p1p0.x / orth_p1p0_length); - if (orth_p1p0.y < 0.f) - sa = 2 * M_PI - sa; - - bool anticlockwise = false; - - float factor_p1p2 = tangent / p1p2_length; - Point t_p1p2((p1.x + factor_p1p2 * p1p2.x), (p1.y + factor_p1p2 * p1p2.y)); - Point orth_p1p2((t_p1p2.x - p.x),(t_p1p2.y - p.y)); - float orth_p1p2_length = sqrtf(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y); - float ea = acos(orth_p1p2.x / orth_p1p2_length); - - if (orth_p1p2.y < 0) ea = 2 * M_PI - ea; - if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true; - if ((sa < ea) && ((ea - sa) > M_PI)) anticlockwise = true; - - cairo_line_to(ctx, t_p1p0.x, t_p1p0.y); - - if (anticlockwise && M_PI * 2 != radius) { - cairo_arc_negative(ctx - , p.x - , p.y - , radius - , sa - , ea); - } else { - cairo_arc(ctx - , p.x - , p.y - , radius - , sa - , ea); - } - - NanReturnUndefined(); -} diff --git a/scripts/external/three/canvas/src/CanvasRenderingContext2d.h b/scripts/external/three/canvas/src/CanvasRenderingContext2d.h deleted file mode 100644 index b5920a5..0000000 --- a/scripts/external/three/canvas/src/CanvasRenderingContext2d.h +++ /dev/null @@ -1,183 +0,0 @@ - -// -// CanvasRenderingContext2d.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_CONTEXT2D_H__ -#define __NODE_CONTEXT2D_H__ - -#include "color.h" -#include "Canvas.h" -#include "CanvasGradient.h" - -#ifdef HAVE_FREETYPE -#include -#include -#include FT_FREETYPE_H -#endif - -#include -using namespace std; - -typedef enum { - TEXT_DRAW_PATHS, - TEXT_DRAW_GLYPHS -} canvas_draw_mode_t; - -/* - * State struct. - * - * Used in conjunction with Save() / Restore() since - * cairo's gstate maintains only a single source pattern at a time. - */ - -typedef struct { - rgba_t fill; - rgba_t stroke; - cairo_filter_t patternQuality; - cairo_pattern_t *fillPattern; - cairo_pattern_t *strokePattern; - cairo_pattern_t *fillGradient; - cairo_pattern_t *strokeGradient; - float globalAlpha; - short textAlignment; - short textBaseline; - rgba_t shadow; - int shadowBlur; - double shadowOffsetX; - double shadowOffsetY; - canvas_draw_mode_t textDrawingMode; - -#if HAVE_PANGO - PangoWeight fontWeight; - PangoStyle fontStyle; - double fontSize; - char *fontFamily; -#endif - -} canvas_state_t; - -#if HAVE_PANGO -void state_assign_fontFamily(canvas_state_t *state, const char *str); -#endif - -class Context2d: public node::ObjectWrap { - public: - short stateno; - canvas_state_t *states[CANVAS_MAX_STATES]; - canvas_state_t *state; - Context2d(Canvas *canvas); - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_METHOD(DrawImage); - static NAN_METHOD(PutImageData); - static NAN_METHOD(Save); - static NAN_METHOD(Restore); - static NAN_METHOD(Rotate); - static NAN_METHOD(Translate); - static NAN_METHOD(Scale); - static NAN_METHOD(Transform); - static NAN_METHOD(ResetTransform); - static NAN_METHOD(IsPointInPath); - static NAN_METHOD(BeginPath); - static NAN_METHOD(ClosePath); - static NAN_METHOD(AddPage); - static NAN_METHOD(Clip); - static NAN_METHOD(Fill); - static NAN_METHOD(Stroke); - static NAN_METHOD(FillText); - static NAN_METHOD(StrokeText); - static NAN_METHOD(SetFont); -#ifdef HAVE_FREETYPE - static NAN_METHOD(SetFontFace); -#endif - static NAN_METHOD(SetFillColor); - static NAN_METHOD(SetStrokeColor); - static NAN_METHOD(SetFillPattern); - static NAN_METHOD(SetStrokePattern); - static NAN_METHOD(SetTextBaseline); - static NAN_METHOD(SetTextAlignment); - static NAN_METHOD(SetLineDash); - static NAN_METHOD(GetLineDash); - static NAN_METHOD(MeasureText); - static NAN_METHOD(BezierCurveTo); - static NAN_METHOD(QuadraticCurveTo); - static NAN_METHOD(LineTo); - static NAN_METHOD(MoveTo); - static NAN_METHOD(FillRect); - static NAN_METHOD(StrokeRect); - static NAN_METHOD(ClearRect); - static NAN_METHOD(Rect); - static NAN_METHOD(Arc); - static NAN_METHOD(ArcTo); - static NAN_GETTER(GetPatternQuality); - static NAN_GETTER(GetGlobalCompositeOperation); - static NAN_GETTER(GetGlobalAlpha); - static NAN_GETTER(GetShadowColor); - static NAN_GETTER(GetFillColor); - static NAN_GETTER(GetStrokeColor); - static NAN_GETTER(GetMiterLimit); - static NAN_GETTER(GetLineCap); - static NAN_GETTER(GetLineJoin); - static NAN_GETTER(GetLineWidth); - static NAN_GETTER(GetLineDashOffset); - static NAN_GETTER(GetShadowOffsetX); - static NAN_GETTER(GetShadowOffsetY); - static NAN_GETTER(GetShadowBlur); - static NAN_GETTER(GetAntiAlias); - static NAN_GETTER(GetTextDrawingMode); - static NAN_GETTER(GetFilter); - static NAN_SETTER(SetPatternQuality); - static NAN_SETTER(SetGlobalCompositeOperation); - static NAN_SETTER(SetGlobalAlpha); - static NAN_SETTER(SetShadowColor); - static NAN_SETTER(SetMiterLimit); - static NAN_SETTER(SetLineCap); - static NAN_SETTER(SetLineJoin); - static NAN_SETTER(SetLineWidth); - static NAN_SETTER(SetLineDashOffset); - static NAN_SETTER(SetShadowOffsetX); - static NAN_SETTER(SetShadowOffsetY); - static NAN_SETTER(SetShadowBlur); - static NAN_SETTER(SetAntiAlias); - static NAN_SETTER(SetTextDrawingMode); - static NAN_SETTER(SetFilter); - inline void setContext(cairo_t *ctx) { _context = ctx; } - inline cairo_t *context(){ return _context; } - inline Canvas *canvas(){ return _canvas; } - inline bool hasShadow(); - void inline setSourceRGBA(rgba_t color); - void inline setSourceRGBA(cairo_t *ctx, rgba_t color); - void setTextPath(const char *str, double x, double y); - void blur(cairo_surface_t *surface, int radius); - void shadow(void (fn)(cairo_t *cr)); - void shadowStart(); - void shadowApply(); - void savePath(); - void restorePath(); - void saveState(); - void restoreState(); - void fill(bool preserve = false); - void stroke(bool preserve = false); - void save(); - void restore(); - -#if HAVE_PANGO - void setFontFromState(); - inline PangoLayout *layout(){ return _layout; } -#endif - - private: - ~Context2d(); - Canvas *_canvas; - cairo_t *_context; - cairo_path_t *_path; -#if HAVE_PANGO - PangoLayout *_layout; -#endif -}; - -#endif diff --git a/scripts/external/three/canvas/src/FontFace.cc b/scripts/external/three/canvas/src/FontFace.cc deleted file mode 100755 index 2028f9b..0000000 --- a/scripts/external/three/canvas/src/FontFace.cc +++ /dev/null @@ -1,112 +0,0 @@ -// -// FontFace.cc -// -// Copyright (c) 2012 Julian Viereck -// - -#include "FontFace.h" - -#include - -Persistent FontFace::constructor; - -/* - * Destroy ft_face. - */ - -FontFace::~FontFace() { - // Decrement extra reference count added in ::New(...). - // Once there is no reference left to crFace, cairo will release the - // free type font face as well. - cairo_font_face_destroy(_crFace); -} - -/* - * Initialize FontFace. - */ - -void -FontFace::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(FontFace::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("FontFace")); - - // Prototype - target->Set(NanNew("FontFace"), ctor->GetFunction()); -} - -/* - * Initialize a new FontFace object. - */ - -FT_Library library; /* handle to library */ - -bool FontFace::_initLibrary = true; -static cairo_user_data_key_t key; - -/* - * Initialize a new FontFace. - */ - -NAN_METHOD(FontFace::New) { - NanScope(); - - if (!args[0]->IsString() - || !args[1]->IsNumber()) { - return NanThrowError("Wrong argument types passed to FontFace constructor"); - } - - String::Utf8Value filePath(args[0]); - int faceIdx = int(args[1]->NumberValue()); - - FT_Face ftFace; - FT_Error ftError; - cairo_font_face_t *crFace; - - if (_initLibrary) { - _initLibrary = false; - ftError = FT_Init_FreeType(&library); - if (ftError) { - return NanThrowError("Could not load library"); - } - } - - // Create new freetype font face. - ftError = FT_New_Face(library, *filePath, faceIdx, &ftFace); - if (ftError) { - return NanThrowError("Could not load font file"); - } - - #if HAVE_PANGO - // Load the font file in fontconfig - FcBool ok = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(*filePath)); - if (!ok) { - return NanThrowError("Could not load font in FontConfig"); - } - #endif - - // Create new cairo font face. - crFace = cairo_ft_font_face_create_for_ft_face(ftFace, 0); - - // If the cairo font face is released, release the FreeType font face as well. - int status = cairo_font_face_set_user_data (crFace, &key, - ftFace, (cairo_destroy_func_t) FT_Done_Face); - if (status) { - cairo_font_face_destroy (crFace); - FT_Done_Face (ftFace); - return NanThrowError("Failed to setup cairo font face user data"); - } - - // Explicit reference count the cairo font face. Otherwise the font face might - // get released by cairo although the JS font face object is still alive. - cairo_font_face_reference(crFace); - - FontFace *face = new FontFace(ftFace, crFace); - face->Wrap(args.This()); - NanReturnValue(args.This()); -} - diff --git a/scripts/external/three/canvas/src/FontFace.h b/scripts/external/three/canvas/src/FontFace.h deleted file mode 100644 index b1e13e4..0000000 --- a/scripts/external/three/canvas/src/FontFace.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// FontFace.h -// -// Copyright (c) 2012 Julian Viereck -// - -#ifndef __NODE_TRUE_TYPE_FONT_FACE_H__ -#define __NODE_TRUE_TYPE_FONT_FACE_H__ - -#include "Canvas.h" - -#include -#include -#include FT_FREETYPE_H - -class FontFace: public node::ObjectWrap { - public: - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - FontFace(FT_Face ftFace, cairo_font_face_t *crFace) - :_ftFace(ftFace), _crFace(crFace) {} - - inline cairo_font_face_t *cairoFace(){ return _crFace; } - private: - ~FontFace(); - FT_Face _ftFace; - cairo_font_face_t *_crFace; - static bool _initLibrary; -}; - -#endif - diff --git a/scripts/external/three/canvas/src/Image.cc b/scripts/external/three/canvas/src/Image.cc deleted file mode 100644 index d47ab9c..0000000 --- a/scripts/external/three/canvas/src/Image.cc +++ /dev/null @@ -1,971 +0,0 @@ -// -// Image.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "Canvas.h" -#include "Image.h" -#include -#include -#include -#include - -#ifdef HAVE_GIF -typedef struct { - uint8_t *buf; - unsigned len; - unsigned pos; -} gif_data_t; -#endif - -/* - * Read closure used by loadFromBuffer. - */ - -typedef struct { - unsigned len; - uint8_t *buf; -} read_closure_t; - -Persistent Image::constructor; - -/* - * Initialize Image. - */ - -void -Image::Initialize(Handle target) { - NanScope(); - - Local ctor = NanNew(Image::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("Image")); - - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("Image")); - - // Prototype - Local proto = ctor->PrototypeTemplate(); - proto->SetAccessor(NanNew("source"), GetSource, SetSource); - proto->SetAccessor(NanNew("complete"), GetComplete); - proto->SetAccessor(NanNew("width"), GetWidth); - proto->SetAccessor(NanNew("height"), GetHeight); - proto->SetAccessor(NanNew("onload"), GetOnload, SetOnload); - proto->SetAccessor(NanNew("onerror"), GetOnerror, SetOnerror); -#if CAIRO_VERSION_MINOR >= 10 - proto->SetAccessor(NanNew("dataMode"), GetDataMode, SetDataMode); - ctor->Set(NanNew("MODE_IMAGE"), NanNew(DATA_IMAGE)); - ctor->Set(NanNew("MODE_MIME"), NanNew(DATA_MIME)); -#endif - target->Set(NanNew("Image"), ctor->GetFunction()); -} - -/* - * Initialize a new Image. - */ - -NAN_METHOD(Image::New) { - NanScope(); - Image *img = new Image; - img->data_mode = DATA_IMAGE; - img->Wrap(args.This()); - NanReturnValue(args.This()); -} - -/* - * Get complete boolean. - */ - -NAN_GETTER(Image::GetComplete) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(Image::COMPLETE == img->state)); -} - -#if CAIRO_VERSION_MINOR >= 10 - -/* - * Get dataMode. - */ - -NAN_GETTER(Image::GetDataMode) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(img->data_mode)); -} - -/* - * Set dataMode. - */ - -NAN_SETTER(Image::SetDataMode) { - if (value->IsNumber()) { - Image *img = ObjectWrap::Unwrap(args.This()); - int mode = value->Uint32Value(); - img->data_mode = (data_mode_t) mode; - } -} - -#endif - -/* - * Get width. - */ - -NAN_GETTER(Image::GetWidth) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(img->width)); -} -/* - * Get height. - */ - -NAN_GETTER(Image::GetHeight) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(img->height)); -} - -/* - * Get src path. - */ - -NAN_GETTER(Image::GetSource) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(img->filename ? img->filename : "")); -} - -/* - * Clean up assets and variables. - */ - -void -Image::clearData() { - if (_surface) { - cairo_surface_destroy(_surface); - NanAdjustExternalMemory(-_data_len); - _data_len = 0; - _surface = NULL; - } - - free(_data); - _data = NULL; - - free(filename); - filename = NULL; - - width = height = 0; - state = DEFAULT; -} - -/* - * Set src path. - */ - -NAN_SETTER(Image::SetSource) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - cairo_status_t status = CAIRO_STATUS_READ_ERROR; - - img->clearData(); - - // url string - if (value->IsString()) { - String::Utf8Value src(value); - if (img->filename) free(img->filename); - img->filename = strdup(*src); - status = img->load(); - // Buffer - } else if (Buffer::HasInstance(value)) { - uint8_t *buf = (uint8_t *) Buffer::Data(value->ToObject()); - unsigned len = Buffer::Length(value->ToObject()); - status = img->loadFromBuffer(buf, len); - } - - // check status - if (status) { - img->error(Canvas::Error(status)); - } else { - img->loaded(); - } -} - -/* - * Load image data from `buf` by sniffing - * the bytes to determine format. - */ - -cairo_status_t -Image::loadFromBuffer(uint8_t *buf, unsigned len) { - if (isPNG(buf)) return loadPNGFromBuffer(buf); -#ifdef HAVE_GIF - if (isGIF(buf)) return loadGIFFromBuffer(buf, len); -#endif -#ifdef HAVE_JPEG -#if CAIRO_VERSION_MINOR < 10 - if (isJPEG(buf)) return loadJPEGFromBuffer(buf, len); -#else - if (isJPEG(buf)) { - if (DATA_IMAGE == data_mode) return loadJPEGFromBuffer(buf, len); - if (DATA_MIME == data_mode) return decodeJPEGBufferIntoMimeSurface(buf, len); - if ((DATA_IMAGE | DATA_MIME) == data_mode) { - cairo_status_t status; - status = loadJPEGFromBuffer(buf, len); - if (status) return status; - return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); - } - } -#endif -#endif - return CAIRO_STATUS_READ_ERROR; -} - -/* - * Load PNG data from `buf`. - */ - -cairo_status_t -Image::loadPNGFromBuffer(uint8_t *buf) { - read_closure_t closure; - closure.len = 0; - closure.buf = buf; - _surface = cairo_image_surface_create_from_png_stream(readPNG, &closure); - cairo_status_t status = cairo_surface_status(_surface); - if (status) return status; - return CAIRO_STATUS_SUCCESS; -} - -/* - * Read PNG data. - */ - -cairo_status_t -Image::readPNG(void *c, uint8_t *data, unsigned int len) { - read_closure_t *closure = (read_closure_t *) c; - memcpy(data, closure->buf + closure->len, len); - closure->len += len; - return CAIRO_STATUS_SUCCESS; -} - -/* - * Get onload callback. - */ - -NAN_GETTER(Image::GetOnload) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - if (img->onload) { - NanReturnValue(img->onload->GetFunction()); - } else { - NanReturnNull(); - } -} - -/* - * Set onload callback. - */ - -NAN_SETTER(Image::SetOnload) { - if (value->IsFunction()) { - Image *img = ObjectWrap::Unwrap(args.This()); - img->onload = new NanCallback(value.As()); - } -} - -/* - * Get onerror callback. - */ - -NAN_GETTER(Image::GetOnerror) { - NanScope(); - Image *img = ObjectWrap::Unwrap(args.This()); - if (img->onerror) { - NanReturnValue(img->onerror->GetFunction()); - } else { - NanReturnNull(); - } -} - -/* - * Set onerror callback. - */ - -NAN_SETTER(Image::SetOnerror) { - if (value->IsFunction()) { - Image *img = ObjectWrap::Unwrap(args.This()); - img->onerror = new NanCallback(value.As()); - } -} - -/* - * Initialize a new Image. - */ - -Image::Image() { - filename = NULL; - _data = NULL; - _data_len = 0; - _surface = NULL; - width = height = 0; - state = DEFAULT; - onload = NULL; - onerror = NULL; -} - -/* - * Destroy image and associated surface. - */ - -Image::~Image() { - clearData(); - - if (onerror) { - delete onerror; - onerror = NULL; - } - - if (onload) { - delete onload; - onload = NULL; - } -} - -/* - * Initiate image loading. - */ - -cairo_status_t -Image::load() { - if (LOADING != state) { - state = LOADING; - return loadSurface(); - } - return CAIRO_STATUS_READ_ERROR; -} - -/* - * Invoke onload (when assigned) and assign dimensions. - */ - -void -Image::loaded() { - NanScope(); - state = COMPLETE; - - width = cairo_image_surface_get_width(_surface); - height = cairo_image_surface_get_height(_surface); - _data_len = height * cairo_image_surface_get_stride(_surface); - NanAdjustExternalMemory(_data_len); - - if (onload != NULL) { - onload->Call(0, NULL); - delete onload; - onload = NULL; - } -} - -/* - * Invoke onerror (when assigned) with the given err. - */ - -void -Image::error(Local err) { - NanScope(); - if (onerror != NULL) { - Local argv[1] = { err }; - onerror->Call(1, argv); - delete onerror; - onerror = NULL; - } -} - -/* - * Load cairo surface from the image src. - * - * TODO: support more formats - * TODO: use node IO or at least thread pool - */ - -cairo_status_t -Image::loadSurface() { - FILE *stream = fopen(filename, "rb"); - if (!stream) return CAIRO_STATUS_READ_ERROR; - uint8_t buf[5]; - if (1 != fread(&buf, 5, 1, stream)) { - fclose(stream); - return CAIRO_STATUS_READ_ERROR; - } - fseek(stream, 0, SEEK_SET); - - // png - if (isPNG(buf)) { - fclose(stream); - return loadPNG(); - } - - // gif -#ifdef HAVE_GIF - if (isGIF(buf)) return loadGIF(stream); -#endif - - // jpeg -#ifdef HAVE_JPEG - if (isJPEG(buf)) return loadJPEG(stream); -#endif - - fclose(stream); - return CAIRO_STATUS_READ_ERROR; -} - -/* - * Load PNG. - */ - -cairo_status_t -Image::loadPNG() { - _surface = cairo_image_surface_create_from_png(filename); - return cairo_surface_status(_surface); -} - -// GIF support - -#ifdef HAVE_GIF - -/* - * Return the alpha color for `gif` at `frame`, or -1. - */ - -int -get_gif_transparent_color(GifFileType *gif, int frame) { - ExtensionBlock *ext = gif->SavedImages[frame].ExtensionBlocks; - int len = gif->SavedImages[frame].ExtensionBlockCount; - for (int x = 0; x < len; ++x, ++ext) { - if ((ext->Function == GRAPHICS_EXT_FUNC_CODE) && (ext->Bytes[0] & 1)) { - return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3]; - } - } - return -1; -} - -/* - * Memory GIF reader callback. - */ - -int -read_gif_from_memory(GifFileType *gif, GifByteType *buf, int len) { - gif_data_t *data = (gif_data_t *) gif->UserData; - if ((data->pos + len) > data->len) len = data->len - data->pos; - memcpy(buf, data->pos + data->buf, len); - data->pos += len; - return len; -} - -/* - * Load GIF. - */ - -cairo_status_t -Image::loadGIF(FILE *stream) { - struct stat s; - int fd = fileno(stream); - - // stat - if (fstat(fd, &s) < 0) { - fclose(stream); - return CAIRO_STATUS_READ_ERROR; - } - - uint8_t *buf = (uint8_t *) malloc(s.st_size); - - if (!buf) { - fclose(stream); - return CAIRO_STATUS_NO_MEMORY; - } - - size_t read = fread(buf, s.st_size, 1, stream); - fclose(stream); - - cairo_status_t result = CAIRO_STATUS_READ_ERROR; - if (1 == read) result = loadGIFFromBuffer(buf, s.st_size); - free(buf); - - return result; -} - -/* - * Load give from `buf` and the given `len`. - */ - -cairo_status_t -Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) { - int i = 0; - GifFileType* gif; - - gif_data_t gifd = { buf, len, 0 }; - -#if GIFLIB_MAJOR >= 5 - int errorcode; - if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory, &errorcode)) == NULL) - return CAIRO_STATUS_READ_ERROR; -#else - if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory)) == NULL) - return CAIRO_STATUS_READ_ERROR; -#endif - - if (GIF_OK != DGifSlurp(gif)) { - GIF_CLOSE_FILE(gif); - return CAIRO_STATUS_READ_ERROR; - } - - width = gif->SWidth; - height = gif->SHeight; - - uint8_t *data = (uint8_t *) malloc(width * height * 4); - if (!data) { - GIF_CLOSE_FILE(gif); - return CAIRO_STATUS_NO_MEMORY; - } - - GifImageDesc *img = &gif->SavedImages[i].ImageDesc; - - // local colormap takes precedence over global - ColorMapObject *colormap = img->ColorMap - ? img->ColorMap - : gif->SColorMap; - - int bgColor = 0; - int alphaColor = get_gif_transparent_color(gif, i); - if (gif->SColorMap) bgColor = (uint8_t) gif->SBackGroundColor; - else if(alphaColor >= 0) bgColor = alphaColor; - - uint8_t *src_data = (uint8_t*) gif->SavedImages[i].RasterBits; - uint32_t *dst_data = (uint32_t*) data; - - if (!gif->Image.Interlace) { - if (width == img->Width && height == img->Height) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24 - | colormap->Colors[*src_data].Red << 16 - | colormap->Colors[*src_data].Green << 8 - | colormap->Colors[*src_data].Blue; - - dst_data++; - src_data++; - } - } - } else { - // Image does not take up whole "screen" so we need to fill-in the background - int bottom = img->Top + img->Height; - int right = img->Left + img->Width; - - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - if (y < img->Top || y >= bottom || x < img->Left || x >= right) { - *dst_data = ((bgColor == alphaColor) ? 0 : 255) << 24 - | colormap->Colors[bgColor].Red << 16 - | colormap->Colors[bgColor].Green << 8 - | colormap->Colors[bgColor].Blue; - } else { - *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24 - | colormap->Colors[*src_data].Red << 16 - | colormap->Colors[*src_data].Green << 8 - | colormap->Colors[*src_data].Blue; - } - - dst_data++; - src_data++; - } - } - } - } else { - // Image is interlaced so that it streams nice over 14.4k and 28.8k modems :) - // We first load in 1/8 of the image, followed by another 1/8, followed by - // 1/4 and finally the remaining 1/2. - int ioffs[] = { 0, 4, 2, 1 }; - int ijumps[] = { 8, 8, 4, 2 }; - - uint8_t *src_ptr = src_data; - uint32_t *dst_ptr; - - for(int z = 0; z < 4; z++) { - for(int y = ioffs[z]; y < height; y += ijumps[z]) { - dst_ptr = dst_data + width * y; - for(int x = 0; x < width; ++x) { - *dst_ptr = ((*src_ptr == alphaColor) ? 0 : 255) << 24 - | (colormap->Colors[*src_ptr].Red) << 16 - | (colormap->Colors[*src_ptr].Green) << 8 - | (colormap->Colors[*src_ptr].Blue); - - dst_ptr++; - src_ptr++; - } - } - } - } - - GIF_CLOSE_FILE(gif); - - // New image surface - _surface = cairo_image_surface_create_for_data( - data - , CAIRO_FORMAT_ARGB32 - , width - , height - , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); - - cairo_status_t status = cairo_surface_status(_surface); - - if (status) { - free(data); - return status; - } - - _data = data; - - return CAIRO_STATUS_SUCCESS; -} -#endif /* HAVE_GIF */ - -// JPEG support - -#ifdef HAVE_JPEG - -// libjpeg 6.2 does not have jpeg_mem_src; define it ourselves here unless -// libjpeg 8 is installed. -#if JPEG_LIB_VERSION < 80 - -/* Read JPEG image from a memory segment */ -static void -init_source(j_decompress_ptr cinfo) {} - -static boolean -fill_input_buffer(j_decompress_ptr cinfo) { - ERREXIT(cinfo, JERR_INPUT_EMPTY); - return TRUE; -} -static void -skip_input_data(j_decompress_ptr cinfo, long num_bytes) { - struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src; - if (num_bytes > 0) { - src->next_input_byte += (size_t) num_bytes; - src->bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void term_source (j_decompress_ptr cinfo) {} -static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes) { - struct jpeg_source_mgr* src; - - if (cinfo->src == NULL) { - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(struct jpeg_source_mgr)); - } - - src = (struct jpeg_source_mgr*) cinfo->src; - src->init_source = init_source; - src->fill_input_buffer = fill_input_buffer; - src->skip_input_data = skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->term_source = term_source; - src->bytes_in_buffer = nbytes; - src->next_input_byte = (JOCTET*)buffer; -} - -#endif - -/* - * Takes an initialised jpeg_decompress_struct and decodes the - * data into _surface. - */ - -cairo_status_t -Image::decodeJPEGIntoSurface(jpeg_decompress_struct *args) { - int stride = width * 4; - cairo_status_t status; - - uint8_t *data = (uint8_t *) malloc(width * height * 4); - if (!data) { - jpeg_abort_decompress(args); - jpeg_destroy_decompress(args); - return CAIRO_STATUS_NO_MEMORY; - } - - uint8_t *src = (uint8_t *) malloc(width * args->output_components); - if (!src) { - free(data); - jpeg_abort_decompress(args); - jpeg_destroy_decompress(args); - return CAIRO_STATUS_NO_MEMORY; - } - - for (int y = 0; y < height; ++y) { - jpeg_read_scanlines(args, &src, 1); - uint32_t *row = (uint32_t *)(data + stride * y); - for (int x = 0; x < width; ++x) { - if (args->jpeg_color_space == 1) { - uint32_t *pixel = row + x; - *pixel = 255 << 24 - | src[x] << 16 - | src[x] << 8 - | src[x]; - } else { - int bx = 3 * x; - uint32_t *pixel = row + x; - *pixel = 255 << 24 - | src[bx + 0] << 16 - | src[bx + 1] << 8 - | src[bx + 2]; - } - } - } - - _surface = cairo_image_surface_create_for_data( - data - , CAIRO_FORMAT_ARGB32 - , width - , height - , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); - - jpeg_finish_decompress(args); - jpeg_destroy_decompress(args); - status = cairo_surface_status(_surface); - - if (status) { - free(data); - free(src); - return status; - } - - free(src); - - _data = data; - - return CAIRO_STATUS_SUCCESS; -} - -#if CAIRO_VERSION_MINOR >= 10 - -/* - * Takes a jpeg data buffer and assigns it as mime data to a - * dummy surface - */ - -cairo_status_t -Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) { - // TODO: remove this duplicate logic - // JPEG setup - struct jpeg_decompress_struct args; - struct jpeg_error_mgr err; - args.err = jpeg_std_error(&err); - jpeg_create_decompress(&args); - - jpeg_mem_src(&args, buf, len); - - jpeg_read_header(&args, 1); - jpeg_start_decompress(&args); - width = args.output_width; - height = args.output_height; - - // Data alloc - // 8 pixels per byte using Alpha Channel format to reduce memory requirement. - int buf_size = height * cairo_format_stride_for_width(CAIRO_FORMAT_A1, width); - uint8_t *data = (uint8_t *) malloc(buf_size); - if (!data) return CAIRO_STATUS_NO_MEMORY; - - // New image surface - _surface = cairo_image_surface_create_for_data( - data - , CAIRO_FORMAT_A1 - , width - , height - , cairo_format_stride_for_width(CAIRO_FORMAT_A1, width)); - - // Cleanup - jpeg_abort_decompress(&args); - jpeg_destroy_decompress(&args); - cairo_status_t status = cairo_surface_status(_surface); - - if (status) { - free(data); - return status; - } - - _data = data; - - return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); -} - -/* - * Helper function for disposing of a mime data closure. - */ - -void -clearMimeData(void *closure) { - NanAdjustExternalMemory(-((read_closure_t *)closure)->len); - free(((read_closure_t *) closure)->buf); - free(closure); -} - -/* - * Assign a given buffer as mime data against the surface. - * The provided buffer will be copied, and the copy will - * be automatically freed when the surface is destroyed. - */ - -cairo_status_t -Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) { - uint8_t *mime_data = (uint8_t *) malloc(len); - if (!mime_data) return CAIRO_STATUS_NO_MEMORY; - - read_closure_t *mime_closure = (read_closure_t *) malloc(sizeof(read_closure_t)); - if (!mime_closure) { - free(mime_data); - return CAIRO_STATUS_NO_MEMORY; - } - - memcpy(mime_data, data, len); - - mime_closure->buf = mime_data; - mime_closure->len = len; - - NanAdjustExternalMemory(len); - - return cairo_surface_set_mime_data(_surface - , mime_type - , mime_data - , len - , clearMimeData - , mime_closure); -} - -#endif - -/* - * Load jpeg from buffer. - */ - -cairo_status_t -Image::loadJPEGFromBuffer(uint8_t *buf, unsigned len) { - // TODO: remove this duplicate logic - // JPEG setup - struct jpeg_decompress_struct args; - struct jpeg_error_mgr err; - args.err = jpeg_std_error(&err); - jpeg_create_decompress(&args); - - jpeg_mem_src(&args, buf, len); - - jpeg_read_header(&args, 1); - jpeg_start_decompress(&args); - width = args.output_width; - height = args.output_height; - - return decodeJPEGIntoSurface(&args); -} - -/* - * Load JPEG, convert RGB to ARGB. - */ - -cairo_status_t -Image::loadJPEG(FILE *stream) { - cairo_status_t status; - - if (data_mode == DATA_IMAGE) { // Can lazily read in the JPEG. - // JPEG setup - struct jpeg_decompress_struct args; - struct jpeg_error_mgr err; - args.err = jpeg_std_error(&err); - jpeg_create_decompress(&args); - - jpeg_stdio_src(&args, stream); - - jpeg_read_header(&args, 1); - jpeg_start_decompress(&args); - width = args.output_width; - height = args.output_height; - - status = decodeJPEGIntoSurface(&args); - fclose(stream); - } else { // We'll need the actual source jpeg data, so read fully. -#if CAIRO_VERSION_MINOR >= 10 - uint8_t *buf; - unsigned len; - - fseek(stream, 0, SEEK_END); - len = ftell(stream); - fseek(stream, 0, SEEK_SET); - - buf = (uint8_t *) malloc(len); - if (!buf) return CAIRO_STATUS_NO_MEMORY; - - if (fread(buf, len, 1, stream) != 1) { - status = CAIRO_STATUS_READ_ERROR; - } else if ((DATA_IMAGE | DATA_MIME) == data_mode) { - status = loadJPEGFromBuffer(buf, len); - if (!status) status = assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG); - } else if (DATA_MIME == data_mode) { - status = decodeJPEGBufferIntoMimeSurface(buf, len); - } else { - status = CAIRO_STATUS_READ_ERROR; - } - - fclose(stream); - free(buf); -#else - status = CAIRO_STATUS_READ_ERROR; -#endif - } - - return status; -} - -#endif /* HAVE_JPEG */ - -/* - * Return UNKNOWN, JPEG, or PNG based on the filename. - */ - -Image::type -Image::extension(const char *filename) { - size_t len = strlen(filename); - filename += len; - if (len >= 5 && 0 == strcmp(".jpeg", filename - 5)) return Image::JPEG; - if (len >= 4 && 0 == strcmp(".gif", filename - 4)) return Image::GIF; - if (len >= 4 && 0 == strcmp(".jpg", filename - 4)) return Image::JPEG; - if (len >= 4 && 0 == strcmp(".png", filename - 4)) return Image::PNG; - return Image::UNKNOWN; -} - -/* - * Sniff bytes for JPEG's magic number ff d8. - */ - -int -Image::isJPEG(uint8_t *data) { - return 0xff == data[0] && 0xd8 == data[1]; -} - -/* - * Sniff bytes 0..2 for "GIF". - */ - -int -Image::isGIF(uint8_t *data) { - return 'G' == data[0] && 'I' == data[1] && 'F' == data[2]; -} - -/* - * Sniff bytes 1..3 for "PNG". - */ - -int -Image::isPNG(uint8_t *data) { - return 'P' == data[1] && 'N' == data[2] && 'G' == data[3]; -} diff --git a/scripts/external/three/canvas/src/Image.h b/scripts/external/three/canvas/src/Image.h deleted file mode 100644 index 805fb80..0000000 --- a/scripts/external/three/canvas/src/Image.h +++ /dev/null @@ -1,108 +0,0 @@ - -// -// Image.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_IMAGE_H__ -#define __NODE_IMAGE_H__ - -#include "Canvas.h" - -#ifdef HAVE_JPEG -#include -#include -#endif - -#ifdef HAVE_GIF -#include - - #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 - #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL) - #else - #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif) - #endif -#endif - - - -class Image: public node::ObjectWrap { - public: - char *filename; - int width, height; - NanCallback *onload; - NanCallback *onerror; - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_GETTER(GetSource); - static NAN_GETTER(GetOnload); - static NAN_GETTER(GetOnerror); - static NAN_GETTER(GetComplete); - static NAN_GETTER(GetWidth); - static NAN_GETTER(GetHeight); - static NAN_GETTER(GetDataMode); - static NAN_SETTER(SetSource); - static NAN_SETTER(SetOnload); - static NAN_SETTER(SetOnerror); - static NAN_SETTER(SetDataMode); - inline cairo_surface_t *surface(){ return _surface; } - inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } - inline int stride(){ return cairo_image_surface_get_stride(_surface); } - static int isPNG(uint8_t *data); - static int isJPEG(uint8_t *data); - static int isGIF(uint8_t *data); - static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len); - inline int isComplete(){ return COMPLETE == state; } - cairo_status_t loadSurface(); - cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len); - cairo_status_t loadPNGFromBuffer(uint8_t *buf); - cairo_status_t loadPNG(); - void clearData(); -#ifdef HAVE_GIF - cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len); - cairo_status_t loadGIF(FILE *stream); -#endif -#ifdef HAVE_JPEG - cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len); - cairo_status_t loadJPEG(FILE *stream); - cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info); -#if CAIRO_VERSION_MINOR >= 10 - cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len); - cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type); -#endif -#endif - void error(Local error); - void loaded(); - cairo_status_t load(); - Image(); - - enum { - DEFAULT - , LOADING - , COMPLETE - } state; - - enum data_mode_t { - DATA_IMAGE = 1 - , DATA_MIME = 2 - } data_mode; - - typedef enum { - UNKNOWN - , GIF - , JPEG - , PNG - } type; - - static type extension(const char *filename); - - private: - cairo_surface_t *_surface; - uint8_t *_data; - int _data_len; - ~Image(); -}; - -#endif diff --git a/scripts/external/three/canvas/src/ImageData.cc b/scripts/external/three/canvas/src/ImageData.cc deleted file mode 100644 index bbacb75..0000000 --- a/scripts/external/three/canvas/src/ImageData.cc +++ /dev/null @@ -1,69 +0,0 @@ - -// -// ImageData.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "ImageData.h" - -Persistent ImageData::constructor; - -/* - * Initialize ImageData. - */ - -void -ImageData::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(ImageData::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("ImageData")); - - // Prototype - Local proto = ctor->PrototypeTemplate(); - proto->SetAccessor(NanNew("width"), GetWidth); - proto->SetAccessor(NanNew("height"), GetHeight); - target->Set(NanNew("ImageData"), ctor->GetFunction()); -} - -/* - * Initialize a new ImageData object. - */ - -NAN_METHOD(ImageData::New) { - NanScope(); - Local obj = args[0]->ToObject(); - - if (!NanHasInstance(PixelArray::constructor, obj)) - return NanThrowTypeError("CanvasPixelArray expected"); - - PixelArray *arr = ObjectWrap::Unwrap(obj); - ImageData *imageData = new ImageData(arr); - args.This()->Set(NanNew("data"), args[0]); - imageData->Wrap(args.This()); - NanReturnValue(args.This()); -} - -/* - * Get width. - */ - -NAN_GETTER(ImageData::GetWidth) { - NanScope(); - ImageData *imageData = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(imageData->pixelArray()->width())); -} - -/* - * Get height. - */ - -NAN_GETTER(ImageData::GetHeight) { - NanScope(); - ImageData *imageData = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(imageData->pixelArray()->height())); -} diff --git a/scripts/external/three/canvas/src/ImageData.h b/scripts/external/three/canvas/src/ImageData.h deleted file mode 100644 index 150f662..0000000 --- a/scripts/external/three/canvas/src/ImageData.h +++ /dev/null @@ -1,28 +0,0 @@ - -// -// ImageData.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_IMAGE_DATA_H__ -#define __NODE_IMAGE_DATA_H__ - -#include "Canvas.h" -#include "PixelArray.h" -#include - -class ImageData: public node::ObjectWrap { - public: - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_GETTER(GetWidth); - static NAN_GETTER(GetHeight); - inline PixelArray *pixelArray(){ return _arr; } - ImageData(PixelArray *arr): _arr(arr) {} - private: - PixelArray *_arr; -}; - -#endif diff --git a/scripts/external/three/canvas/src/JPEGStream.h b/scripts/external/three/canvas/src/JPEGStream.h deleted file mode 100644 index 95962e3..0000000 --- a/scripts/external/three/canvas/src/JPEGStream.h +++ /dev/null @@ -1,155 +0,0 @@ - -// -// JPEGStream.h -// - -#ifndef __NODE_JPEG_STREAM_H__ -#define __NODE_JPEG_STREAM_H__ - -#include "Canvas.h" -#include -#include - -/* - * Expanded data destination object for closure output, - * inspired by IJG's jdatadst.c - */ - -typedef struct { - struct jpeg_destination_mgr pub; - closure_t *closure; - JOCTET *buffer; - int bufsize; -} closure_destination_mgr; - -void -init_closure_destination(j_compress_ptr cinfo){ - // we really don't have to do anything here -} - -boolean -empty_closure_output_buffer(j_compress_ptr cinfo){ - NanScope(); - closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest; - Local buf = NanNewBufferHandle((char *)dest->buffer, dest->bufsize); - Local argv[3] = { - NanNew(NanNull()) - , NanNew(buf) - , NanNew(dest->bufsize) - }; - NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, argv); - cinfo->dest->next_output_byte = dest->buffer; - cinfo->dest->free_in_buffer = dest->bufsize; - return true; -} - -void -term_closure_destination(j_compress_ptr cinfo){ - NanScope(); - closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest; - /* emit remaining data */ - size_t remaining = dest->bufsize - cinfo->dest->free_in_buffer; - Local buf = NanNewBufferHandle((char *)dest->buffer, remaining); - - Local data_argv[3] = { - NanNew(NanNull()) - , NanNew(buf) - , NanNew(remaining) - }; - - NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, data_argv); - - // emit "end" - Local end_argv[3] = { - NanNew(NanNull()) - , NanNew(NanNull()) - , NanNew(0) - }; - - NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, end_argv); -} - -void -jpeg_closure_dest(j_compress_ptr cinfo, closure_t * closure, int bufsize){ - closure_destination_mgr * dest; - - /* The destination object is made permanent so that multiple JPEG images - * can be written to the same buffer without re-executing jpeg_mem_dest. - */ - if (cinfo->dest == NULL) { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(closure_destination_mgr)); - } - - dest = (closure_destination_mgr *) cinfo->dest; - - cinfo->dest->init_destination = &init_closure_destination; - cinfo->dest->empty_output_buffer = &empty_closure_output_buffer; - cinfo->dest->term_destination = &term_closure_destination; - - dest->closure = closure; - dest->bufsize = bufsize; - dest->buffer = (JOCTET *)malloc(bufsize); - - cinfo->dest->next_output_byte = dest->buffer; - cinfo->dest->free_in_buffer = dest->bufsize; -} - -void -jpeg_free_custom_allocations(j_compress_ptr cinfo){ - closure_destination_mgr * dest; - dest = (closure_destination_mgr *) cinfo->dest; - if (dest->buffer) { - free(dest->buffer); - dest->buffer = NULL; - } -} - -void -write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, int quality, bool progressive, closure_t *closure){ - int w = cairo_image_surface_get_width(surface); - int h = cairo_image_surface_get_height(surface); - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - - JSAMPROW slr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - cinfo.in_color_space = JCS_RGB; - cinfo.input_components = 3; - cinfo.image_width = w; - cinfo.image_height = h; - jpeg_set_defaults(&cinfo); - if (progressive) - jpeg_simple_progression(&cinfo); - jpeg_set_quality(&cinfo, quality, (quality<25)?0:1); - jpeg_closure_dest(&cinfo, closure, bufsize); - - jpeg_start_compress(&cinfo, TRUE); - unsigned char *dst; - unsigned int *src = (unsigned int *) cairo_image_surface_get_data(surface); - int sl = 0; - dst = (unsigned char *) malloc(w * 3); - while (sl < h) { - unsigned char *dp = dst; - int x = 0; - while (x < w) { - dp[0] = (*src >> 16) & 255; - dp[1] = (*src >> 8) & 255; - dp[2] = *src & 255; - src++; - dp += 3; - x++; - } - slr = dst; - jpeg_write_scanlines(&cinfo, &slr, 1); - sl++; - } - free(dst); - jpeg_finish_compress(&cinfo); - jpeg_free_custom_allocations(&cinfo); - jpeg_destroy_compress(&cinfo); -} - -#endif diff --git a/scripts/external/three/canvas/src/PNG.h b/scripts/external/three/canvas/src/PNG.h deleted file mode 100644 index d3ba4f1..0000000 --- a/scripts/external/three/canvas/src/PNG.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef _CANVAS_PNG_H -#define _CANVAS_PNG_H -#include -#include -#include -#include -#include -#include "closure.h" - -#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) -#define likely(expr) (__builtin_expect (!!(expr), 1)) -#define unlikely(expr) (__builtin_expect (!!(expr), 0)) -#else -#define likely(expr) (expr) -#define unlikely(expr) (expr) -#endif - -#ifndef CAIRO_FORMAT_INVALID -#define CAIRO_FORMAT_INVALID -1 -#endif - -static void canvas_png_flush(png_structp png_ptr) { - /* Do nothing; fflush() is said to be just a waste of energy. */ - (void) png_ptr; /* Stifle compiler warning */ -} - -/* Converts native endian xRGB => RGBx bytes */ -static void canvas_convert_data_to_bytes(png_structp png, png_row_infop row_info, png_bytep data) { - unsigned int i; - - for (i = 0; i < row_info->rowbytes; i += 4) { - uint8_t *b = &data[i]; - uint32_t pixel; - - memcpy(&pixel, b, sizeof (uint32_t)); - - b[0] = (pixel & 0xff0000) >> 16; - b[1] = (pixel & 0x00ff00) >> 8; - b[2] = (pixel & 0x0000ff) >> 0; - b[3] = 0; - } -} - -/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ -static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) { - unsigned int i; - - for (i = 0; i < row_info->rowbytes; i += 4) { - uint8_t *b = &data[i]; - uint32_t pixel; - uint8_t alpha; - - memcpy(&pixel, b, sizeof (uint32_t)); - alpha = (pixel & 0xff000000) >> 24; - if (alpha == 0) { - b[0] = b[1] = b[2] = b[3] = 0; - } else { - b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; - b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; - b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; - b[3] = alpha; - } - } -} - -struct canvas_png_write_closure_t { - cairo_write_func_t write_func; - void *closure; -}; - -static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) { - unsigned int i; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - uint8_t *data; - png_structp png; - png_infop info; - png_bytep *volatile rows = NULL; - png_color_16 white; - int png_color_type; - int bpc; - unsigned int width = cairo_image_surface_get_width(surface); - unsigned int height = cairo_image_surface_get_height(surface); - - data = cairo_image_surface_get_data(surface); - if (data == NULL) { - status = CAIRO_STATUS_SURFACE_TYPE_MISMATCH; - return status; - } - cairo_surface_flush(surface); - - if (width == 0 || height == 0) { - status = CAIRO_STATUS_WRITE_ERROR; - return status; - } - - rows = (png_bytep *) malloc(height * sizeof (png_byte*)); - if (unlikely(rows == NULL)) { - status = CAIRO_STATUS_NO_MEMORY; - return status; - } - - for (i = 0; i < height; i++) { - rows[i] = (png_byte *) data + i * cairo_image_surface_get_stride(surface); - } - -#ifdef PNG_USER_MEM_SUPPORTED - png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL); -#else - png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); -#endif - - if (unlikely(png == NULL)) { - status = CAIRO_STATUS_NO_MEMORY; - free(rows); - return status; - } - - info = png_create_info_struct (png); - if (unlikely(info == NULL)) { - status = CAIRO_STATUS_NO_MEMORY; - png_destroy_write_struct(&png, &info); - free(rows); - return status; - - } - -#ifdef PNG_SETJMP_SUPPORTED - if (setjmp (png_jmpbuf (png))) { - png_destroy_write_struct(&png, &info); - free(rows); - return status; - } -#endif - - png_set_write_fn(png, closure, write_func, canvas_png_flush); - png_set_compression_level(png, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->compression_level); - png_set_filter(png, 0, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->filter); - - switch (cairo_image_surface_get_format(surface)) { - case CAIRO_FORMAT_ARGB32: - bpc = 8; - png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; - break; -#ifdef CAIRO_FORMAT_RGB30 - case CAIRO_FORMAT_RGB30: - bpc = 10; - png_color_type = PNG_COLOR_TYPE_RGB; - break; -#endif - case CAIRO_FORMAT_RGB24: - bpc = 8; - png_color_type = PNG_COLOR_TYPE_RGB; - break; - case CAIRO_FORMAT_A8: - bpc = 8; - png_color_type = PNG_COLOR_TYPE_GRAY; - break; - case CAIRO_FORMAT_A1: - bpc = 1; - png_color_type = PNG_COLOR_TYPE_GRAY; -#ifndef WORDS_BIGENDIAN - png_set_packswap(png); -#endif - break; - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_RGB16_565: - default: - status = CAIRO_STATUS_INVALID_FORMAT; - png_destroy_write_struct(&png, &info); - free(rows); - return status; - } - - png_set_IHDR(png, info, width, height, bpc, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - white.gray = (1 << bpc) - 1; - white.red = white.blue = white.green = white.gray; - png_set_bKGD(png, info, &white); - - /* We have to call png_write_info() before setting up the write - * transformation, since it stores data internally in 'png' - * that is needed for the write transformation functions to work. - */ - png_write_info(png, info); - if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - png_set_write_user_transform_fn(png, canvas_unpremultiply_data); - } else if (png_color_type == PNG_COLOR_TYPE_RGB) { - png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes); - png_set_filler(png, 0, PNG_FILLER_AFTER); - } - - png_write_image(png, rows); - png_write_end(png, info); - - png_destroy_write_struct(&png, &info); - free(rows); - return status; -} - -static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) { - cairo_status_t status; - struct canvas_png_write_closure_t *png_closure; - - png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png); - status = png_closure->write_func(png_closure->closure, data, size); - if (unlikely(status)) { - cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png); - if (*error == CAIRO_STATUS_SUCCESS) { - *error = status; - } - png_error(png, NULL); - } -} - -static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) { - struct canvas_png_write_closure_t png_closure; - - if (cairo_surface_status(surface)) { - return cairo_surface_status(surface); - } - - png_closure.write_func = write_func; - png_closure.closure = closure; - - return canvas_write_png(surface, canvas_stream_write_func, &png_closure); -} -#endif diff --git a/scripts/external/three/canvas/src/PixelArray.cc b/scripts/external/three/canvas/src/PixelArray.cc deleted file mode 100644 index 0a773cc..0000000 --- a/scripts/external/three/canvas/src/PixelArray.cc +++ /dev/null @@ -1,154 +0,0 @@ - -// -// PixelArray.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "PixelArray.h" -#include -#include - -Persistent PixelArray::constructor; - -/* - * Initialize PixelArray. - */ - -void -PixelArray::Initialize(Handle target) { - NanScope(); - - // Constructor - Local ctor = NanNew(PixelArray::New); - NanAssignPersistent(constructor, ctor); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanNew("CanvasPixelArray")); - - // Prototype - Local proto = ctor->InstanceTemplate(); - proto->SetAccessor(NanNew("length"), GetLength); - target->Set(NanNew("CanvasPixelArray"), ctor->GetFunction()); -} - -/* - * Initialize a new PixelArray. - */ - -NAN_METHOD(PixelArray::New) { - NanScope(); - PixelArray *arr; - Local obj = args[0]->ToObject(); - - switch (args.Length()) { - // width, height - case 2: - arr = new PixelArray( - args[0]->Int32Value() - , args[1]->Int32Value()); - break; - // canvas, x, y, width, height - case 5: { - if (!NanHasInstance(Canvas::constructor, obj)) - return NanThrowTypeError("Canvas expected"); - - Canvas *canvas = ObjectWrap::Unwrap(obj); - arr = new PixelArray( - canvas - , args[1]->Int32Value() - , args[2]->Int32Value() - , args[3]->Int32Value() - , args[4]->Int32Value()); - } - break; - default: - return NanThrowTypeError("invalid arguments"); - } - - // Let v8 handle accessors (and clamping) - args.This()->SetIndexedPropertiesToPixelData( - arr->data() - , arr->length()); - - arr->Wrap(args.This()); - NanReturnValue(args.This()); -} - -/* - * Get length. - */ - -NAN_GETTER(PixelArray::GetLength) { - NanScope(); - NanReturnValue(NanNew(args.This()->GetIndexedPropertiesPixelDataLength())); -} - -/* - * Initialize a new PixelArray copying data - * from the canvas surface using the given rect. - */ - -PixelArray::PixelArray(Canvas *canvas, int sx, int sy, int width, int height): - _width(width), _height(height) { - - // Alloc space for our new data - uint8_t *dst = alloc(); - uint8_t *src = canvas->data(); - int srcStride = canvas->stride() - , dstStride = stride(); - - if (sx < 0) width += sx, sx = 0; - if (sy < 0) height += sy, sy = 0; - if (sx + width > canvas->width) width = canvas->width - sx; - if (sy + height > canvas->height) height = canvas->height - sy; - if (width <= 0 || height <= 0) return; - - // Normalize data (argb -> rgba) - for (int y = 0; y < height; ++y) { - uint32_t *row = (uint32_t *)(src + srcStride * (y + sy)); - for (int x = 0; x < width; ++x) { - int bx = x * 4; - uint32_t *pixel = row + x + sx; - uint8_t a = *pixel >> 24; - uint8_t r = *pixel >> 16; - uint8_t g = *pixel >> 8; - uint8_t b = *pixel; - dst[bx + 3] = a; - float alpha = (float) a / 255; - dst[bx + 0] = (int)((float) r / alpha); - dst[bx + 1] = (int)((float) g / alpha); - dst[bx + 2] = (int)((float) b / alpha); - } - dst += dstStride; - } -} - -/* - * Initialize an empty PixelArray with the given dimensions. - */ - -PixelArray::PixelArray(int width, int height): - _width(width), _height(height) { - alloc(); -} - -/* - * Allocate / zero data buffer. Hint mem adjustment. - */ - -uint8_t * -PixelArray::alloc() { - int len = length(); - _data = (uint8_t *) calloc(1, len); - NanAdjustExternalMemory(len); - return _data; -} - -/* - * Hint mem adjustment. - */ - -PixelArray::~PixelArray() { - NanAdjustExternalMemory(-length()); - free(_data); -} diff --git a/scripts/external/three/canvas/src/PixelArray.h b/scripts/external/three/canvas/src/PixelArray.h deleted file mode 100644 index 21e68f1..0000000 --- a/scripts/external/three/canvas/src/PixelArray.h +++ /dev/null @@ -1,33 +0,0 @@ - -// -// PixelArray.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_PIXEL_ARRAY_H__ -#define __NODE_PIXEL_ARRAY_H__ - -#include "Canvas.h" - -class PixelArray: public node::ObjectWrap { - public: - static Persistent constructor; - static void Initialize(Handle target); - static NAN_METHOD(New); - static NAN_GETTER(GetLength); - inline int length(){ return _width * _height * 4; } - inline int width(){ return _width; } - inline int height(){ return _height; } - inline int stride(){ return _width * 4; } - inline uint8_t *data(){ return _data; } - PixelArray(Canvas *canvas, int x, int y, int width, int height); - PixelArray(int width, int height); - ~PixelArray(); - private: - uint8_t *alloc(); - uint8_t *_data; - int _width, _height; -}; - -#endif diff --git a/scripts/external/three/canvas/src/Point.h b/scripts/external/three/canvas/src/Point.h deleted file mode 100644 index 5baef10..0000000 --- a/scripts/external/three/canvas/src/Point.h +++ /dev/null @@ -1,19 +0,0 @@ - - -// -// Point.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_POINT_H__ -#define __NODE_POINT_H__ - -template -class Point { - public: - T x, y; - Point(T x, T y): x(x), y(y) {} -}; - -#endif /* __NODE_POINT_H__ */ diff --git a/scripts/external/three/canvas/src/closure.h b/scripts/external/three/canvas/src/closure.h deleted file mode 100644 index 3ac6632..0000000 --- a/scripts/external/three/canvas/src/closure.h +++ /dev/null @@ -1,65 +0,0 @@ - -// -// closure.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __NODE_CLOSURE_H__ -#define __NODE_CLOSURE_H__ - -#ifdef __unix__ - #include -#endif - -#ifndef PAGE_SIZE - #define PAGE_SIZE 4096 -#endif - -#include - -/* - * PNG stream closure. - */ - -typedef struct { - NanCallback *pfn; - Handle fn; - unsigned len; - unsigned max_len; - uint8_t *data; - Canvas *canvas; - cairo_status_t status; - uint32_t compression_level; - uint32_t filter; -} closure_t; - -/* - * Initialize the given closure. - */ - -cairo_status_t -closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level, unsigned int filter) { - closure->len = 0; - closure->canvas = canvas; - closure->data = (uint8_t *) malloc(closure->max_len = PAGE_SIZE); - if (!closure->data) return CAIRO_STATUS_NO_MEMORY; - closure->compression_level = compression_level; - closure->filter = filter; - return CAIRO_STATUS_SUCCESS; -} - -/* - * Free the given closure's data, - * and hint V8 at the memory dealloc. - */ - -void -closure_destroy(closure_t *closure) { - if (closure->len) { - free(closure->data); - NanAdjustExternalMemory(-((intptr_t) closure->max_len)); - } -} - -#endif /* __NODE_CLOSURE_H__ */ diff --git a/scripts/external/three/canvas/src/color.cc b/scripts/external/three/canvas/src/color.cc deleted file mode 100644 index effcf89..0000000 --- a/scripts/external/three/canvas/src/color.cc +++ /dev/null @@ -1,739 +0,0 @@ - -// -// color.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include "color.h" -#include -#include -#include - -/* - * Parse integer value - */ - -template -static bool -parse_integer(const char** pStr, parsed_t *pParsed) { - parsed_t& c = *pParsed; - const char*& str = *pStr; - int8_t sign=1; - - c = 0; - if (*str == '-') { - sign=-1; - ++str; - } - else if (*str == '+') - ++str; - - if (*str >= '0' && *str <= '9') { - do { - c *= 10; - c += *str++ - '0'; - } while (*str >= '0' && *str <= '9'); - } else { - return false; - } - if (sign<0) - c=-c; - return true; -} - - -/* - * Parse CSS value - * Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html - */ - -template -static bool -parse_css_number(const char** pStr, parsed_t *pParsed) { - parsed_t &parsed = *pParsed; - const char*& str = *pStr; - const char* startStr = str; - if (!str || !*str) - return false; - parsed_t integerPart = 0; - parsed_t fractionPart = 0; - int divisorForFraction = 1; - int sign = 1; - int exponent = 0; - int digits = 0; - bool inFraction = false; - - if (*str == '-') { - ++str; - sign = -1; - } - else if (*str == '+') - ++str; - while (*str != '\0') { - if (*str >= '0' && *str <= '9') { - if (digits>=std::numeric_limits::digits10) { - if (!inFraction) - return false; - } - else { - ++digits; - - if (inFraction) { - fractionPart = fractionPart*10 + (*str - '0'); - divisorForFraction *= 10; - } - else { - integerPart = integerPart*10 + (*str - '0'); - } - } - } - else if (*str == '.') { - if (inFraction) - break; - else - inFraction = true; - } - else if (*str == 'e') { - ++str; - if (!parse_integer(&str, &exponent)) - return false; - break; - } - else - break; - ++str; - } - if (str != startStr) { - parsed = sign * (integerPart + fractionPart/divisorForFraction); - for (;exponent>0;--exponent) - parsed *= 10; - for (;exponent<0;++exponent) - parsed /= 10; - return true; - } - return false; -} - -/* - * Clip value to the range [minValue, maxValue] - */ - -template -static T -clip(T value, T minValue, T maxValue) { - if (value > maxValue) - value = maxValue; - if (value < minValue) - value = minValue; - return value; -} - -/* - * Wrap value to the range [0, limit] - */ - -template -static T -wrap_float(T value, T limit) { - return fmod(fmod(value, limit) + limit, limit); -} - -/* - * Wrap value to the range [0, limit] - currently-unused integer version of wrap_float - */ - -// template -// static T wrap_int(T value, T limit) { -// return (value % limit + limit) % limit; -// } - -/* - * Parse color channel value - */ - -static bool -parse_rgb_channel(const char** pStr, uint8_t *pChannel) { - int channel; - if (parse_integer(pStr, &channel)) { - *pChannel = clip(channel, 0, 255); - return true; - } - return false; -} - -/* - * Parse a value in degrees - */ - -static bool -parse_degrees(const char** pStr, float *pDegrees) { - float degrees; - if (parse_css_number(pStr, °rees)) { - *pDegrees = wrap_float(degrees, 360.0f); - return true; - } - return false; -} - -/* - * Parse and clip a percentage value. Returns a float in the range [0, 1]. - */ - -static bool -parse_clipped_percentage(const char** pStr, float *pFraction) { - float percentage; - bool result = parse_css_number(pStr,&percentage); - const char*& str = *pStr; - if (result) { - if (*str == '%') { - ++str; - *pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f; - return result; - } - } - return false; -} - -/* - * Macros to help with parsing inside rgba_from_*_string - */ - -#define WHITESPACE \ - while (' ' == *str) ++str; - -#define WHITESPACE_OR_COMMA \ - while (' ' == *str || ',' == *str) ++str; - -#define CHANNEL(NAME) \ - if (!parse_rgb_channel(&str, &NAME)) \ - return 0; \ - -#define HUE(NAME) \ - if (!parse_degrees(&str, &NAME)) \ - return 0; - -#define SATURATION(NAME) \ - if (!parse_clipped_percentage(&str, &NAME)) \ - return 0; - -#define LIGHTNESS(NAME) SATURATION(NAME) - -#define ALPHA(NAME) \ - if (*str >= '1' && *str <= '9') { \ - NAME = 1; \ - } else { \ - if ('0' == *str) ++str; \ - if ('.' == *str) { \ - ++str; \ - float n = .1f; \ - while (*str >= '0' && *str <= '9') { \ - NAME += (*str++ - '0') * n; \ - n *= .1f; \ - } \ - } \ - } \ - do {} while (0) // require trailing semicolon - -/* - * Named colors. - */ - -static struct named_color { - const char *name; - uint32_t val; -} named_colors[] = { - { "transparent", 0xFFFFFF00} - , { "aliceblue", 0xF0F8FFFF } - , { "antiquewhite", 0xFAEBD7FF } - , { "aqua", 0x00FFFFFF } - , { "aquamarine", 0x7FFFD4FF } - , { "azure", 0xF0FFFFFF } - , { "beige", 0xF5F5DCFF } - , { "bisque", 0xFFE4C4FF } - , { "black", 0x000000FF } - , { "blanchedalmond", 0xFFEBCDFF } - , { "blue", 0x0000FFFF } - , { "blueviolet", 0x8A2BE2FF } - , { "brown", 0xA52A2AFF } - , { "burlywood", 0xDEB887FF } - , { "cadetblue", 0x5F9EA0FF } - , { "chartreuse", 0x7FFF00FF } - , { "chocolate", 0xD2691EFF } - , { "coral", 0xFF7F50FF } - , { "cornflowerblue", 0x6495EDFF } - , { "cornsilk", 0xFFF8DCFF } - , { "crimson", 0xDC143CFF } - , { "cyan", 0x00FFFFFF } - , { "darkblue", 0x00008BFF } - , { "darkcyan", 0x008B8BFF } - , { "darkgoldenrod", 0xB8860BFF } - , { "darkgray", 0xA9A9A9FF } - , { "darkgreen", 0x006400FF } - , { "darkgrey", 0xA9A9A9FF } - , { "darkkhaki", 0xBDB76BFF } - , { "darkmagenta", 0x8B008BFF } - , { "darkolivegreen", 0x556B2FFF } - , { "darkorange", 0xFF8C00FF } - , { "darkorchid", 0x9932CCFF } - , { "darkred", 0x8B0000FF } - , { "darksalmon", 0xE9967AFF } - , { "darkseagreen", 0x8FBC8FFF } - , { "darkslateblue", 0x483D8BFF } - , { "darkslategray", 0x2F4F4FFF } - , { "darkslategrey", 0x2F4F4FFF } - , { "darkturquoise", 0x00CED1FF } - , { "darkviolet", 0x9400D3FF } - , { "deeppink", 0xFF1493FF } - , { "deepskyblue", 0x00BFFFFF } - , { "dimgray", 0x696969FF } - , { "dimgrey", 0x696969FF } - , { "dodgerblue", 0x1E90FFFF } - , { "firebrick", 0xB22222FF } - , { "floralwhite", 0xFFFAF0FF } - , { "forestgreen", 0x228B22FF } - , { "fuchsia", 0xFF00FFFF } - , { "gainsboro", 0xDCDCDCFF } - , { "ghostwhite", 0xF8F8FFFF } - , { "gold", 0xFFD700FF } - , { "goldenrod", 0xDAA520FF } - , { "gray", 0x808080FF } - , { "green", 0x008000FF } - , { "greenyellow", 0xADFF2FFF } - , { "grey", 0x808080FF } - , { "honeydew", 0xF0FFF0FF } - , { "hotpink", 0xFF69B4FF } - , { "indianred", 0xCD5C5CFF } - , { "indigo", 0x4B0082FF } - , { "ivory", 0xFFFFF0FF } - , { "khaki", 0xF0E68CFF } - , { "lavender", 0xE6E6FAFF } - , { "lavenderblush", 0xFFF0F5FF } - , { "lawngreen", 0x7CFC00FF } - , { "lemonchiffon", 0xFFFACDFF } - , { "lightblue", 0xADD8E6FF } - , { "lightcoral", 0xF08080FF } - , { "lightcyan", 0xE0FFFFFF } - , { "lightgoldenrodyellow", 0xFAFAD2FF } - , { "lightgray", 0xD3D3D3FF } - , { "lightgreen", 0x90EE90FF } - , { "lightgrey", 0xD3D3D3FF } - , { "lightpink", 0xFFB6C1FF } - , { "lightsalmon", 0xFFA07AFF } - , { "lightseagreen", 0x20B2AAFF } - , { "lightskyblue", 0x87CEFAFF } - , { "lightslategray", 0x778899FF } - , { "lightslategrey", 0x778899FF } - , { "lightsteelblue", 0xB0C4DEFF } - , { "lightyellow", 0xFFFFE0FF } - , { "lime", 0x00FF00FF } - , { "limegreen", 0x32CD32FF } - , { "linen", 0xFAF0E6FF } - , { "magenta", 0xFF00FFFF } - , { "maroon", 0x800000FF } - , { "mediumaquamarine", 0x66CDAAFF } - , { "mediumblue", 0x0000CDFF } - , { "mediumorchid", 0xBA55D3FF } - , { "mediumpurple", 0x9370DBFF } - , { "mediumseagreen", 0x3CB371FF } - , { "mediumslateblue", 0x7B68EEFF } - , { "mediumspringgreen", 0x00FA9AFF } - , { "mediumturquoise", 0x48D1CCFF } - , { "mediumvioletred", 0xC71585FF } - , { "midnightblue", 0x191970FF } - , { "mintcream", 0xF5FFFAFF } - , { "mistyrose", 0xFFE4E1FF } - , { "moccasin", 0xFFE4B5FF } - , { "navajowhite", 0xFFDEADFF } - , { "navy", 0x000080FF } - , { "oldlace", 0xFDF5E6FF } - , { "olive", 0x808000FF } - , { "olivedrab", 0x6B8E23FF } - , { "orange", 0xFFA500FF } - , { "orangered", 0xFF4500FF } - , { "orchid", 0xDA70D6FF } - , { "palegoldenrod", 0xEEE8AAFF } - , { "palegreen", 0x98FB98FF } - , { "paleturquoise", 0xAFEEEEFF } - , { "palevioletred", 0xDB7093FF } - , { "papayawhip", 0xFFEFD5FF } - , { "peachpuff", 0xFFDAB9FF } - , { "peru", 0xCD853FFF } - , { "pink", 0xFFC0CBFF } - , { "plum", 0xDDA0DDFF } - , { "powderblue", 0xB0E0E6FF } - , { "purple", 0x800080FF } - , { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft - , { "red", 0xFF0000FF } - , { "rosybrown", 0xBC8F8FFF } - , { "royalblue", 0x4169E1FF } - , { "saddlebrown", 0x8B4513FF } - , { "salmon", 0xFA8072FF } - , { "sandybrown", 0xF4A460FF } - , { "seagreen", 0x2E8B57FF } - , { "seashell", 0xFFF5EEFF } - , { "sienna", 0xA0522DFF } - , { "silver", 0xC0C0C0FF } - , { "skyblue", 0x87CEEBFF } - , { "slateblue", 0x6A5ACDFF } - , { "slategray", 0x708090FF } - , { "slategrey", 0x708090FF } - , { "snow", 0xFFFAFAFF } - , { "springgreen", 0x00FF7FFF } - , { "steelblue", 0x4682B4FF } - , { "tan", 0xD2B48CFF } - , { "teal", 0x008080FF } - , { "thistle", 0xD8BFD8FF } - , { "tomato", 0xFF6347FF } - , { "turquoise", 0x40E0D0FF } - , { "violet", 0xEE82EEFF } - , { "wheat", 0xF5DEB3FF } - , { "white", 0xFFFFFFFF } - , { "whitesmoke", 0xF5F5F5FF } - , { "yellow", 0xFFFF00FF } - , { "yellowgreen", 0x9ACD32FF } - , { NULL, 0 } -}; - -/* - * Hex digit int val. - */ - -static int -h(char c) { - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return c - '0'; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return (c - 'a') + 10; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - return (c - 'A') + 10; - } - return 0; -} - -/* - * Return rgba_t from rgba. - */ - -rgba_t -rgba_create(uint32_t rgba) { - rgba_t color; - color.r = (double) (rgba >> 24) / 255; - color.g = (double) (rgba >> 16 & 0xff) / 255; - color.b = (double) (rgba >> 8 & 0xff) / 255; - color.a = (double) (rgba & 0xff) / 255; - return color; -} - -/* - * Return a string representation of the color. - */ - -void -rgba_to_string(rgba_t rgba, char *buf, size_t len) { - if (1 == rgba.a) { - snprintf(buf, len, "#%.2x%.2x%.2x" - , (int) (rgba.r * 255) - , (int) (rgba.g * 255) - , (int) (rgba.b * 255)); - } else { - snprintf(buf, len, "rgba(%d, %d, %d, %.2f)" - , (int) (rgba.r * 255) - , (int) (rgba.g * 255) - , (int) (rgba.b * 255) - , rgba.a); - } -} - -/* - * Return rgba from (r,g,b,a). - */ - -static inline int32_t -rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return - r << 24 - | g << 16 - | b << 8 - | a; -} - -/* - * Helper function used in rgba_from_hsla(). - * Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb - */ - -static float -hue_to_rgb(float t1, float t2, float hue) { - if (hue < 0) - hue += 6; - if (hue >= 6) - hue -= 6; - - if (hue < 1) - return (t2 - t1) * hue + t1; - else if (hue < 3) - return t2; - else if (hue < 4) - return (t2 - t1) * (4 - hue) + t1; - else - return t1; -} - -/* - * Return rgba from (h,s,l,a). - * Expects h values in the range [0, 360), and s, l, a in the range [0, 1]. - * Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb - */ - -static inline int32_t -rgba_from_hsla(float h_deg, float s, float l, float a) { - uint8_t r, g, b; - float h = (6 * h_deg) / 360.0f, m1, m2; - - if (l<=0.5) - m2=l*(s+1); - else - m2=l+s-l*s; - m1 = l*2 - m2; - - // Scale and round the RGB components - r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5); - g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5); - b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5); - - return rgba_from_rgba(r, g, b, (uint8_t) (a * 255)); -} - -/* - * Return rgba from (h,s,l). - * Expects h values in the range [0, 360), and s, l in the range [0, 1]. - */ - -static inline int32_t -rgba_from_hsl(float h_deg, float s, float l) { - return rgba_from_hsla(h_deg, s, l, 1.0); -} - - -/* - * Return rgba from (r,g,b). - */ - -static int32_t -rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { - return rgba_from_rgba(r, g, b, 255); -} - -/* - * Return rgb from "#RRGGBB". - */ - -static int32_t -rgba_from_hex6_string(const char *str) { - return rgba_from_rgb( - (h(str[0]) << 4) + h(str[1]) - , (h(str[2]) << 4) + h(str[3]) - , (h(str[4]) << 4) + h(str[5]) - ); -} - -/* - * Return rgb from "#RGB" - */ - -static int32_t -rgba_from_hex3_string(const char *str) { - return rgba_from_rgb( - (h(str[0]) << 4) + h(str[0]) - , (h(str[1]) << 4) + h(str[1]) - , (h(str[2]) << 4) + h(str[2]) - ); -} - -/* - * Return rgb from "rgb()" - */ - -static int32_t -rgba_from_rgb_string(const char *str, short *ok) { - if (str == strstr(str, "rgb(")) { - str += 4; - WHITESPACE; - uint8_t r = 0, g = 0, b = 0; - CHANNEL(r); - WHITESPACE_OR_COMMA; - CHANNEL(g); - WHITESPACE_OR_COMMA; - CHANNEL(b); - WHITESPACE; - return *ok = 1, rgba_from_rgb(r, g, b); - } - return *ok = 0; -} - -/* - * Return rgb from "rgba()" - */ - -static int32_t -rgba_from_rgba_string(const char *str, short *ok) { - if (str == strstr(str, "rgba(")) { - str += 5; - WHITESPACE; - uint8_t r = 0, g = 0, b = 0; - float a = 0; - CHANNEL(r); - WHITESPACE_OR_COMMA; - CHANNEL(g); - WHITESPACE_OR_COMMA; - CHANNEL(b); - WHITESPACE_OR_COMMA; - ALPHA(a); - WHITESPACE; - return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255)); - } - return *ok = 0; -} - -/* - * Return rgb from "hsla()" - */ - -static int32_t -rgba_from_hsla_string(const char *str, short *ok) { - if (str == strstr(str, "hsla(")) { - str += 5; - WHITESPACE; - float h_deg = 0; - float s = 0, l = 0; - float a = 0; - HUE(h_deg); - WHITESPACE_OR_COMMA; - SATURATION(s); - WHITESPACE_OR_COMMA; - LIGHTNESS(l); - WHITESPACE_OR_COMMA; - ALPHA(a); - WHITESPACE; - return *ok = 1, rgba_from_hsla(h_deg, s, l, a); - } - return *ok = 0; -} - -/* - * Return rgb from "hsl()" - */ - -static int32_t -rgba_from_hsl_string(const char *str, short *ok) { - if (str == strstr(str, "hsl(")) { - str += 4; - WHITESPACE; - float h_deg = 0; - float s = 0, l = 0; - HUE(h_deg); - WHITESPACE_OR_COMMA; - SATURATION(s); - WHITESPACE_OR_COMMA; - LIGHTNESS(l); - WHITESPACE; - return *ok = 1, rgba_from_hsl(h_deg, s, l); - } - return *ok = 0; -} - - -/* - * Return rgb from: - * - * - "#RGB" - * - "#RRGGBB" - * - */ - -static int32_t -rgba_from_hex_string(const char *str, short *ok) { - size_t len = strlen(str); - *ok = 1; - if (6 == len) return rgba_from_hex6_string(str); - if (3 == len) return rgba_from_hex3_string(str); - return *ok = 0; -} - -/* - * Return named color value. - */ - -static int32_t -rgba_from_name_string(const char *str, short *ok) { - int i = 0; - struct named_color color; - while ((color = named_colors[i++]).name) { - if (*str == *color.name && 0 == strcmp(str, color.name)) - return *ok = 1, color.val; - } - return *ok = 0; -} - -/* - * Return rgb from: - * - * - #RGB - * - #RRGGBB - * - rgb(r,g,b) - * - rgba(r,g,b,a) - * - hsl(h,s,l) - * - hsla(h,s,l,a) - * - name - * - */ - -int32_t -rgba_from_string(const char *str, short *ok) { - if ('#' == str[0]) - return rgba_from_hex_string(++str, ok); - if (str == strstr(str, "rgba")) - return rgba_from_rgba_string(str, ok); - if (str == strstr(str, "rgb")) - return rgba_from_rgb_string(str, ok); - if (str == strstr(str, "hsla")) - return rgba_from_hsla_string(str, ok); - if (str == strstr(str, "hsl")) - return rgba_from_hsl_string(str, ok); - return rgba_from_name_string(str, ok); -} - -/* - * Inspect the given rgba color. - */ - -void -rgba_inspect(int32_t rgba) { - printf("rgba(%d,%d,%d,%d)\n" - , rgba >> 24 & 0xff - , rgba >> 16 & 0xff - , rgba >> 8 & 0xff - , rgba & 0xff - ); -} diff --git a/scripts/external/three/canvas/src/color.h b/scripts/external/three/canvas/src/color.h deleted file mode 100644 index c570c4a..0000000 --- a/scripts/external/three/canvas/src/color.h +++ /dev/null @@ -1,40 +0,0 @@ - -// -// color.h -// -// Copyright (c) 2010 LearnBoost -// - -#ifndef __COLOR_PARSER_H__ -#define __COLOR_PARSER_H__ - -#include -#include -#include -#include - -/* - * RGBA struct. - */ - -typedef struct { - double r, g, b, a; -} rgba_t; - -/* - * Prototypes. - */ - -rgba_t -rgba_create(uint32_t rgba); - -int32_t -rgba_from_string(const char *str, short *ok); - -void -rgba_to_string(rgba_t rgba, char *buf, size_t len); - -void -rgba_inspect(int32_t rgba); - -#endif /* __COLOR_PARSER_H__ */ diff --git a/scripts/external/three/canvas/src/init.cc b/scripts/external/three/canvas/src/init.cc deleted file mode 100755 index 6628cee..0000000 --- a/scripts/external/three/canvas/src/init.cc +++ /dev/null @@ -1,74 +0,0 @@ - -// -// init.cc -// -// Copyright (c) 2010 LearnBoost -// - -#include -#include "Canvas.h" -#include "Image.h" -#include "ImageData.h" -#include "PixelArray.h" -#include "CanvasGradient.h" -#include "CanvasPattern.h" -#include "CanvasRenderingContext2d.h" - -#ifdef HAVE_FREETYPE -#include "FontFace.h" -#endif - -extern "C" void -init (Handle target) { - NanScope(); - Canvas::Initialize(target); - Image::Initialize(target); - ImageData::Initialize(target); - PixelArray::Initialize(target); - Context2d::Initialize(target); - Gradient::Initialize(target); - Pattern::Initialize(target); -#ifdef HAVE_FREETYPE - FontFace::Initialize(target); -#endif - - target->Set(NanNew("cairoVersion"), NanNew(cairo_version_string())); -#ifdef HAVE_JPEG - -#ifndef JPEG_LIB_VERSION_MAJOR -#ifdef JPEG_LIB_VERSION -#define JPEG_LIB_VERSION_MAJOR (JPEG_LIB_VERSION / 10) -#else -#define JPEG_LIB_VERSION_MAJOR 0 -#endif -#endif - -#ifndef JPEG_LIB_VERSION_MINOR -#ifdef JPEG_LIB_VERSION -#define JPEG_LIB_VERSION_MINOR (JPEG_LIB_VERSION % 10) -#else -#define JPEG_LIB_VERSION_MINOR 0 -#endif -#endif - - char jpeg_version[10]; - if (JPEG_LIB_VERSION_MINOR > 0) { - snprintf(jpeg_version, 10, "%d%c", JPEG_LIB_VERSION_MAJOR, JPEG_LIB_VERSION_MINOR + 'a' - 1); - } else { - snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR); - } - target->Set(NanNew("jpegVersion"), NanNew(jpeg_version)); -#endif - -#ifdef HAVE_GIF -#ifndef GIF_LIB_VERSION - char gif_version[10]; - snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE); - target->Set(NanNew("gifVersion"), NanNew(gif_version)); -#else - target->Set(NanNew("gifVersion"), NanNew(GIF_LIB_VERSION)); -#endif -#endif -} - -NODE_MODULE(canvas,init); diff --git a/scripts/external/three/canvas/util/cairo_include.sh b/scripts/external/three/canvas/util/cairo_include.sh deleted file mode 100755 index 57ec476..0000000 --- a/scripts/external/three/canvas/util/cairo_include.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -# Make pkg-config lookup include files from the build directory. -export PKG_CONFIG_PATH=$(cd "$(dirname "$0")"; pwd)/../build_cairo/lib/pkgconfig; - -pkg-config cairo --cflags-only-I | sed s/-I//g \ No newline at end of file diff --git a/scripts/external/three/canvas/util/has_cairo_freetype.sh b/scripts/external/three/canvas/util/has_cairo_freetype.sh deleted file mode 100755 index 91bdd47..0000000 --- a/scripts/external/three/canvas/util/has_cairo_freetype.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -has_freetype() { - pkg-config cairo --cflags-only-I | grep freetype2 -} - -has_freetype > /dev/null - -if test $? -eq 0; then - echo true -else - echo false -fi diff --git a/scripts/external/three/canvas/util/has_lib.sh b/scripts/external/three/canvas/util/has_lib.sh deleted file mode 100755 index 27911b6..0000000 --- a/scripts/external/three/canvas/util/has_lib.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -has_lib() { - local regex="lib$1.+(so|dylib)" - - # Add /sbin to path as ldconfig is located there on some systems - e.g. Debian - # (and it still can be used by unprivileged users): - PATH="$PATH:/sbin" - export PATH - # Try using ldconfig on linux systems - for LINE in `which ldconfig > /dev/null && ldconfig -p 2>/dev/null | grep -E $regex`; do - return 0 - done - - # Try just checking common library locations - for dir in /lib /usr/lib /usr/local/lib /opt/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu; do - test -d $dir && ls $dir | grep -E $regex && return 0 - done - - return 1 -} - -has_lib $1 > /dev/null -if test $? -eq 0; then - echo true -else - echo false -fi diff --git a/scripts/external/three/canvas/util/lib_lookup.sh b/scripts/external/three/canvas/util/lib_lookup.sh deleted file mode 100755 index 8f19ce2..0000000 --- a/scripts/external/three/canvas/util/lib_lookup.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -# Make pkg-config lookup include files from the build directory. -export PKG_CONFIG_PATH=$(cd "$(dirname "$0")"; pwd)/../build_cairo/lib/pkgconfig; - -pkg-config $1 --libs \ No newline at end of file diff --git a/scripts/external/three/fonts/helvetiker_regular.js b/scripts/external/three/fonts/helvetiker_regular.js index 3823b6a..2247530 100644 --- a/scripts/external/three/fonts/helvetiker_regular.js +++ b/scripts/external/three/fonts/helvetiker_regular.js @@ -1 +1 @@ -if (_typeface_js && _typeface_js.loadFace) _typeface_js.loadFace({"glyphs":{"ο":{"x_min":0,"x_max":712,"ha":815,"o":"m 356 -25 q 96 88 192 -25 q 0 368 0 201 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 "},"S":{"x_min":0,"x_max":788,"ha":890,"o":"m 788 291 q 662 54 788 144 q 397 -26 550 -26 q 116 68 226 -26 q 0 337 0 168 l 131 337 q 200 152 131 220 q 384 85 269 85 q 557 129 479 85 q 650 270 650 183 q 490 429 650 379 q 194 513 341 470 q 33 739 33 584 q 142 964 33 881 q 388 1041 242 1041 q 644 957 543 1041 q 756 716 756 867 l 625 716 q 561 874 625 816 q 395 933 497 933 q 243 891 309 933 q 164 759 164 841 q 325 609 164 656 q 625 526 475 568 q 788 291 788 454 "},"¦":{"x_min":343,"x_max":449,"ha":792,"o":"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"/":{"x_min":183.25,"x_max":608.328125,"ha":792,"o":"m 608 1041 l 266 -129 l 183 -129 l 520 1041 l 608 1041 "},"Τ":{"x_min":-0.4375,"x_max":777.453125,"ha":839,"o":"m 777 893 l 458 893 l 458 0 l 319 0 l 319 892 l 0 892 l 0 1013 l 777 1013 l 777 893 "},"y":{"x_min":0,"x_max":684.78125,"ha":771,"o":"m 684 738 l 388 -83 q 311 -216 356 -167 q 173 -279 252 -279 q 97 -266 133 -279 l 97 -149 q 132 -155 109 -151 q 168 -160 155 -160 q 240 -114 213 -160 q 274 -26 248 -98 l 0 738 l 137 737 l 341 139 l 548 737 l 684 738 "},"Π":{"x_min":0,"x_max":803,"ha":917,"o":"m 803 0 l 667 0 l 667 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 803 1012 l 803 0 "},"ΐ":{"x_min":-111,"x_max":339,"ha":361,"o":"m 339 800 l 229 800 l 229 925 l 339 925 l 339 800 m -1 800 l -111 800 l -111 925 l -1 925 l -1 800 m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 m 302 1040 l 113 819 l 30 819 l 165 1040 l 302 1040 "},"g":{"x_min":0,"x_max":686,"ha":838,"o":"m 686 34 q 586 -213 686 -121 q 331 -306 487 -306 q 131 -252 216 -306 q 31 -84 31 -190 l 155 -84 q 228 -174 166 -138 q 345 -207 284 -207 q 514 -109 454 -207 q 564 89 564 -27 q 461 6 521 36 q 335 -23 401 -23 q 88 100 184 -23 q 0 370 0 215 q 87 634 0 522 q 330 758 183 758 q 457 728 398 758 q 564 644 515 699 l 564 737 l 686 737 l 686 34 m 582 367 q 529 560 582 481 q 358 652 468 652 q 189 561 250 652 q 135 369 135 482 q 189 176 135 255 q 361 85 251 85 q 529 176 468 85 q 582 367 582 255 "},"²":{"x_min":0,"x_max":442,"ha":539,"o":"m 442 383 l 0 383 q 91 566 0 492 q 260 668 176 617 q 354 798 354 727 q 315 875 354 845 q 227 905 277 905 q 136 869 173 905 q 99 761 99 833 l 14 761 q 82 922 14 864 q 232 974 141 974 q 379 926 316 974 q 442 797 442 878 q 351 635 442 704 q 183 539 321 611 q 92 455 92 491 l 442 455 l 442 383 "},"–":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},"Κ":{"x_min":0,"x_max":819.5625,"ha":893,"o":"m 819 0 l 650 0 l 294 509 l 139 356 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},"ƒ":{"x_min":-46.265625,"x_max":392,"ha":513,"o":"m 392 651 l 259 651 l 79 -279 l -46 -278 l 134 651 l 14 651 l 14 751 l 135 751 q 151 948 135 900 q 304 1041 185 1041 q 334 1040 319 1041 q 392 1034 348 1039 l 392 922 q 337 931 360 931 q 271 883 287 931 q 260 793 260 853 l 260 751 l 392 751 l 392 651 "},"e":{"x_min":0,"x_max":714,"ha":813,"o":"m 714 326 l 140 326 q 200 157 140 227 q 359 87 260 87 q 488 130 431 87 q 561 245 545 174 l 697 245 q 577 48 670 123 q 358 -26 484 -26 q 97 85 195 -26 q 0 363 0 197 q 94 642 0 529 q 358 765 195 765 q 626 627 529 765 q 714 326 714 503 m 576 429 q 507 583 564 522 q 355 650 445 650 q 206 583 266 650 q 140 429 152 522 l 576 429 "},"ό":{"x_min":0,"x_max":712,"ha":815,"o":"m 356 -25 q 94 91 194 -25 q 0 368 0 202 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 m 576 1040 l 387 819 l 303 819 l 438 1040 l 576 1040 "},"J":{"x_min":0,"x_max":588,"ha":699,"o":"m 588 279 q 287 -26 588 -26 q 58 73 126 -26 q 0 327 0 158 l 133 327 q 160 172 133 227 q 288 96 198 96 q 426 171 391 96 q 449 336 449 219 l 449 1013 l 588 1013 l 588 279 "},"»":{"x_min":-1,"x_max":503,"ha":601,"o":"m 503 302 l 280 136 l 281 256 l 429 373 l 281 486 l 280 608 l 503 440 l 503 302 m 221 302 l 0 136 l 0 255 l 145 372 l 0 486 l -1 608 l 221 440 l 221 302 "},"©":{"x_min":-3,"x_max":1008,"ha":1106,"o":"m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 741 394 q 661 246 731 302 q 496 190 591 190 q 294 285 369 190 q 228 497 228 370 q 295 714 228 625 q 499 813 370 813 q 656 762 588 813 q 733 625 724 711 l 634 625 q 589 704 629 673 q 498 735 550 735 q 377 666 421 735 q 334 504 334 597 q 374 340 334 408 q 490 272 415 272 q 589 304 549 272 q 638 394 628 337 l 741 394 "},"ώ":{"x_min":0,"x_max":922,"ha":1030,"o":"m 687 1040 l 498 819 l 415 819 l 549 1040 l 687 1040 m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 338 0 202 q 45 551 0 444 q 161 737 84 643 l 302 737 q 175 552 219 647 q 124 336 124 446 q 155 179 124 248 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 341 797 257 q 745 555 797 450 q 619 737 705 637 l 760 737 q 874 551 835 640 q 922 339 922 444 "},"^":{"x_min":193.0625,"x_max":598.609375,"ha":792,"o":"m 598 772 l 515 772 l 395 931 l 277 772 l 193 772 l 326 1013 l 462 1013 l 598 772 "},"«":{"x_min":0,"x_max":507.203125,"ha":604,"o":"m 506 136 l 284 302 l 284 440 l 506 608 l 507 485 l 360 371 l 506 255 l 506 136 m 222 136 l 0 302 l 0 440 l 222 608 l 221 486 l 73 373 l 222 256 l 222 136 "},"D":{"x_min":0,"x_max":828,"ha":935,"o":"m 389 1013 q 714 867 593 1013 q 828 521 828 729 q 712 161 828 309 q 382 0 587 0 l 0 0 l 0 1013 l 389 1013 m 376 124 q 607 247 523 124 q 681 510 681 355 q 607 771 681 662 q 376 896 522 896 l 139 896 l 139 124 l 376 124 "},"∙":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"ÿ":{"x_min":0,"x_max":47,"ha":125,"o":"m 47 3 q 37 -7 47 -7 q 28 0 30 -7 q 39 -4 32 -4 q 45 3 45 -1 l 37 0 q 28 9 28 0 q 39 19 28 19 l 47 16 l 47 19 l 47 3 m 37 1 q 44 8 44 1 q 37 16 44 16 q 30 8 30 16 q 37 1 30 1 m 26 1 l 23 22 l 14 0 l 3 22 l 3 3 l 0 25 l 13 1 l 22 25 l 26 1 "},"w":{"x_min":0,"x_max":1009.71875,"ha":1100,"o":"m 1009 738 l 783 0 l 658 0 l 501 567 l 345 0 l 222 0 l 0 738 l 130 738 l 284 174 l 432 737 l 576 738 l 721 173 l 881 737 l 1009 738 "},"$":{"x_min":0,"x_max":700,"ha":793,"o":"m 664 717 l 542 717 q 490 825 531 785 q 381 872 450 865 l 381 551 q 620 446 540 522 q 700 241 700 370 q 618 45 700 116 q 381 -25 536 -25 l 381 -152 l 307 -152 l 307 -25 q 81 62 162 -25 q 0 297 0 149 l 124 297 q 169 146 124 204 q 307 81 215 89 l 307 441 q 80 536 148 469 q 13 725 13 603 q 96 910 13 839 q 307 982 180 982 l 307 1077 l 381 1077 l 381 982 q 574 917 494 982 q 664 717 664 845 m 307 565 l 307 872 q 187 831 233 872 q 142 724 142 791 q 180 618 142 656 q 307 565 218 580 m 381 76 q 562 237 562 96 q 517 361 562 313 q 381 423 472 409 l 381 76 "},"\\":{"x_min":-0.015625,"x_max":425.0625,"ha":522,"o":"m 425 -129 l 337 -129 l 0 1041 l 83 1041 l 425 -129 "},"µ":{"x_min":0,"x_max":697.21875,"ha":747,"o":"m 697 -4 q 629 -14 658 -14 q 498 97 513 -14 q 422 9 470 41 q 313 -23 374 -23 q 207 4 258 -23 q 119 81 156 32 l 119 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 173 124 246 q 308 83 216 83 q 452 178 402 83 q 493 359 493 255 l 493 738 l 617 738 l 617 214 q 623 136 617 160 q 673 92 637 92 q 697 96 684 92 l 697 -4 "},"Ι":{"x_min":42,"x_max":181,"ha":297,"o":"m 181 0 l 42 0 l 42 1013 l 181 1013 l 181 0 "},"Ύ":{"x_min":0,"x_max":1144.5,"ha":1214,"o":"m 1144 1012 l 807 416 l 807 0 l 667 0 l 667 416 l 325 1012 l 465 1012 l 736 533 l 1004 1012 l 1144 1012 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"’":{"x_min":0,"x_max":139,"ha":236,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"Ν":{"x_min":0,"x_max":801,"ha":915,"o":"m 801 0 l 651 0 l 131 822 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 191 l 670 1013 l 801 1013 l 801 0 "},"-":{"x_min":8.71875,"x_max":350.390625,"ha":478,"o":"m 350 317 l 8 317 l 8 428 l 350 428 l 350 317 "},"Q":{"x_min":0,"x_max":968,"ha":1072,"o":"m 954 5 l 887 -79 l 744 35 q 622 -11 687 2 q 483 -26 556 -26 q 127 130 262 -26 q 0 504 0 279 q 127 880 0 728 q 484 1041 262 1041 q 841 884 708 1041 q 968 507 968 735 q 933 293 968 398 q 832 104 899 188 l 954 5 m 723 191 q 802 330 777 248 q 828 499 828 412 q 744 790 828 673 q 483 922 650 922 q 228 791 322 922 q 142 505 142 673 q 227 221 142 337 q 487 91 323 91 q 632 123 566 91 l 520 215 l 587 301 l 723 191 "},"ς":{"x_min":1,"x_max":676.28125,"ha":740,"o":"m 676 460 l 551 460 q 498 595 542 546 q 365 651 448 651 q 199 578 263 651 q 136 401 136 505 q 266 178 136 241 q 508 106 387 142 q 640 -50 640 62 q 625 -158 640 -105 q 583 -278 611 -211 l 465 -278 q 498 -182 490 -211 q 515 -80 515 -126 q 381 12 515 -15 q 134 91 197 51 q 1 388 1 179 q 100 651 1 542 q 354 761 199 761 q 587 680 498 761 q 676 460 676 599 "},"M":{"x_min":0,"x_max":954,"ha":1067,"o":"m 954 0 l 819 0 l 819 869 l 537 0 l 405 0 l 128 866 l 128 0 l 0 0 l 0 1013 l 200 1013 l 472 160 l 757 1013 l 954 1013 l 954 0 "},"Ψ":{"x_min":0,"x_max":1006,"ha":1094,"o":"m 1006 678 q 914 319 1006 429 q 571 200 814 200 l 571 0 l 433 0 l 433 200 q 92 319 194 200 q 0 678 0 429 l 0 1013 l 139 1013 l 139 679 q 191 417 139 492 q 433 326 255 326 l 433 1013 l 571 1013 l 571 326 l 580 326 q 813 423 747 326 q 868 679 868 502 l 868 1013 l 1006 1013 l 1006 678 "},"C":{"x_min":0,"x_max":886,"ha":944,"o":"m 886 379 q 760 87 886 201 q 455 -26 634 -26 q 112 136 236 -26 q 0 509 0 283 q 118 882 0 737 q 469 1041 245 1041 q 748 955 630 1041 q 879 708 879 859 l 745 708 q 649 862 724 805 q 473 920 573 920 q 219 791 312 920 q 136 509 136 675 q 217 229 136 344 q 470 99 311 99 q 672 179 591 99 q 753 379 753 259 l 886 379 "},"!":{"x_min":0,"x_max":138,"ha":236,"o":"m 138 684 q 116 409 138 629 q 105 244 105 299 l 33 244 q 16 465 33 313 q 0 684 0 616 l 0 1013 l 138 1013 l 138 684 m 138 0 l 0 0 l 0 151 l 138 151 l 138 0 "},"{":{"x_min":0,"x_max":480.5625,"ha":578,"o":"m 480 -286 q 237 -213 303 -286 q 187 -45 187 -159 q 194 48 187 -15 q 201 141 201 112 q 164 264 201 225 q 0 314 118 314 l 0 417 q 164 471 119 417 q 201 605 201 514 q 199 665 201 644 q 193 772 193 769 q 241 941 193 887 q 480 1015 308 1015 l 480 915 q 336 866 375 915 q 306 742 306 828 q 310 662 306 717 q 314 577 314 606 q 288 452 314 500 q 176 365 256 391 q 289 275 257 337 q 314 143 314 226 q 313 84 314 107 q 310 -11 310 -5 q 339 -131 310 -94 q 480 -182 377 -182 l 480 -286 "},"X":{"x_min":-0.015625,"x_max":854.15625,"ha":940,"o":"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 428 637 l 675 1013 l 836 1013 l 504 520 l 854 0 "},"#":{"x_min":0,"x_max":963.890625,"ha":1061,"o":"m 963 690 l 927 590 l 719 590 l 655 410 l 876 410 l 840 310 l 618 310 l 508 -3 l 393 -2 l 506 309 l 329 310 l 215 -2 l 102 -3 l 212 310 l 0 310 l 36 410 l 248 409 l 312 590 l 86 590 l 120 690 l 347 690 l 459 1006 l 573 1006 l 462 690 l 640 690 l 751 1006 l 865 1006 l 754 690 l 963 690 m 606 590 l 425 590 l 362 410 l 543 410 l 606 590 "},"ι":{"x_min":42,"x_max":284,"ha":361,"o":"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 738 l 167 738 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 "},"Ά":{"x_min":0,"x_max":906.953125,"ha":982,"o":"m 283 1040 l 88 799 l 5 799 l 145 1040 l 283 1040 m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1012 l 529 1012 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},")":{"x_min":0,"x_max":318,"ha":415,"o":"m 318 365 q 257 25 318 191 q 87 -290 197 -141 l 0 -290 q 140 21 93 -128 q 193 360 193 189 q 141 704 193 537 q 0 1024 97 850 l 87 1024 q 257 706 197 871 q 318 365 318 542 "},"ε":{"x_min":0,"x_max":634.71875,"ha":714,"o":"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 314 0 265 q 128 390 67 353 q 56 460 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 "},"Δ":{"x_min":0,"x_max":952.78125,"ha":1028,"o":"m 952 0 l 0 0 l 400 1013 l 551 1013 l 952 0 m 762 124 l 476 867 l 187 124 l 762 124 "},"}":{"x_min":0,"x_max":481,"ha":578,"o":"m 481 314 q 318 262 364 314 q 282 136 282 222 q 284 65 282 97 q 293 -58 293 -48 q 241 -217 293 -166 q 0 -286 174 -286 l 0 -182 q 143 -130 105 -182 q 171 -2 171 -93 q 168 81 171 22 q 165 144 165 140 q 188 275 165 229 q 306 365 220 339 q 191 455 224 391 q 165 588 165 505 q 168 681 165 624 q 171 742 171 737 q 141 865 171 827 q 0 915 102 915 l 0 1015 q 243 942 176 1015 q 293 773 293 888 q 287 675 293 741 q 282 590 282 608 q 318 466 282 505 q 481 417 364 417 l 481 314 "},"‰":{"x_min":-3,"x_max":1672,"ha":1821,"o":"m 846 0 q 664 76 732 0 q 603 244 603 145 q 662 412 603 344 q 846 489 729 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 846 0 962 0 m 845 103 q 945 143 910 103 q 981 243 981 184 q 947 340 981 301 q 845 385 910 385 q 745 342 782 385 q 709 243 709 300 q 742 147 709 186 q 845 103 781 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 m 1428 0 q 1246 76 1314 0 q 1185 244 1185 145 q 1244 412 1185 344 q 1428 489 1311 489 q 1610 412 1542 489 q 1672 244 1672 343 q 1612 76 1672 144 q 1428 0 1545 0 m 1427 103 q 1528 143 1492 103 q 1564 243 1564 184 q 1530 340 1564 301 q 1427 385 1492 385 q 1327 342 1364 385 q 1291 243 1291 300 q 1324 147 1291 186 q 1427 103 1363 103 "},"a":{"x_min":0,"x_max":698.609375,"ha":794,"o":"m 698 0 q 661 -12 679 -7 q 615 -17 643 -17 q 536 12 564 -17 q 500 96 508 41 q 384 6 456 37 q 236 -25 312 -25 q 65 31 130 -25 q 0 194 0 88 q 118 390 0 334 q 328 435 180 420 q 488 483 476 451 q 495 523 495 504 q 442 619 495 584 q 325 654 389 654 q 209 617 257 654 q 152 513 161 580 l 33 513 q 123 705 33 633 q 332 772 207 772 q 528 712 448 772 q 617 531 617 645 l 617 163 q 624 108 617 126 q 664 90 632 90 l 698 94 l 698 0 m 491 262 l 491 372 q 272 329 350 347 q 128 201 128 294 q 166 113 128 144 q 264 83 205 83 q 414 130 346 83 q 491 262 491 183 "},"—":{"x_min":0,"x_max":941.671875,"ha":1039,"o":"m 941 334 l 0 334 l 0 410 l 941 410 l 941 334 "},"=":{"x_min":8.71875,"x_max":780.953125,"ha":792,"o":"m 780 510 l 8 510 l 8 606 l 780 606 l 780 510 m 780 235 l 8 235 l 8 332 l 780 332 l 780 235 "},"N":{"x_min":0,"x_max":801,"ha":914,"o":"m 801 0 l 651 0 l 131 823 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 193 l 670 1013 l 801 1013 l 801 0 "},"ρ":{"x_min":0,"x_max":712,"ha":797,"o":"m 712 369 q 620 94 712 207 q 362 -26 521 -26 q 230 2 292 -26 q 119 83 167 30 l 119 -278 l 0 -278 l 0 362 q 91 643 0 531 q 355 764 190 764 q 617 647 517 764 q 712 369 712 536 m 583 366 q 530 559 583 480 q 359 651 469 651 q 190 562 252 651 q 135 370 135 483 q 189 176 135 257 q 359 85 250 85 q 528 175 466 85 q 583 366 583 254 "},"2":{"x_min":59,"x_max":731,"ha":792,"o":"m 731 0 l 59 0 q 197 314 59 188 q 457 487 199 315 q 598 691 598 580 q 543 819 598 772 q 411 867 488 867 q 272 811 328 867 q 209 630 209 747 l 81 630 q 182 901 81 805 q 408 986 271 986 q 629 909 536 986 q 731 694 731 826 q 613 449 731 541 q 378 316 495 383 q 201 122 235 234 l 731 122 l 731 0 "},"¯":{"x_min":0,"x_max":941.671875,"ha":938,"o":"m 941 1033 l 0 1033 l 0 1109 l 941 1109 l 941 1033 "},"Z":{"x_min":0,"x_max":779,"ha":849,"o":"m 779 0 l 0 0 l 0 113 l 621 896 l 40 896 l 40 1013 l 779 1013 l 778 887 l 171 124 l 779 124 l 779 0 "},"u":{"x_min":0,"x_max":617,"ha":729,"o":"m 617 0 l 499 0 l 499 110 q 391 10 460 45 q 246 -25 322 -25 q 61 58 127 -25 q 0 258 0 136 l 0 738 l 125 738 l 125 284 q 156 148 125 202 q 273 82 197 82 q 433 165 369 82 q 493 340 493 243 l 493 738 l 617 738 l 617 0 "},"k":{"x_min":0,"x_max":612.484375,"ha":697,"o":"m 612 738 l 338 465 l 608 0 l 469 0 l 251 382 l 121 251 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 402 l 456 738 l 612 738 "},"Η":{"x_min":0,"x_max":803,"ha":917,"o":"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"Α":{"x_min":0,"x_max":906.953125,"ha":985,"o":"m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},"s":{"x_min":0,"x_max":604,"ha":697,"o":"m 604 217 q 501 36 604 104 q 292 -23 411 -23 q 86 43 166 -23 q 0 238 0 114 l 121 237 q 175 122 121 164 q 300 85 223 85 q 415 112 363 85 q 479 207 479 147 q 361 309 479 276 q 140 372 141 370 q 21 544 21 426 q 111 708 21 647 q 298 761 190 761 q 492 705 413 761 q 583 531 583 643 l 462 531 q 412 625 462 594 q 298 657 363 657 q 199 636 242 657 q 143 558 143 608 q 262 454 143 486 q 484 394 479 397 q 604 217 604 341 "},"B":{"x_min":0,"x_max":778,"ha":876,"o":"m 580 546 q 724 469 670 535 q 778 311 778 403 q 673 83 778 171 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 892 q 691 633 732 693 q 580 546 650 572 m 393 899 l 139 899 l 139 588 l 379 588 q 521 624 462 588 q 592 744 592 667 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 303 635 219 q 559 436 635 389 q 402 477 494 477 l 139 477 l 139 124 l 419 124 "},"…":{"x_min":0,"x_max":614,"ha":708,"o":"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 m 378 0 l 236 0 l 236 151 l 378 151 l 378 0 m 614 0 l 472 0 l 472 151 l 614 151 l 614 0 "},"?":{"x_min":0,"x_max":607,"ha":704,"o":"m 607 777 q 543 599 607 674 q 422 474 482 537 q 357 272 357 391 l 236 272 q 297 487 236 395 q 411 619 298 490 q 474 762 474 691 q 422 885 474 838 q 301 933 371 933 q 179 880 228 933 q 124 706 124 819 l 0 706 q 94 963 0 872 q 302 1044 177 1044 q 511 973 423 1044 q 607 777 607 895 m 370 0 l 230 0 l 230 151 l 370 151 l 370 0 "},"H":{"x_min":0,"x_max":803,"ha":915,"o":"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"ν":{"x_min":0,"x_max":675,"ha":761,"o":"m 675 738 l 404 0 l 272 0 l 0 738 l 133 738 l 340 147 l 541 738 l 675 738 "},"c":{"x_min":1,"x_max":701.390625,"ha":775,"o":"m 701 264 q 584 53 681 133 q 353 -26 487 -26 q 91 91 188 -26 q 1 370 1 201 q 92 645 1 537 q 353 761 190 761 q 572 688 479 761 q 690 493 666 615 l 556 493 q 487 606 545 562 q 356 650 428 650 q 186 563 246 650 q 134 372 134 487 q 188 179 134 258 q 359 88 250 88 q 492 136 437 88 q 566 264 548 185 l 701 264 "},"¶":{"x_min":0,"x_max":566.671875,"ha":678,"o":"m 21 892 l 52 892 l 98 761 l 145 892 l 176 892 l 178 741 l 157 741 l 157 867 l 108 741 l 88 741 l 40 871 l 40 741 l 21 741 l 21 892 m 308 854 l 308 731 q 252 691 308 691 q 227 691 240 691 q 207 696 213 695 l 207 712 l 253 706 q 288 733 288 706 l 288 763 q 244 741 279 741 q 193 797 193 741 q 261 860 193 860 q 287 860 273 860 q 308 854 302 855 m 288 842 l 263 843 q 213 796 213 843 q 248 756 213 756 q 288 796 288 756 l 288 842 m 566 988 l 502 988 l 502 -1 l 439 -1 l 439 988 l 317 988 l 317 -1 l 252 -1 l 252 602 q 81 653 155 602 q 0 805 0 711 q 101 989 0 918 q 309 1053 194 1053 l 566 1053 l 566 988 "},"β":{"x_min":0,"x_max":660,"ha":745,"o":"m 471 550 q 610 450 561 522 q 660 280 660 378 q 578 64 660 151 q 367 -22 497 -22 q 239 5 299 -22 q 126 82 178 32 l 126 -278 l 0 -278 l 0 593 q 54 903 0 801 q 318 1042 127 1042 q 519 964 436 1042 q 603 771 603 887 q 567 644 603 701 q 471 550 532 586 m 337 79 q 476 138 418 79 q 535 279 535 198 q 427 437 535 386 q 226 477 344 477 l 226 583 q 398 620 329 583 q 486 762 486 668 q 435 884 486 833 q 312 935 384 935 q 169 861 219 935 q 126 698 126 797 l 126 362 q 170 169 126 242 q 337 79 224 79 "},"Μ":{"x_min":0,"x_max":954,"ha":1068,"o":"m 954 0 l 819 0 l 819 868 l 537 0 l 405 0 l 128 865 l 128 0 l 0 0 l 0 1013 l 199 1013 l 472 158 l 758 1013 l 954 1013 l 954 0 "},"Ό":{"x_min":0.109375,"x_max":1120,"ha":1217,"o":"m 1120 505 q 994 132 1120 282 q 642 -29 861 -29 q 290 130 422 -29 q 167 505 167 280 q 294 883 167 730 q 650 1046 430 1046 q 999 882 868 1046 q 1120 505 1120 730 m 977 504 q 896 784 977 669 q 644 915 804 915 q 391 785 484 915 q 307 504 307 669 q 391 224 307 339 q 644 95 486 95 q 894 224 803 95 q 977 504 977 339 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Ή":{"x_min":0,"x_max":1158,"ha":1275,"o":"m 1158 0 l 1022 0 l 1022 475 l 496 475 l 496 0 l 356 0 l 356 1012 l 496 1012 l 496 599 l 1022 599 l 1022 1012 l 1158 1012 l 1158 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"•":{"x_min":0,"x_max":663.890625,"ha":775,"o":"m 663 529 q 566 293 663 391 q 331 196 469 196 q 97 294 194 196 q 0 529 0 393 q 96 763 0 665 q 331 861 193 861 q 566 763 469 861 q 663 529 663 665 "},"¥":{"x_min":0.1875,"x_max":819.546875,"ha":886,"o":"m 563 561 l 697 561 l 696 487 l 520 487 l 482 416 l 482 380 l 697 380 l 695 308 l 482 308 l 482 0 l 342 0 l 342 308 l 125 308 l 125 380 l 342 380 l 342 417 l 303 487 l 125 487 l 125 561 l 258 561 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 l 563 561 "},"(":{"x_min":0,"x_max":318.0625,"ha":415,"o":"m 318 -290 l 230 -290 q 61 23 122 -142 q 0 365 0 190 q 62 712 0 540 q 230 1024 119 869 l 318 1024 q 175 705 219 853 q 125 360 125 542 q 176 22 125 187 q 318 -290 223 -127 "},"U":{"x_min":0,"x_max":796,"ha":904,"o":"m 796 393 q 681 93 796 212 q 386 -25 566 -25 q 101 95 208 -25 q 0 393 0 211 l 0 1013 l 138 1013 l 138 391 q 204 191 138 270 q 394 107 276 107 q 586 191 512 107 q 656 391 656 270 l 656 1013 l 796 1013 l 796 393 "},"γ":{"x_min":0.5,"x_max":744.953125,"ha":822,"o":"m 744 737 l 463 54 l 463 -278 l 338 -278 l 338 54 l 154 495 q 104 597 124 569 q 13 651 67 651 l 0 651 l 0 751 l 39 753 q 168 711 121 753 q 242 594 207 676 l 403 208 l 617 737 l 744 737 "},"α":{"x_min":0,"x_max":765.5625,"ha":809,"o":"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 728 407 760 q 563 637 524 696 l 563 739 l 685 739 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 96 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 "},"F":{"x_min":0,"x_max":683.328125,"ha":717,"o":"m 683 888 l 140 888 l 140 583 l 613 583 l 613 458 l 140 458 l 140 0 l 0 0 l 0 1013 l 683 1013 l 683 888 "},"­":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},":":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"Χ":{"x_min":0,"x_max":854.171875,"ha":935,"o":"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 427 637 l 675 1013 l 836 1013 l 504 521 l 854 0 "},"*":{"x_min":116,"x_max":674,"ha":792,"o":"m 674 768 l 475 713 l 610 544 l 517 477 l 394 652 l 272 478 l 178 544 l 314 713 l 116 766 l 153 876 l 341 812 l 342 1013 l 446 1013 l 446 811 l 635 874 l 674 768 "},"†":{"x_min":0,"x_max":777,"ha":835,"o":"m 458 804 l 777 804 l 777 683 l 458 683 l 458 0 l 319 0 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 "},"°":{"x_min":0,"x_max":347,"ha":444,"o":"m 173 802 q 43 856 91 802 q 0 977 0 905 q 45 1101 0 1049 q 173 1153 90 1153 q 303 1098 255 1153 q 347 977 347 1049 q 303 856 347 905 q 173 802 256 802 m 173 884 q 238 910 214 884 q 262 973 262 937 q 239 1038 262 1012 q 173 1064 217 1064 q 108 1037 132 1064 q 85 973 85 1010 q 108 910 85 937 q 173 884 132 884 "},"V":{"x_min":0,"x_max":862.71875,"ha":940,"o":"m 862 1013 l 505 0 l 361 0 l 0 1013 l 143 1013 l 434 165 l 718 1012 l 862 1013 "},"Ξ":{"x_min":0,"x_max":734.71875,"ha":763,"o":"m 723 889 l 9 889 l 9 1013 l 723 1013 l 723 889 m 673 463 l 61 463 l 61 589 l 673 589 l 673 463 m 734 0 l 0 0 l 0 124 l 734 124 l 734 0 "}," ":{"x_min":0,"x_max":0,"ha":853},"Ϋ":{"x_min":0.328125,"x_max":819.515625,"ha":889,"o":"m 588 1046 l 460 1046 l 460 1189 l 588 1189 l 588 1046 m 360 1046 l 232 1046 l 232 1189 l 360 1189 l 360 1046 m 819 1012 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1012 l 140 1012 l 411 533 l 679 1012 l 819 1012 "},"0":{"x_min":73,"x_max":715,"ha":792,"o":"m 394 -29 q 153 129 242 -29 q 73 479 73 272 q 152 829 73 687 q 394 989 241 989 q 634 829 545 989 q 715 479 715 684 q 635 129 715 270 q 394 -29 546 -29 m 394 89 q 546 211 489 89 q 598 479 598 322 q 548 748 598 640 q 394 871 491 871 q 241 748 298 871 q 190 479 190 637 q 239 211 190 319 q 394 89 296 89 "},"”":{"x_min":0,"x_max":347,"ha":454,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 m 347 851 q 310 737 347 784 q 208 669 273 690 l 208 734 q 267 787 250 741 q 280 873 280 821 l 208 873 l 208 1013 l 347 1013 l 347 851 "},"@":{"x_min":0,"x_max":1260,"ha":1357,"o":"m 1098 -45 q 877 -160 1001 -117 q 633 -203 752 -203 q 155 -29 327 -203 q 0 360 0 127 q 176 802 0 616 q 687 1008 372 1008 q 1123 854 969 1008 q 1260 517 1260 718 q 1155 216 1260 341 q 868 82 1044 82 q 772 106 801 82 q 737 202 737 135 q 647 113 700 144 q 527 82 594 82 q 367 147 420 82 q 314 312 314 212 q 401 565 314 452 q 639 690 498 690 q 810 588 760 690 l 849 668 l 938 668 q 877 441 900 532 q 833 226 833 268 q 853 182 833 198 q 902 167 873 167 q 1088 272 1012 167 q 1159 512 1159 372 q 1051 793 1159 681 q 687 925 925 925 q 248 747 415 925 q 97 361 97 586 q 226 26 97 159 q 627 -122 370 -122 q 856 -87 737 -122 q 1061 8 976 -53 l 1098 -45 m 786 488 q 738 580 777 545 q 643 615 700 615 q 483 517 548 615 q 425 322 425 430 q 457 203 425 250 q 552 156 490 156 q 722 273 665 156 q 786 488 738 309 "},"Ί":{"x_min":0,"x_max":499,"ha":613,"o":"m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 m 499 0 l 360 0 l 360 1012 l 499 1012 l 499 0 "},"i":{"x_min":14,"x_max":136,"ha":275,"o":"m 136 873 l 14 873 l 14 1013 l 136 1013 l 136 873 m 136 0 l 14 0 l 14 737 l 136 737 l 136 0 "},"Β":{"x_min":0,"x_max":778,"ha":877,"o":"m 580 545 q 724 468 671 534 q 778 310 778 402 q 673 83 778 170 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 891 q 691 632 732 692 q 580 545 650 571 m 393 899 l 139 899 l 139 587 l 379 587 q 521 623 462 587 q 592 744 592 666 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 302 635 219 q 559 435 635 388 q 402 476 494 476 l 139 476 l 139 124 l 419 124 "},"υ":{"x_min":0,"x_max":617,"ha":725,"o":"m 617 352 q 540 94 617 199 q 308 -24 455 -24 q 76 94 161 -24 q 0 352 0 199 l 0 739 l 126 739 l 126 355 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 355 492 257 l 492 739 l 617 739 l 617 352 "},"]":{"x_min":0,"x_max":275,"ha":372,"o":"m 275 -281 l 0 -281 l 0 -187 l 151 -187 l 151 920 l 0 920 l 0 1013 l 275 1013 l 275 -281 "},"m":{"x_min":0,"x_max":1019,"ha":1128,"o":"m 1019 0 l 897 0 l 897 454 q 860 591 897 536 q 739 660 816 660 q 613 586 659 660 q 573 436 573 522 l 573 0 l 447 0 l 447 455 q 412 591 447 535 q 294 657 372 657 q 165 586 213 657 q 122 437 122 521 l 122 0 l 0 0 l 0 738 l 117 738 l 117 640 q 202 730 150 697 q 316 763 254 763 q 437 730 381 763 q 525 642 494 697 q 621 731 559 700 q 753 763 682 763 q 943 694 867 763 q 1019 512 1019 625 l 1019 0 "},"χ":{"x_min":8.328125,"x_max":780.5625,"ha":815,"o":"m 780 -278 q 715 -294 747 -294 q 616 -257 663 -294 q 548 -175 576 -227 l 379 133 l 143 -277 l 9 -277 l 313 254 l 163 522 q 127 586 131 580 q 36 640 91 640 q 8 637 27 640 l 8 752 l 52 757 q 162 719 113 757 q 236 627 200 690 l 383 372 l 594 737 l 726 737 l 448 250 l 625 -69 q 670 -153 647 -110 q 743 -188 695 -188 q 780 -184 759 -188 l 780 -278 "},"8":{"x_min":55,"x_max":736,"ha":792,"o":"m 571 527 q 694 424 652 491 q 736 280 736 358 q 648 71 736 158 q 395 -26 551 -26 q 142 69 238 -26 q 55 279 55 157 q 96 425 55 359 q 220 527 138 491 q 120 615 153 562 q 88 726 88 668 q 171 904 88 827 q 395 986 261 986 q 618 905 529 986 q 702 727 702 830 q 670 616 702 667 q 571 527 638 565 m 394 565 q 519 610 475 565 q 563 717 563 655 q 521 823 563 781 q 392 872 474 872 q 265 824 312 872 q 224 720 224 783 q 265 613 224 656 q 394 565 312 565 m 395 91 q 545 150 488 91 q 597 280 597 204 q 546 408 597 355 q 395 465 492 465 q 244 408 299 465 q 194 280 194 356 q 244 150 194 203 q 395 91 299 91 "},"ί":{"x_min":42,"x_max":326.71875,"ha":361,"o":"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 102 239 101 q 284 112 257 104 l 284 3 m 326 1040 l 137 819 l 54 819 l 189 1040 l 326 1040 "},"Ζ":{"x_min":0,"x_max":779.171875,"ha":850,"o":"m 779 0 l 0 0 l 0 113 l 620 896 l 40 896 l 40 1013 l 779 1013 l 779 887 l 170 124 l 779 124 l 779 0 "},"R":{"x_min":0,"x_max":781.953125,"ha":907,"o":"m 781 0 l 623 0 q 587 242 590 52 q 407 433 585 433 l 138 433 l 138 0 l 0 0 l 0 1013 l 396 1013 q 636 946 539 1013 q 749 731 749 868 q 711 597 749 659 q 608 502 674 534 q 718 370 696 474 q 729 207 722 352 q 781 26 736 62 l 781 0 m 373 551 q 533 594 465 551 q 614 731 614 645 q 532 859 614 815 q 373 896 465 896 l 138 896 l 138 551 l 373 551 "},"o":{"x_min":0,"x_max":713,"ha":821,"o":"m 357 -25 q 94 91 194 -25 q 0 368 0 202 q 93 642 0 533 q 357 761 193 761 q 618 644 518 761 q 713 368 713 533 q 619 91 713 201 q 357 -25 521 -25 m 357 85 q 528 175 465 85 q 584 369 584 255 q 529 562 584 484 q 357 651 467 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 357 85 250 85 "},"5":{"x_min":54.171875,"x_max":738,"ha":792,"o":"m 738 314 q 626 60 738 153 q 382 -23 526 -23 q 155 47 248 -23 q 54 256 54 125 l 183 256 q 259 132 204 174 q 382 91 314 91 q 533 149 471 91 q 602 314 602 213 q 538 469 602 411 q 386 528 475 528 q 284 506 332 528 q 197 439 237 484 l 81 439 l 159 958 l 684 958 l 684 840 l 254 840 l 214 579 q 306 627 258 612 q 407 643 354 643 q 636 552 540 643 q 738 314 738 457 "},"7":{"x_min":58.71875,"x_max":730.953125,"ha":792,"o":"m 730 839 q 469 448 560 641 q 335 0 378 255 l 192 0 q 328 441 235 252 q 593 830 421 630 l 58 830 l 58 958 l 730 958 l 730 839 "},"K":{"x_min":0,"x_max":819.46875,"ha":906,"o":"m 819 0 l 649 0 l 294 509 l 139 355 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},",":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 -12 q 105 -132 142 -82 q 0 -205 68 -182 l 0 -138 q 57 -82 40 -124 q 70 0 70 -51 l 0 0 l 0 151 l 142 151 l 142 -12 "},"d":{"x_min":0,"x_max":683,"ha":796,"o":"m 683 0 l 564 0 l 564 93 q 456 6 516 38 q 327 -25 395 -25 q 87 100 181 -25 q 0 365 0 215 q 90 639 0 525 q 343 763 187 763 q 564 647 486 763 l 564 1013 l 683 1013 l 683 0 m 582 373 q 529 562 582 484 q 361 653 468 653 q 190 561 253 653 q 135 365 135 479 q 189 175 135 254 q 358 85 251 85 q 529 178 468 85 q 582 373 582 258 "},"¨":{"x_min":-109,"x_max":247,"ha":232,"o":"m 247 1046 l 119 1046 l 119 1189 l 247 1189 l 247 1046 m 19 1046 l -109 1046 l -109 1189 l 19 1189 l 19 1046 "},"E":{"x_min":0,"x_max":736.109375,"ha":789,"o":"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},"Y":{"x_min":0,"x_max":820,"ha":886,"o":"m 820 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 534 l 679 1012 l 820 1013 "},"\"":{"x_min":0,"x_max":299,"ha":396,"o":"m 299 606 l 203 606 l 203 988 l 299 988 l 299 606 m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"‹":{"x_min":17.984375,"x_max":773.609375,"ha":792,"o":"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"„":{"x_min":0,"x_max":364,"ha":467,"o":"m 141 -12 q 104 -132 141 -82 q 0 -205 67 -182 l 0 -138 q 56 -82 40 -124 q 69 0 69 -51 l 0 0 l 0 151 l 141 151 l 141 -12 m 364 -12 q 327 -132 364 -82 q 222 -205 290 -182 l 222 -138 q 279 -82 262 -124 q 292 0 292 -51 l 222 0 l 222 151 l 364 151 l 364 -12 "},"δ":{"x_min":1,"x_max":710,"ha":810,"o":"m 710 360 q 616 87 710 196 q 356 -28 518 -28 q 99 82 197 -28 q 1 356 1 192 q 100 606 1 509 q 355 703 199 703 q 180 829 288 754 q 70 903 124 866 l 70 1012 l 643 1012 l 643 901 l 258 901 q 462 763 422 794 q 636 592 577 677 q 710 360 710 485 m 584 365 q 552 501 584 447 q 451 602 521 555 q 372 611 411 611 q 197 541 258 611 q 136 355 136 472 q 190 171 136 245 q 358 85 252 85 q 528 173 465 85 q 584 365 584 252 "},"έ":{"x_min":0,"x_max":634.71875,"ha":714,"o":"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 313 0 265 q 128 390 67 352 q 56 459 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 m 520 1040 l 331 819 l 248 819 l 383 1040 l 520 1040 "},"ω":{"x_min":0,"x_max":922,"ha":1031,"o":"m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 339 0 203 q 45 551 0 444 q 161 738 84 643 l 302 738 q 175 553 219 647 q 124 336 124 446 q 155 179 124 249 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 342 797 257 q 745 556 797 450 q 619 738 705 638 l 760 738 q 874 551 835 640 q 922 339 922 444 "},"´":{"x_min":0,"x_max":96,"ha":251,"o":"m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"±":{"x_min":11,"x_max":781,"ha":792,"o":"m 781 490 l 446 490 l 446 255 l 349 255 l 349 490 l 11 490 l 11 586 l 349 586 l 349 819 l 446 819 l 446 586 l 781 586 l 781 490 m 781 21 l 11 21 l 11 115 l 781 115 l 781 21 "},"|":{"x_min":343,"x_max":449,"ha":792,"o":"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"ϋ":{"x_min":0,"x_max":617,"ha":725,"o":"m 482 800 l 372 800 l 372 925 l 482 925 l 482 800 m 239 800 l 129 800 l 129 925 l 239 925 l 239 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 "},"§":{"x_min":0,"x_max":593,"ha":690,"o":"m 593 425 q 554 312 593 369 q 467 233 516 254 q 537 83 537 172 q 459 -74 537 -12 q 288 -133 387 -133 q 115 -69 184 -133 q 47 96 47 -6 l 166 96 q 199 7 166 40 q 288 -26 232 -26 q 371 -5 332 -26 q 420 60 420 21 q 311 201 420 139 q 108 309 210 255 q 0 490 0 383 q 33 602 0 551 q 124 687 66 654 q 75 743 93 712 q 58 812 58 773 q 133 984 58 920 q 300 1043 201 1043 q 458 987 394 1043 q 529 814 529 925 l 411 814 q 370 908 404 877 q 289 939 336 939 q 213 911 246 939 q 180 841 180 883 q 286 720 180 779 q 484 612 480 615 q 593 425 593 534 m 467 409 q 355 544 467 473 q 196 630 228 612 q 146 587 162 609 q 124 525 124 558 q 239 387 124 462 q 398 298 369 315 q 448 345 429 316 q 467 409 467 375 "},"b":{"x_min":0,"x_max":685,"ha":783,"o":"m 685 372 q 597 99 685 213 q 347 -25 501 -25 q 219 5 277 -25 q 121 93 161 36 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 634 q 214 723 157 692 q 341 754 272 754 q 591 637 493 754 q 685 372 685 526 m 554 356 q 499 550 554 470 q 328 644 437 644 q 162 556 223 644 q 108 369 108 478 q 160 176 108 256 q 330 83 221 83 q 498 169 435 83 q 554 356 554 245 "},"q":{"x_min":0,"x_max":683,"ha":876,"o":"m 683 -278 l 564 -278 l 564 97 q 474 8 533 39 q 345 -23 415 -23 q 91 93 188 -23 q 0 364 0 203 q 87 635 0 522 q 337 760 184 760 q 466 727 408 760 q 564 637 523 695 l 564 737 l 683 737 l 683 -278 m 582 375 q 527 564 582 488 q 358 652 466 652 q 190 565 253 652 q 135 377 135 488 q 189 179 135 261 q 361 84 251 84 q 530 179 469 84 q 582 375 582 260 "},"Ω":{"x_min":-0.171875,"x_max":969.5625,"ha":1068,"o":"m 969 0 l 555 0 l 555 123 q 744 308 675 194 q 814 558 814 423 q 726 812 814 709 q 484 922 633 922 q 244 820 334 922 q 154 567 154 719 q 223 316 154 433 q 412 123 292 199 l 412 0 l 0 0 l 0 124 l 217 124 q 68 327 122 210 q 15 572 15 444 q 144 911 15 781 q 484 1041 274 1041 q 822 909 691 1041 q 953 569 953 777 q 899 326 953 443 q 750 124 846 210 l 969 124 l 969 0 "},"ύ":{"x_min":0,"x_max":617,"ha":725,"o":"m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 535 1040 l 346 819 l 262 819 l 397 1040 l 535 1040 "},"z":{"x_min":-0.015625,"x_max":613.890625,"ha":697,"o":"m 613 0 l 0 0 l 0 100 l 433 630 l 20 630 l 20 738 l 594 738 l 593 636 l 163 110 l 613 110 l 613 0 "},"™":{"x_min":0,"x_max":894,"ha":1000,"o":"m 389 951 l 229 951 l 229 503 l 160 503 l 160 951 l 0 951 l 0 1011 l 389 1011 l 389 951 m 894 503 l 827 503 l 827 939 l 685 503 l 620 503 l 481 937 l 481 503 l 417 503 l 417 1011 l 517 1011 l 653 580 l 796 1010 l 894 1011 l 894 503 "},"ή":{"x_min":0.78125,"x_max":697,"ha":810,"o":"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 721 124 755 q 200 630 193 687 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 m 479 1040 l 290 819 l 207 819 l 341 1040 l 479 1040 "},"Θ":{"x_min":0,"x_max":960,"ha":1056,"o":"m 960 507 q 833 129 960 280 q 476 -32 698 -32 q 123 129 255 -32 q 0 507 0 280 q 123 883 0 732 q 476 1045 255 1045 q 832 883 696 1045 q 960 507 960 732 m 817 500 q 733 789 817 669 q 476 924 639 924 q 223 792 317 924 q 142 507 142 675 q 222 222 142 339 q 476 89 315 89 q 730 218 636 89 q 817 500 817 334 m 716 449 l 243 449 l 243 571 l 716 571 l 716 449 "},"®":{"x_min":-3,"x_max":1008,"ha":1106,"o":"m 503 532 q 614 562 566 532 q 672 658 672 598 q 614 747 672 716 q 503 772 569 772 l 338 772 l 338 532 l 503 532 m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 788 146 l 678 146 q 653 316 655 183 q 527 449 652 449 l 338 449 l 338 146 l 241 146 l 241 854 l 518 854 q 688 808 621 854 q 766 658 766 755 q 739 563 766 607 q 668 497 713 519 q 751 331 747 472 q 788 164 756 190 l 788 146 "},"~":{"x_min":0,"x_max":833,"ha":931,"o":"m 833 958 q 778 753 833 831 q 594 665 716 665 q 402 761 502 665 q 240 857 302 857 q 131 795 166 857 q 104 665 104 745 l 0 665 q 54 867 0 789 q 237 958 116 958 q 429 861 331 958 q 594 765 527 765 q 704 827 670 765 q 729 958 729 874 l 833 958 "},"Ε":{"x_min":0,"x_max":736.21875,"ha":778,"o":"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},"³":{"x_min":0,"x_max":450,"ha":547,"o":"m 450 552 q 379 413 450 464 q 220 366 313 366 q 69 414 130 366 q 0 567 0 470 l 85 567 q 126 470 85 504 q 225 437 168 437 q 320 467 280 437 q 360 552 360 498 q 318 632 360 608 q 213 657 276 657 q 195 657 203 657 q 176 657 181 657 l 176 722 q 279 733 249 722 q 334 815 334 752 q 300 881 334 856 q 220 907 267 907 q 133 875 169 907 q 97 781 97 844 l 15 781 q 78 926 15 875 q 220 972 135 972 q 364 930 303 972 q 426 817 426 888 q 344 697 426 733 q 421 642 392 681 q 450 552 450 603 "},"[":{"x_min":0,"x_max":273.609375,"ha":371,"o":"m 273 -281 l 0 -281 l 0 1013 l 273 1013 l 273 920 l 124 920 l 124 -187 l 273 -187 l 273 -281 "},"L":{"x_min":0,"x_max":645.828125,"ha":696,"o":"m 645 0 l 0 0 l 0 1013 l 140 1013 l 140 126 l 645 126 l 645 0 "},"σ":{"x_min":0,"x_max":803.390625,"ha":894,"o":"m 803 628 l 633 628 q 713 368 713 512 q 618 93 713 204 q 357 -25 518 -25 q 94 91 194 -25 q 0 368 0 201 q 94 644 0 533 q 356 761 194 761 q 481 750 398 761 q 608 739 564 739 l 803 739 l 803 628 m 360 85 q 529 180 467 85 q 584 374 584 262 q 527 566 584 490 q 352 651 463 651 q 187 559 247 651 q 135 368 135 478 q 189 175 135 254 q 360 85 251 85 "},"ζ":{"x_min":0,"x_max":573,"ha":642,"o":"m 573 -40 q 553 -162 573 -97 q 510 -278 543 -193 l 400 -278 q 441 -187 428 -219 q 462 -90 462 -132 q 378 -14 462 -14 q 108 45 197 -14 q 0 290 0 117 q 108 631 0 462 q 353 901 194 767 l 55 901 l 55 1012 l 561 1012 l 561 924 q 261 669 382 831 q 128 301 128 489 q 243 117 128 149 q 458 98 350 108 q 573 -40 573 80 "},"θ":{"x_min":0,"x_max":674,"ha":778,"o":"m 674 496 q 601 160 674 304 q 336 -26 508 -26 q 73 153 165 -26 q 0 485 0 296 q 72 840 0 683 q 343 1045 166 1045 q 605 844 516 1045 q 674 496 674 692 m 546 579 q 498 798 546 691 q 336 935 437 935 q 178 798 237 935 q 126 579 137 701 l 546 579 m 546 475 l 126 475 q 170 233 126 348 q 338 80 230 80 q 504 233 447 80 q 546 475 546 346 "},"Ο":{"x_min":0,"x_max":958,"ha":1054,"o":"m 485 1042 q 834 883 703 1042 q 958 511 958 735 q 834 136 958 287 q 481 -26 701 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 729 q 485 1042 263 1042 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 670 q 480 913 640 913 q 226 785 321 913 q 142 504 142 671 q 226 224 142 339 q 480 98 319 98 "},"Γ":{"x_min":0,"x_max":705.28125,"ha":749,"o":"m 705 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 705 1012 l 705 886 "}," ":{"x_min":0,"x_max":0,"ha":375},"%":{"x_min":-3,"x_max":1089,"ha":1186,"o":"m 845 0 q 663 76 731 0 q 602 244 602 145 q 661 412 602 344 q 845 489 728 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 845 0 962 0 m 844 103 q 945 143 909 103 q 981 243 981 184 q 947 340 981 301 q 844 385 909 385 q 744 342 781 385 q 708 243 708 300 q 741 147 708 186 q 844 103 780 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 "},"P":{"x_min":0,"x_max":726,"ha":806,"o":"m 424 1013 q 640 931 555 1013 q 726 719 726 850 q 637 506 726 587 q 413 426 548 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 379 889 l 140 889 l 140 548 l 372 548 q 522 589 459 548 q 593 720 593 637 q 528 845 593 801 q 379 889 463 889 "},"Έ":{"x_min":0,"x_max":1078.21875,"ha":1118,"o":"m 1078 0 l 342 0 l 342 1013 l 1067 1013 l 1067 889 l 481 889 l 481 585 l 1019 585 l 1019 467 l 481 467 l 481 125 l 1078 125 l 1078 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Ώ":{"x_min":0.125,"x_max":1136.546875,"ha":1235,"o":"m 1136 0 l 722 0 l 722 123 q 911 309 842 194 q 981 558 981 423 q 893 813 981 710 q 651 923 800 923 q 411 821 501 923 q 321 568 321 720 q 390 316 321 433 q 579 123 459 200 l 579 0 l 166 0 l 166 124 l 384 124 q 235 327 289 210 q 182 572 182 444 q 311 912 182 782 q 651 1042 441 1042 q 989 910 858 1042 q 1120 569 1120 778 q 1066 326 1120 443 q 917 124 1013 210 l 1136 124 l 1136 0 m 277 1040 l 83 800 l 0 800 l 140 1041 l 277 1040 "},"_":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 -334 l 0 -334 l 0 -234 l 705 -234 l 705 -334 "},"Ϊ":{"x_min":-110,"x_max":246,"ha":275,"o":"m 246 1046 l 118 1046 l 118 1189 l 246 1189 l 246 1046 m 18 1046 l -110 1046 l -110 1189 l 18 1189 l 18 1046 m 136 0 l 0 0 l 0 1012 l 136 1012 l 136 0 "},"+":{"x_min":23,"x_max":768,"ha":792,"o":"m 768 372 l 444 372 l 444 0 l 347 0 l 347 372 l 23 372 l 23 468 l 347 468 l 347 840 l 444 840 l 444 468 l 768 468 l 768 372 "},"½":{"x_min":0,"x_max":1050,"ha":1149,"o":"m 1050 0 l 625 0 q 712 178 625 108 q 878 277 722 187 q 967 385 967 328 q 932 456 967 429 q 850 484 897 484 q 759 450 798 484 q 721 352 721 416 l 640 352 q 706 502 640 448 q 851 551 766 551 q 987 509 931 551 q 1050 385 1050 462 q 976 251 1050 301 q 829 179 902 215 q 717 68 740 133 l 1050 68 l 1050 0 m 834 985 l 215 -28 l 130 -28 l 750 984 l 834 985 m 224 422 l 142 422 l 142 811 l 0 811 l 0 867 q 104 889 62 867 q 164 973 157 916 l 224 973 l 224 422 "},"Ρ":{"x_min":0,"x_max":720,"ha":783,"o":"m 424 1013 q 637 933 554 1013 q 720 723 720 853 q 633 508 720 591 q 413 426 546 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 378 889 l 140 889 l 140 548 l 371 548 q 521 589 458 548 q 592 720 592 637 q 527 845 592 801 q 378 889 463 889 "},"'":{"x_min":0,"x_max":139,"ha":236,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"ª":{"x_min":0,"x_max":350,"ha":397,"o":"m 350 625 q 307 616 328 616 q 266 631 281 616 q 247 673 251 645 q 190 628 225 644 q 116 613 156 613 q 32 641 64 613 q 0 722 0 669 q 72 826 0 800 q 247 866 159 846 l 247 887 q 220 934 247 916 q 162 953 194 953 q 104 934 129 953 q 76 882 80 915 l 16 882 q 60 976 16 941 q 166 1011 104 1011 q 266 979 224 1011 q 308 891 308 948 l 308 706 q 311 679 308 688 q 331 670 315 670 l 350 672 l 350 625 m 247 757 l 247 811 q 136 790 175 798 q 64 726 64 773 q 83 682 64 697 q 132 667 103 667 q 207 690 174 667 q 247 757 247 718 "},"΅":{"x_min":0,"x_max":450,"ha":553,"o":"m 450 800 l 340 800 l 340 925 l 450 925 l 450 800 m 406 1040 l 212 800 l 129 800 l 269 1040 l 406 1040 m 110 800 l 0 800 l 0 925 l 110 925 l 110 800 "},"T":{"x_min":0,"x_max":777,"ha":835,"o":"m 777 894 l 458 894 l 458 0 l 319 0 l 319 894 l 0 894 l 0 1013 l 777 1013 l 777 894 "},"Φ":{"x_min":0,"x_max":915,"ha":997,"o":"m 527 0 l 389 0 l 389 122 q 110 231 220 122 q 0 509 0 340 q 110 785 0 677 q 389 893 220 893 l 389 1013 l 527 1013 l 527 893 q 804 786 693 893 q 915 509 915 679 q 805 231 915 341 q 527 122 696 122 l 527 0 m 527 226 q 712 310 641 226 q 779 507 779 389 q 712 705 779 627 q 527 787 641 787 l 527 226 m 389 226 l 389 787 q 205 698 275 775 q 136 505 136 620 q 206 308 136 391 q 389 226 276 226 "},"⁋":{"x_min":0,"x_max":0,"ha":694},"j":{"x_min":-77.78125,"x_max":167,"ha":349,"o":"m 167 871 l 42 871 l 42 1013 l 167 1013 l 167 871 m 167 -80 q 121 -231 167 -184 q -26 -278 76 -278 l -77 -278 l -77 -164 l -41 -164 q 26 -143 11 -164 q 42 -65 42 -122 l 42 737 l 167 737 l 167 -80 "},"Σ":{"x_min":0,"x_max":756.953125,"ha":819,"o":"m 756 0 l 0 0 l 0 107 l 395 523 l 22 904 l 22 1013 l 745 1013 l 745 889 l 209 889 l 566 523 l 187 125 l 756 125 l 756 0 "},"1":{"x_min":215.671875,"x_max":574,"ha":792,"o":"m 574 0 l 442 0 l 442 697 l 215 697 l 215 796 q 386 833 330 796 q 475 986 447 875 l 574 986 l 574 0 "},"›":{"x_min":18.0625,"x_max":774,"ha":792,"o":"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},"<":{"x_min":17.984375,"x_max":773.609375,"ha":792,"o":"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"£":{"x_min":0,"x_max":704.484375,"ha":801,"o":"m 704 41 q 623 -10 664 5 q 543 -26 583 -26 q 359 15 501 -26 q 243 36 288 36 q 158 23 197 36 q 73 -21 119 10 l 6 76 q 125 195 90 150 q 175 331 175 262 q 147 443 175 383 l 0 443 l 0 512 l 108 512 q 43 734 43 623 q 120 929 43 854 q 358 1010 204 1010 q 579 936 487 1010 q 678 729 678 857 l 678 684 l 552 684 q 504 838 552 780 q 362 896 457 896 q 216 852 263 896 q 176 747 176 815 q 199 627 176 697 q 248 512 217 574 l 468 512 l 468 443 l 279 443 q 297 356 297 398 q 230 194 297 279 q 153 107 211 170 q 227 133 190 125 q 293 142 264 142 q 410 119 339 142 q 516 96 482 96 q 579 105 550 96 q 648 142 608 115 l 704 41 "},"t":{"x_min":0,"x_max":367,"ha":458,"o":"m 367 0 q 312 -5 339 -2 q 262 -8 284 -8 q 145 28 183 -8 q 108 143 108 64 l 108 638 l 0 638 l 0 738 l 108 738 l 108 944 l 232 944 l 232 738 l 367 738 l 367 638 l 232 638 l 232 185 q 248 121 232 140 q 307 102 264 102 q 345 104 330 102 q 367 107 360 107 l 367 0 "},"¬":{"x_min":0,"x_max":706,"ha":803,"o":"m 706 411 l 706 158 l 630 158 l 630 335 l 0 335 l 0 411 l 706 411 "},"λ":{"x_min":0,"x_max":750,"ha":803,"o":"m 750 -7 q 679 -15 716 -15 q 538 59 591 -15 q 466 214 512 97 l 336 551 l 126 0 l 0 0 l 270 705 q 223 837 247 770 q 116 899 190 899 q 90 898 100 899 l 90 1004 q 152 1011 125 1011 q 298 938 244 1011 q 373 783 326 901 l 605 192 q 649 115 629 136 q 716 95 669 95 l 736 95 q 750 97 745 97 l 750 -7 "},"W":{"x_min":0,"x_max":1263.890625,"ha":1351,"o":"m 1263 1013 l 995 0 l 859 0 l 627 837 l 405 0 l 265 0 l 0 1013 l 136 1013 l 342 202 l 556 1013 l 701 1013 l 921 207 l 1133 1012 l 1263 1013 "},">":{"x_min":18.0625,"x_max":774,"ha":792,"o":"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},"v":{"x_min":0,"x_max":675.15625,"ha":761,"o":"m 675 738 l 404 0 l 272 0 l 0 738 l 133 737 l 340 147 l 541 737 l 675 738 "},"τ":{"x_min":0.28125,"x_max":644.5,"ha":703,"o":"m 644 628 l 382 628 l 382 179 q 388 120 382 137 q 436 91 401 91 q 474 94 447 91 q 504 97 501 97 l 504 0 q 454 -9 482 -5 q 401 -14 426 -14 q 278 67 308 -14 q 260 233 260 118 l 260 628 l 0 628 l 0 739 l 644 739 l 644 628 "},"ξ":{"x_min":0,"x_max":624.9375,"ha":699,"o":"m 624 -37 q 608 -153 624 -96 q 563 -278 593 -211 l 454 -278 q 491 -183 486 -200 q 511 -83 511 -126 q 484 -23 511 -44 q 370 1 452 1 q 323 0 354 1 q 283 -1 293 -1 q 84 76 169 -1 q 0 266 0 154 q 56 431 0 358 q 197 538 108 498 q 94 613 134 562 q 54 730 54 665 q 77 823 54 780 q 143 901 101 867 l 27 901 l 27 1012 l 576 1012 l 576 901 l 380 901 q 244 863 303 901 q 178 745 178 820 q 312 600 178 636 q 532 582 380 582 l 532 479 q 276 455 361 479 q 118 281 118 410 q 165 173 118 217 q 274 120 208 133 q 494 101 384 110 q 624 -37 624 76 "},"&":{"x_min":-3,"x_max":894.25,"ha":992,"o":"m 894 0 l 725 0 l 624 123 q 471 0 553 40 q 306 -41 390 -41 q 168 -7 231 -41 q 62 92 105 26 q 14 187 31 139 q -3 276 -3 235 q 55 433 -3 358 q 248 581 114 508 q 170 689 196 640 q 137 817 137 751 q 214 985 137 922 q 384 1041 284 1041 q 548 988 483 1041 q 622 824 622 928 q 563 666 622 739 q 431 556 516 608 l 621 326 q 649 407 639 361 q 663 493 653 426 l 781 493 q 703 229 781 352 l 894 0 m 504 818 q 468 908 504 877 q 384 940 433 940 q 293 907 331 940 q 255 818 255 875 q 289 714 255 767 q 363 628 313 678 q 477 729 446 682 q 504 818 504 771 m 556 209 l 314 499 q 179 395 223 449 q 135 283 135 341 q 146 222 135 253 q 183 158 158 192 q 333 80 241 80 q 556 209 448 80 "},"Λ":{"x_min":0,"x_max":862.5,"ha":942,"o":"m 862 0 l 719 0 l 426 847 l 143 0 l 0 0 l 356 1013 l 501 1013 l 862 0 "},"I":{"x_min":41,"x_max":180,"ha":293,"o":"m 180 0 l 41 0 l 41 1013 l 180 1013 l 180 0 "},"G":{"x_min":0,"x_max":921,"ha":1011,"o":"m 921 0 l 832 0 l 801 136 q 655 15 741 58 q 470 -28 568 -28 q 126 133 259 -28 q 0 499 0 284 q 125 881 0 731 q 486 1043 259 1043 q 763 957 647 1043 q 905 709 890 864 l 772 709 q 668 866 747 807 q 486 926 589 926 q 228 795 322 926 q 142 507 142 677 q 228 224 142 342 q 483 94 323 94 q 712 195 625 94 q 796 435 796 291 l 477 435 l 477 549 l 921 549 l 921 0 "},"ΰ":{"x_min":0,"x_max":617,"ha":725,"o":"m 524 800 l 414 800 l 414 925 l 524 925 l 524 800 m 183 800 l 73 800 l 73 925 l 183 925 l 183 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 489 1040 l 300 819 l 216 819 l 351 1040 l 489 1040 "},"`":{"x_min":0,"x_max":138.890625,"ha":236,"o":"m 138 699 l 0 699 l 0 861 q 36 974 0 929 q 138 1041 72 1020 l 138 977 q 82 931 95 969 q 69 839 69 893 l 138 839 l 138 699 "},"·":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"Υ":{"x_min":0.328125,"x_max":819.515625,"ha":889,"o":"m 819 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 "},"r":{"x_min":0,"x_max":355.5625,"ha":432,"o":"m 355 621 l 343 621 q 179 569 236 621 q 122 411 122 518 l 122 0 l 0 0 l 0 737 l 117 737 l 117 604 q 204 719 146 686 q 355 753 262 753 l 355 621 "},"x":{"x_min":0,"x_max":675,"ha":764,"o":"m 675 0 l 525 0 l 331 286 l 144 0 l 0 0 l 256 379 l 12 738 l 157 737 l 336 473 l 516 738 l 661 738 l 412 380 l 675 0 "},"μ":{"x_min":0,"x_max":696.609375,"ha":747,"o":"m 696 -4 q 628 -14 657 -14 q 498 97 513 -14 q 422 8 470 41 q 313 -24 374 -24 q 207 3 258 -24 q 120 80 157 31 l 120 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 172 124 246 q 308 82 216 82 q 451 177 402 82 q 492 358 492 254 l 492 738 l 616 738 l 616 214 q 623 136 616 160 q 673 92 636 92 q 696 95 684 92 l 696 -4 "},"h":{"x_min":0,"x_max":615,"ha":724,"o":"m 615 472 l 615 0 l 490 0 l 490 454 q 456 590 490 535 q 338 654 416 654 q 186 588 251 654 q 122 436 122 522 l 122 0 l 0 0 l 0 1013 l 122 1013 l 122 633 q 218 727 149 694 q 362 760 287 760 q 552 676 484 760 q 615 472 615 600 "},".":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"φ":{"x_min":-2,"x_max":878,"ha":974,"o":"m 496 -279 l 378 -279 l 378 -17 q 101 88 204 -17 q -2 367 -2 194 q 68 626 -2 510 q 283 758 151 758 l 283 646 q 167 537 209 626 q 133 373 133 462 q 192 177 133 254 q 378 93 259 93 l 378 758 q 445 764 426 763 q 476 765 464 765 q 765 659 653 765 q 878 377 878 553 q 771 96 878 209 q 496 -17 665 -17 l 496 -279 m 496 93 l 514 93 q 687 183 623 93 q 746 380 746 265 q 691 569 746 491 q 522 658 629 658 l 496 656 l 496 93 "},";":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 -12 q 105 -132 142 -82 q 0 -206 68 -182 l 0 -138 q 58 -82 43 -123 q 68 0 68 -56 l 0 0 l 0 151 l 142 151 l 142 -12 "},"f":{"x_min":0,"x_max":378,"ha":472,"o":"m 378 638 l 246 638 l 246 0 l 121 0 l 121 638 l 0 638 l 0 738 l 121 738 q 137 935 121 887 q 290 1028 171 1028 q 320 1027 305 1028 q 378 1021 334 1026 l 378 908 q 323 918 346 918 q 257 870 273 918 q 246 780 246 840 l 246 738 l 378 738 l 378 638 "},"“":{"x_min":1,"x_max":348.21875,"ha":454,"o":"m 140 670 l 1 670 l 1 830 q 37 943 1 897 q 140 1011 74 990 l 140 947 q 82 900 97 940 q 68 810 68 861 l 140 810 l 140 670 m 348 670 l 209 670 l 209 830 q 245 943 209 897 q 348 1011 282 990 l 348 947 q 290 900 305 940 q 276 810 276 861 l 348 810 l 348 670 "},"A":{"x_min":0.03125,"x_max":906.953125,"ha":1008,"o":"m 906 0 l 756 0 l 648 303 l 251 303 l 142 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 610 421 l 452 867 l 293 421 l 610 421 "},"6":{"x_min":53,"x_max":739,"ha":792,"o":"m 739 312 q 633 62 739 162 q 400 -31 534 -31 q 162 78 257 -31 q 53 439 53 206 q 178 859 53 712 q 441 986 284 986 q 643 912 559 986 q 732 713 732 833 l 601 713 q 544 830 594 786 q 426 875 494 875 q 268 793 331 875 q 193 517 193 697 q 301 597 240 570 q 427 624 362 624 q 643 540 552 624 q 739 312 739 451 m 603 298 q 540 461 603 400 q 404 516 484 516 q 268 461 323 516 q 207 300 207 401 q 269 137 207 198 q 405 83 325 83 q 541 137 486 83 q 603 298 603 197 "},"‘":{"x_min":1,"x_max":139.890625,"ha":236,"o":"m 139 670 l 1 670 l 1 830 q 37 943 1 897 q 139 1011 74 990 l 139 947 q 82 900 97 940 q 68 810 68 861 l 139 810 l 139 670 "},"ϊ":{"x_min":-70,"x_max":283,"ha":361,"o":"m 283 800 l 173 800 l 173 925 l 283 925 l 283 800 m 40 800 l -70 800 l -70 925 l 40 925 l 40 800 m 283 3 q 232 -10 257 -5 q 181 -15 206 -15 q 84 26 118 -15 q 41 200 41 79 l 41 737 l 166 737 l 167 215 q 171 141 167 157 q 225 101 182 101 q 247 103 238 101 q 283 112 256 104 l 283 3 "},"π":{"x_min":-0.21875,"x_max":773.21875,"ha":857,"o":"m 773 -7 l 707 -11 q 575 40 607 -11 q 552 174 552 77 l 552 226 l 552 626 l 222 626 l 222 0 l 97 0 l 97 626 l 0 626 l 0 737 l 773 737 l 773 626 l 676 626 l 676 171 q 695 103 676 117 q 773 90 714 90 l 773 -7 "},"ά":{"x_min":0,"x_max":765.5625,"ha":809,"o":"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 727 407 760 q 563 637 524 695 l 563 738 l 685 738 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 95 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 m 604 1040 l 415 819 l 332 819 l 466 1040 l 604 1040 "},"O":{"x_min":0,"x_max":958,"ha":1057,"o":"m 485 1041 q 834 882 702 1041 q 958 512 958 734 q 834 136 958 287 q 481 -26 702 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 728 q 485 1041 263 1041 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 669 q 480 912 640 912 q 226 784 321 912 q 142 504 142 670 q 226 224 142 339 q 480 98 319 98 "},"n":{"x_min":0,"x_max":615,"ha":724,"o":"m 615 463 l 615 0 l 490 0 l 490 454 q 453 592 490 537 q 331 656 410 656 q 178 585 240 656 q 117 421 117 514 l 117 0 l 0 0 l 0 738 l 117 738 l 117 630 q 218 728 150 693 q 359 764 286 764 q 552 675 484 764 q 615 463 615 593 "},"3":{"x_min":54,"x_max":737,"ha":792,"o":"m 737 284 q 635 55 737 141 q 399 -25 541 -25 q 156 52 248 -25 q 54 308 54 140 l 185 308 q 245 147 185 202 q 395 96 302 96 q 539 140 484 96 q 602 280 602 190 q 510 429 602 390 q 324 454 451 454 l 324 565 q 487 584 441 565 q 565 719 565 617 q 515 835 565 791 q 395 879 466 879 q 255 824 307 879 q 203 661 203 769 l 78 661 q 166 909 78 822 q 387 992 250 992 q 603 921 513 992 q 701 723 701 844 q 669 607 701 656 q 578 524 637 558 q 696 434 655 499 q 737 284 737 369 "},"9":{"x_min":53,"x_max":739,"ha":792,"o":"m 739 524 q 619 94 739 241 q 362 -32 516 -32 q 150 47 242 -32 q 59 244 59 126 l 191 244 q 246 129 191 176 q 373 82 301 82 q 526 161 466 82 q 597 440 597 255 q 363 334 501 334 q 130 432 216 334 q 53 650 53 521 q 134 880 53 786 q 383 986 226 986 q 659 841 566 986 q 739 524 739 719 m 388 449 q 535 514 480 449 q 585 658 585 573 q 535 805 585 744 q 388 873 480 873 q 242 809 294 873 q 191 658 191 745 q 239 514 191 572 q 388 449 292 449 "},"l":{"x_min":41,"x_max":166,"ha":279,"o":"m 166 0 l 41 0 l 41 1013 l 166 1013 l 166 0 "},"¤":{"x_min":40.09375,"x_max":728.796875,"ha":825,"o":"m 728 304 l 649 224 l 512 363 q 383 331 458 331 q 256 363 310 331 l 119 224 l 40 304 l 177 441 q 150 553 150 493 q 184 673 150 621 l 40 818 l 119 898 l 267 749 q 321 766 291 759 q 384 773 351 773 q 447 766 417 773 q 501 749 477 759 l 649 898 l 728 818 l 585 675 q 612 618 604 648 q 621 553 621 587 q 591 441 621 491 l 728 304 m 384 682 q 280 643 318 682 q 243 551 243 604 q 279 461 243 499 q 383 423 316 423 q 487 461 449 423 q 525 553 525 500 q 490 641 525 605 q 384 682 451 682 "},"κ":{"x_min":0,"x_max":632.328125,"ha":679,"o":"m 632 0 l 482 0 l 225 384 l 124 288 l 124 0 l 0 0 l 0 738 l 124 738 l 124 446 l 433 738 l 596 738 l 312 466 l 632 0 "},"4":{"x_min":48,"x_max":742.453125,"ha":792,"o":"m 742 243 l 602 243 l 602 0 l 476 0 l 476 243 l 48 243 l 48 368 l 476 958 l 602 958 l 602 354 l 742 354 l 742 243 m 476 354 l 476 792 l 162 354 l 476 354 "},"p":{"x_min":0,"x_max":685,"ha":786,"o":"m 685 364 q 598 96 685 205 q 350 -23 504 -23 q 121 89 205 -23 l 121 -278 l 0 -278 l 0 738 l 121 738 l 121 633 q 220 726 159 691 q 351 761 280 761 q 598 636 504 761 q 685 364 685 522 m 557 371 q 501 560 557 481 q 330 651 437 651 q 162 559 223 651 q 108 366 108 479 q 162 177 108 254 q 333 87 224 87 q 502 178 441 87 q 557 371 557 258 "},"‡":{"x_min":0,"x_max":777,"ha":835,"o":"m 458 238 l 458 0 l 319 0 l 319 238 l 0 238 l 0 360 l 319 360 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 l 777 804 l 777 683 l 458 683 l 458 360 l 777 360 l 777 238 l 458 238 "},"ψ":{"x_min":0,"x_max":808,"ha":907,"o":"m 465 -278 l 341 -278 l 341 -15 q 87 102 180 -15 q 0 378 0 210 l 0 739 l 133 739 l 133 379 q 182 195 133 275 q 341 98 242 98 l 341 922 l 465 922 l 465 98 q 623 195 563 98 q 675 382 675 278 l 675 742 l 808 742 l 808 381 q 720 104 808 213 q 466 -13 627 -13 l 465 -278 "},"η":{"x_min":0.78125,"x_max":697,"ha":810,"o":"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 720 124 755 q 200 630 193 686 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 "}},"cssFontWeight":"normal","ascender":1189,"underlinePosition":-100,"cssFontStyle":"normal","boundingBox":{"yMin":-334,"xMin":-111,"yMax":1189,"xMax":1672},"resolution":1000,"original_font_information":{"postscript_name":"Helvetiker-Regular","version_string":"Version 1.00 2004 initial release","vendor_url":"http://www.magenta.gr/","full_font_name":"Helvetiker","font_family_name":"Helvetiker","copyright":"Copyright (c) Μagenta ltd, 2004","description":"","trademark":"","designer":"","designer_url":"","unique_font_identifier":"Μagenta ltd:Helvetiker:22-10-104","license_url":"http://www.ellak.gr/fonts/MgOpen/license.html","license_description":"Copyright (c) 2004 by MAGENTA Ltd. All Rights Reserved.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license (\"Fonts\") and associated documentation files (the \"Font Software\"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: \r\n\r\nThe above copyright and this permission notice shall be included in all copies of one or more of the Font Software typefaces.\r\n\r\nThe Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing the word \"MgOpen\", or if the modifications are accepted for inclusion in the Font Software itself by the each appointed Administrator.\r\n\r\nThis License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the \"MgOpen\" name.\r\n\r\nThe Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. \r\n\r\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL MAGENTA OR PERSONS OR BODIES IN CHARGE OF ADMINISTRATION AND MAINTENANCE OF THE FONT SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.","manufacturer_name":"Μagenta ltd","font_sub_family_name":"Regular"},"descender":-334,"familyName":"Helvetiker","lineHeight":1522,"underlineThickness":50}); \ No newline at end of file +_typeface_js = THREE.typeface_js; if (_typeface_js && _typeface_js.loadFace) _typeface_js.loadFace({"glyphs":{"ο":{"x_min":0,"x_max":712,"ha":815,"o":"m 356 -25 q 96 88 192 -25 q 0 368 0 201 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 "},"S":{"x_min":0,"x_max":788,"ha":890,"o":"m 788 291 q 662 54 788 144 q 397 -26 550 -26 q 116 68 226 -26 q 0 337 0 168 l 131 337 q 200 152 131 220 q 384 85 269 85 q 557 129 479 85 q 650 270 650 183 q 490 429 650 379 q 194 513 341 470 q 33 739 33 584 q 142 964 33 881 q 388 1041 242 1041 q 644 957 543 1041 q 756 716 756 867 l 625 716 q 561 874 625 816 q 395 933 497 933 q 243 891 309 933 q 164 759 164 841 q 325 609 164 656 q 625 526 475 568 q 788 291 788 454 "},"¦":{"x_min":343,"x_max":449,"ha":792,"o":"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"/":{"x_min":183.25,"x_max":608.328125,"ha":792,"o":"m 608 1041 l 266 -129 l 183 -129 l 520 1041 l 608 1041 "},"Τ":{"x_min":-0.4375,"x_max":777.453125,"ha":839,"o":"m 777 893 l 458 893 l 458 0 l 319 0 l 319 892 l 0 892 l 0 1013 l 777 1013 l 777 893 "},"y":{"x_min":0,"x_max":684.78125,"ha":771,"o":"m 684 738 l 388 -83 q 311 -216 356 -167 q 173 -279 252 -279 q 97 -266 133 -279 l 97 -149 q 132 -155 109 -151 q 168 -160 155 -160 q 240 -114 213 -160 q 274 -26 248 -98 l 0 738 l 137 737 l 341 139 l 548 737 l 684 738 "},"Π":{"x_min":0,"x_max":803,"ha":917,"o":"m 803 0 l 667 0 l 667 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 803 1012 l 803 0 "},"ΐ":{"x_min":-111,"x_max":339,"ha":361,"o":"m 339 800 l 229 800 l 229 925 l 339 925 l 339 800 m -1 800 l -111 800 l -111 925 l -1 925 l -1 800 m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 m 302 1040 l 113 819 l 30 819 l 165 1040 l 302 1040 "},"g":{"x_min":0,"x_max":686,"ha":838,"o":"m 686 34 q 586 -213 686 -121 q 331 -306 487 -306 q 131 -252 216 -306 q 31 -84 31 -190 l 155 -84 q 228 -174 166 -138 q 345 -207 284 -207 q 514 -109 454 -207 q 564 89 564 -27 q 461 6 521 36 q 335 -23 401 -23 q 88 100 184 -23 q 0 370 0 215 q 87 634 0 522 q 330 758 183 758 q 457 728 398 758 q 564 644 515 699 l 564 737 l 686 737 l 686 34 m 582 367 q 529 560 582 481 q 358 652 468 652 q 189 561 250 652 q 135 369 135 482 q 189 176 135 255 q 361 85 251 85 q 529 176 468 85 q 582 367 582 255 "},"²":{"x_min":0,"x_max":442,"ha":539,"o":"m 442 383 l 0 383 q 91 566 0 492 q 260 668 176 617 q 354 798 354 727 q 315 875 354 845 q 227 905 277 905 q 136 869 173 905 q 99 761 99 833 l 14 761 q 82 922 14 864 q 232 974 141 974 q 379 926 316 974 q 442 797 442 878 q 351 635 442 704 q 183 539 321 611 q 92 455 92 491 l 442 455 l 442 383 "},"–":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},"Κ":{"x_min":0,"x_max":819.5625,"ha":893,"o":"m 819 0 l 650 0 l 294 509 l 139 356 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},"ƒ":{"x_min":-46.265625,"x_max":392,"ha":513,"o":"m 392 651 l 259 651 l 79 -279 l -46 -278 l 134 651 l 14 651 l 14 751 l 135 751 q 151 948 135 900 q 304 1041 185 1041 q 334 1040 319 1041 q 392 1034 348 1039 l 392 922 q 337 931 360 931 q 271 883 287 931 q 260 793 260 853 l 260 751 l 392 751 l 392 651 "},"e":{"x_min":0,"x_max":714,"ha":813,"o":"m 714 326 l 140 326 q 200 157 140 227 q 359 87 260 87 q 488 130 431 87 q 561 245 545 174 l 697 245 q 577 48 670 123 q 358 -26 484 -26 q 97 85 195 -26 q 0 363 0 197 q 94 642 0 529 q 358 765 195 765 q 626 627 529 765 q 714 326 714 503 m 576 429 q 507 583 564 522 q 355 650 445 650 q 206 583 266 650 q 140 429 152 522 l 576 429 "},"ό":{"x_min":0,"x_max":712,"ha":815,"o":"m 356 -25 q 94 91 194 -25 q 0 368 0 202 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 m 576 1040 l 387 819 l 303 819 l 438 1040 l 576 1040 "},"J":{"x_min":0,"x_max":588,"ha":699,"o":"m 588 279 q 287 -26 588 -26 q 58 73 126 -26 q 0 327 0 158 l 133 327 q 160 172 133 227 q 288 96 198 96 q 426 171 391 96 q 449 336 449 219 l 449 1013 l 588 1013 l 588 279 "},"»":{"x_min":-1,"x_max":503,"ha":601,"o":"m 503 302 l 280 136 l 281 256 l 429 373 l 281 486 l 280 608 l 503 440 l 503 302 m 221 302 l 0 136 l 0 255 l 145 372 l 0 486 l -1 608 l 221 440 l 221 302 "},"©":{"x_min":-3,"x_max":1008,"ha":1106,"o":"m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 741 394 q 661 246 731 302 q 496 190 591 190 q 294 285 369 190 q 228 497 228 370 q 295 714 228 625 q 499 813 370 813 q 656 762 588 813 q 733 625 724 711 l 634 625 q 589 704 629 673 q 498 735 550 735 q 377 666 421 735 q 334 504 334 597 q 374 340 334 408 q 490 272 415 272 q 589 304 549 272 q 638 394 628 337 l 741 394 "},"ώ":{"x_min":0,"x_max":922,"ha":1030,"o":"m 687 1040 l 498 819 l 415 819 l 549 1040 l 687 1040 m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 338 0 202 q 45 551 0 444 q 161 737 84 643 l 302 737 q 175 552 219 647 q 124 336 124 446 q 155 179 124 248 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 341 797 257 q 745 555 797 450 q 619 737 705 637 l 760 737 q 874 551 835 640 q 922 339 922 444 "},"^":{"x_min":193.0625,"x_max":598.609375,"ha":792,"o":"m 598 772 l 515 772 l 395 931 l 277 772 l 193 772 l 326 1013 l 462 1013 l 598 772 "},"«":{"x_min":0,"x_max":507.203125,"ha":604,"o":"m 506 136 l 284 302 l 284 440 l 506 608 l 507 485 l 360 371 l 506 255 l 506 136 m 222 136 l 0 302 l 0 440 l 222 608 l 221 486 l 73 373 l 222 256 l 222 136 "},"D":{"x_min":0,"x_max":828,"ha":935,"o":"m 389 1013 q 714 867 593 1013 q 828 521 828 729 q 712 161 828 309 q 382 0 587 0 l 0 0 l 0 1013 l 389 1013 m 376 124 q 607 247 523 124 q 681 510 681 355 q 607 771 681 662 q 376 896 522 896 l 139 896 l 139 124 l 376 124 "},"∙":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"ÿ":{"x_min":0,"x_max":47,"ha":125,"o":"m 47 3 q 37 -7 47 -7 q 28 0 30 -7 q 39 -4 32 -4 q 45 3 45 -1 l 37 0 q 28 9 28 0 q 39 19 28 19 l 47 16 l 47 19 l 47 3 m 37 1 q 44 8 44 1 q 37 16 44 16 q 30 8 30 16 q 37 1 30 1 m 26 1 l 23 22 l 14 0 l 3 22 l 3 3 l 0 25 l 13 1 l 22 25 l 26 1 "},"w":{"x_min":0,"x_max":1009.71875,"ha":1100,"o":"m 1009 738 l 783 0 l 658 0 l 501 567 l 345 0 l 222 0 l 0 738 l 130 738 l 284 174 l 432 737 l 576 738 l 721 173 l 881 737 l 1009 738 "},"$":{"x_min":0,"x_max":700,"ha":793,"o":"m 664 717 l 542 717 q 490 825 531 785 q 381 872 450 865 l 381 551 q 620 446 540 522 q 700 241 700 370 q 618 45 700 116 q 381 -25 536 -25 l 381 -152 l 307 -152 l 307 -25 q 81 62 162 -25 q 0 297 0 149 l 124 297 q 169 146 124 204 q 307 81 215 89 l 307 441 q 80 536 148 469 q 13 725 13 603 q 96 910 13 839 q 307 982 180 982 l 307 1077 l 381 1077 l 381 982 q 574 917 494 982 q 664 717 664 845 m 307 565 l 307 872 q 187 831 233 872 q 142 724 142 791 q 180 618 142 656 q 307 565 218 580 m 381 76 q 562 237 562 96 q 517 361 562 313 q 381 423 472 409 l 381 76 "},"\\":{"x_min":-0.015625,"x_max":425.0625,"ha":522,"o":"m 425 -129 l 337 -129 l 0 1041 l 83 1041 l 425 -129 "},"µ":{"x_min":0,"x_max":697.21875,"ha":747,"o":"m 697 -4 q 629 -14 658 -14 q 498 97 513 -14 q 422 9 470 41 q 313 -23 374 -23 q 207 4 258 -23 q 119 81 156 32 l 119 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 173 124 246 q 308 83 216 83 q 452 178 402 83 q 493 359 493 255 l 493 738 l 617 738 l 617 214 q 623 136 617 160 q 673 92 637 92 q 697 96 684 92 l 697 -4 "},"Ι":{"x_min":42,"x_max":181,"ha":297,"o":"m 181 0 l 42 0 l 42 1013 l 181 1013 l 181 0 "},"Ύ":{"x_min":0,"x_max":1144.5,"ha":1214,"o":"m 1144 1012 l 807 416 l 807 0 l 667 0 l 667 416 l 325 1012 l 465 1012 l 736 533 l 1004 1012 l 1144 1012 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"’":{"x_min":0,"x_max":139,"ha":236,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"Ν":{"x_min":0,"x_max":801,"ha":915,"o":"m 801 0 l 651 0 l 131 822 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 191 l 670 1013 l 801 1013 l 801 0 "},"-":{"x_min":8.71875,"x_max":350.390625,"ha":478,"o":"m 350 317 l 8 317 l 8 428 l 350 428 l 350 317 "},"Q":{"x_min":0,"x_max":968,"ha":1072,"o":"m 954 5 l 887 -79 l 744 35 q 622 -11 687 2 q 483 -26 556 -26 q 127 130 262 -26 q 0 504 0 279 q 127 880 0 728 q 484 1041 262 1041 q 841 884 708 1041 q 968 507 968 735 q 933 293 968 398 q 832 104 899 188 l 954 5 m 723 191 q 802 330 777 248 q 828 499 828 412 q 744 790 828 673 q 483 922 650 922 q 228 791 322 922 q 142 505 142 673 q 227 221 142 337 q 487 91 323 91 q 632 123 566 91 l 520 215 l 587 301 l 723 191 "},"ς":{"x_min":1,"x_max":676.28125,"ha":740,"o":"m 676 460 l 551 460 q 498 595 542 546 q 365 651 448 651 q 199 578 263 651 q 136 401 136 505 q 266 178 136 241 q 508 106 387 142 q 640 -50 640 62 q 625 -158 640 -105 q 583 -278 611 -211 l 465 -278 q 498 -182 490 -211 q 515 -80 515 -126 q 381 12 515 -15 q 134 91 197 51 q 1 388 1 179 q 100 651 1 542 q 354 761 199 761 q 587 680 498 761 q 676 460 676 599 "},"M":{"x_min":0,"x_max":954,"ha":1067,"o":"m 954 0 l 819 0 l 819 869 l 537 0 l 405 0 l 128 866 l 128 0 l 0 0 l 0 1013 l 200 1013 l 472 160 l 757 1013 l 954 1013 l 954 0 "},"Ψ":{"x_min":0,"x_max":1006,"ha":1094,"o":"m 1006 678 q 914 319 1006 429 q 571 200 814 200 l 571 0 l 433 0 l 433 200 q 92 319 194 200 q 0 678 0 429 l 0 1013 l 139 1013 l 139 679 q 191 417 139 492 q 433 326 255 326 l 433 1013 l 571 1013 l 571 326 l 580 326 q 813 423 747 326 q 868 679 868 502 l 868 1013 l 1006 1013 l 1006 678 "},"C":{"x_min":0,"x_max":886,"ha":944,"o":"m 886 379 q 760 87 886 201 q 455 -26 634 -26 q 112 136 236 -26 q 0 509 0 283 q 118 882 0 737 q 469 1041 245 1041 q 748 955 630 1041 q 879 708 879 859 l 745 708 q 649 862 724 805 q 473 920 573 920 q 219 791 312 920 q 136 509 136 675 q 217 229 136 344 q 470 99 311 99 q 672 179 591 99 q 753 379 753 259 l 886 379 "},"!":{"x_min":0,"x_max":138,"ha":236,"o":"m 138 684 q 116 409 138 629 q 105 244 105 299 l 33 244 q 16 465 33 313 q 0 684 0 616 l 0 1013 l 138 1013 l 138 684 m 138 0 l 0 0 l 0 151 l 138 151 l 138 0 "},"{":{"x_min":0,"x_max":480.5625,"ha":578,"o":"m 480 -286 q 237 -213 303 -286 q 187 -45 187 -159 q 194 48 187 -15 q 201 141 201 112 q 164 264 201 225 q 0 314 118 314 l 0 417 q 164 471 119 417 q 201 605 201 514 q 199 665 201 644 q 193 772 193 769 q 241 941 193 887 q 480 1015 308 1015 l 480 915 q 336 866 375 915 q 306 742 306 828 q 310 662 306 717 q 314 577 314 606 q 288 452 314 500 q 176 365 256 391 q 289 275 257 337 q 314 143 314 226 q 313 84 314 107 q 310 -11 310 -5 q 339 -131 310 -94 q 480 -182 377 -182 l 480 -286 "},"X":{"x_min":-0.015625,"x_max":854.15625,"ha":940,"o":"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 428 637 l 675 1013 l 836 1013 l 504 520 l 854 0 "},"#":{"x_min":0,"x_max":963.890625,"ha":1061,"o":"m 963 690 l 927 590 l 719 590 l 655 410 l 876 410 l 840 310 l 618 310 l 508 -3 l 393 -2 l 506 309 l 329 310 l 215 -2 l 102 -3 l 212 310 l 0 310 l 36 410 l 248 409 l 312 590 l 86 590 l 120 690 l 347 690 l 459 1006 l 573 1006 l 462 690 l 640 690 l 751 1006 l 865 1006 l 754 690 l 963 690 m 606 590 l 425 590 l 362 410 l 543 410 l 606 590 "},"ι":{"x_min":42,"x_max":284,"ha":361,"o":"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 738 l 167 738 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 "},"Ά":{"x_min":0,"x_max":906.953125,"ha":982,"o":"m 283 1040 l 88 799 l 5 799 l 145 1040 l 283 1040 m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1012 l 529 1012 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},")":{"x_min":0,"x_max":318,"ha":415,"o":"m 318 365 q 257 25 318 191 q 87 -290 197 -141 l 0 -290 q 140 21 93 -128 q 193 360 193 189 q 141 704 193 537 q 0 1024 97 850 l 87 1024 q 257 706 197 871 q 318 365 318 542 "},"ε":{"x_min":0,"x_max":634.71875,"ha":714,"o":"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 314 0 265 q 128 390 67 353 q 56 460 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 "},"Δ":{"x_min":0,"x_max":952.78125,"ha":1028,"o":"m 952 0 l 0 0 l 400 1013 l 551 1013 l 952 0 m 762 124 l 476 867 l 187 124 l 762 124 "},"}":{"x_min":0,"x_max":481,"ha":578,"o":"m 481 314 q 318 262 364 314 q 282 136 282 222 q 284 65 282 97 q 293 -58 293 -48 q 241 -217 293 -166 q 0 -286 174 -286 l 0 -182 q 143 -130 105 -182 q 171 -2 171 -93 q 168 81 171 22 q 165 144 165 140 q 188 275 165 229 q 306 365 220 339 q 191 455 224 391 q 165 588 165 505 q 168 681 165 624 q 171 742 171 737 q 141 865 171 827 q 0 915 102 915 l 0 1015 q 243 942 176 1015 q 293 773 293 888 q 287 675 293 741 q 282 590 282 608 q 318 466 282 505 q 481 417 364 417 l 481 314 "},"‰":{"x_min":-3,"x_max":1672,"ha":1821,"o":"m 846 0 q 664 76 732 0 q 603 244 603 145 q 662 412 603 344 q 846 489 729 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 846 0 962 0 m 845 103 q 945 143 910 103 q 981 243 981 184 q 947 340 981 301 q 845 385 910 385 q 745 342 782 385 q 709 243 709 300 q 742 147 709 186 q 845 103 781 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 m 1428 0 q 1246 76 1314 0 q 1185 244 1185 145 q 1244 412 1185 344 q 1428 489 1311 489 q 1610 412 1542 489 q 1672 244 1672 343 q 1612 76 1672 144 q 1428 0 1545 0 m 1427 103 q 1528 143 1492 103 q 1564 243 1564 184 q 1530 340 1564 301 q 1427 385 1492 385 q 1327 342 1364 385 q 1291 243 1291 300 q 1324 147 1291 186 q 1427 103 1363 103 "},"a":{"x_min":0,"x_max":698.609375,"ha":794,"o":"m 698 0 q 661 -12 679 -7 q 615 -17 643 -17 q 536 12 564 -17 q 500 96 508 41 q 384 6 456 37 q 236 -25 312 -25 q 65 31 130 -25 q 0 194 0 88 q 118 390 0 334 q 328 435 180 420 q 488 483 476 451 q 495 523 495 504 q 442 619 495 584 q 325 654 389 654 q 209 617 257 654 q 152 513 161 580 l 33 513 q 123 705 33 633 q 332 772 207 772 q 528 712 448 772 q 617 531 617 645 l 617 163 q 624 108 617 126 q 664 90 632 90 l 698 94 l 698 0 m 491 262 l 491 372 q 272 329 350 347 q 128 201 128 294 q 166 113 128 144 q 264 83 205 83 q 414 130 346 83 q 491 262 491 183 "},"—":{"x_min":0,"x_max":941.671875,"ha":1039,"o":"m 941 334 l 0 334 l 0 410 l 941 410 l 941 334 "},"=":{"x_min":8.71875,"x_max":780.953125,"ha":792,"o":"m 780 510 l 8 510 l 8 606 l 780 606 l 780 510 m 780 235 l 8 235 l 8 332 l 780 332 l 780 235 "},"N":{"x_min":0,"x_max":801,"ha":914,"o":"m 801 0 l 651 0 l 131 823 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 193 l 670 1013 l 801 1013 l 801 0 "},"ρ":{"x_min":0,"x_max":712,"ha":797,"o":"m 712 369 q 620 94 712 207 q 362 -26 521 -26 q 230 2 292 -26 q 119 83 167 30 l 119 -278 l 0 -278 l 0 362 q 91 643 0 531 q 355 764 190 764 q 617 647 517 764 q 712 369 712 536 m 583 366 q 530 559 583 480 q 359 651 469 651 q 190 562 252 651 q 135 370 135 483 q 189 176 135 257 q 359 85 250 85 q 528 175 466 85 q 583 366 583 254 "},"2":{"x_min":59,"x_max":731,"ha":792,"o":"m 731 0 l 59 0 q 197 314 59 188 q 457 487 199 315 q 598 691 598 580 q 543 819 598 772 q 411 867 488 867 q 272 811 328 867 q 209 630 209 747 l 81 630 q 182 901 81 805 q 408 986 271 986 q 629 909 536 986 q 731 694 731 826 q 613 449 731 541 q 378 316 495 383 q 201 122 235 234 l 731 122 l 731 0 "},"¯":{"x_min":0,"x_max":941.671875,"ha":938,"o":"m 941 1033 l 0 1033 l 0 1109 l 941 1109 l 941 1033 "},"Z":{"x_min":0,"x_max":779,"ha":849,"o":"m 779 0 l 0 0 l 0 113 l 621 896 l 40 896 l 40 1013 l 779 1013 l 778 887 l 171 124 l 779 124 l 779 0 "},"u":{"x_min":0,"x_max":617,"ha":729,"o":"m 617 0 l 499 0 l 499 110 q 391 10 460 45 q 246 -25 322 -25 q 61 58 127 -25 q 0 258 0 136 l 0 738 l 125 738 l 125 284 q 156 148 125 202 q 273 82 197 82 q 433 165 369 82 q 493 340 493 243 l 493 738 l 617 738 l 617 0 "},"k":{"x_min":0,"x_max":612.484375,"ha":697,"o":"m 612 738 l 338 465 l 608 0 l 469 0 l 251 382 l 121 251 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 402 l 456 738 l 612 738 "},"Η":{"x_min":0,"x_max":803,"ha":917,"o":"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"Α":{"x_min":0,"x_max":906.953125,"ha":985,"o":"m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},"s":{"x_min":0,"x_max":604,"ha":697,"o":"m 604 217 q 501 36 604 104 q 292 -23 411 -23 q 86 43 166 -23 q 0 238 0 114 l 121 237 q 175 122 121 164 q 300 85 223 85 q 415 112 363 85 q 479 207 479 147 q 361 309 479 276 q 140 372 141 370 q 21 544 21 426 q 111 708 21 647 q 298 761 190 761 q 492 705 413 761 q 583 531 583 643 l 462 531 q 412 625 462 594 q 298 657 363 657 q 199 636 242 657 q 143 558 143 608 q 262 454 143 486 q 484 394 479 397 q 604 217 604 341 "},"B":{"x_min":0,"x_max":778,"ha":876,"o":"m 580 546 q 724 469 670 535 q 778 311 778 403 q 673 83 778 171 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 892 q 691 633 732 693 q 580 546 650 572 m 393 899 l 139 899 l 139 588 l 379 588 q 521 624 462 588 q 592 744 592 667 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 303 635 219 q 559 436 635 389 q 402 477 494 477 l 139 477 l 139 124 l 419 124 "},"…":{"x_min":0,"x_max":614,"ha":708,"o":"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 m 378 0 l 236 0 l 236 151 l 378 151 l 378 0 m 614 0 l 472 0 l 472 151 l 614 151 l 614 0 "},"?":{"x_min":0,"x_max":607,"ha":704,"o":"m 607 777 q 543 599 607 674 q 422 474 482 537 q 357 272 357 391 l 236 272 q 297 487 236 395 q 411 619 298 490 q 474 762 474 691 q 422 885 474 838 q 301 933 371 933 q 179 880 228 933 q 124 706 124 819 l 0 706 q 94 963 0 872 q 302 1044 177 1044 q 511 973 423 1044 q 607 777 607 895 m 370 0 l 230 0 l 230 151 l 370 151 l 370 0 "},"H":{"x_min":0,"x_max":803,"ha":915,"o":"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"ν":{"x_min":0,"x_max":675,"ha":761,"o":"m 675 738 l 404 0 l 272 0 l 0 738 l 133 738 l 340 147 l 541 738 l 675 738 "},"c":{"x_min":1,"x_max":701.390625,"ha":775,"o":"m 701 264 q 584 53 681 133 q 353 -26 487 -26 q 91 91 188 -26 q 1 370 1 201 q 92 645 1 537 q 353 761 190 761 q 572 688 479 761 q 690 493 666 615 l 556 493 q 487 606 545 562 q 356 650 428 650 q 186 563 246 650 q 134 372 134 487 q 188 179 134 258 q 359 88 250 88 q 492 136 437 88 q 566 264 548 185 l 701 264 "},"¶":{"x_min":0,"x_max":566.671875,"ha":678,"o":"m 21 892 l 52 892 l 98 761 l 145 892 l 176 892 l 178 741 l 157 741 l 157 867 l 108 741 l 88 741 l 40 871 l 40 741 l 21 741 l 21 892 m 308 854 l 308 731 q 252 691 308 691 q 227 691 240 691 q 207 696 213 695 l 207 712 l 253 706 q 288 733 288 706 l 288 763 q 244 741 279 741 q 193 797 193 741 q 261 860 193 860 q 287 860 273 860 q 308 854 302 855 m 288 842 l 263 843 q 213 796 213 843 q 248 756 213 756 q 288 796 288 756 l 288 842 m 566 988 l 502 988 l 502 -1 l 439 -1 l 439 988 l 317 988 l 317 -1 l 252 -1 l 252 602 q 81 653 155 602 q 0 805 0 711 q 101 989 0 918 q 309 1053 194 1053 l 566 1053 l 566 988 "},"β":{"x_min":0,"x_max":660,"ha":745,"o":"m 471 550 q 610 450 561 522 q 660 280 660 378 q 578 64 660 151 q 367 -22 497 -22 q 239 5 299 -22 q 126 82 178 32 l 126 -278 l 0 -278 l 0 593 q 54 903 0 801 q 318 1042 127 1042 q 519 964 436 1042 q 603 771 603 887 q 567 644 603 701 q 471 550 532 586 m 337 79 q 476 138 418 79 q 535 279 535 198 q 427 437 535 386 q 226 477 344 477 l 226 583 q 398 620 329 583 q 486 762 486 668 q 435 884 486 833 q 312 935 384 935 q 169 861 219 935 q 126 698 126 797 l 126 362 q 170 169 126 242 q 337 79 224 79 "},"Μ":{"x_min":0,"x_max":954,"ha":1068,"o":"m 954 0 l 819 0 l 819 868 l 537 0 l 405 0 l 128 865 l 128 0 l 0 0 l 0 1013 l 199 1013 l 472 158 l 758 1013 l 954 1013 l 954 0 "},"Ό":{"x_min":0.109375,"x_max":1120,"ha":1217,"o":"m 1120 505 q 994 132 1120 282 q 642 -29 861 -29 q 290 130 422 -29 q 167 505 167 280 q 294 883 167 730 q 650 1046 430 1046 q 999 882 868 1046 q 1120 505 1120 730 m 977 504 q 896 784 977 669 q 644 915 804 915 q 391 785 484 915 q 307 504 307 669 q 391 224 307 339 q 644 95 486 95 q 894 224 803 95 q 977 504 977 339 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Ή":{"x_min":0,"x_max":1158,"ha":1275,"o":"m 1158 0 l 1022 0 l 1022 475 l 496 475 l 496 0 l 356 0 l 356 1012 l 496 1012 l 496 599 l 1022 599 l 1022 1012 l 1158 1012 l 1158 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"•":{"x_min":0,"x_max":663.890625,"ha":775,"o":"m 663 529 q 566 293 663 391 q 331 196 469 196 q 97 294 194 196 q 0 529 0 393 q 96 763 0 665 q 331 861 193 861 q 566 763 469 861 q 663 529 663 665 "},"¥":{"x_min":0.1875,"x_max":819.546875,"ha":886,"o":"m 563 561 l 697 561 l 696 487 l 520 487 l 482 416 l 482 380 l 697 380 l 695 308 l 482 308 l 482 0 l 342 0 l 342 308 l 125 308 l 125 380 l 342 380 l 342 417 l 303 487 l 125 487 l 125 561 l 258 561 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 l 563 561 "},"(":{"x_min":0,"x_max":318.0625,"ha":415,"o":"m 318 -290 l 230 -290 q 61 23 122 -142 q 0 365 0 190 q 62 712 0 540 q 230 1024 119 869 l 318 1024 q 175 705 219 853 q 125 360 125 542 q 176 22 125 187 q 318 -290 223 -127 "},"U":{"x_min":0,"x_max":796,"ha":904,"o":"m 796 393 q 681 93 796 212 q 386 -25 566 -25 q 101 95 208 -25 q 0 393 0 211 l 0 1013 l 138 1013 l 138 391 q 204 191 138 270 q 394 107 276 107 q 586 191 512 107 q 656 391 656 270 l 656 1013 l 796 1013 l 796 393 "},"γ":{"x_min":0.5,"x_max":744.953125,"ha":822,"o":"m 744 737 l 463 54 l 463 -278 l 338 -278 l 338 54 l 154 495 q 104 597 124 569 q 13 651 67 651 l 0 651 l 0 751 l 39 753 q 168 711 121 753 q 242 594 207 676 l 403 208 l 617 737 l 744 737 "},"α":{"x_min":0,"x_max":765.5625,"ha":809,"o":"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 728 407 760 q 563 637 524 696 l 563 739 l 685 739 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 96 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 "},"F":{"x_min":0,"x_max":683.328125,"ha":717,"o":"m 683 888 l 140 888 l 140 583 l 613 583 l 613 458 l 140 458 l 140 0 l 0 0 l 0 1013 l 683 1013 l 683 888 "},"­":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},":":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"Χ":{"x_min":0,"x_max":854.171875,"ha":935,"o":"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 427 637 l 675 1013 l 836 1013 l 504 521 l 854 0 "},"*":{"x_min":116,"x_max":674,"ha":792,"o":"m 674 768 l 475 713 l 610 544 l 517 477 l 394 652 l 272 478 l 178 544 l 314 713 l 116 766 l 153 876 l 341 812 l 342 1013 l 446 1013 l 446 811 l 635 874 l 674 768 "},"†":{"x_min":0,"x_max":777,"ha":835,"o":"m 458 804 l 777 804 l 777 683 l 458 683 l 458 0 l 319 0 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 "},"°":{"x_min":0,"x_max":347,"ha":444,"o":"m 173 802 q 43 856 91 802 q 0 977 0 905 q 45 1101 0 1049 q 173 1153 90 1153 q 303 1098 255 1153 q 347 977 347 1049 q 303 856 347 905 q 173 802 256 802 m 173 884 q 238 910 214 884 q 262 973 262 937 q 239 1038 262 1012 q 173 1064 217 1064 q 108 1037 132 1064 q 85 973 85 1010 q 108 910 85 937 q 173 884 132 884 "},"V":{"x_min":0,"x_max":862.71875,"ha":940,"o":"m 862 1013 l 505 0 l 361 0 l 0 1013 l 143 1013 l 434 165 l 718 1012 l 862 1013 "},"Ξ":{"x_min":0,"x_max":734.71875,"ha":763,"o":"m 723 889 l 9 889 l 9 1013 l 723 1013 l 723 889 m 673 463 l 61 463 l 61 589 l 673 589 l 673 463 m 734 0 l 0 0 l 0 124 l 734 124 l 734 0 "}," ":{"x_min":0,"x_max":0,"ha":853},"Ϋ":{"x_min":0.328125,"x_max":819.515625,"ha":889,"o":"m 588 1046 l 460 1046 l 460 1189 l 588 1189 l 588 1046 m 360 1046 l 232 1046 l 232 1189 l 360 1189 l 360 1046 m 819 1012 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1012 l 140 1012 l 411 533 l 679 1012 l 819 1012 "},"0":{"x_min":73,"x_max":715,"ha":792,"o":"m 394 -29 q 153 129 242 -29 q 73 479 73 272 q 152 829 73 687 q 394 989 241 989 q 634 829 545 989 q 715 479 715 684 q 635 129 715 270 q 394 -29 546 -29 m 394 89 q 546 211 489 89 q 598 479 598 322 q 548 748 598 640 q 394 871 491 871 q 241 748 298 871 q 190 479 190 637 q 239 211 190 319 q 394 89 296 89 "},"”":{"x_min":0,"x_max":347,"ha":454,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 m 347 851 q 310 737 347 784 q 208 669 273 690 l 208 734 q 267 787 250 741 q 280 873 280 821 l 208 873 l 208 1013 l 347 1013 l 347 851 "},"@":{"x_min":0,"x_max":1260,"ha":1357,"o":"m 1098 -45 q 877 -160 1001 -117 q 633 -203 752 -203 q 155 -29 327 -203 q 0 360 0 127 q 176 802 0 616 q 687 1008 372 1008 q 1123 854 969 1008 q 1260 517 1260 718 q 1155 216 1260 341 q 868 82 1044 82 q 772 106 801 82 q 737 202 737 135 q 647 113 700 144 q 527 82 594 82 q 367 147 420 82 q 314 312 314 212 q 401 565 314 452 q 639 690 498 690 q 810 588 760 690 l 849 668 l 938 668 q 877 441 900 532 q 833 226 833 268 q 853 182 833 198 q 902 167 873 167 q 1088 272 1012 167 q 1159 512 1159 372 q 1051 793 1159 681 q 687 925 925 925 q 248 747 415 925 q 97 361 97 586 q 226 26 97 159 q 627 -122 370 -122 q 856 -87 737 -122 q 1061 8 976 -53 l 1098 -45 m 786 488 q 738 580 777 545 q 643 615 700 615 q 483 517 548 615 q 425 322 425 430 q 457 203 425 250 q 552 156 490 156 q 722 273 665 156 q 786 488 738 309 "},"Ί":{"x_min":0,"x_max":499,"ha":613,"o":"m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 m 499 0 l 360 0 l 360 1012 l 499 1012 l 499 0 "},"i":{"x_min":14,"x_max":136,"ha":275,"o":"m 136 873 l 14 873 l 14 1013 l 136 1013 l 136 873 m 136 0 l 14 0 l 14 737 l 136 737 l 136 0 "},"Β":{"x_min":0,"x_max":778,"ha":877,"o":"m 580 545 q 724 468 671 534 q 778 310 778 402 q 673 83 778 170 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 891 q 691 632 732 692 q 580 545 650 571 m 393 899 l 139 899 l 139 587 l 379 587 q 521 623 462 587 q 592 744 592 666 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 302 635 219 q 559 435 635 388 q 402 476 494 476 l 139 476 l 139 124 l 419 124 "},"υ":{"x_min":0,"x_max":617,"ha":725,"o":"m 617 352 q 540 94 617 199 q 308 -24 455 -24 q 76 94 161 -24 q 0 352 0 199 l 0 739 l 126 739 l 126 355 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 355 492 257 l 492 739 l 617 739 l 617 352 "},"]":{"x_min":0,"x_max":275,"ha":372,"o":"m 275 -281 l 0 -281 l 0 -187 l 151 -187 l 151 920 l 0 920 l 0 1013 l 275 1013 l 275 -281 "},"m":{"x_min":0,"x_max":1019,"ha":1128,"o":"m 1019 0 l 897 0 l 897 454 q 860 591 897 536 q 739 660 816 660 q 613 586 659 660 q 573 436 573 522 l 573 0 l 447 0 l 447 455 q 412 591 447 535 q 294 657 372 657 q 165 586 213 657 q 122 437 122 521 l 122 0 l 0 0 l 0 738 l 117 738 l 117 640 q 202 730 150 697 q 316 763 254 763 q 437 730 381 763 q 525 642 494 697 q 621 731 559 700 q 753 763 682 763 q 943 694 867 763 q 1019 512 1019 625 l 1019 0 "},"χ":{"x_min":8.328125,"x_max":780.5625,"ha":815,"o":"m 780 -278 q 715 -294 747 -294 q 616 -257 663 -294 q 548 -175 576 -227 l 379 133 l 143 -277 l 9 -277 l 313 254 l 163 522 q 127 586 131 580 q 36 640 91 640 q 8 637 27 640 l 8 752 l 52 757 q 162 719 113 757 q 236 627 200 690 l 383 372 l 594 737 l 726 737 l 448 250 l 625 -69 q 670 -153 647 -110 q 743 -188 695 -188 q 780 -184 759 -188 l 780 -278 "},"8":{"x_min":55,"x_max":736,"ha":792,"o":"m 571 527 q 694 424 652 491 q 736 280 736 358 q 648 71 736 158 q 395 -26 551 -26 q 142 69 238 -26 q 55 279 55 157 q 96 425 55 359 q 220 527 138 491 q 120 615 153 562 q 88 726 88 668 q 171 904 88 827 q 395 986 261 986 q 618 905 529 986 q 702 727 702 830 q 670 616 702 667 q 571 527 638 565 m 394 565 q 519 610 475 565 q 563 717 563 655 q 521 823 563 781 q 392 872 474 872 q 265 824 312 872 q 224 720 224 783 q 265 613 224 656 q 394 565 312 565 m 395 91 q 545 150 488 91 q 597 280 597 204 q 546 408 597 355 q 395 465 492 465 q 244 408 299 465 q 194 280 194 356 q 244 150 194 203 q 395 91 299 91 "},"ί":{"x_min":42,"x_max":326.71875,"ha":361,"o":"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 102 239 101 q 284 112 257 104 l 284 3 m 326 1040 l 137 819 l 54 819 l 189 1040 l 326 1040 "},"Ζ":{"x_min":0,"x_max":779.171875,"ha":850,"o":"m 779 0 l 0 0 l 0 113 l 620 896 l 40 896 l 40 1013 l 779 1013 l 779 887 l 170 124 l 779 124 l 779 0 "},"R":{"x_min":0,"x_max":781.953125,"ha":907,"o":"m 781 0 l 623 0 q 587 242 590 52 q 407 433 585 433 l 138 433 l 138 0 l 0 0 l 0 1013 l 396 1013 q 636 946 539 1013 q 749 731 749 868 q 711 597 749 659 q 608 502 674 534 q 718 370 696 474 q 729 207 722 352 q 781 26 736 62 l 781 0 m 373 551 q 533 594 465 551 q 614 731 614 645 q 532 859 614 815 q 373 896 465 896 l 138 896 l 138 551 l 373 551 "},"o":{"x_min":0,"x_max":713,"ha":821,"o":"m 357 -25 q 94 91 194 -25 q 0 368 0 202 q 93 642 0 533 q 357 761 193 761 q 618 644 518 761 q 713 368 713 533 q 619 91 713 201 q 357 -25 521 -25 m 357 85 q 528 175 465 85 q 584 369 584 255 q 529 562 584 484 q 357 651 467 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 357 85 250 85 "},"5":{"x_min":54.171875,"x_max":738,"ha":792,"o":"m 738 314 q 626 60 738 153 q 382 -23 526 -23 q 155 47 248 -23 q 54 256 54 125 l 183 256 q 259 132 204 174 q 382 91 314 91 q 533 149 471 91 q 602 314 602 213 q 538 469 602 411 q 386 528 475 528 q 284 506 332 528 q 197 439 237 484 l 81 439 l 159 958 l 684 958 l 684 840 l 254 840 l 214 579 q 306 627 258 612 q 407 643 354 643 q 636 552 540 643 q 738 314 738 457 "},"7":{"x_min":58.71875,"x_max":730.953125,"ha":792,"o":"m 730 839 q 469 448 560 641 q 335 0 378 255 l 192 0 q 328 441 235 252 q 593 830 421 630 l 58 830 l 58 958 l 730 958 l 730 839 "},"K":{"x_min":0,"x_max":819.46875,"ha":906,"o":"m 819 0 l 649 0 l 294 509 l 139 355 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},",":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 -12 q 105 -132 142 -82 q 0 -205 68 -182 l 0 -138 q 57 -82 40 -124 q 70 0 70 -51 l 0 0 l 0 151 l 142 151 l 142 -12 "},"d":{"x_min":0,"x_max":683,"ha":796,"o":"m 683 0 l 564 0 l 564 93 q 456 6 516 38 q 327 -25 395 -25 q 87 100 181 -25 q 0 365 0 215 q 90 639 0 525 q 343 763 187 763 q 564 647 486 763 l 564 1013 l 683 1013 l 683 0 m 582 373 q 529 562 582 484 q 361 653 468 653 q 190 561 253 653 q 135 365 135 479 q 189 175 135 254 q 358 85 251 85 q 529 178 468 85 q 582 373 582 258 "},"¨":{"x_min":-109,"x_max":247,"ha":232,"o":"m 247 1046 l 119 1046 l 119 1189 l 247 1189 l 247 1046 m 19 1046 l -109 1046 l -109 1189 l 19 1189 l 19 1046 "},"E":{"x_min":0,"x_max":736.109375,"ha":789,"o":"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},"Y":{"x_min":0,"x_max":820,"ha":886,"o":"m 820 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 534 l 679 1012 l 820 1013 "},"\"":{"x_min":0,"x_max":299,"ha":396,"o":"m 299 606 l 203 606 l 203 988 l 299 988 l 299 606 m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"‹":{"x_min":17.984375,"x_max":773.609375,"ha":792,"o":"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"„":{"x_min":0,"x_max":364,"ha":467,"o":"m 141 -12 q 104 -132 141 -82 q 0 -205 67 -182 l 0 -138 q 56 -82 40 -124 q 69 0 69 -51 l 0 0 l 0 151 l 141 151 l 141 -12 m 364 -12 q 327 -132 364 -82 q 222 -205 290 -182 l 222 -138 q 279 -82 262 -124 q 292 0 292 -51 l 222 0 l 222 151 l 364 151 l 364 -12 "},"δ":{"x_min":1,"x_max":710,"ha":810,"o":"m 710 360 q 616 87 710 196 q 356 -28 518 -28 q 99 82 197 -28 q 1 356 1 192 q 100 606 1 509 q 355 703 199 703 q 180 829 288 754 q 70 903 124 866 l 70 1012 l 643 1012 l 643 901 l 258 901 q 462 763 422 794 q 636 592 577 677 q 710 360 710 485 m 584 365 q 552 501 584 447 q 451 602 521 555 q 372 611 411 611 q 197 541 258 611 q 136 355 136 472 q 190 171 136 245 q 358 85 252 85 q 528 173 465 85 q 584 365 584 252 "},"έ":{"x_min":0,"x_max":634.71875,"ha":714,"o":"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 313 0 265 q 128 390 67 352 q 56 459 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 m 520 1040 l 331 819 l 248 819 l 383 1040 l 520 1040 "},"ω":{"x_min":0,"x_max":922,"ha":1031,"o":"m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 339 0 203 q 45 551 0 444 q 161 738 84 643 l 302 738 q 175 553 219 647 q 124 336 124 446 q 155 179 124 249 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 342 797 257 q 745 556 797 450 q 619 738 705 638 l 760 738 q 874 551 835 640 q 922 339 922 444 "},"´":{"x_min":0,"x_max":96,"ha":251,"o":"m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"±":{"x_min":11,"x_max":781,"ha":792,"o":"m 781 490 l 446 490 l 446 255 l 349 255 l 349 490 l 11 490 l 11 586 l 349 586 l 349 819 l 446 819 l 446 586 l 781 586 l 781 490 m 781 21 l 11 21 l 11 115 l 781 115 l 781 21 "},"|":{"x_min":343,"x_max":449,"ha":792,"o":"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"ϋ":{"x_min":0,"x_max":617,"ha":725,"o":"m 482 800 l 372 800 l 372 925 l 482 925 l 482 800 m 239 800 l 129 800 l 129 925 l 239 925 l 239 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 "},"§":{"x_min":0,"x_max":593,"ha":690,"o":"m 593 425 q 554 312 593 369 q 467 233 516 254 q 537 83 537 172 q 459 -74 537 -12 q 288 -133 387 -133 q 115 -69 184 -133 q 47 96 47 -6 l 166 96 q 199 7 166 40 q 288 -26 232 -26 q 371 -5 332 -26 q 420 60 420 21 q 311 201 420 139 q 108 309 210 255 q 0 490 0 383 q 33 602 0 551 q 124 687 66 654 q 75 743 93 712 q 58 812 58 773 q 133 984 58 920 q 300 1043 201 1043 q 458 987 394 1043 q 529 814 529 925 l 411 814 q 370 908 404 877 q 289 939 336 939 q 213 911 246 939 q 180 841 180 883 q 286 720 180 779 q 484 612 480 615 q 593 425 593 534 m 467 409 q 355 544 467 473 q 196 630 228 612 q 146 587 162 609 q 124 525 124 558 q 239 387 124 462 q 398 298 369 315 q 448 345 429 316 q 467 409 467 375 "},"b":{"x_min":0,"x_max":685,"ha":783,"o":"m 685 372 q 597 99 685 213 q 347 -25 501 -25 q 219 5 277 -25 q 121 93 161 36 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 634 q 214 723 157 692 q 341 754 272 754 q 591 637 493 754 q 685 372 685 526 m 554 356 q 499 550 554 470 q 328 644 437 644 q 162 556 223 644 q 108 369 108 478 q 160 176 108 256 q 330 83 221 83 q 498 169 435 83 q 554 356 554 245 "},"q":{"x_min":0,"x_max":683,"ha":876,"o":"m 683 -278 l 564 -278 l 564 97 q 474 8 533 39 q 345 -23 415 -23 q 91 93 188 -23 q 0 364 0 203 q 87 635 0 522 q 337 760 184 760 q 466 727 408 760 q 564 637 523 695 l 564 737 l 683 737 l 683 -278 m 582 375 q 527 564 582 488 q 358 652 466 652 q 190 565 253 652 q 135 377 135 488 q 189 179 135 261 q 361 84 251 84 q 530 179 469 84 q 582 375 582 260 "},"Ω":{"x_min":-0.171875,"x_max":969.5625,"ha":1068,"o":"m 969 0 l 555 0 l 555 123 q 744 308 675 194 q 814 558 814 423 q 726 812 814 709 q 484 922 633 922 q 244 820 334 922 q 154 567 154 719 q 223 316 154 433 q 412 123 292 199 l 412 0 l 0 0 l 0 124 l 217 124 q 68 327 122 210 q 15 572 15 444 q 144 911 15 781 q 484 1041 274 1041 q 822 909 691 1041 q 953 569 953 777 q 899 326 953 443 q 750 124 846 210 l 969 124 l 969 0 "},"ύ":{"x_min":0,"x_max":617,"ha":725,"o":"m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 535 1040 l 346 819 l 262 819 l 397 1040 l 535 1040 "},"z":{"x_min":-0.015625,"x_max":613.890625,"ha":697,"o":"m 613 0 l 0 0 l 0 100 l 433 630 l 20 630 l 20 738 l 594 738 l 593 636 l 163 110 l 613 110 l 613 0 "},"™":{"x_min":0,"x_max":894,"ha":1000,"o":"m 389 951 l 229 951 l 229 503 l 160 503 l 160 951 l 0 951 l 0 1011 l 389 1011 l 389 951 m 894 503 l 827 503 l 827 939 l 685 503 l 620 503 l 481 937 l 481 503 l 417 503 l 417 1011 l 517 1011 l 653 580 l 796 1010 l 894 1011 l 894 503 "},"ή":{"x_min":0.78125,"x_max":697,"ha":810,"o":"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 721 124 755 q 200 630 193 687 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 m 479 1040 l 290 819 l 207 819 l 341 1040 l 479 1040 "},"Θ":{"x_min":0,"x_max":960,"ha":1056,"o":"m 960 507 q 833 129 960 280 q 476 -32 698 -32 q 123 129 255 -32 q 0 507 0 280 q 123 883 0 732 q 476 1045 255 1045 q 832 883 696 1045 q 960 507 960 732 m 817 500 q 733 789 817 669 q 476 924 639 924 q 223 792 317 924 q 142 507 142 675 q 222 222 142 339 q 476 89 315 89 q 730 218 636 89 q 817 500 817 334 m 716 449 l 243 449 l 243 571 l 716 571 l 716 449 "},"®":{"x_min":-3,"x_max":1008,"ha":1106,"o":"m 503 532 q 614 562 566 532 q 672 658 672 598 q 614 747 672 716 q 503 772 569 772 l 338 772 l 338 532 l 503 532 m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 788 146 l 678 146 q 653 316 655 183 q 527 449 652 449 l 338 449 l 338 146 l 241 146 l 241 854 l 518 854 q 688 808 621 854 q 766 658 766 755 q 739 563 766 607 q 668 497 713 519 q 751 331 747 472 q 788 164 756 190 l 788 146 "},"~":{"x_min":0,"x_max":833,"ha":931,"o":"m 833 958 q 778 753 833 831 q 594 665 716 665 q 402 761 502 665 q 240 857 302 857 q 131 795 166 857 q 104 665 104 745 l 0 665 q 54 867 0 789 q 237 958 116 958 q 429 861 331 958 q 594 765 527 765 q 704 827 670 765 q 729 958 729 874 l 833 958 "},"Ε":{"x_min":0,"x_max":736.21875,"ha":778,"o":"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},"³":{"x_min":0,"x_max":450,"ha":547,"o":"m 450 552 q 379 413 450 464 q 220 366 313 366 q 69 414 130 366 q 0 567 0 470 l 85 567 q 126 470 85 504 q 225 437 168 437 q 320 467 280 437 q 360 552 360 498 q 318 632 360 608 q 213 657 276 657 q 195 657 203 657 q 176 657 181 657 l 176 722 q 279 733 249 722 q 334 815 334 752 q 300 881 334 856 q 220 907 267 907 q 133 875 169 907 q 97 781 97 844 l 15 781 q 78 926 15 875 q 220 972 135 972 q 364 930 303 972 q 426 817 426 888 q 344 697 426 733 q 421 642 392 681 q 450 552 450 603 "},"[":{"x_min":0,"x_max":273.609375,"ha":371,"o":"m 273 -281 l 0 -281 l 0 1013 l 273 1013 l 273 920 l 124 920 l 124 -187 l 273 -187 l 273 -281 "},"L":{"x_min":0,"x_max":645.828125,"ha":696,"o":"m 645 0 l 0 0 l 0 1013 l 140 1013 l 140 126 l 645 126 l 645 0 "},"σ":{"x_min":0,"x_max":803.390625,"ha":894,"o":"m 803 628 l 633 628 q 713 368 713 512 q 618 93 713 204 q 357 -25 518 -25 q 94 91 194 -25 q 0 368 0 201 q 94 644 0 533 q 356 761 194 761 q 481 750 398 761 q 608 739 564 739 l 803 739 l 803 628 m 360 85 q 529 180 467 85 q 584 374 584 262 q 527 566 584 490 q 352 651 463 651 q 187 559 247 651 q 135 368 135 478 q 189 175 135 254 q 360 85 251 85 "},"ζ":{"x_min":0,"x_max":573,"ha":642,"o":"m 573 -40 q 553 -162 573 -97 q 510 -278 543 -193 l 400 -278 q 441 -187 428 -219 q 462 -90 462 -132 q 378 -14 462 -14 q 108 45 197 -14 q 0 290 0 117 q 108 631 0 462 q 353 901 194 767 l 55 901 l 55 1012 l 561 1012 l 561 924 q 261 669 382 831 q 128 301 128 489 q 243 117 128 149 q 458 98 350 108 q 573 -40 573 80 "},"θ":{"x_min":0,"x_max":674,"ha":778,"o":"m 674 496 q 601 160 674 304 q 336 -26 508 -26 q 73 153 165 -26 q 0 485 0 296 q 72 840 0 683 q 343 1045 166 1045 q 605 844 516 1045 q 674 496 674 692 m 546 579 q 498 798 546 691 q 336 935 437 935 q 178 798 237 935 q 126 579 137 701 l 546 579 m 546 475 l 126 475 q 170 233 126 348 q 338 80 230 80 q 504 233 447 80 q 546 475 546 346 "},"Ο":{"x_min":0,"x_max":958,"ha":1054,"o":"m 485 1042 q 834 883 703 1042 q 958 511 958 735 q 834 136 958 287 q 481 -26 701 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 729 q 485 1042 263 1042 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 670 q 480 913 640 913 q 226 785 321 913 q 142 504 142 671 q 226 224 142 339 q 480 98 319 98 "},"Γ":{"x_min":0,"x_max":705.28125,"ha":749,"o":"m 705 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 705 1012 l 705 886 "}," ":{"x_min":0,"x_max":0,"ha":375},"%":{"x_min":-3,"x_max":1089,"ha":1186,"o":"m 845 0 q 663 76 731 0 q 602 244 602 145 q 661 412 602 344 q 845 489 728 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 845 0 962 0 m 844 103 q 945 143 909 103 q 981 243 981 184 q 947 340 981 301 q 844 385 909 385 q 744 342 781 385 q 708 243 708 300 q 741 147 708 186 q 844 103 780 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 "},"P":{"x_min":0,"x_max":726,"ha":806,"o":"m 424 1013 q 640 931 555 1013 q 726 719 726 850 q 637 506 726 587 q 413 426 548 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 379 889 l 140 889 l 140 548 l 372 548 q 522 589 459 548 q 593 720 593 637 q 528 845 593 801 q 379 889 463 889 "},"Έ":{"x_min":0,"x_max":1078.21875,"ha":1118,"o":"m 1078 0 l 342 0 l 342 1013 l 1067 1013 l 1067 889 l 481 889 l 481 585 l 1019 585 l 1019 467 l 481 467 l 481 125 l 1078 125 l 1078 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Ώ":{"x_min":0.125,"x_max":1136.546875,"ha":1235,"o":"m 1136 0 l 722 0 l 722 123 q 911 309 842 194 q 981 558 981 423 q 893 813 981 710 q 651 923 800 923 q 411 821 501 923 q 321 568 321 720 q 390 316 321 433 q 579 123 459 200 l 579 0 l 166 0 l 166 124 l 384 124 q 235 327 289 210 q 182 572 182 444 q 311 912 182 782 q 651 1042 441 1042 q 989 910 858 1042 q 1120 569 1120 778 q 1066 326 1120 443 q 917 124 1013 210 l 1136 124 l 1136 0 m 277 1040 l 83 800 l 0 800 l 140 1041 l 277 1040 "},"_":{"x_min":0,"x_max":705.5625,"ha":803,"o":"m 705 -334 l 0 -334 l 0 -234 l 705 -234 l 705 -334 "},"Ϊ":{"x_min":-110,"x_max":246,"ha":275,"o":"m 246 1046 l 118 1046 l 118 1189 l 246 1189 l 246 1046 m 18 1046 l -110 1046 l -110 1189 l 18 1189 l 18 1046 m 136 0 l 0 0 l 0 1012 l 136 1012 l 136 0 "},"+":{"x_min":23,"x_max":768,"ha":792,"o":"m 768 372 l 444 372 l 444 0 l 347 0 l 347 372 l 23 372 l 23 468 l 347 468 l 347 840 l 444 840 l 444 468 l 768 468 l 768 372 "},"½":{"x_min":0,"x_max":1050,"ha":1149,"o":"m 1050 0 l 625 0 q 712 178 625 108 q 878 277 722 187 q 967 385 967 328 q 932 456 967 429 q 850 484 897 484 q 759 450 798 484 q 721 352 721 416 l 640 352 q 706 502 640 448 q 851 551 766 551 q 987 509 931 551 q 1050 385 1050 462 q 976 251 1050 301 q 829 179 902 215 q 717 68 740 133 l 1050 68 l 1050 0 m 834 985 l 215 -28 l 130 -28 l 750 984 l 834 985 m 224 422 l 142 422 l 142 811 l 0 811 l 0 867 q 104 889 62 867 q 164 973 157 916 l 224 973 l 224 422 "},"Ρ":{"x_min":0,"x_max":720,"ha":783,"o":"m 424 1013 q 637 933 554 1013 q 720 723 720 853 q 633 508 720 591 q 413 426 546 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 378 889 l 140 889 l 140 548 l 371 548 q 521 589 458 548 q 592 720 592 637 q 527 845 592 801 q 378 889 463 889 "},"'":{"x_min":0,"x_max":139,"ha":236,"o":"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"ª":{"x_min":0,"x_max":350,"ha":397,"o":"m 350 625 q 307 616 328 616 q 266 631 281 616 q 247 673 251 645 q 190 628 225 644 q 116 613 156 613 q 32 641 64 613 q 0 722 0 669 q 72 826 0 800 q 247 866 159 846 l 247 887 q 220 934 247 916 q 162 953 194 953 q 104 934 129 953 q 76 882 80 915 l 16 882 q 60 976 16 941 q 166 1011 104 1011 q 266 979 224 1011 q 308 891 308 948 l 308 706 q 311 679 308 688 q 331 670 315 670 l 350 672 l 350 625 m 247 757 l 247 811 q 136 790 175 798 q 64 726 64 773 q 83 682 64 697 q 132 667 103 667 q 207 690 174 667 q 247 757 247 718 "},"΅":{"x_min":0,"x_max":450,"ha":553,"o":"m 450 800 l 340 800 l 340 925 l 450 925 l 450 800 m 406 1040 l 212 800 l 129 800 l 269 1040 l 406 1040 m 110 800 l 0 800 l 0 925 l 110 925 l 110 800 "},"T":{"x_min":0,"x_max":777,"ha":835,"o":"m 777 894 l 458 894 l 458 0 l 319 0 l 319 894 l 0 894 l 0 1013 l 777 1013 l 777 894 "},"Φ":{"x_min":0,"x_max":915,"ha":997,"o":"m 527 0 l 389 0 l 389 122 q 110 231 220 122 q 0 509 0 340 q 110 785 0 677 q 389 893 220 893 l 389 1013 l 527 1013 l 527 893 q 804 786 693 893 q 915 509 915 679 q 805 231 915 341 q 527 122 696 122 l 527 0 m 527 226 q 712 310 641 226 q 779 507 779 389 q 712 705 779 627 q 527 787 641 787 l 527 226 m 389 226 l 389 787 q 205 698 275 775 q 136 505 136 620 q 206 308 136 391 q 389 226 276 226 "},"⁋":{"x_min":0,"x_max":0,"ha":694},"j":{"x_min":-77.78125,"x_max":167,"ha":349,"o":"m 167 871 l 42 871 l 42 1013 l 167 1013 l 167 871 m 167 -80 q 121 -231 167 -184 q -26 -278 76 -278 l -77 -278 l -77 -164 l -41 -164 q 26 -143 11 -164 q 42 -65 42 -122 l 42 737 l 167 737 l 167 -80 "},"Σ":{"x_min":0,"x_max":756.953125,"ha":819,"o":"m 756 0 l 0 0 l 0 107 l 395 523 l 22 904 l 22 1013 l 745 1013 l 745 889 l 209 889 l 566 523 l 187 125 l 756 125 l 756 0 "},"1":{"x_min":215.671875,"x_max":574,"ha":792,"o":"m 574 0 l 442 0 l 442 697 l 215 697 l 215 796 q 386 833 330 796 q 475 986 447 875 l 574 986 l 574 0 "},"›":{"x_min":18.0625,"x_max":774,"ha":792,"o":"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},"<":{"x_min":17.984375,"x_max":773.609375,"ha":792,"o":"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"£":{"x_min":0,"x_max":704.484375,"ha":801,"o":"m 704 41 q 623 -10 664 5 q 543 -26 583 -26 q 359 15 501 -26 q 243 36 288 36 q 158 23 197 36 q 73 -21 119 10 l 6 76 q 125 195 90 150 q 175 331 175 262 q 147 443 175 383 l 0 443 l 0 512 l 108 512 q 43 734 43 623 q 120 929 43 854 q 358 1010 204 1010 q 579 936 487 1010 q 678 729 678 857 l 678 684 l 552 684 q 504 838 552 780 q 362 896 457 896 q 216 852 263 896 q 176 747 176 815 q 199 627 176 697 q 248 512 217 574 l 468 512 l 468 443 l 279 443 q 297 356 297 398 q 230 194 297 279 q 153 107 211 170 q 227 133 190 125 q 293 142 264 142 q 410 119 339 142 q 516 96 482 96 q 579 105 550 96 q 648 142 608 115 l 704 41 "},"t":{"x_min":0,"x_max":367,"ha":458,"o":"m 367 0 q 312 -5 339 -2 q 262 -8 284 -8 q 145 28 183 -8 q 108 143 108 64 l 108 638 l 0 638 l 0 738 l 108 738 l 108 944 l 232 944 l 232 738 l 367 738 l 367 638 l 232 638 l 232 185 q 248 121 232 140 q 307 102 264 102 q 345 104 330 102 q 367 107 360 107 l 367 0 "},"¬":{"x_min":0,"x_max":706,"ha":803,"o":"m 706 411 l 706 158 l 630 158 l 630 335 l 0 335 l 0 411 l 706 411 "},"λ":{"x_min":0,"x_max":750,"ha":803,"o":"m 750 -7 q 679 -15 716 -15 q 538 59 591 -15 q 466 214 512 97 l 336 551 l 126 0 l 0 0 l 270 705 q 223 837 247 770 q 116 899 190 899 q 90 898 100 899 l 90 1004 q 152 1011 125 1011 q 298 938 244 1011 q 373 783 326 901 l 605 192 q 649 115 629 136 q 716 95 669 95 l 736 95 q 750 97 745 97 l 750 -7 "},"W":{"x_min":0,"x_max":1263.890625,"ha":1351,"o":"m 1263 1013 l 995 0 l 859 0 l 627 837 l 405 0 l 265 0 l 0 1013 l 136 1013 l 342 202 l 556 1013 l 701 1013 l 921 207 l 1133 1012 l 1263 1013 "},">":{"x_min":18.0625,"x_max":774,"ha":792,"o":"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},"v":{"x_min":0,"x_max":675.15625,"ha":761,"o":"m 675 738 l 404 0 l 272 0 l 0 738 l 133 737 l 340 147 l 541 737 l 675 738 "},"τ":{"x_min":0.28125,"x_max":644.5,"ha":703,"o":"m 644 628 l 382 628 l 382 179 q 388 120 382 137 q 436 91 401 91 q 474 94 447 91 q 504 97 501 97 l 504 0 q 454 -9 482 -5 q 401 -14 426 -14 q 278 67 308 -14 q 260 233 260 118 l 260 628 l 0 628 l 0 739 l 644 739 l 644 628 "},"ξ":{"x_min":0,"x_max":624.9375,"ha":699,"o":"m 624 -37 q 608 -153 624 -96 q 563 -278 593 -211 l 454 -278 q 491 -183 486 -200 q 511 -83 511 -126 q 484 -23 511 -44 q 370 1 452 1 q 323 0 354 1 q 283 -1 293 -1 q 84 76 169 -1 q 0 266 0 154 q 56 431 0 358 q 197 538 108 498 q 94 613 134 562 q 54 730 54 665 q 77 823 54 780 q 143 901 101 867 l 27 901 l 27 1012 l 576 1012 l 576 901 l 380 901 q 244 863 303 901 q 178 745 178 820 q 312 600 178 636 q 532 582 380 582 l 532 479 q 276 455 361 479 q 118 281 118 410 q 165 173 118 217 q 274 120 208 133 q 494 101 384 110 q 624 -37 624 76 "},"&":{"x_min":-3,"x_max":894.25,"ha":992,"o":"m 894 0 l 725 0 l 624 123 q 471 0 553 40 q 306 -41 390 -41 q 168 -7 231 -41 q 62 92 105 26 q 14 187 31 139 q -3 276 -3 235 q 55 433 -3 358 q 248 581 114 508 q 170 689 196 640 q 137 817 137 751 q 214 985 137 922 q 384 1041 284 1041 q 548 988 483 1041 q 622 824 622 928 q 563 666 622 739 q 431 556 516 608 l 621 326 q 649 407 639 361 q 663 493 653 426 l 781 493 q 703 229 781 352 l 894 0 m 504 818 q 468 908 504 877 q 384 940 433 940 q 293 907 331 940 q 255 818 255 875 q 289 714 255 767 q 363 628 313 678 q 477 729 446 682 q 504 818 504 771 m 556 209 l 314 499 q 179 395 223 449 q 135 283 135 341 q 146 222 135 253 q 183 158 158 192 q 333 80 241 80 q 556 209 448 80 "},"Λ":{"x_min":0,"x_max":862.5,"ha":942,"o":"m 862 0 l 719 0 l 426 847 l 143 0 l 0 0 l 356 1013 l 501 1013 l 862 0 "},"I":{"x_min":41,"x_max":180,"ha":293,"o":"m 180 0 l 41 0 l 41 1013 l 180 1013 l 180 0 "},"G":{"x_min":0,"x_max":921,"ha":1011,"o":"m 921 0 l 832 0 l 801 136 q 655 15 741 58 q 470 -28 568 -28 q 126 133 259 -28 q 0 499 0 284 q 125 881 0 731 q 486 1043 259 1043 q 763 957 647 1043 q 905 709 890 864 l 772 709 q 668 866 747 807 q 486 926 589 926 q 228 795 322 926 q 142 507 142 677 q 228 224 142 342 q 483 94 323 94 q 712 195 625 94 q 796 435 796 291 l 477 435 l 477 549 l 921 549 l 921 0 "},"ΰ":{"x_min":0,"x_max":617,"ha":725,"o":"m 524 800 l 414 800 l 414 925 l 524 925 l 524 800 m 183 800 l 73 800 l 73 925 l 183 925 l 183 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 489 1040 l 300 819 l 216 819 l 351 1040 l 489 1040 "},"`":{"x_min":0,"x_max":138.890625,"ha":236,"o":"m 138 699 l 0 699 l 0 861 q 36 974 0 929 q 138 1041 72 1020 l 138 977 q 82 931 95 969 q 69 839 69 893 l 138 839 l 138 699 "},"·":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"Υ":{"x_min":0.328125,"x_max":819.515625,"ha":889,"o":"m 819 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 "},"r":{"x_min":0,"x_max":355.5625,"ha":432,"o":"m 355 621 l 343 621 q 179 569 236 621 q 122 411 122 518 l 122 0 l 0 0 l 0 737 l 117 737 l 117 604 q 204 719 146 686 q 355 753 262 753 l 355 621 "},"x":{"x_min":0,"x_max":675,"ha":764,"o":"m 675 0 l 525 0 l 331 286 l 144 0 l 0 0 l 256 379 l 12 738 l 157 737 l 336 473 l 516 738 l 661 738 l 412 380 l 675 0 "},"μ":{"x_min":0,"x_max":696.609375,"ha":747,"o":"m 696 -4 q 628 -14 657 -14 q 498 97 513 -14 q 422 8 470 41 q 313 -24 374 -24 q 207 3 258 -24 q 120 80 157 31 l 120 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 172 124 246 q 308 82 216 82 q 451 177 402 82 q 492 358 492 254 l 492 738 l 616 738 l 616 214 q 623 136 616 160 q 673 92 636 92 q 696 95 684 92 l 696 -4 "},"h":{"x_min":0,"x_max":615,"ha":724,"o":"m 615 472 l 615 0 l 490 0 l 490 454 q 456 590 490 535 q 338 654 416 654 q 186 588 251 654 q 122 436 122 522 l 122 0 l 0 0 l 0 1013 l 122 1013 l 122 633 q 218 727 149 694 q 362 760 287 760 q 552 676 484 760 q 615 472 615 600 "},".":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"φ":{"x_min":-2,"x_max":878,"ha":974,"o":"m 496 -279 l 378 -279 l 378 -17 q 101 88 204 -17 q -2 367 -2 194 q 68 626 -2 510 q 283 758 151 758 l 283 646 q 167 537 209 626 q 133 373 133 462 q 192 177 133 254 q 378 93 259 93 l 378 758 q 445 764 426 763 q 476 765 464 765 q 765 659 653 765 q 878 377 878 553 q 771 96 878 209 q 496 -17 665 -17 l 496 -279 m 496 93 l 514 93 q 687 183 623 93 q 746 380 746 265 q 691 569 746 491 q 522 658 629 658 l 496 656 l 496 93 "},";":{"x_min":0,"x_max":142,"ha":239,"o":"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 -12 q 105 -132 142 -82 q 0 -206 68 -182 l 0 -138 q 58 -82 43 -123 q 68 0 68 -56 l 0 0 l 0 151 l 142 151 l 142 -12 "},"f":{"x_min":0,"x_max":378,"ha":472,"o":"m 378 638 l 246 638 l 246 0 l 121 0 l 121 638 l 0 638 l 0 738 l 121 738 q 137 935 121 887 q 290 1028 171 1028 q 320 1027 305 1028 q 378 1021 334 1026 l 378 908 q 323 918 346 918 q 257 870 273 918 q 246 780 246 840 l 246 738 l 378 738 l 378 638 "},"“":{"x_min":1,"x_max":348.21875,"ha":454,"o":"m 140 670 l 1 670 l 1 830 q 37 943 1 897 q 140 1011 74 990 l 140 947 q 82 900 97 940 q 68 810 68 861 l 140 810 l 140 670 m 348 670 l 209 670 l 209 830 q 245 943 209 897 q 348 1011 282 990 l 348 947 q 290 900 305 940 q 276 810 276 861 l 348 810 l 348 670 "},"A":{"x_min":0.03125,"x_max":906.953125,"ha":1008,"o":"m 906 0 l 756 0 l 648 303 l 251 303 l 142 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 610 421 l 452 867 l 293 421 l 610 421 "},"6":{"x_min":53,"x_max":739,"ha":792,"o":"m 739 312 q 633 62 739 162 q 400 -31 534 -31 q 162 78 257 -31 q 53 439 53 206 q 178 859 53 712 q 441 986 284 986 q 643 912 559 986 q 732 713 732 833 l 601 713 q 544 830 594 786 q 426 875 494 875 q 268 793 331 875 q 193 517 193 697 q 301 597 240 570 q 427 624 362 624 q 643 540 552 624 q 739 312 739 451 m 603 298 q 540 461 603 400 q 404 516 484 516 q 268 461 323 516 q 207 300 207 401 q 269 137 207 198 q 405 83 325 83 q 541 137 486 83 q 603 298 603 197 "},"‘":{"x_min":1,"x_max":139.890625,"ha":236,"o":"m 139 670 l 1 670 l 1 830 q 37 943 1 897 q 139 1011 74 990 l 139 947 q 82 900 97 940 q 68 810 68 861 l 139 810 l 139 670 "},"ϊ":{"x_min":-70,"x_max":283,"ha":361,"o":"m 283 800 l 173 800 l 173 925 l 283 925 l 283 800 m 40 800 l -70 800 l -70 925 l 40 925 l 40 800 m 283 3 q 232 -10 257 -5 q 181 -15 206 -15 q 84 26 118 -15 q 41 200 41 79 l 41 737 l 166 737 l 167 215 q 171 141 167 157 q 225 101 182 101 q 247 103 238 101 q 283 112 256 104 l 283 3 "},"π":{"x_min":-0.21875,"x_max":773.21875,"ha":857,"o":"m 773 -7 l 707 -11 q 575 40 607 -11 q 552 174 552 77 l 552 226 l 552 626 l 222 626 l 222 0 l 97 0 l 97 626 l 0 626 l 0 737 l 773 737 l 773 626 l 676 626 l 676 171 q 695 103 676 117 q 773 90 714 90 l 773 -7 "},"ά":{"x_min":0,"x_max":765.5625,"ha":809,"o":"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 727 407 760 q 563 637 524 695 l 563 738 l 685 738 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 95 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 m 604 1040 l 415 819 l 332 819 l 466 1040 l 604 1040 "},"O":{"x_min":0,"x_max":958,"ha":1057,"o":"m 485 1041 q 834 882 702 1041 q 958 512 958 734 q 834 136 958 287 q 481 -26 702 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 728 q 485 1041 263 1041 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 669 q 480 912 640 912 q 226 784 321 912 q 142 504 142 670 q 226 224 142 339 q 480 98 319 98 "},"n":{"x_min":0,"x_max":615,"ha":724,"o":"m 615 463 l 615 0 l 490 0 l 490 454 q 453 592 490 537 q 331 656 410 656 q 178 585 240 656 q 117 421 117 514 l 117 0 l 0 0 l 0 738 l 117 738 l 117 630 q 218 728 150 693 q 359 764 286 764 q 552 675 484 764 q 615 463 615 593 "},"3":{"x_min":54,"x_max":737,"ha":792,"o":"m 737 284 q 635 55 737 141 q 399 -25 541 -25 q 156 52 248 -25 q 54 308 54 140 l 185 308 q 245 147 185 202 q 395 96 302 96 q 539 140 484 96 q 602 280 602 190 q 510 429 602 390 q 324 454 451 454 l 324 565 q 487 584 441 565 q 565 719 565 617 q 515 835 565 791 q 395 879 466 879 q 255 824 307 879 q 203 661 203 769 l 78 661 q 166 909 78 822 q 387 992 250 992 q 603 921 513 992 q 701 723 701 844 q 669 607 701 656 q 578 524 637 558 q 696 434 655 499 q 737 284 737 369 "},"9":{"x_min":53,"x_max":739,"ha":792,"o":"m 739 524 q 619 94 739 241 q 362 -32 516 -32 q 150 47 242 -32 q 59 244 59 126 l 191 244 q 246 129 191 176 q 373 82 301 82 q 526 161 466 82 q 597 440 597 255 q 363 334 501 334 q 130 432 216 334 q 53 650 53 521 q 134 880 53 786 q 383 986 226 986 q 659 841 566 986 q 739 524 739 719 m 388 449 q 535 514 480 449 q 585 658 585 573 q 535 805 585 744 q 388 873 480 873 q 242 809 294 873 q 191 658 191 745 q 239 514 191 572 q 388 449 292 449 "},"l":{"x_min":41,"x_max":166,"ha":279,"o":"m 166 0 l 41 0 l 41 1013 l 166 1013 l 166 0 "},"¤":{"x_min":40.09375,"x_max":728.796875,"ha":825,"o":"m 728 304 l 649 224 l 512 363 q 383 331 458 331 q 256 363 310 331 l 119 224 l 40 304 l 177 441 q 150 553 150 493 q 184 673 150 621 l 40 818 l 119 898 l 267 749 q 321 766 291 759 q 384 773 351 773 q 447 766 417 773 q 501 749 477 759 l 649 898 l 728 818 l 585 675 q 612 618 604 648 q 621 553 621 587 q 591 441 621 491 l 728 304 m 384 682 q 280 643 318 682 q 243 551 243 604 q 279 461 243 499 q 383 423 316 423 q 487 461 449 423 q 525 553 525 500 q 490 641 525 605 q 384 682 451 682 "},"κ":{"x_min":0,"x_max":632.328125,"ha":679,"o":"m 632 0 l 482 0 l 225 384 l 124 288 l 124 0 l 0 0 l 0 738 l 124 738 l 124 446 l 433 738 l 596 738 l 312 466 l 632 0 "},"4":{"x_min":48,"x_max":742.453125,"ha":792,"o":"m 742 243 l 602 243 l 602 0 l 476 0 l 476 243 l 48 243 l 48 368 l 476 958 l 602 958 l 602 354 l 742 354 l 742 243 m 476 354 l 476 792 l 162 354 l 476 354 "},"p":{"x_min":0,"x_max":685,"ha":786,"o":"m 685 364 q 598 96 685 205 q 350 -23 504 -23 q 121 89 205 -23 l 121 -278 l 0 -278 l 0 738 l 121 738 l 121 633 q 220 726 159 691 q 351 761 280 761 q 598 636 504 761 q 685 364 685 522 m 557 371 q 501 560 557 481 q 330 651 437 651 q 162 559 223 651 q 108 366 108 479 q 162 177 108 254 q 333 87 224 87 q 502 178 441 87 q 557 371 557 258 "},"‡":{"x_min":0,"x_max":777,"ha":835,"o":"m 458 238 l 458 0 l 319 0 l 319 238 l 0 238 l 0 360 l 319 360 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 l 777 804 l 777 683 l 458 683 l 458 360 l 777 360 l 777 238 l 458 238 "},"ψ":{"x_min":0,"x_max":808,"ha":907,"o":"m 465 -278 l 341 -278 l 341 -15 q 87 102 180 -15 q 0 378 0 210 l 0 739 l 133 739 l 133 379 q 182 195 133 275 q 341 98 242 98 l 341 922 l 465 922 l 465 98 q 623 195 563 98 q 675 382 675 278 l 675 742 l 808 742 l 808 381 q 720 104 808 213 q 466 -13 627 -13 l 465 -278 "},"η":{"x_min":0.78125,"x_max":697,"ha":810,"o":"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 720 124 755 q 200 630 193 686 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 "}},"cssFontWeight":"normal","ascender":1189,"underlinePosition":-100,"cssFontStyle":"normal","boundingBox":{"yMin":-334,"xMin":-111,"yMax":1189,"xMax":1672},"resolution":1000,"original_font_information":{"postscript_name":"Helvetiker-Regular","version_string":"Version 1.00 2004 initial release","vendor_url":"http://www.magenta.gr/","full_font_name":"Helvetiker","font_family_name":"Helvetiker","copyright":"Copyright (c) Μagenta ltd, 2004","description":"","trademark":"","designer":"","designer_url":"","unique_font_identifier":"Μagenta ltd:Helvetiker:22-10-104","license_url":"http://www.ellak.gr/fonts/MgOpen/license.html","license_description":"Copyright (c) 2004 by MAGENTA Ltd. All Rights Reserved.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license (\"Fonts\") and associated documentation files (the \"Font Software\"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: \r\n\r\nThe above copyright and this permission notice shall be included in all copies of one or more of the Font Software typefaces.\r\n\r\nThe Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing the word \"MgOpen\", or if the modifications are accepted for inclusion in the Font Software itself by the each appointed Administrator.\r\n\r\nThis License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the \"MgOpen\" name.\r\n\r\nThe Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. \r\n\r\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL MAGENTA OR PERSONS OR BODIES IN CHARGE OF ADMINISTRATION AND MAINTENANCE OF THE FONT SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.","manufacturer_name":"Μagenta ltd","font_sub_family_name":"Regular"},"descender":-334,"familyName":"Helvetiker","lineHeight":1522,"underlineThickness":50}); \ No newline at end of file diff --git a/scripts/external/three/nodethree.js b/scripts/external/three/nodethree.js index b4bd217..8500b1d 100644 --- a/scripts/external/three/nodethree.js +++ b/scripts/external/three/nodethree.js @@ -1,4 +1,4 @@ -var Canvas = require('./canvas'); +var Canvas = require('canvas'); var self = {}; @@ -28595,7 +28595,7 @@ THREE.FontUtils = { divisions : 10, getFace : function() { - + console.log('THREE: ',this.faces) return this.faces[ this.face ][ this.weight ][ this.style ]; }, diff --git a/scripts/systems/client.js b/scripts/systems/client.js new file mode 100644 index 0000000..a95fb0e --- /dev/null +++ b/scripts/systems/client.js @@ -0,0 +1,355 @@ + + +elation.extend("engine.systems.client", function(args) { + elation.implement(this, elation.engine.systems.system); + + this.localSyncObjs = []; + this.lastUpdate = Date.now(); + this.lastMessage = null; + var UPDATE_INTERVAL = 25; // ms + var MAX_EXTRAP_TIME = 200; // ms + + this.system_attach = function(ev) { + console.log('INIT: networking client'); + this.world = this.engine.systems.world; + console.log('this.world:', this.world); + this.connection = new elation.engine.systems.client.connection({ + transport: 'webrtc', + host: 'dev.brandonhinshaw.us', + port: '9001' + }); + elation.events.add(this.connection.socket, 'new_message', elation.bind(this, this.onNewMessage)); + elation.events.add(this.world, 'world_thing_add', elation.bind(this, this.onNewThing)); + // elation.events.add(this.world, 'world_thing_remove', this.handleRemovedThing.bind(this)) + }; + + this.onNewThing = function(ev) { + console.log('new thing', ev.data.thing); + var thing = ev.data.thing; + console.log('hastag:',thing.hasTag('local_sync')) + if (thing.hasTag('local_sync')) { + console.log('local sync'); + elation.events.add(thing, 'thing_change', elation.bind(this, this.onThingChange)); + } + }; + + this.onThingChange = function(ev) { + var thing = ev.target; + if (!thing.hasTag('thing_changed')) { + thing.addTag('thing_changed'); + } + }; + + this.sendChanges = function() { + if (Date.now() - this.lastUpdate > UPDATE_INTERVAL) { + var changed = this.world.getThingsByTag('thing_changed'); + for (var i = 0; i < changed.length; i++) { + changed[i].removeTag('thing_changed'); + var msgdata = { + type: 'thing_changed', + data: { + thing: changed[i].serialize(), + } + }; + this.send(msgdata); + } + } + }; + + this.checkExtrapolation = function() { + var things = this.world.getThingsByTag('extrapolating'); + if (things.length > 0){ + for (var i = 0; i < things.length; i++) { + var thing = things[i]; + if (Date.now() - thing.lastUpdate > MAX_EXTRAP_TIME) { + console.log('nulling out extrapolation'); + thing.set('velocity', [0, 0, 0], false); + thing.set('acceleration', [0, 0, 0], false); + thing.set('angular', [0, 0, 0], false); + thing.refresh(); + thing.removeTag('extrapolating'); + } + } + } + }; + + this.onNewMessage = function(ev) { + var msgdata = JSON.parse(ev.data); + var timestamp = msgdata.timestamp; + if (!this.lastMessage) { this.lastMessage = timestamp; } + if (timestamp >= this.lastMessage) { + // console.log('new message', msg, typeof(msg)); + var evdata = { type: msgdata.type, data: msgdata.data }; + elation.events.fire(evdata); + } else { console.log('discarded a message') } + }; + + this.send = function(data) { + // console.log('sending data', data); + data.timestamp = Date.now(); + this.connection.send(data); + // console.log('networking: sent data:', data); + }; + + this.engine_frame = function(ev) { + // this.sendMessages(); + // this.connection.send('ping'); + + this.checkExtrapolation(); + this.sendChanges(); + }; + + this.engine_stop = function(ev) { + console.log('SHUTDOWN: networking'); + this.connection.close(); + this.connection = null; + }; +}); + +// client connection objects + +elation.extend('engine.systems.client.connection', function(opts) { + // a transport-agnostic object representing the connection from the client + // to the server. + // + // should take opts for transport, server host, server port + // expose send() + // fire events on connection, disconnection, and received messages + + var socketOpts = { host: opts.host, port: opts.port }; + this.init = function() { + if (opts.transport == 'websocket') { + this.socket = new elation.engine.systems.client.websocket(socketOpts); + } + if (opts.transport == 'webrtc') { + this.socket = new elation.engine.systems.client.webrtc(socketOpts); + } + + }; + + this.send = function(data) { + this.socket.send(data); + }; + + this.init(); +}); + +elation.extend('engine.systems.client.websocket', function(opts) { + this.address = 'ws://' + opts.address + opts.port; + + this.init = function() { + this.connect(); + }; + + this.connect = function() { + if (!this.websocket) { + this.websocket = new WebSocket(this.address); + elation.events.add(this.websocket, "open", elation.bind(this, this.onOpen)); + elation.events.add(this.websocket, "message", elation.bind(this, this.onMessage)); + elation.events.add(this.websocket, "close", elation.bind(this, this.onClose)); + } + }; + + this.close = function() { + if (this.websocket) { + this.websocket.close(); + this.websocket = null; + } + }; + + this.send = function(data) { + this.websocket.send(data); + }; + + this.onOpen = function(ev) { + this.connected = true; + elation.events.fire({type: 'socket_connected'}); + }; + + this.onMessage = function(ev) { + elation.events.fire({type: 'new_message', data: ev.data}); + }; + + this.onClose = function(ev) { + elation.events.fire({type: 'socket_closed'}); + this.websocket = null; + }; + +}); + +elation.extend('engine.systems.client.webrtc', function(socketOpts) { + // TODO: + // take opts address and port + // expose connect(), send(data), and close(); + // fire socket_connected, new_message, socket_closed + + this.connect = function() { + doCreateDataChannels(); + }; + + this.init = function() { + this.connect(); + }; + + this.send = function(data) { + dataChannels['reliable'].send(JSON.stringify(data)); + }; + + var host = socketOpts.host || window.location.host.split(':')[0]; + var bridge = socketOpts.host + ':' + socketOpts.port || window.location.toString().split('?')[1]; + + // TODO: add other vender prefixes + var RTCPeerConnection = window.webkitRTCPeerConnection || + window.mozRTCPeerConnection || + window.RTCPeerConnection; + + var RTCSessionDescription = window.RTCSessionDescription || + window.mozRTCSessionDescription; + + var RTCIceCandidate = window.RTCIceCandidate || + window.mozRTCIceCandidate; + + var dataChannelSettings = { + 'reliable': { + ordered: false, + maxRetransmits: 0 + }, + // 'unreliable': {} + }; + + var pendingDataChannels = {}; + var dataChannels = {}; + var pendingCandidates = []; + + function doHandleError(error) { + throw error; + } + + function doComplete() { + console.log('complete'); + elation.events.fire({type: 'socket_connected'}); + } + + function doWaitforDataChannels() { + console.log('awaiting data channels'); + } + + this.channel = null; + var ws = null; + var pc = new RTCPeerConnection({ iceServers: [{ url:'stun:stun.l.google.com:19302' }] }, { 'optional': [] }); + + // pc.onsignalingstatechange = function(event) { + // console.info("signaling state change: ", event.target.signalingState); + // }; + // pc.oniceconnectionstatechange = function(event) { + // console.info("ice connection state change: ", event.target.iceConnectionState); + // }; + // pc.onicegatheringstatechange = function(event) { + // console.info("ice gathering state change: ", event.target.iceGatheringState); + // }; + + pc.onicecandidate = function(event) { + var candidate = event.candidate; + if(!candidate) return; + if(WebSocket.OPEN == ws.readyState) { + ws.send(JSON.stringify( + {'type': 'ice', + 'sdp': {'candidate': candidate.candidate, 'sdpMid': candidate.sdpMid, 'sdpMLineIndex': candidate.sdpMLineIndex} + })); + } + else { + pendingCandidates.push(candidate); + } + }; + + function doCreateDataChannels() { + var labels = Object.keys(dataChannelSettings); + labels.forEach(function(label) { + var channelOptions = dataChannelSettings[label]; + var channel = pendingDataChannels[label] = pc.createDataChannel(label, channelOptions); + channel.binaryType = 'arraybuffer'; + channel.onopen = function() { + this.channel = channel; + console.info('onopen'); + dataChannels[label] = channel; + delete pendingDataChannels[label]; + if(Object.keys(dataChannels).length === labels.length) { + doComplete(); + } + }.bind(this); + channel.onmessage = function(event) { + elation.events.fire({ type: 'new_message', data: event.data }); + // if('string' == typeof data) { + // console.log('onmessage:', data); + // } else { + // console.log('onmessage:', new Uint8Array(data)); + // } + }; + channel.onclose = function(event) { + console.info('onclose'); + elation.events.fire({type:'socket_closed'}); + }; + channel.onerror = doHandleError; + }); + doCreateOffer(); + } + + function doCreateOffer() { + pc.createOffer( + doSetLocalDesc, + doHandleError + ); + } + + function doSetLocalDesc(desc) { + pc.setLocalDescription( + new RTCSessionDescription(desc), + doSendOffer.bind('test', desc), + doHandleError + ); + } + + function doSendOffer(offer) { + ws = new WebSocket("ws://" + bridge); + ws.onopen = function() + { + pendingCandidates.forEach(function(candidate) + { + ws.send(JSON.stringify( + {'type': 'ice', + 'sdp': {'candidate': candidate.candidate, 'sdpMid': candidate.sdpMid, 'sdpMLineIndex': candidate.sdpMLineIndex} + }) + ); + }); + ws.send(JSON.stringify( + {'type': offer.type, 'sdp': offer.sdp}) + ); + }; + ws.onmessage = function(event) { + // console.log(candidate); + var data = JSON.parse(event.data); + if('answer' == data.type) { + doSetRemoteDesc(data); + } + else if('ice' == data.type && data.sdp.candidate) { + var candidate = new RTCIceCandidate(data.sdp.candidate); + if(candidate.candidate) { + pc.addIceCandidate(candidate, handleAddIceCandidateSuccess, handleAddIceCandidateError); + } + } + }; + } + + function handleAddIceCandidateSuccess() { } + + function handleAddIceCandidateError() { } + + function doSetRemoteDesc(desc) { + pc.setRemoteDescription( + new RTCSessionDescription(desc), + doWaitforDataChannels, + doHandleError + ); + } + this.init(); +}); diff --git a/scripts/systems/networking.js b/scripts/systems/networking.js deleted file mode 100644 index 2a728fa..0000000 --- a/scripts/systems/networking.js +++ /dev/null @@ -1,177 +0,0 @@ -elation.extend("engine.systems.networking.client", function(args) { - - if (ENV_IS_NODE) { - this.server = true; - } - else if (ENV_IS_BROWSER) { - this.client = true; - } - elation.implement(this, elation.engine.systems.system); - this.connected = false; - this.websocket = new WebSocket("ws://ec2-54-201-16-112.us-west-2.compute.amazonaws.com:8080"); - this.connection = this.websocket; - this.tagged = []; - this.toSend = []; - - this.remotePlayers = {}; - - this.websocket.onopen = function() { - this.connected = true; - console.log('networking: connected to server'); - }.bind(this); - - this.websocket.onmessage = function(ev) { - this.newMessage(JSON.parse(ev.data)); - }.bind(this); - - - this.system_attach = function(ev) { - console.log('INIT: networking'); - this.world = this.engine.systems.world; - elation.events.add(this.world, 'engine_thing_create,world_thing_add', this.handleNewThing.bind(this)); - elation.events.add(this.world, 'world_thing_remove', this.handleRemovedThing.bind(this)) - }; - - this.handleNewThing = function(ev) { - if (ev.data.thing.hasTag('networking_local_sync')) { - this.tagged.push(ev.data.thing); - console.log('networking: tagged - ', this.tagged); - if (ev.data.thing.componentname == 'engine.things.vrcadeplayer') { - // TODO: better handling of local player vs remote player - ev.data.thing.network_id = Math.floor(Math.random() * 10000); // TODO - this.addToMessages({type: 'new_player', position: ev.data.thing.properties.position.toArray(), network_id: ev.data.thing.network_id}); - elation.events.add(ev.data.thing, 'thing_change', this.handleChange.bind(this)); - } - else { - this.addToMessages({type: 'new_thing', position: ev.data.thing.properties.position.toArray()}); - } - } - }; - - - this.newMessage = function(msg) { - if (msg.type == "new_player") { - var remotePlayer = this.world.spawn('remoteplayer', 'player' + msg.network_id, {'position': msg.position, 'collidable': false}); - this.remotePlayers[msg.network_id] = remotePlayer; - } - else if (msg.type = "thing_change") { - if (this.remotePlayers[msg.network_id]) { - this.remotePlayers[msg.network_id].properties.position.set(msg.position[0], msg.position[1], msg.position[2]); - this.remotePlayers[msg.network_id].refresh(); - } - } - - }; - - this.handleChange = function(ev) { - this.addToMessages({type: 'thing_change', position: ev.target.properties.position.toArray(), network_id: ev.target.network_id}); - // console.log(ev.target.properties.position.toArray()); - }; - - this.handleRemovedThing = function(ev) { - if (this.tagged.indexOf(ev.data.thing) !== -1) { - // TODO: splice it out - } - }; - this.send = function(data) { - this.connection.send(data); - // console.log('networking: sent data:', data); - }; - - this.addToMessages = function(data) { - this.toSend.push(data); - }; - - this.sendMessages = function() { - if (this.toSend.length > 0 && this.connected) { - for (var i = 0; i < this.toSend.length; i++) { - this.send(JSON.stringify(this.toSend[i])); - } - this.toSend = []; - } - }; - - this.engine_frame = function(ev) { - this.sendMessages(); - }; - - this.engine_stop = function(ev) { - console.log('SHUTDOWN: networking'); - this.websocket.close(); - this.websocket = null; - }; -}); - -// client connection objects - -elation.extend('engine.systems.networking.client.connection', function(opts) { - // a transport-agnostic object representing the connection from the client - // to the server. - // - // should take opts for transport, server host, server port - // expose send() - // fire events on connection, disconnection, and received messages - - var socketOpts = { host: opts.host, port: opts.port }; - if (opts.transport == 'websocket') { - this.socket = new engine.systems.networking.websocket(socketOpts); - } - if (opts.transport == 'webrtc') { - this.socket = new engine.systems.networking.webrtc(socketOpts); - } - - this.send = function(data) { - this.socket.send(data); - }; - -}); - -elation.extend('engine.systems.networking.websocket', function(opts) { - this.address = 'ws://' + opts.address + opts.port; - - this.init = function() { - this.connect(); - }; - - this.connect = function() { - if (!this.websocket) { - this.websocket = new WebSocket(this.address); - elation.events.add(this.websocket, "open", elation.bind(this, this.onOpen)); - elation.events.add(this.websocket, "message", elation.bind(this, this.onMessage)); - elation.events.add(this.websocket, "close", elation.bind(this, this.onClose)); - } - }; - - this.close = function() { - if (this.websocket) { - this.websocket.close(); - this.websocket = null; - } - }; - - this.send = function(data) { - this.websocket.send(data); - }; - - this.onOpen = function(ev) { - this.connected = true; - elation.events.fire({type: 'socket_connected'}); - }; - - this.onMessage = function(ev) { - elation.events.fire({type: 'new_message', data: ev.data}); - }; - - this.onClose = function(ev) { - elation.events.fire({type: 'socket_closed'}); - this.websocket = null; - }; - -}); - -elation.extend('engine.systems.networking.webrtc', function() { - // TODO: - // take opts address and port - // expose connect(), send(data), and close(); - // fire socket_connected, new_message, socket_closed -}); diff --git a/scripts/systems/server.js b/scripts/systems/server.js new file mode 100644 index 0000000..e2c181c --- /dev/null +++ b/scripts/systems/server.js @@ -0,0 +1,309 @@ +elation.extend("engine.systems.server", function(args) { + elation.implement(this, elation.engine.systems.system); + var wrtc = require('wrtc'); + this.clients = {}; + this.transport = 'webrtc'; + + this.system_attach = function(ev) { + console.log('INIT: networking server'); + this.world = this.engine.systems.world; + this.webrtc = new elation.engine.systems.server.webrtc; + + var events = [ + [this.webrtc, 'client_disconnected', this.onClientConnect], + [this.webrtc, 'client_connected', this.onClientConnect], + [this.world, 'world_thing_remove', this.onThingRemove], + [this.world, 'world_thing_add', this.onThingAdd], + // [this.world, 'world_thing_change', this.onThingChange] + ]; + + for (var i = 0; i < events.length; i++) { + this.addEvent(events[i]) + }; + }; + + this.addEvent = function(args) { + elation.events.add(args[0], args[1], elation.bind(this, args[2])); + }; + + this.serialize_world = function() { + var worldmsg = { + type: 'world_data', + data: this.world.serialize(true) + }; + return worldmsg; + }; + + this.engine_frame = function() { + + }; + + this.sendToAll = function(data) { + for (var client in this.clients) { + if (this.clients.hasOwnProperty(client)) { + this.clients[client].send(data); + } + } + } + + this.onClientConnect = function(ev) { + var client = new elation.engine.systems.server.client({ + transport: 'webrtc', + id: ev.data.id, + socket: ev.data.channel + }); + this.clients[ev.data.id] = client; + elation.events.add(client, 'received_id', elation.bind(this, this.sendWorldData)); + elation.events.add(client, 'new_player', elation.bind(this, this.handleNewPlayer)); + elation.events.add(client, 'thing_changed', elation.bind(this, this.onRemoteThingChange)); + console.log('client connected', client.id); + client.send({ type: 'id_token', data: client.id }); + }; + + this.handleNewPlayer = function(ev) { + // console.log(ev); + elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing}}); + } + + this.sendWorldData = function(evt) { + // console.log('got id', evt); + var client = this.clients[evt.data.data]; + client.send(this.serialize_world()); + }; + + this.onThingAdd = function(ev) { + console.log('thing add', ev.data.thing.name); + this.sendToAll({ type: 'thing_added', data: ev.data.thing.serialize() }); + }; + + this.onThingRemove = function(ev) { + console.log('thing remove', ev.data.thing.name); + this.sendToAll({ type:'thing_removed', data: ev.data.thing.name }); + }; + + this.onThingChange = function(ev) { + // console.log('world thing changed', ev.target.serialize()); + var msg = { type: 'thing_changed', data: ev.target.serialize() }; + if (this.clients.hasOwnProperty(ev.target.name)) { + for (var client in this.clients) { + if (this.clients.hasOwnProperty(client) && client != ev.target.name) { + // console.log('sending msg to', client, 'about change in', ev.target.name); + this.clients[client].send(msg); + } + } + } + else { + // console.log('sending to all'); + this.sendToAll(msg); + } + } + + this.onRemoteThingChange = function(ev) { + elation.events.fire('remote_thing_change', ev.data); + } + + this.removeClient = function(id) { + delete this.clients[id]; + }; + + this.onClientDisconnect = function(ev) { + // console.log(ev); + var client = this.clients[ev.data]; + elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); + elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); + this.removeClient(ev.data); + elation.events.fire({type: 'destroy_player', data: ev.data}); + console.log('Client disconnected, num clients:', Object.keys(this.clients).length); + }; + +}); + +elation.extend("engine.systems.server.client", function(args) { + /** + * This object represents a client connection + * + */ + this.transport = args.transport; + this.id = args.id; + this.socket = args.socket; + this.lastMessage = null; + + this.send = function(data) { + if (this.socket.readyState == 'open') { + // console.log('sent a msg'); + data.timestamp = Date.now(); + this.socket.send(JSON.stringify(data)); + } + }; + + this.socket.onmessage = function(evt) { + var msgdata = JSON.parse(evt.data); + var timestamp = msgdata.timestamp; + if (!this.lastMessage) this.lastMessage = timestamp; + if (timestamp >= this.lastMessage) { + // only fire an event if the message is newer than the last received msg + var evdata = { + type: msgdata.type, + data: { id: this.id, data: msgdata.data } + }; + elation.events.fire(evdata); + this.lastMessage = timestamp; + } else { console.log('discarded a message'); } + }; + +}); + +elation.extend("engine.systems.server.webrtc", function() { + var http = require('http'); + var webrtc = require('wrtc'); + var ws = require('ws'); + var net = require('net'); + + // var args = require('minimist')(process.argv.slice(2)); + var MAX_REQUEST_LENGTH = 1024; + var pc = null, + offer = null, + answer = null, + remoteReceived = false; + + var dataChannelsettings = { + // 'reliable': { + // ordered: false, + // maxRetransmits: 0 + // } + 'unreliable': {} + }; + + this.pendingDataChannels = [], + this.dataChannels = [], + this.pendingCandidates = []; + + var socketPort = 9001; + var self = this; + + var wss = new ws.Server({'port': 9001}); + wss.on('connection', function(ws) { + function doComplete(chan) { + console.info('complete'); + } + function doHandleError(error) { + throw error; + } + function doCreateAnswer() { + remoteReceived = true; + self.pendingCandidates.forEach(function(candidate) { + if (candidate.sdp) { + pc.addIceCandidate(new webrtc.RTCIceCandidate(candidate.sdp)); + } + }); + pc.createAnswer(doSetLocalDesc, doHandleError); + } + function doSetLocalDesc(desc) { + answer = desc; + pc.setLocalDescription(desc, doSendAnswer, doHandleError); + } + function doSendAnswer() { + ws.send(JSON.stringify(answer)); + console.log('awaiting data channels'); + } + + function doHandledataChannels() { + var labels = Object.keys(dataChannelsettings); + pc.ondatachannel = function(evt) { + var channel = evt.channel; + var id = Date.now(); + console.log('ondatachannel', channel.label, channel.readyState); + self.pendingDataChannels.push(channel); + + channel.binaryType = 'arraybuffer'; + + channel.onopen = function() { + self.dataChannels.push(channel); + self.pendingDataChannels.splice(self.pendingDataChannels.indexOf(channel), 1); + elation.events.fire({ type: 'client_connected', data: {id: id, channel: channel}}); + doComplete(self.dataChannels[self.dataChannels.indexOf(channel)]); + // } + }; + + channel.onmessage = function(evt) { + var msgdata = JSON.parse(evt.data); + console.log('onmessage:', evt.data); + var evdata = { + type: msgdata.type, + data: { + id: id, + data: msgdata.data + } + } + elation.events.fire(evdata); + }; + + channel.onclose = function() { + self.dataChannels.splice(self.dataChannels.indexOf(channel), 1); + elation.events.fire({type: 'client_disconnected', data: {id: id, channel: channel}}) + console.info('onclose'); + }; + + channel.onerror = doHandleError; + }; + + doSetRemoteDesc(); + }; + + function doSetRemoteDesc() { + // console.info(offer); + pc.setRemoteDescription( + offer, + doCreateAnswer, + doHandleError + ); + }; + + ws.on('message', function(data) { + data = JSON.parse(data); + if('offer' == data.type) { + offer = new webrtc.RTCSessionDescription(data); + answer = null; + remoteReceived = false; + + pc = new webrtc.RTCPeerConnection( + { iceServers: [{ url:'stun:stun.l.google.com:19302' }] }, + { 'optional': [{DtlsSrtpKeyAgreement: false}] } + ); + + pc.onsignalingstatechange = function(state) { + console.info('signaling state change:', state); + }; + + pc.oniceconnectionstatechange = function(state) { + console.info('ice connection state change:', state); + }; + + pc.onicegatheringstatechange = function(state) { + console.info('ice gathering state change:', state); + }; + + pc.onicecandidate = function(candidate) { + // console.log('onicecandidate', candidate); + ws.send(JSON.stringify( + {'type': 'ice', + 'sdp': {'candidate': candidate.candidate, 'sdpMid': candidate.sdpMid, 'sdpMLineIndex': candidate.sdpMLineIndex} + })); + }; + + doHandledataChannels(); + } + else if('ice' == data.type) { + if(remoteReceived) { + if(data.sdp.candidate) { + pc.addIceCandidate(new webrtc.RTCIceCandidate(data.sdp.candidate)); + } + } + else { + self.pendingCandidates.push(data); + } + } + }.bind(this)); + }.bind(this)); + +}); \ No newline at end of file diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 708e524..4f3a175 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -416,7 +416,7 @@ elation.component.add("engine.things.generic", function() { if (this.objects['3d'] && thing.objects['3d']) { this.objects['3d'].remove(thing.objects['3d']); } - if (thing.container.parentNode) { + if (thing.container && thing.container.parentNode) { thing.container.parentNode.removeChild(thing.container); } if (thing.objects['dynamics'] && thing.objects['dynamics'].parent) { diff --git a/scripts/things/remoteplayer.js b/scripts/things/remoteplayer.js new file mode 100644 index 0000000..2efae55 --- /dev/null +++ b/scripts/things/remoteplayer.js @@ -0,0 +1,13 @@ + +elation.require(['engine.things.generic'], function() { + +elation.component.add('engine.things.remoteplayer', function() { + this.createObject3D = function() { + // var geo = new THREE.SphereGeometry(1); + var geo = new THREE.BoxGeometry(1, 1, 1); + var mat = new THREE.MeshPhongMaterial({color: 0x00ff00}); + return new THREE.Mesh(geo, mat); + } +}, elation.engine.things.generic); + +}); From 409456b8fea051b267d4ce789f71431cbd1a98ae Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Apr 2015 01:20:17 -0400 Subject: [PATCH 05/43] cleanup after rebase --- scripts/things/generic.js | 1 - scripts/things/player.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 4f3a175..a1a4e27 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -285,7 +285,6 @@ elation.component.add("engine.things.generic", function() { this.createObject3D = function() { if (this.properties.exists === false || !ENV_IS_BROWSER) return; var object = null, geometry = null, material = null; - if (this.properties.render) { if (this.properties.render.scene) { this.loadJSONScene(this.properties.render.scene, this.properties.render.texturepath); diff --git a/scripts/things/player.js b/scripts/things/player.js index a8f5c28..39afb87 100644 --- a/scripts/things/player.js +++ b/scripts/things/player.js @@ -3,7 +3,7 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' this.targetrange = 1.8; this.postinit = function() { if (this.engine.systems.controls) { - this.controlstate = this.engine.systems.controls.addContext('player', { + this.controlstate = this.engine.systems.controls.addContext('player', { 'move_forward': ['keyboard_w', elation.bind(this, this.updateControls)], 'move_backward': ['keyboard_s,gamepad_0_axis_1', elation.bind(this, this.updateControls)], 'move_left': ['keyboard_a', elation.bind(this, this.updateControls)], From 28461376d3de81a89f31cc083fe76a8bc2aefbdf Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Apr 2015 02:37:39 -0400 Subject: [PATCH 06/43] repack nodethree.js with three.js 72dev --- scripts/external/three/nodethree.js | 44851 ++++++++++++-------------- 1 file changed, 20879 insertions(+), 23972 deletions(-) diff --git a/scripts/external/three/nodethree.js b/scripts/external/three/nodethree.js index 8500b1d..687bf20 100644 --- a/scripts/external/three/nodethree.js +++ b/scripts/external/three/nodethree.js @@ -21,62 +21,46 @@ var document = { } }; +// File:src/Three.js + /** * @author mrdoob / http://mrdoob.com/ - * @author Larry Battle / http://bateru.com/news - * @author bhouston / http://exocortex.com */ -var THREE = { REVISION: '67dev' }; - -self.console = self.console || { - - info: function () {}, - log: function () {}, - debug: function () {}, - warn: function () {}, - error: function () {} +var THREE = { REVISION: '72dev' }; -}; +// browserify support -// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ -// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating +if ( typeof module === 'object' ) { -// requestAnimationFrame polyfill by Erik Möller -// fixes from Paul Irish and Tino Zijdel -// using 'self' instead of 'window' for compatibility with both NodeJS and IE10. -( function () { + module.exports = THREE; - var lastTime = 0; - var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; +} - for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { +// polyfills - self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; - self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; +if ( Math.sign === undefined ) { - } + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign - if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { + Math.sign = function ( x ) { - self.requestAnimationFrame = function ( callback ) { + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x; - var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); - var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); - lastTime = currTime + timeToCall; - return id; + }; - }; +} - } - if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { +// set the default log handlers +THREE.log = function() { console.log.apply( console, arguments ); } +THREE.warn = function() { console.warn.apply( console, arguments ); } +THREE.error = function() { console.error.apply( console, arguments ); } - self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; - } +// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button -}() ); +THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; // GL STATE CONSTANTS @@ -130,6 +114,8 @@ THREE.CustomBlending = 5; THREE.AddEquation = 100; THREE.SubtractEquation = 101; THREE.ReverseSubtractEquation = 102; +THREE.MinEquation = 103; +THREE.MaxEquation = 104; // custom blending destination factors @@ -163,13 +149,15 @@ THREE.AddOperation = 2; // Mapping modes -THREE.UVMapping = function () {}; +THREE.UVMapping = 300; -THREE.CubeReflectionMapping = function () {}; -THREE.CubeRefractionMapping = function () {}; +THREE.CubeReflectionMapping = 301; +THREE.CubeRefractionMapping = 302; -THREE.SphericalReflectionMapping = function () {}; -THREE.SphericalRefractionMapping = function () {}; +THREE.EquirectangularReflectionMapping = 303; +THREE.EquirectangularRefractionMapping = 304; + +THREE.SphericalReflectionMapping = 305; // Wrapping modes @@ -195,6 +183,7 @@ THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; +THREE.HalfFloatType = 1025; // Pixel types @@ -210,21 +199,66 @@ THREE.RGBFormat = 1020; THREE.RGBAFormat = 1021; THREE.LuminanceFormat = 1022; THREE.LuminanceAlphaFormat = 1023; +// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders +THREE.RGBEFormat = THREE.RGBAFormat; //1024; -// Compressed texture formats +// DDS / ST3C Compressed texture formats THREE.RGB_S3TC_DXT1_Format = 2001; THREE.RGBA_S3TC_DXT1_Format = 2002; THREE.RGBA_S3TC_DXT3_Format = 2003; THREE.RGBA_S3TC_DXT5_Format = 2004; -/* -// Potential future PVRTC compressed texture formats + +// PVRTC compressed texture formats + THREE.RGB_PVRTC_4BPPV1_Format = 2100; THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; -*/ + + +// DEPRECATED + +THREE.Projector = function () { + + THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + + this.projectVector = function ( vector, camera ) { + + THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + vector.project( camera ); + + }; + + this.unprojectVector = function ( vector, camera ) { + + THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + vector.unproject( camera ); + + }; + + this.pickingRay = function ( vector, camera ) { + + THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + + }; + +}; + +THREE.CanvasRenderer = function () { + + THREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); + + this.domElement = document.createElement( 'canvas' ); + this.clear = function () {}; + this.render = function () {}; + this.setClearColor = function () {}; + this.setSize = function () {}; + +}; + +// File:src/math/Color.js /** * @author mrdoob / http://mrdoob.com/ @@ -232,406 +266,420 @@ THREE.RGBA_PVRTC_2BPPV1_Format = 2103; THREE.Color = function ( color ) { - if ( arguments.length === 3 ) { + if ( arguments.length === 3 ) { - return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); + return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); - } + } - return this.set( color ) + return this.set( color ) }; THREE.Color.prototype = { - constructor: THREE.Color, + constructor: THREE.Color, + + r: 1, g: 1, b: 1, + + set: function ( value ) { + + if ( value instanceof THREE.Color ) { + + this.copy( value ); - r: 1, g: 1, b: 1, + } else if ( typeof value === 'number' ) { - set: function ( value ) { + this.setHex( value ); - if ( value instanceof THREE.Color ) { + } else if ( typeof value === 'string' ) { - this.copy( value ); + this.setStyle( value ); - } else if ( typeof value === 'number' ) { + } - this.setHex( value ); + return this; - } else if ( typeof value === 'string' ) { + }, - this.setStyle( value ); + setHex: function ( hex ) { - } + hex = Math.floor( hex ); - return this; + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - }, + return this; - setHex: function ( hex ) { + }, - hex = Math.floor( hex ); + setRGB: function ( r, g, b ) { - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + this.r = r; + this.g = g; + this.b = b; - return this; + return this; - }, + }, - setRGB: function ( r, g, b ) { + setHSL: function ( h, s, l ) { - this.r = r; - this.g = g; - this.b = b; + // h,s,l ranges are in 0.0 - 1.0 - return this; + if ( s === 0 ) { - }, + this.r = this.g = this.b = l; - setHSL: function ( h, s, l ) { + } else { - // h,s,l ranges are in 0.0 - 1.0 + var hue2rgb = function ( p, q, t ) { - if ( s === 0 ) { + 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; - 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; - var hue2rgb = function ( p, q, t ) { + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - 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 this; - 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 ); + setStyle: function ( style ) { - } + // rgb(255,0,0) - return this; + if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { - }, + var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); - setStyle: function ( style ) { + 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; - // rgb(255,0,0) + return this; - if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { + } - var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); + // rgb(100%,0%,0%) - 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; + if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { - return this; + var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); - } + 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; - // rgb(100%,0%,0%) + return this; - if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { + } - var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); + // #ff0000 - 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; + if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { - return this; + var color = /^\#([0-9a-f]{6})$/i.exec( style ); - } + this.setHex( parseInt( color[ 1 ], 16 ) ); - // #ff0000 + return this; - if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { + } - var color = /^\#([0-9a-f]{6})$/i.exec( style ); + // #f00 - this.setHex( parseInt( color[ 1 ], 16 ) ); + if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { - return this; + var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); - } + this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); - // #f00 + return this; - if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { + } - var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); + // red - this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); + if ( /^(\w+)$/i.test( style ) ) { - return this; + this.setHex( THREE.ColorKeywords[ style ] ); - } + return this; - // red + } - if ( /^(\w+)$/i.test( style ) ) { - this.setHex( THREE.ColorKeywords[ style ] ); + }, - return this; + copy: function ( color ) { - } + this.r = color.r; + this.g = color.g; + this.b = color.b; + return this; - }, + }, - copy: function ( color ) { + copyGammaToLinear: function ( color, gammaFactor ) { - this.r = color.r; - this.g = color.g; - this.b = color.b; + if ( gammaFactor === undefined ) gammaFactor = 2.0; - return this; + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); - }, + return this; - copyGammaToLinear: function ( color ) { + }, - this.r = color.r * color.r; - this.g = color.g * color.g; - this.b = color.b * color.b; + copyLinearToGamma: function ( color, gammaFactor ) { - return this; + if ( gammaFactor === undefined ) gammaFactor = 2.0; - }, + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - copyLinearToGamma: function ( color ) { + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); - this.r = Math.sqrt( color.r ); - this.g = Math.sqrt( color.g ); - this.b = Math.sqrt( color.b ); + return this; - return this; + }, - }, + convertGammaToLinear: function () { - convertGammaToLinear: function () { + var r = this.r, g = this.g, b = this.b; - var r = this.r, g = this.g, b = this.b; + this.r = r * r; + this.g = g * g; + this.b = b * b; - this.r = r * r; - this.g = g * g; - this.b = b * b; + return this; - return this; + }, - }, + convertLinearToGamma: function () { - convertLinearToGamma: function () { + this.r = Math.sqrt( this.r ); + this.g = Math.sqrt( this.g ); + this.b = Math.sqrt( this.b ); - this.r = Math.sqrt( this.r ); - this.g = Math.sqrt( this.g ); - this.b = Math.sqrt( this.b ); + return this; - return this; + }, - }, + getHex: function () { - getHex: function () { + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + }, - }, + getHexString: function () { - getHexString: function () { + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + }, - }, + getHSL: function ( optionalTarget ) { - getHSL: function ( optionalTarget ) { + // h,s,l ranges are in 0.0 - 1.0 - // h,s,l ranges are in 0.0 - 1.0 + var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; - var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; + var r = this.r, g = this.g, b = this.b; - 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 max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); + var hue, saturation; + var lightness = ( min + max ) / 2.0; - var hue, saturation; - var lightness = ( min + max ) / 2.0; + if ( min === max ) { - if ( min === max ) { + hue = 0; + saturation = 0; - hue = 0; - saturation = 0; + } else { - } else { + var delta = max - min; - var delta = max - min; + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + switch ( max ) { - 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; - 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; - hue /= 6; + } - } + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; + return hsl; - return hsl; + }, - }, + getStyle: function () { - getStyle: function () { + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + }, - }, + offsetHSL: function ( h, s, l ) { - offsetHSL: function ( h, s, l ) { + var hsl = this.getHSL(); - var hsl = this.getHSL(); + hsl.h += h; hsl.s += s; hsl.l += l; - hsl.h += h; hsl.s += s; hsl.l += l; + this.setHSL( hsl.h, hsl.s, hsl.l ); - this.setHSL( hsl.h, hsl.s, hsl.l ); + return this; - return this; + }, - }, + add: function ( color ) { - add: function ( color ) { + this.r += color.r; + this.g += color.g; + this.b += color.b; - this.r += color.r; - this.g += color.g; - this.b += color.b; + return this; - return this; + }, - }, + addColors: function ( color1, color2 ) { - addColors: function ( color1, color2 ) { + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + return this; - return this; + }, - }, + addScalar: function ( s ) { - addScalar: function ( s ) { + this.r += s; + this.g += s; + this.b += s; - this.r += s; - this.g += s; - this.b += s; + return this; - return this; + }, - }, + multiply: function ( color ) { - multiply: function ( color ) { + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + return this; - return this; + }, - }, + multiplyScalar: function ( s ) { - multiplyScalar: function ( s ) { + this.r *= s; + this.g *= s; + this.b *= s; - this.r *= s; - this.g *= s; - this.b *= s; + return this; - return this; + }, - }, + lerp: function ( color, alpha ) { - 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; - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + return this; - return this; + }, - }, + equals: function ( c ) { - equals: function ( c ) { + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + }, - }, + fromArray: function ( array ) { - fromArray: function ( array ) { + this.r = array[ 0 ]; + this.g = array[ 1 ]; + this.b = array[ 2 ]; - this.r = array[ 0 ]; - this.g = array[ 1 ]; - this.b = array[ 2 ]; + return this; - return this; + }, - }, + toArray: function ( array, offset ) { - toArray: function () { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this.r, this.g, this.b ]; + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - }, + return array; + }, - clone: function () { + clone: function () { - return new THREE.Color().setRGB( this.r, this.g, this.b ); + return new THREE.Color().setRGB( this.r, this.g, this.b ); - } + } }; -THREE.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 }; +THREE.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 }; + +// File:src/math/Quaternion.js /** * @author mikael emtinger / http://gomo.se/ @@ -642,476 +690,522 @@ THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": THREE.Quaternion = function ( x, y, z, w ) { - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; }; THREE.Quaternion.prototype = { - constructor: THREE.Quaternion, + constructor: THREE.Quaternion, + + _x: 0,_y: 0, _z: 0, _w: 0, + + 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; - _x: 0,_y: 0, _z: 0, _w: 0, + }, - _euler: undefined, + set z ( value ) { - _updateEuler: function ( callback ) { + this._z = value; + this.onChangeCallback(); - if ( this._euler !== undefined ) { + }, - this._euler.setFromQuaternion( this, undefined, false ); + get w () { - } + return this._w; - }, + }, - get x () { + set w ( value ) { - return this._x; + this._w = value; + this.onChangeCallback(); - }, + }, - set x ( value ) { + set: function ( x, y, z, w ) { - this._x = value; - this._updateEuler(); + this._x = x; + this._y = y; + this._z = z; + this._w = w; - }, + this.onChangeCallback(); - get y () { + return this; - return this._y; + }, - }, + copy: function ( quaternion ) { - set y ( value ) { + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - this._y = value; - this._updateEuler(); + this.onChangeCallback(); - }, + return this; - get z () { + }, - return this._z; + setFromEuler: function ( euler, update ) { - }, + if ( euler instanceof THREE.Euler === false ) { - set z ( value ) { + throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a 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 ); + + if ( euler.order === 'XYZ' ) { - this._z = value; - this._updateEuler(); + 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 ( euler.order === 'YXZ' ) { - get w () { + 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; - return this._w; + } else if ( euler.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; - set w ( value ) { + } else if ( euler.order === 'ZYX' ) { - this._w = value; - this._updateEuler(); + 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 ( euler.order === 'YZX' ) { - set: function ( x, y, z, w ) { + 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; - this._x = x; - this._y = y; - this._z = z; - this._w = w; + } else if ( euler.order === 'XZY' ) { - this._updateEuler(); + 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; - return this; + } - }, + if ( update !== false ) this.onChangeCallback(); - copy: function ( quaternion ) { + return this; - this._x = quaternion._x; - this._y = quaternion._y; - this._z = quaternion._z; - this._w = quaternion._w; + }, - this._updateEuler(); + setFromAxisAngle: function ( axis, angle ) { - return this; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - }, + // assumes axis is normalized - setFromEuler: function ( euler, update ) { + var halfAngle = angle / 2, s = Math.sin( halfAngle ); - if ( euler instanceof THREE.Euler === false ) { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); - } + this.onChangeCallback(); - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m + return this; - 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 ); + }, - if ( euler.order === 'XYZ' ) { + setFromRotationMatrix: function ( m ) { - 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; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - } else if ( euler.order === 'YXZ' ) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - 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; + var te = m.elements, - } else if ( euler.order === 'ZXY' ) { + 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 ], - 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; + trace = m11 + m22 + m33, + s; - } else if ( euler.order === 'ZYX' ) { + if ( trace > 0 ) { - 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; + s = 0.5 / Math.sqrt( trace + 1.0 ); - } else if ( euler.order === 'YZX' ) { + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - 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 ( m11 > m22 && m11 > m33 ) { - } else if ( euler.order === 'XZY' ) { + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - 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; + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - } + } else if ( m22 > m33 ) { - if ( update !== false ) this._updateEuler(); + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - return this; + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - }, + } else { - setFromAxisAngle: function ( axis, angle ) { + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - // assumes axis is normalized + } - var halfAngle = angle / 2, s = Math.sin( halfAngle ); + this.onChangeCallback(); - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + return this; - this._updateEuler(); + }, - return this; + setFromUnitVectors: function () { - }, + // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final - setFromRotationMatrix: function ( m ) { + // assumes direction vectors vFrom and vTo are normalized - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + var v1, r; - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + var EPS = 0.000001; - var te = m.elements, + return function ( vFrom, vTo ) { - 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 ( v1 === undefined ) v1 = new THREE.Vector3(); - trace = m11 + m22 + m33, - s; + r = vFrom.dot( vTo ) + 1; - if ( trace > 0 ) { + if ( r < EPS ) { - s = 0.5 / Math.sqrt( trace + 1.0 ); + r = 0; - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - } else if ( m11 > m22 && m11 > m33 ) { + v1.set( - vFrom.y, vFrom.x, 0 ); - s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + } else { - this._w = (m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = (m12 + m21 ) / s; - this._z = (m13 + m31 ) / s; + v1.set( 0, - vFrom.z, vFrom.y ); - } else if ( m22 > m33 ) { + } - s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + } else { - this._w = (m13 - m31 ) / s; - this._x = (m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = (m23 + m32 ) / s; + v1.crossVectors( vFrom, vTo ); - } else { + } - s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + this._x = v1.x; + this._y = v1.y; + this._z = v1.z; + this._w = r; - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + this.normalize(); - } + return this; - this._updateEuler(); + } - return this; + }(), - }, + inverse: function () { - setFromUnitVectors: function () { + this.conjugate().normalize(); - // http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors + return this; - // assumes direction vectors vFrom and vTo are normalized + }, - var v1; + conjugate: function () { - return function( vFrom, vTo ) { + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - if ( v1 === undefined ) v1 = new THREE.Vector3(); + this.onChangeCallback(); - v1.crossVectors( vFrom, vTo ); + return this; - this.set( v1.x, v1.y, v1.z, vFrom.dot( vTo ) + 1 ).normalize(); + }, - this._updateEuler(); + dot: function ( v ) { - return this; + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - } + }, - }(), + lengthSq: function () { - inverse: function () { + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - this.conjugate().normalize(); + }, - return this; + length: function () { - }, + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - conjugate: function () { + }, - this._x *= -1; - this._y *= -1; - this._z *= -1; + normalize: function () { - this._updateEuler(); + var l = this.length(); - return this; + if ( l === 0 ) { - }, + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - lengthSq: function () { + } else { - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + l = 1 / l; - }, + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - length: function () { + } - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + this.onChangeCallback(); - }, + return this; - normalize: function () { + }, - var l = this.length(); + multiply: function ( q, p ) { - if ( l === 0 ) { + if ( p !== undefined ) { - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); - } else { + } - l = 1 / l; + return this.multiplyQuaternions( this, q ); - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + }, - } + multiplyQuaternions: function ( a, b ) { - return this; + // 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; - multiply: function ( q, p ) { + 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; - if ( p !== undefined ) { + this.onChangeCallback(); - console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); + return this; - } + }, - return this.multiplyQuaternions( this, q ); + multiplyVector3: function ( vector ) { - }, + THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); - multiplyQuaternions: function ( a, b ) { + }, - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + slerp: function ( qb, t ) { - 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; + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - 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; + var x = this._x, y = this._y, z = this._z, w = this._w; - this._updateEuler(); + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - return this; + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - }, + if ( cosHalfTheta < 0 ) { - multiplyVector3: function ( vector ) { + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); + cosHalfTheta = - cosHalfTheta; - }, + } else { - slerp: function ( qb, t ) { + 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/ + if ( cosHalfTheta >= 1.0 ) { - var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + this._w = w; + this._x = x; + this._y = y; + this._z = z; - if ( cosHalfTheta < 0 ) { + return this; - this._w = -qb._w; - this._x = -qb._x; - this._y = -qb._y; - this._z = -qb._z; + } - cosHalfTheta = -cosHalfTheta; + var halfTheta = Math.acos( cosHalfTheta ); + var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); - } else { + if ( Math.abs( sinHalfTheta ) < 0.001 ) { - this.copy( qb ); + 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; - if ( cosHalfTheta >= 1.0 ) { + } - this._w = w; - this._x = x; - this._y = y; - this._z = z; + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - return this; + 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(); - var halfTheta = Math.acos( cosHalfTheta ); - var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); + return this; - 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 ); + equals: function ( quaternion ) { - return this; + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - } + }, - var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + fromArray: function ( array, offset ) { - 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 ); + if ( offset === undefined ) offset = 0; - this._updateEuler(); + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - return this; + this.onChangeCallback(); - }, + return this; - equals: function ( quaternion ) { + }, - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + toArray: function ( array, offset ) { - }, + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - fromArray: function ( array ) { + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - this._w = array[ 3 ]; + return array; - this._updateEuler(); + }, - return this; + onChange: function ( callback ) { - }, + this.onChangeCallback = callback; - toArray: function () { + return this; - return [ this._x, this._y, this._z, this._w ]; + }, - }, + onChangeCallback: function () {}, - clone: function () { + clone: function () { - return new THREE.Quaternion( this._x, this._y, this._z, this._w ); + return new THREE.Quaternion( this._x, this._y, this._z, this._w ); - } + } }; THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { - return qm.copy( qa ).slerp( qb, t ); + return qm.copy( qa ).slerp( qb, t ); } +// File:src/math/Vector2.js + /** * @author mrdoob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ @@ -1121,395 +1215,437 @@ THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { THREE.Vector2 = function ( x, y ) { - this.x = x || 0; - this.y = y || 0; + this.x = x || 0; + this.y = y || 0; }; THREE.Vector2.prototype = { - constructor: THREE.Vector2, + constructor: THREE.Vector2, + + set: function ( x, y ) { + + this.x = x; + this.y = y; + + 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 ); + + } + + }, - set: function ( x, y ) { + getComponent: function ( index ) { - this.x = x; - this.y = y; + switch ( index ) { - return this; + case 0: return this.x; + case 1: return this.y; + default: throw new Error( 'index is out of range: ' + index ); - }, + } + + }, - setX: function ( x ) { + copy: function ( v ) { - this.x = x; + this.x = v.x; + this.y = v.y; - return this; + return this; - }, + }, - setY: function ( y ) { + add: function ( v, w ) { - this.y = y; + if ( w !== undefined ) { - return this; + THREE.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; - setComponent: function ( index, value ) { + }, - switch ( index ) { + addScalar: function ( s ) { - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( "index is out of range: " + index ); + this.x += s; + this.y += s; - } + return this; - }, + }, - getComponent: function ( index ) { + addVectors: function ( a, b ) { - switch ( index ) { + this.x = a.x + b.x; + this.y = a.y + b.y; - case 0: return this.x; - case 1: return this.y; - default: throw new Error( "index is out of range: " + index ); + return this; - } + }, - }, + sub: function ( v, w ) { - copy: function ( v ) { + if ( w !== undefined ) { - this.x = v.x; - this.y = v.y; + THREE.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); - return this; + } - }, + this.x -= v.x; + this.y -= v.y; - add: function ( v, w ) { + return this; - if ( w !== undefined ) { + }, - console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); + subScalar: function ( s ) { - } + this.x -= s; + this.y -= s; - this.x += v.x; - this.y += v.y; + return this; - return this; + }, - }, + subVectors: function ( a, b ) { - addVectors: function ( a, b ) { + this.x = a.x - b.x; + this.y = a.y - b.y; - this.x = a.x + b.x; - this.y = a.y + b.y; + return this; - return this; + }, - }, + multiply: function ( v ) { - addScalar: function ( s ) { + this.x *= v.x; + this.y *= v.y; - this.x += s; - this.y += s; + return this; - return this; + }, - }, + multiplyScalar: function ( s ) { - sub: function ( v, w ) { + this.x *= s; + this.y *= s; - if ( w !== undefined ) { + return this; - console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); + }, - } + divide: function ( v ) { - this.x -= v.x; - this.y -= v.y; + this.x /= v.x; + this.y /= v.y; - return this; + return this; - }, + }, - subVectors: function ( a, b ) { + divideScalar: function ( scalar ) { - this.x = a.x - b.x; - this.y = a.y - b.y; + if ( scalar !== 0 ) { - return this; + var invScalar = 1 / scalar; - }, - - multiply: function ( v ) { + this.x *= invScalar; + this.y *= invScalar; - this.x *= v.x; - this.y *= v.y; + } else { - return this; + this.x = 0; + this.y = 0; - }, + } - multiplyScalar: function ( s ) { + return this; - this.x *= s; - this.y *= s; + }, - return this; + min: function ( v ) { - }, + if ( this.x > v.x ) { - divide: function ( v ) { + this.x = v.x; - this.x /= v.x; - this.y /= v.y; + } - return this; + if ( this.y > v.y ) { - }, + this.y = v.y; - divideScalar: function ( scalar ) { + } - if ( scalar !== 0 ) { + return this; - var invScalar = 1 / scalar; + }, - this.x *= invScalar; - this.y *= invScalar; + max: function ( v ) { - } else { + if ( this.x < v.x ) { - this.x = 0; - this.y = 0; + this.x = v.x; - } + } - return this; + if ( this.y < v.y ) { - }, + this.y = v.y; - min: function ( v ) { + } - if ( this.x > v.x ) { + return this; - this.x = v.x; + }, - } + clamp: function ( min, max ) { - if ( this.y > v.y ) { + // This function assumes min < max, if this assumption isn't true it will not operate correctly - this.y = v.y; + if ( this.x < min.x ) { - } + this.x = min.x; - return this; + } else if ( this.x > max.x ) { - }, + this.x = max.x; - max: function ( v ) { + } - if ( this.x < v.x ) { + if ( this.y < min.y ) { - this.x = v.x; + this.y = min.y; - } + } else if ( this.y > max.y ) { - if ( this.y < v.y ) { + this.y = max.y; - this.y = v.y; + } - } + return this; + }, - return this; + clampScalar: ( function () { - }, + var min, max; - clamp: function ( min, max ) { + return function ( minVal, maxVal ) { - // This function assumes min < max, if this assumption isn't true it will not operate correctly + if ( min === undefined ) { - if ( this.x < min.x ) { + min = new THREE.Vector2(); + max = new THREE.Vector2(); - this.x = min.x; + } - } else if ( this.x > max.x ) { + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); - this.x = max.x; + return this.clamp( min, max ); - } + }; - if ( this.y < min.y ) { + } )(), - this.y = min.y; + floor: function () { - } else if ( this.y > max.y ) { + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); - this.y = max.y; + return this; - } + }, - return this; - }, + ceil: function () { - clampScalar: ( function () { + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); - var min, max; + return this; - return function ( minVal, maxVal ) { + }, - if ( min === undefined ) { + round: function () { - min = new THREE.Vector2(); - max = new THREE.Vector2(); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); - } + return this; - min.set( minVal, minVal ); - max.set( maxVal, maxVal ); + }, - return this.clamp( min, max ); + 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 ); - floor: function () { + return this; - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); + }, - return this; + negate: function () { - }, + this.x = - this.x; + this.y = - this.y; - ceil: function () { + return this; - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); + }, - return this; + dot: function ( v ) { - }, + return this.x * v.x + this.y * v.y; - round: function () { + }, - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); + lengthSq: function () { - return this; + return this.x * this.x + this.y * this.y; - }, + }, - roundToZero: function () { + length: 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 Math.sqrt( this.x * this.x + this.y * this.y ); - return this; + }, - }, + normalize: function () { - negate: function () { + return this.divideScalar( this.length() ); - return this.multiplyScalar( - 1 ); + }, - }, + distanceTo: function ( v ) { - dot: function ( v ) { + return Math.sqrt( this.distanceToSquared( v ) ); - return this.x * v.x + this.y * v.y; + }, - }, + distanceToSquared: function ( v ) { - lengthSq: function () { + var dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; - return this.x * this.x + this.y * this.y; + }, - }, + setLength: function ( l ) { - length: function () { + var oldLength = this.length(); - return Math.sqrt( this.x * this.x + this.y * this.y ); + if ( oldLength !== 0 && l !== oldLength ) { - }, + this.multiplyScalar( l / oldLength ); + } - normalize: function () { + return this; - return this.divideScalar( this.length() ); + }, - }, + lerp: function ( v, alpha ) { - distanceTo: function ( v ) { + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; - return Math.sqrt( this.distanceToSquared( v ) ); + return this; - }, + }, - distanceToSquared: function ( v ) { + lerpVectors: function ( v1, v2, alpha ) { - var dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - }, + return this; - setLength: function ( l ) { + }, - var oldLength = this.length(); + equals: function ( v ) { - if ( oldLength !== 0 && l !== oldLength ) { + return ( ( v.x === this.x ) && ( v.y === this.y ) ); - this.multiplyScalar( l / oldLength ); - } + }, - return this; + fromArray: function ( array, offset ) { - }, + if ( offset === undefined ) offset = 0; - lerp: function ( v, alpha ) { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; + return this; - return this; + }, - }, + toArray: function ( array, offset ) { - equals: function( v ) { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return ( ( v.x === this.x ) && ( v.y === this.y ) ); + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; - }, + return array; - fromArray: function ( array ) { + }, - this.x = array[ 0 ]; - this.y = array[ 1 ]; + fromAttribute: function ( attribute, index, offset ) { - return this; + if ( offset === undefined ) offset = 0; - }, + index = index * attribute.itemSize + offset; - toArray: function () { + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; - return [ this.x, this.y ]; + return this; - }, + }, - clone: function () { + clone: function () { - return new THREE.Vector2( this.x, this.y ); + return new THREE.Vector2( this.x, this.y ); - } + } }; +// File:src/math/Vector3.js + /** * @author mrdoob / http://mrdoob.com/ * @author *kile / http://kile.stravaganza.org/ @@ -1521,770 +1657,848 @@ THREE.Vector2.prototype = { THREE.Vector3 = function ( x, y, z ) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; }; THREE.Vector3.prototype = { - constructor: THREE.Vector3, + constructor: THREE.Vector3, + + set: function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + 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 ) { - set: function ( x, y, z ) { + 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 ); - this.x = x; - this.y = y; - this.z = z; + } + + }, + + 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 ); + + } + + }, - return this; + copy: function ( v ) { - }, + this.x = v.x; + this.y = v.y; + this.z = v.z; - setX: function ( x ) { + return this; - this.x = x; + }, - return this; + add: function ( v, w ) { - }, + if ( w !== undefined ) { - setY: function ( y ) { + THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - this.y = y; + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + }, - return this; + addScalar: function ( s ) { - }, + this.x += s; + this.y += s; + this.z += s; - setZ: function ( z ) { + return this; - this.z = z; + }, - return this; + addVectors: function ( a, b ) { - }, + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - setComponent: function ( index, value ) { + return this; - 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 ); + sub: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.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; - getComponent: function ( index ) { + }, + + subScalar: function ( s ) { - switch ( index ) { + this.x -= s; + this.y -= s; + this.z -= s; - 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 ); + return this; - } + }, - }, + subVectors: function ( a, b ) { - copy: function ( v ) { + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - this.x = v.x; - this.y = v.y; - this.z = v.z; + return this; - return this; + }, - }, + multiply: function ( v, w ) { - add: function ( v, w ) { + if ( w !== undefined ) { - if ( w !== undefined ) { + THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); - console.warn( 'DEPRECATED: Vector3\'s .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.x += v.x; - this.y += v.y; - this.z += v.z; + return this; - return this; + }, - }, + multiplyScalar: function ( scalar ) { - addScalar: function ( s ) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - this.x += s; - this.y += s; - this.z += s; + return this; - return this; + }, - }, + multiplyVectors: function ( a, b ) { - addVectors: function ( a, b ) { + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + return this; - return this; + }, - }, + applyEuler: function () { - sub: function ( v, w ) { + var quaternion; - if ( w !== undefined ) { + return function ( euler ) { - console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); + if ( euler instanceof THREE.Euler === false ) { - } + THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + } - return this; + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - }, + this.applyQuaternion( quaternion.setFromEuler( euler ) ); - subVectors: function ( a, b ) { + return this; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + }; - return this; + }(), - }, + applyAxisAngle: function () { - multiply: function ( v, w ) { + var quaternion; - if ( w !== undefined ) { + return function ( axis, angle ) { - console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); - return this.multiplyVectors( v, w ); + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - } + this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + return this; - return this; + }; - }, + }(), - multiplyScalar: function ( scalar ) { + applyMatrix3: function ( m ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + var x = this.x; + var y = this.y; + var z = this.z; - return this; + 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; - multiplyVectors: function ( a, b ) { + return this; - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + }, - return this; + applyMatrix4: function ( m ) { - }, + // input: THREE.Matrix4 affine matrix - applyEuler: function () { + var x = this.x, y = this.y, z = this.z; - var quaternion; + var e = m.elements; - return function ( euler ) { + 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 ]; - if ( euler instanceof THREE.Euler === false ) { + return this; - console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + }, - } + applyProjection: function ( m ) { - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + // input: THREE.Matrix4 projection matrix - this.applyQuaternion( quaternion.setFromEuler( euler ) ); + var x = this.x, y = this.y, z = this.z; - return this; + var e = m.elements; + var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide - }; + this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d; + this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d; + this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d; - }(), + return this; - applyAxisAngle: function () { + }, - var quaternion; + applyQuaternion: function ( q ) { - return function ( axis, angle ) { + var x = this.x; + var y = this.y; + var z = this.z; - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; - this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + // calculate quat * vector - return this; + 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; - applyMatrix3: function ( m ) { + return this; - var x = this.x; - var y = this.y; - var z = this.z; + }, - var e = m.elements; + project: function () { - 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; + var matrix; - return this; + return function ( camera ) { - }, + if ( matrix === undefined ) matrix = new THREE.Matrix4(); - applyMatrix4: function ( m ) { + matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); + return this.applyProjection( matrix ); - // input: THREE.Matrix4 affine matrix + }; - var x = this.x, y = this.y, z = this.z; + }(), - var e = m.elements; + unproject: function () { - 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 matrix; - return this; + return function ( camera ) { - }, + if ( matrix === undefined ) matrix = new THREE.Matrix4(); - applyProjection: function ( m ) { + matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); + return this.applyProjection( matrix ); - // input: THREE.Matrix4 projection matrix + }; - var x = this.x, y = this.y, z = this.z; + }(), - var e = m.elements; - var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide + transformDirection: function ( m ) { - this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; - this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; - this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - return this; + var x = this.x, y = this.y, z = this.z; - }, + var e = m.elements; - applyQuaternion: function ( q ) { + 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; - var x = this.x; - var y = this.y; - var z = this.z; + this.normalize(); - var qx = q.x; - var qy = q.y; - var qz = q.z; - var qw = q.w; + return this; - // 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; + divide: function ( v ) { - // calculate result * inverse quat + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; - 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; - return this; + }, - }, + divideScalar: function ( scalar ) { - transformDirection: function ( m ) { + if ( scalar !== 0 ) { - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + var invScalar = 1 / scalar; - var x = this.x, y = this.y, z = this.z; + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; - var e = m.elements; + } else { - 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; + this.x = 0; + this.y = 0; + this.z = 0; - this.normalize(); + } - return this; + return this; - }, + }, - divide: function ( v ) { + min: function ( v ) { - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + if ( this.x > v.x ) { - return this; + this.x = v.x; - }, + } - divideScalar: function ( scalar ) { + if ( this.y > v.y ) { - if ( scalar !== 0 ) { + this.y = v.y; - var invScalar = 1 / scalar; + } - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; + if ( this.z > v.z ) { - } else { + this.z = v.z; - this.x = 0; - this.y = 0; - this.z = 0; + } - } + return this; - return this; + }, - }, + max: function ( v ) { - min: function ( v ) { + if ( this.x < v.x ) { - if ( this.x > v.x ) { + this.x = v.x; - this.x = v.x; + } - } + if ( this.y < v.y ) { - if ( this.y > v.y ) { + this.y = v.y; - this.y = v.y; + } - } + if ( this.z < v.z ) { - if ( this.z > v.z ) { + this.z = v.z; - this.z = v.z; + } - } + return this; - return this; + }, - }, + clamp: function ( min, max ) { - max: function ( v ) { + // This function assumes min < max, if this assumption isn't true it will not operate correctly - if ( this.x < v.x ) { + if ( this.x < min.x ) { - this.x = v.x; + this.x = min.x; - } + } else if ( this.x > max.x ) { - if ( this.y < v.y ) { + this.x = max.x; - this.y = v.y; + } - } + if ( this.y < min.y ) { - if ( this.z < v.z ) { + this.y = min.y; - this.z = v.z; + } else if ( this.y > max.y ) { - } + this.y = max.y; - return this; + } - }, + if ( this.z < min.z ) { - clamp: function ( min, max ) { + this.z = min.z; - // This function assumes min < max, if this assumption isn't true it will not operate correctly + } else if ( this.z > max.z ) { - if ( this.x < min.x ) { + this.z = max.z; - this.x = min.x; + } - } else if ( this.x > max.x ) { + return this; - this.x = max.x; + }, - } + clampScalar: ( function () { - if ( this.y < min.y ) { + var min, max; - this.y = min.y; + return function ( minVal, maxVal ) { - } else if ( this.y > max.y ) { + if ( min === undefined ) { - this.y = max.y; + min = new THREE.Vector3(); + max = new THREE.Vector3(); - } + } - if ( this.z < min.z ) { + min.set( minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal ); - this.z = min.z; + return this.clamp( min, max ); - } else if ( this.z > max.z ) { + }; - this.z = max.z; + } )(), - } + floor: function () { - return this; + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - }, + return this; - clampScalar: ( function () { + }, - var min, max; + ceil: function () { - return function ( minVal, maxVal ) { + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - if ( min === undefined ) { + return this; - min = new THREE.Vector3(); - max = new THREE.Vector3(); + }, - } + round: function () { - min.set( minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal ); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); - return this.clamp( min, max ); + return this; - }; + }, - } )(), + roundToZero: function () { - floor: 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.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); + return this; - return this; + }, - }, + negate: function () { - ceil: function () { + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); + return this; - return this; + }, - }, + dot: function ( v ) { - round: function () { + return this.x * v.x + this.y * v.y + this.z * v.z; - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); + }, - return this; + lengthSq: function () { - }, + return this.x * this.x + this.y * this.y + this.z * this.z; - 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 ); + length: function () { - return this; + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - }, + }, - negate: function () { + lengthManhattan: function () { - return this.multiplyScalar( - 1 ); + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - }, + }, - dot: function ( v ) { + normalize: function () { - return this.x * v.x + this.y * v.y + this.z * v.z; + return this.divideScalar( this.length() ); - }, + }, - lengthSq: function () { + setLength: function ( l ) { - return this.x * this.x + this.y * this.y + this.z * this.z; + var oldLength = this.length(); - }, + if ( oldLength !== 0 && l !== oldLength ) { - length: function () { + this.multiplyScalar( l / oldLength ); + } - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return this; - }, + }, - lengthManhattan: function () { + lerp: function ( v, alpha ) { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; - }, + return this; - normalize: function () { + }, - return this.divideScalar( this.length() ); + lerpVectors: function ( v1, v2, alpha ) { - }, + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - setLength: function ( l ) { + return this; - var oldLength = this.length(); + }, - if ( oldLength !== 0 && l !== oldLength ) { + cross: function ( v, w ) { - this.multiplyScalar( l / oldLength ); - } + if ( w !== undefined ) { - return this; + THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); - }, + } - lerp: function ( v, alpha ) { + var x = this.x, y = this.y, z = this.z; - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + 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; + return this; - }, + }, - cross: function ( v, w ) { + crossVectors: function ( a, b ) { - if ( w !== undefined ) { + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; - console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); - return this.crossVectors( v, w ); + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; - } + return this; - 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; + projectOnVector: function () { - return this; + var v1, dot; - }, + return function ( vector ) { - crossVectors: function ( a, b ) { + if ( v1 === undefined ) v1 = new THREE.Vector3(); - var ax = a.x, ay = a.y, az = a.z; - var bx = b.x, by = b.y, bz = b.z; + v1.copy( vector ).normalize(); - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + dot = this.dot( v1 ); - return this; + return this.copy( v1 ).multiplyScalar( dot ); - }, + }; - projectOnVector: function () { + }(), - var v1, dot; + projectOnPlane: function () { - return function ( vector ) { + var v1; - if ( v1 === undefined ) v1 = new THREE.Vector3(); + return function ( planeNormal ) { - v1.copy( vector ).normalize(); + if ( v1 === undefined ) v1 = new THREE.Vector3(); - dot = this.dot( v1 ); + v1.copy( this ).projectOnVector( planeNormal ); - return this.copy( v1 ).multiplyScalar( dot ); + return this.sub( v1 ); - }; + } - }(), + }(), - projectOnPlane: function () { + reflect: function () { - var v1; + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - return function ( planeNormal ) { + var v1; - if ( v1 === undefined ) v1 = new THREE.Vector3(); + return function ( normal ) { - v1.copy( this ).projectOnVector( planeNormal ); + if ( v1 === undefined ) v1 = new THREE.Vector3(); - return this.sub( v1 ); + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - } + } - }(), + }(), - reflect: function () { + angleTo: function ( v ) { - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length + var theta = this.dot( v ) / ( this.length() * v.length() ); - var v1; + // clamp, to handle numerical problems - return function ( normal ) { + return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) ); - if ( v1 === undefined ) v1 = new THREE.Vector3(); + }, - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + distanceTo: function ( v ) { - } + return Math.sqrt( this.distanceToSquared( v ) ); - }(), + }, - angleTo: function ( v ) { + distanceToSquared: function ( v ) { - var theta = this.dot( v ) / ( this.length() * v.length() ); + var dx = this.x - v.x; + var dy = this.y - v.y; + var dz = this.z - v.z; - // clamp, to handle numerical problems + return dx * dx + dy * dy + dz * dz; - return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); + }, - }, + setEulerFromRotationMatrix: function ( m, order ) { - distanceTo: function ( v ) { + THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - return Math.sqrt( this.distanceToSquared( v ) ); + }, - }, + setEulerFromQuaternion: function ( q, order ) { - distanceToSquared: function ( v ) { + THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - var dx = this.x - v.x; - var dy = this.y - v.y; - var dz = this.z - v.z; + }, - return dx * dx + dy * dy + dz * dz; + getPositionFromMatrix: function ( m ) { - }, + THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - setEulerFromRotationMatrix: function ( m, order ) { + return this.setFromMatrixPosition( m ); - console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); + }, - }, + getScaleFromMatrix: function ( m ) { - setEulerFromQuaternion: function ( q, order ) { + THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); + return this.setFromMatrixScale( m ); + }, - }, + getColumnFromMatrix: function ( index, matrix ) { - getPositionFromMatrix: function ( m ) { + THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - console.warn( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); + return this.setFromMatrixColumn( index, matrix ); - return this.setFromMatrixPosition( m ); + }, - }, + setFromMatrixPosition: function ( m ) { - getScaleFromMatrix: function ( m ) { + this.x = m.elements[ 12 ]; + this.y = m.elements[ 13 ]; + this.z = m.elements[ 14 ]; - console.warn( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); + return this; - return this.setFromMatrixScale( m ); - }, + }, - getColumnFromMatrix: function ( index, matrix ) { + setFromMatrixScale: function ( m ) { - console.warn( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); + var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); + var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); + var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); - return this.setFromMatrixColumn( index, matrix ); + this.x = sx; + this.y = sy; + this.z = sz; - }, + return this; + }, - setFromMatrixPosition: function ( m ) { + setFromMatrixColumn: function ( index, matrix ) { + + var offset = index * 4; - this.x = m.elements[ 12 ]; - this.y = m.elements[ 13 ]; - this.z = m.elements[ 14 ]; + var me = matrix.elements; - return this; + this.x = me[ offset ]; + this.y = me[ offset + 1 ]; + this.z = me[ offset + 2 ]; - }, + return this; - setFromMatrixScale: function ( m ) { + }, - var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); - var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); - var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); + equals: function ( v ) { - this.x = sx; - this.y = sy; - this.z = sz; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - return this; - }, + }, - setFromMatrixColumn: function ( index, matrix ) { + fromArray: function ( array, offset ) { - var offset = index * 4; + if ( offset === undefined ) offset = 0; - var me = matrix.elements; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; - this.x = me[ offset ]; - this.y = me[ offset + 1 ]; - this.z = me[ offset + 2 ]; + return this; - return this; + }, - }, + toArray: function ( array, offset ) { - equals: function ( v ) { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - }, + return array; - fromArray: function ( array ) { + }, - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; + fromAttribute: function ( attribute, index, offset ) { - return this; + if ( offset === undefined ) offset = 0; - }, + index = index * attribute.itemSize + offset; - toArray: function () { + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; - return [ this.x, this.y, this.z ]; + return this; - }, + }, - clone: function () { + clone: function () { - return new THREE.Vector3( this.x, this.y, this.z ); + return new THREE.Vector3( this.x, this.y, this.z ); - } + } }; + +// File:src/math/Vector4.js + /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ @@ -2295,689 +2509,690 @@ THREE.Vector3.prototype = { THREE.Vector4 = function ( x, y, z, w ) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; }; THREE.Vector4.prototype = { - constructor: THREE.Vector4, + constructor: THREE.Vector4, - set: function ( x, y, z, w ) { + set: function ( x, y, z, w ) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - return this; + return this; - }, + }, - setX: function ( x ) { + setX: function ( x ) { - this.x = x; + this.x = x; - return this; + return this; - }, + }, - setY: function ( y ) { + setY: function ( y ) { - this.y = y; + this.y = y; - return this; + return this; - }, + }, - setZ: function ( z ) { + setZ: function ( z ) { - this.z = z; + this.z = z; - return this; + return this; - }, + }, - setW: function ( w ) { + setW: function ( w ) { - this.w = w; + this.w = w; - return this; + return this; - }, + }, - setComponent: function ( index, value ) { + setComponent: function ( index, value ) { - switch ( index ) { + 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 ); + 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 ); - } + } - }, + }, - getComponent: function ( index ) { + getComponent: function ( index ) { - switch ( 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 ); + 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 ); - } + } - }, + }, - copy: function ( v ) { + copy: function ( v ) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - return this; + return this; - }, + }, - add: function ( v, w ) { + add: function ( v, w ) { - if ( w !== undefined ) { + if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); + THREE.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; + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - return this; + return this; - }, + }, - addScalar: function ( s ) { + addScalar: function ( s ) { - this.x += s; - this.y += s; - this.z += s; - this.w += s; + this.x += s; + this.y += s; + this.z += s; + this.w += s; - return this; + return this; - }, + }, - addVectors: function ( a, b ) { + 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; + 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; + return this; - }, + }, - sub: function ( v, w ) { + sub: function ( v, w ) { - if ( w !== undefined ) { + if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); + THREE.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; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; - return this; + return this; - }, + }, - subVectors: function ( a, b ) { + subScalar: function ( s ) { - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - return this; + return this; - }, + }, - multiplyScalar: function ( scalar ) { + subVectors: function ( a, b ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + 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; + return this; - }, + }, - applyMatrix4: function ( m ) { + multiplyScalar: function ( scalar ) { - var x = this.x; - var y = this.y; - var z = this.z; - var w = this.w; + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - var e = m.elements; + return this; - 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; + applyMatrix4: function ( m ) { - }, + var x = this.x; + var y = this.y; + var z = this.z; + var w = this.w; - divideScalar: function ( scalar ) { + var e = m.elements; - if ( scalar !== 0 ) { + 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; - var invScalar = 1 / scalar; + return this; - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - this.w *= invScalar; + }, - } else { + divideScalar: function ( scalar ) { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; + if ( scalar !== 0 ) { - } + var invScalar = 1 / scalar; - return this; + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + this.w *= invScalar; - }, + } else { - setAxisAngleFromQuaternion: function ( q ) { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + } - // q is assumed to be normalized + return this; - this.w = 2 * Math.acos( q.w ); + }, - var s = Math.sqrt( 1 - q.w * q.w ); + setAxisAngleFromQuaternion: function ( q ) { - if ( s < 0.0001 ) { + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - this.x = 1; - this.y = 0; - this.z = 0; + // q is assumed to be normalized - } else { + this.w = 2 * Math.acos( q.w ); - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + var s = Math.sqrt( 1 - q.w * q.w ); - } + if ( s < 0.0001 ) { - return this; + this.x = 1; + this.y = 0; + this.z = 0; - }, + } else { - setAxisAngleFromRotationMatrix: function ( m ) { + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - // 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) + return this; - 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, + setAxisAngleFromRotationMatrix: function ( m ) { - 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]; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - if ( ( Math.abs( m12 - m21 ) < epsilon ) - && ( Math.abs( m13 - m31 ) < epsilon ) - && ( Math.abs( m23 - m32 ) < epsilon ) ) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + 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 - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) - && ( Math.abs( m13 + m31 ) < epsilon2 ) - && ( Math.abs( m23 + m32 ) < epsilon2 ) - && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + te = m.elements, - // this singularity is identity matrix so angle = 0 + 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 ]; - this.set( 1, 0, 0, 0 ); + if ( ( Math.abs( m12 - m21 ) < epsilon ) + && ( Math.abs( m13 - m31 ) < epsilon ) + && ( Math.abs( m23 - m32 ) < epsilon ) ) { - return this; // zero angle, arbitrary axis + // 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 ) ) { - // otherwise this singularity is angle = 180 + // this singularity is identity matrix so angle = 0 - angle = Math.PI; + this.set( 1, 0, 0, 0 ); - 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; + return this; // zero angle, arbitrary axis - if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term + } - if ( xx < epsilon ) { + // otherwise this singularity is angle = 180 - x = 0; - y = 0.707106781; - z = 0.707106781; + angle = Math.PI; - } else { + 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; - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; + if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term - } + if ( xx < epsilon ) { - } else if ( yy > zz ) { // m22 is the largest diagonal term + x = 0; + y = 0.707106781; + z = 0.707106781; - if ( yy < epsilon ) { + } else { - x = 0.707106781; - y = 0; - z = 0.707106781; + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - } else { + } - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + } else if ( yy > zz ) { // m22 is the largest diagonal term - } + if ( yy < epsilon ) { - } else { // m33 is the largest diagonal term so base result on this + x = 0.707106781; + y = 0; + z = 0.707106781; - if ( zz < epsilon ) { + } else { - x = 0.707106781; - y = 0.707106781; - z = 0; + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - } else { + } - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + } else { // m33 is the largest diagonal term so base result on this - } + if ( zz < epsilon ) { - } + x = 0.707106781; + y = 0.707106781; + z = 0; - this.set( x, y, z, angle ); + } else { - return this; // return 180 deg rotation + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - } + } - // 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 + this.set( x, y, z, angle ); - if ( Math.abs( s ) < 0.001 ) s = 1; + return this; // return 180 deg rotation - // 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 ); + // as we have reached here there are no singularities so we can handle normally - return this; + 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; - min: function ( v ) { + // 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 - if ( this.x > v.x ) { + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - this.x = v.x; + return this; - } + }, - if ( this.y > v.y ) { + min: function ( v ) { - this.y = v.y; + if ( this.x > v.x ) { - } + this.x = v.x; - if ( this.z > v.z ) { + } - this.z = v.z; + if ( this.y > v.y ) { - } + this.y = v.y; - if ( this.w > v.w ) { + } - this.w = v.w; + if ( this.z > v.z ) { - } + this.z = v.z; - return this; + } - }, + if ( this.w > v.w ) { - max: function ( v ) { + this.w = v.w; - if ( this.x < v.x ) { + } - this.x = v.x; + return this; - } + }, - if ( this.y < v.y ) { + max: function ( v ) { - this.y = v.y; + if ( this.x < v.x ) { - } + this.x = v.x; - if ( this.z < v.z ) { + } - this.z = v.z; + if ( this.y < v.y ) { - } + this.y = v.y; - if ( this.w < v.w ) { + } - this.w = v.w; + if ( this.z < v.z ) { - } + this.z = v.z; - return this; + } - }, + if ( this.w < v.w ) { - clamp: function ( min, max ) { + this.w = v.w; - // This function assumes min < max, if this assumption isn't true it will not operate correctly + } - if ( this.x < min.x ) { + return this; - this.x = min.x; + }, - } else if ( this.x > max.x ) { + clamp: function ( min, max ) { - this.x = max.x; + // This function assumes min < max, if this assumption isn't true it will not operate correctly - } + if ( this.x < min.x ) { - if ( this.y < min.y ) { + this.x = min.x; - this.y = min.y; + } else if ( this.x > max.x ) { - } else if ( this.y > max.y ) { + this.x = max.x; - this.y = max.y; + } - } + if ( this.y < min.y ) { - if ( this.z < min.z ) { + this.y = min.y; - this.z = min.z; + } else if ( this.y > max.y ) { - } else if ( this.z > max.z ) { + this.y = max.y; - this.z = max.z; + } - } + if ( this.z < min.z ) { - if ( this.w < min.w ) { + this.z = min.z; - this.w = min.w; + } else if ( this.z > max.z ) { - } else if ( this.w > max.w ) { + this.z = max.z; - this.w = max.w; + } - } + if ( this.w < min.w ) { - return this; + this.w = min.w; - }, + } else if ( this.w > max.w ) { - clampScalar: ( function () { + this.w = max.w; - var min, max; + } - return function ( minVal, maxVal ) { + return this; - if ( min === undefined ) { + }, - min = new THREE.Vector4(); - max = new THREE.Vector4(); + clampScalar: ( function () { - } + var min, max; - min.set( minVal, minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal, maxVal ); + return function ( minVal, maxVal ) { - return this.clamp( min, max ); + if ( min === undefined ) { - }; + min = new THREE.Vector4(); + max = new THREE.Vector4(); - } )(), + } - floor: function () { + min.set( minVal, minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal, maxVal ); - 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.clamp( min, max ); - return this; + }; - }, + } )(), - ceil: function () { + floor: 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 ); + 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; + return this; - }, + }, - round: function () { + ceil: 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 ); + 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; + return this; - }, + }, - roundToZero: function () { + round: 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 ); + 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; + return this; - }, + }, - negate: function () { + roundToZero: function () { - return this.multiplyScalar( -1 ); + 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; - dot: function ( v ) { + }, - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + negate: function () { - }, + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - lengthSq: function () { + return this; - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + }, - }, + dot: function ( v ) { - length: function () { + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + }, - }, + lengthSq: function () { - lengthManhattan: function () { + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + }, - }, + length: function () { - normalize: function () { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - return this.divideScalar( this.length() ); + }, - }, + lengthManhattan: function () { - setLength: function ( l ) { + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - var oldLength = this.length(); + }, - if ( oldLength !== 0 && l !== oldLength ) { + normalize: function () { - this.multiplyScalar( l / oldLength ); + return this.divideScalar( this.length() ); - } + }, - return this; + setLength: function ( l ) { - }, + var oldLength = this.length(); - lerp: function ( v, alpha ) { + if ( oldLength !== 0 && l !== oldLength ) { - 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; + this.multiplyScalar( l / oldLength ); - return this; + } - }, + return this; - equals: function ( v ) { + }, - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + 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; - fromArray: function ( array ) { + return this; - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; - this.w = array[ 3 ]; + }, - return this; + lerpVectors: function ( v1, v2, alpha ) { - }, + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - toArray: function () { + return this; - return [ this.x, this.y, this.z, this.w ]; + }, - }, + equals: function ( v ) { - clone: function () { + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - return new THREE.Vector4( this.x, this.y, this.z, this.w ); + }, - } + fromArray: function ( array, offset ) { -}; + if ( offset === undefined ) offset = 0; -/** - * @author mrdoob / http://mrdoob.com/ - */ + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; -THREE.TypedVector2 = function ( array, offset ) { + return this; - this.array = array; - this.offset = offset; - -}; + }, -THREE.TypedVector2.prototype = Object.create( THREE.Vector2.prototype ); + toArray: function ( array, offset ) { -Object.defineProperties( THREE.TypedVector2.prototype, { - 'x': { - get: function () { return this.array[ this.offset ]; }, - set: function ( v ) { this.array[ this.offset ] = v; } - }, - 'y': { - get: function () { return this.array[ this.offset + 1 ]; }, - set: function ( v ) { this.array[ this.offset + 1 ] = v; } - } -} ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + 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; + + }, + + fromAttribute: function ( attribute, index, offset ) { + + if ( offset === undefined ) offset = 0; + + index = index * attribute.itemSize + offset; + + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; + this.w = attribute.array[ index + 3 ]; + + return this; + + }, + + clone: function () { + + return new THREE.Vector4( this.x, this.y, this.z, this.w ); + + } + +}; + +// File:src/math/Euler.js -THREE.TypedVector3 = function ( array, offset ) { - - this.array = array; - this.offset = offset; - -}; - -THREE.TypedVector3.prototype = Object.create( THREE.Vector3.prototype ); - -Object.defineProperties( THREE.TypedVector3.prototype, { - 'x': { - get: function () { return this.array[ this.offset ]; }, - set: function ( v ) { this.array[ this.offset ] = v; } - }, - 'y': { - get: function () { return this.array[ this.offset + 1 ]; }, - set: function ( v ) { this.array[ this.offset + 1 ] = v; } - }, - 'z': { - get: function () { return this.array[ this.offset + 2 ]; }, - set: function ( v ) { this.array[ this.offset + 2 ] = v; } - } -} ); /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -2986,10 +3201,10 @@ Object.defineProperties( THREE.TypedVector3.prototype, { THREE.Euler = function ( x, y, z, order ) { - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || THREE.Euler.DefaultOrder; + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || THREE.Euler.DefaultOrder; }; @@ -2999,729 +3214,679 @@ THREE.Euler.DefaultOrder = 'XYZ'; THREE.Euler.prototype = { - constructor: THREE.Euler, - - _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, - - _quaternion: undefined, - - _updateQuaternion: function () { - - if ( this._quaternion !== undefined ) { - - this._quaternion.setFromEuler( this, false ); + constructor: THREE.Euler, - } + _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, - }, + get x () { - get x () { + return this._x; - return this._x; + }, - }, + set x ( value ) { - set x ( value ) { + this._x = value; + this.onChangeCallback(); - this._x = value; - this._updateQuaternion(); + }, - }, + get y () { - get y () { + return this._y; - return this._y; + }, - }, + set y ( value ) { - set y ( value ) { + this._y = value; + this.onChangeCallback(); - this._y = value; - this._updateQuaternion(); + }, - }, + get z () { - get z () { + return this._z; - return this._z; + }, - }, + set z ( value ) { - set z ( value ) { + this._z = value; + this.onChangeCallback(); - this._z = value; - this._updateQuaternion(); + }, - }, + get order () { - get order () { + return this._order; - return this._order; + }, - }, + set order ( value ) { - set order ( value ) { + this._order = value; + this.onChangeCallback(); - this._order = value; - this._updateQuaternion(); + }, - }, + set: function ( x, y, z, order ) { - set: function ( x, y, z, order ) { + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; + this.onChangeCallback(); - this._updateQuaternion(); + return this; - return this; + }, - }, + copy: function ( euler ) { - copy: function ( euler ) { + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + this.onChangeCallback(); - this._updateQuaternion(); + return this; - return this; + }, - }, + setFromRotationMatrix: function ( m, order, update ) { - setFromRotationMatrix: function ( m, order ) { + var clamp = THREE.Math.clamp; - var clamp = THREE.Math.clamp; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - // 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 ]; - 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; - order = order || this._order; + if ( order === 'XYZ' ) { - if ( order === 'XYZ' ) { + this._y = Math.asin( clamp( m13, - 1, 1 ) ); - this._y = Math.asin( clamp( m13, -1, 1 ) ); + if ( Math.abs( m13 ) < 0.99999 ) { - if ( Math.abs( m13 ) < 0.99999 ) { + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + } else { - } else { + this._x = Math.atan2( m32, m22 ); + this._z = 0; - this._x = Math.atan2( m32, m22 ); - this._z = 0; + } - } + } else if ( order === 'YXZ' ) { - } else if ( order === 'YXZ' ) { + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - this._x = Math.asin( - clamp( m23, -1, 1 ) ); + if ( Math.abs( m23 ) < 0.99999 ) { - if ( Math.abs( m23 ) < 0.99999 ) { + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + } else { - } else { + this._y = Math.atan2( - m31, m11 ); + this._z = 0; - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + } - } + } else if ( order === 'ZXY' ) { - } else if ( order === 'ZXY' ) { + this._x = Math.asin( clamp( m32, - 1, 1 ) ); - this._x = Math.asin( clamp( m32, -1, 1 ) ); + if ( Math.abs( m32 ) < 0.99999 ) { - if ( Math.abs( m32 ) < 0.99999 ) { + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + } else { - } else { + this._y = 0; + this._z = Math.atan2( m21, m11 ); - this._y = 0; - this._z = Math.atan2( m21, m11 ); + } - } + } else if ( order === 'ZYX' ) { - } else if ( order === 'ZYX' ) { + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - this._y = Math.asin( - clamp( m31, -1, 1 ) ); + if ( Math.abs( m31 ) < 0.99999 ) { - if ( Math.abs( m31 ) < 0.99999 ) { + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + } else { - } else { + this._x = 0; + this._z = Math.atan2( - m12, m22 ); - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + } - } + } else if ( order === 'YZX' ) { - } else if ( order === 'YZX' ) { + this._z = Math.asin( clamp( m21, - 1, 1 ) ); - this._z = Math.asin( clamp( m21, -1, 1 ) ); + if ( Math.abs( m21 ) < 0.99999 ) { - if ( Math.abs( m21 ) < 0.99999 ) { + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + } else { - } else { + this._x = 0; + this._y = Math.atan2( m13, m33 ); - this._x = 0; - this._y = Math.atan2( m13, m33 ); + } - } + } else if ( order === 'XZY' ) { - } else if ( order === 'XZY' ) { + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - this._z = Math.asin( - clamp( m12, -1, 1 ) ); + if ( Math.abs( m12 ) < 0.99999 ) { - if ( Math.abs( m12 ) < 0.99999 ) { + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + } else { - } else { + this._x = Math.atan2( - m23, m33 ); + this._y = 0; - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + } - } + } else { - } else { + THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) - console.warn( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) - - } - - this._order = order; - - this._updateQuaternion(); - - return this; + } - }, + this._order = order; - setFromQuaternion: function ( q, order, update ) { + if ( update !== false ) this.onChangeCallback(); - var clamp = THREE.Math.clamp; + return this; - // q is assumed to be normalized + }, - // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m + setFromQuaternion: function () { - var sqx = q.x * q.x; - var sqy = q.y * q.y; - var sqz = q.z * q.z; - var sqw = q.w * q.w; + var matrix; - order = order || this._order; + return function ( q, order, update ) { - if ( order === 'XYZ' ) { + if ( matrix === undefined ) matrix = new THREE.Matrix4(); + matrix.makeRotationFromQuaternion( q ); + this.setFromRotationMatrix( matrix, order, update ); - this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ), -1, 1 ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); + return this; - } else if ( order === 'YXZ' ) { + }; - this._x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ), -1, 1 ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); + }(), - } else if ( order === 'ZXY' ) { + setFromVector3: function ( v, order ) { - this._x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ), -1, 1 ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); + return this.set( v.x, v.y, v.z, order || this._order ); - } else if ( order === 'ZYX' ) { + }, - this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ), -1, 1 ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); + reorder: function () { - } else if ( order === 'YZX' ) { + // WARNING: this discards revolution information -bhouston - this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ), -1, 1 ) ); + var q = new THREE.Quaternion(); - } else if ( order === 'XZY' ) { + return function ( newOrder ) { - this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ), -1, 1 ) ); + q.setFromEuler( this ); + this.setFromQuaternion( q, newOrder ); - } else { + }; - console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order ) + }(), - } + equals: function ( euler ) { - this._order = order; + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - if ( update !== false ) this._updateQuaternion(); + }, - return this; + fromArray: function ( array ) { - }, + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - reorder: function () { + this.onChangeCallback(); - // WARNING: this discards revolution information -bhouston + return this; - var q = new THREE.Quaternion(); + }, - return function ( newOrder ) { + toArray: function ( array, offset ) { - q.setFromEuler( this ); - this.setFromQuaternion( q, newOrder ); + 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 ) { - fromArray: function ( array ) { + if ( optionalResult ) { - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + return optionalResult.set( this._x, this._y, this._z ); - this._updateQuaternion(); + } else { - return this; + return new THREE.Vector3( this._x, this._y, this._z ); - }, + } - toArray: function () { + }, - return [ this._x, this._y, this._z, this._order ]; + onChange: function ( callback ) { - }, + this.onChangeCallback = callback; - equals: function ( euler ) { + return this; - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + }, - }, + onChangeCallback: function () {}, - clone: function () { + clone: function () { - return new THREE.Euler( this._x, this._y, this._z, this._order ); + return new THREE.Euler( this._x, this._y, this._z, this._order ); - } + } }; +// File:src/math/Line3.js + /** * @author bhouston / http://exocortex.com */ THREE.Line3 = function ( start, end ) { - this.start = ( start !== undefined ) ? start : new THREE.Vector3(); - this.end = ( end !== undefined ) ? end : new THREE.Vector3(); + this.start = ( start !== undefined ) ? start : new THREE.Vector3(); + this.end = ( end !== undefined ) ? end : new THREE.Vector3(); }; THREE.Line3.prototype = { - constructor: THREE.Line3, + constructor: THREE.Line3, - set: function ( start, end ) { + set: function ( start, end ) { - this.start.copy( start ); - this.end.copy( end ); + this.start.copy( start ); + this.end.copy( end ); - return this; + return this; - }, + }, - copy: function ( line ) { + copy: function ( line ) { - this.start.copy( line.start ); - this.end.copy( line.end ); + this.start.copy( line.start ); + this.end.copy( line.end ); - return this; + return this; - }, + }, - center: function ( optionalTarget ) { + center: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - }, + }, - delta: function ( optionalTarget ) { + delta: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors( this.end, this.start ); + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.end, this.start ); - }, + }, - distanceSq: function () { + distanceSq: function () { - return this.start.distanceToSquared( this.end ); + return this.start.distanceToSquared( this.end ); - }, + }, - distance: function () { + distance: function () { - return this.start.distanceTo( this.end ); + return this.start.distanceTo( this.end ); - }, + }, - at: function ( t, optionalTarget ) { + at: function ( t, optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - return this.delta( result ).multiplyScalar( t ).add( this.start ); + return this.delta( result ).multiplyScalar( t ).add( this.start ); - }, + }, - closestPointToPointParameter: function() { + closestPointToPointParameter: function () { - var startP = new THREE.Vector3(); - var startEnd = new THREE.Vector3(); + var startP = new THREE.Vector3(); + var startEnd = new THREE.Vector3(); - return function ( point, clampToLine ) { + return function ( point, clampToLine ) { - startP.subVectors( point, this.start ); - startEnd.subVectors( this.end, this.start ); + startP.subVectors( point, this.start ); + startEnd.subVectors( this.end, this.start ); - var startEnd2 = startEnd.dot( startEnd ); - var startEnd_startP = startEnd.dot( startP ); + var startEnd2 = startEnd.dot( startEnd ); + var startEnd_startP = startEnd.dot( startP ); - var t = startEnd_startP / startEnd2; + var t = startEnd_startP / startEnd2; - if ( clampToLine ) { + if ( clampToLine ) { - t = THREE.Math.clamp( t, 0, 1 ); + t = THREE.Math.clamp( t, 0, 1 ); - } + } - return t; + return t; - }; + }; - }(), + }(), - closestPointToPoint: function ( point, clampToLine, optionalTarget ) { + closestPointToPoint: function ( point, clampToLine, optionalTarget ) { - var t = this.closestPointToPointParameter( point, clampToLine ); + var t = this.closestPointToPointParameter( point, clampToLine ); - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - return this.delta( result ).multiplyScalar( t ).add( this.start ); + return this.delta( result ).multiplyScalar( t ).add( this.start ); - }, + }, - applyMatrix4: function ( matrix ) { + applyMatrix4: function ( matrix ) { - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); - return this; + return this; - }, + }, - equals: function ( line ) { + equals: function ( line ) { - return line.start.equals( this.start ) && line.end.equals( this.end ); + return line.start.equals( this.start ) && line.end.equals( this.end ); - }, + }, - clone: function () { + clone: function () { - return new THREE.Line3().copy( this ); + return new THREE.Line3().copy( this ); - } + } }; +// File:src/math/Box2.js + /** * @author bhouston / http://exocortex.com */ THREE.Box2 = function ( min, max ) { - this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); + this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity ); }; THREE.Box2.prototype = { - constructor: THREE.Box2, + constructor: THREE.Box2, - set: function ( min, max ) { + set: function ( min, max ) { - this.min.copy( min ); - this.max.copy( max ); + this.min.copy( min ); + this.max.copy( max ); - return this; + return this; - }, + }, - setFromPoints: function ( points ) { + setFromPoints: function ( points ) { - if ( points.length > 0 ) { + this.makeEmpty(); - var point = points[ 0 ]; + for ( var i = 0, il = points.length; i < il; i ++ ) { - this.min.copy( point ); - this.max.copy( point ); + this.expandByPoint( points[ i ] ) - for ( var i = 1, il = points.length; i < il; i ++ ) { - - point = points[ i ]; - - if ( point.x < this.min.x ) { - - this.min.x = point.x; - - } else if ( point.x > this.max.x ) { - - this.max.x = point.x; - - } - - if ( point.y < this.min.y ) { - - this.min.y = point.y; - - } else if ( point.y > this.max.y ) { - - this.max.y = point.y; - - } - - } - - } else { - - this.makeEmpty(); - - } + } - return this; + return this; - }, + }, - setFromCenterAndSize: function () { + setFromCenterAndSize: function () { - var v1 = new THREE.Vector2(); + var v1 = new THREE.Vector2(); - return function ( center, size ) { + return function ( center, size ) { - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - return this; + return this; - }; + }; - }(), + }(), - copy: function ( box ) { + copy: function ( box ) { - this.min.copy( box.min ); - this.max.copy( box.max ); + this.min.copy( box.min ); + this.max.copy( box.max ); - return this; + return this; - }, + }, - makeEmpty: function () { + makeEmpty: function () { - this.min.x = this.min.y = Infinity; - this.max.x = this.max.y = -Infinity; + this.min.x = this.min.y = Infinity; + this.max.x = this.max.y = - Infinity; - return this; + return this; - }, + }, - empty: function () { + empty: function () { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + // 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 ); + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - }, + }, - center: function ( optionalTarget ) { + center: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector2(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + var result = optionalTarget || new THREE.Vector2(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - }, + }, - size: function ( optionalTarget ) { + size: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector2(); - return result.subVectors( this.max, this.min ); + var result = optionalTarget || new THREE.Vector2(); + return result.subVectors( this.max, this.min ); - }, + }, - expandByPoint: function ( point ) { + expandByPoint: function ( point ) { - this.min.min( point ); - this.max.max( point ); + this.min.min( point ); + this.max.max( point ); - return this; - }, + return this; + }, - expandByVector: function ( vector ) { + expandByVector: function ( vector ) { - this.min.sub( vector ); - this.max.add( vector ); + this.min.sub( vector ); + this.max.add( vector ); - return this; - }, + return this; + }, - expandByScalar: function ( scalar ) { + expandByScalar: function ( scalar ) { - this.min.addScalar( -scalar ); - this.max.addScalar( scalar ); + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - return this; - }, + return this; + }, - containsPoint: function ( point ) { + containsPoint: function ( point ) { - if ( point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ) { + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ) { - return false; + return false; - } + } - return true; + return true; - }, + }, - containsBox: function ( box ) { + containsBox: function ( box ) { - if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { - return true; + return true; - } + } - return false; + return false; - }, + }, - getParameter: function ( point, optionalTarget ) { + getParameter: function ( point, optionalTarget ) { - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - var result = optionalTarget || new THREE.Vector2(); + var result = optionalTarget || new THREE.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 ) - ); + 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 ) + ); - }, + }, - isIntersectionBox: function ( box ) { + isIntersectionBox: function ( box ) { - // using 6 splitting planes to rule out intersections. + // using 6 splitting planes to rule out intersections. - if ( box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ) { + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ) { - return false; + return false; - } + } - return true; + return true; - }, + }, - clampPoint: function ( point, optionalTarget ) { + clampPoint: function ( point, optionalTarget ) { - var result = optionalTarget || new THREE.Vector2(); - return result.copy( point ).clamp( this.min, this.max ); + var result = optionalTarget || new THREE.Vector2(); + return result.copy( point ).clamp( this.min, this.max ); - }, + }, - distanceToPoint: function () { + distanceToPoint: function () { - var v1 = new THREE.Vector2(); + var v1 = new THREE.Vector2(); - return function ( point ) { + return function ( point ) { - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - }; + }; - }(), + }(), - intersect: function ( box ) { + intersect: function ( box ) { - this.min.max( box.min ); - this.max.min( box.max ); + this.min.max( box.min ); + this.max.min( box.max ); - return this; + return this; - }, + }, - union: function ( box ) { + union: function ( box ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.min.min( box.min ); + this.max.max( box.max ); - return this; + return this; - }, + }, - translate: function ( offset ) { + translate: function ( offset ) { - this.min.add( offset ); - this.max.add( offset ); + this.min.add( offset ); + this.max.add( offset ); - return this; + return this; - }, + }, - equals: function ( box ) { + equals: function ( box ) { - return box.min.equals( this.min ) && box.max.equals( this.max ); + return box.min.equals( this.min ) && box.max.equals( this.max ); - }, + }, - clone: function () { + clone: function () { - return new THREE.Box2().copy( this ); + return new THREE.Box2().copy( this ); - } + } }; +// File:src/math/Box3.js + /** * @author bhouston / http://exocortex.com * @author WestLangley / http://github.com/WestLangley @@ -3729,632 +3894,631 @@ THREE.Box2.prototype = { THREE.Box3 = function ( min, max ) { - this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity ); }; THREE.Box3.prototype = { - constructor: THREE.Box3, + constructor: THREE.Box3, - set: function ( min, max ) { + set: function ( min, max ) { - this.min.copy( min ); - this.max.copy( max ); + this.min.copy( min ); + this.max.copy( max ); - return this; + return this; - }, + }, - addPoint: function ( point ) { + setFromPoints: function ( points ) { - if ( point.x < this.min.x ) { + this.makeEmpty(); - this.min.x = point.x; + for ( var i = 0, il = points.length; i < il; i ++ ) { - } else if ( point.x > this.max.x ) { + this.expandByPoint( points[ i ] ) - this.max.x = point.x; + } - } + return this; - if ( point.y < this.min.y ) { + }, - this.min.y = point.y; + setFromCenterAndSize: function () { - } else if ( point.y > this.max.y ) { + var v1 = new THREE.Vector3(); - this.max.y = point.y; + return function ( center, size ) { - } + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - if ( point.z < this.min.z ) { + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - this.min.z = point.z; + return this; - } else if ( point.z > this.max.z ) { + }; - this.max.z = point.z; + }(), - } + setFromObject: function () { - }, + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and childrens', world transforms - setFromPoints: function ( points ) { + var v1 = new THREE.Vector3(); - if ( points.length > 0 ) { + return function ( object ) { - var point = points[ 0 ]; + var scope = this; - this.min.copy( point ); - this.max.copy( point ); + object.updateMatrixWorld( true ); - for ( var i = 1, il = points.length; i < il; i ++ ) { + this.makeEmpty(); - this.addPoint( points[ i ] ) + object.traverse( function ( node ) { - } + var geometry = node.geometry; - } else { + if ( geometry !== undefined ) { - this.makeEmpty(); + if ( geometry instanceof THREE.Geometry ) { - } + var vertices = geometry.vertices; - return this; + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - }, + v1.copy( vertices[ i ] ); - setFromCenterAndSize: function() { + v1.applyMatrix4( node.matrixWorld ); - var v1 = new THREE.Vector3(); + scope.expandByPoint( v1 ); - return function ( center, size ) { + } - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) { - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + var positions = geometry.attributes[ 'position' ].array; - return this; + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - }; + v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - }(), + v1.applyMatrix4( node.matrixWorld ); - setFromObject: function() { + scope.expandByPoint( v1 ); - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and childrens', world transforms + } - var v1 = new THREE.Vector3(); + } - return function( object ) { + } - var scope = this; + } ); - object.updateMatrixWorld( true ); + return this; - this.makeEmpty(); + }; - object.traverse( function ( node ) { + }(), - if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { + copy: function ( box ) { - var vertices = node.geometry.vertices; + this.min.copy( box.min ); + this.max.copy( box.max ); - for ( var i = 0, il = vertices.length; i < il; i++ ) { + return this; - v1.copy( vertices[ i ] ); + }, - v1.applyMatrix4( node.matrixWorld ); + makeEmpty: function () { - scope.expandByPoint( v1 ); + this.min.x = this.min.y = this.min.z = Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; - } + return this; - } + }, - } ); + empty: function () { - return this; + // 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 ); - }(), + }, - copy: function ( box ) { + center: function ( optionalTarget ) { - this.min.copy( box.min ); - this.max.copy( box.max ); + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - return this; + }, - }, + size: function ( optionalTarget ) { - makeEmpty: function () { + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.max, this.min ); - this.min.x = this.min.y = this.min.z = Infinity; - this.max.x = this.max.y = this.max.z = -Infinity; + }, - return this; + expandByPoint: function ( point ) { - }, + this.min.min( point ); + this.max.max( point ); - empty: function () { + return this; - // 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 ); + expandByVector: function ( vector ) { - }, + this.min.sub( vector ); + this.max.add( vector ); - center: function ( optionalTarget ) { + return this; - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + }, - }, + expandByScalar: function ( scalar ) { - size: function ( optionalTarget ) { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors( this.max, this.min ); + return this; - }, + }, - expandByPoint: function ( point ) { + containsPoint: function ( point ) { - this.min.min( point ); - this.max.max( point ); + if ( 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 ) { - return this; + return false; - }, + } - expandByVector: function ( vector ) { + return true; - this.min.sub( vector ); - this.max.add( vector ); + }, - return this; + containsBox: function ( box ) { - }, + if ( ( 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 ) ) { - expandByScalar: function ( scalar ) { + return true; - this.min.addScalar( -scalar ); - this.max.addScalar( scalar ); + } - return this; + return false; - }, + }, - containsPoint: function ( point ) { + getParameter: function ( point, optionalTarget ) { - if ( 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 ) { + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - return false; + var result = optionalTarget || new THREE.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 ) + ); - return true; + }, - }, + isIntersectionBox: function ( box ) { - containsBox: function ( box ) { + // using 6 splitting planes to rule out intersections. - if ( ( 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 ) ) { + if ( 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 ) { - return true; + return false; - } + } - return false; + return true; - }, + }, - getParameter: function ( point, optionalTarget ) { + clampPoint: function ( point, optionalTarget ) { - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + var result = optionalTarget || new THREE.Vector3(); + return result.copy( point ).clamp( this.min, this.max ); - var result = optionalTarget || new THREE.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 ) - ); + distanceToPoint: function () { - }, + var v1 = new THREE.Vector3(); - isIntersectionBox: function ( box ) { + return function ( point ) { - // using 6 splitting planes to rule out intersections. + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - if ( 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 ) { + }; - return false; + }(), - } + getBoundingSphere: function () { - return true; + var v1 = new THREE.Vector3(); - }, + return function ( optionalTarget ) { - clampPoint: function ( point, optionalTarget ) { + var result = optionalTarget || new THREE.Sphere(); - var result = optionalTarget || new THREE.Vector3(); - return result.copy( point ).clamp( this.min, this.max ); + result.center = this.center(); + result.radius = this.size( v1 ).length() * 0.5; - }, + return result; - distanceToPoint: function() { + }; - var v1 = new THREE.Vector3(); + }(), - return function ( point ) { + intersect: function ( box ) { - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + this.min.max( box.min ); + this.max.min( box.max ); - }; + return this; - }(), + }, - getBoundingSphere: function() { + union: function ( box ) { - var v1 = new THREE.Vector3(); + this.min.min( box.min ); + this.max.max( box.max ); - return function ( optionalTarget ) { + return this; - var result = optionalTarget || new THREE.Sphere(); + }, - result.center = this.center(); - result.radius = this.size( v1 ).length() * 0.5; + applyMatrix4: function () { - return result; + var points = [ + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3() + ]; - }; + return function ( matrix ) { - }(), + // 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 - intersect: function ( box ) { + this.makeEmpty(); + this.setFromPoints( points ); - this.min.max( box.min ); - this.max.min( box.max ); + return this; - return this; + }; - }, + }(), - union: function ( box ) { + translate: function ( offset ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.min.add( offset ); + this.max.add( offset ); - return this; + return this; - }, + }, - applyMatrix4: function() { + equals: function ( box ) { - var points = [ - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3() - ]; + return box.min.equals( this.min ) && box.max.equals( this.max ); - return function ( matrix ) { + }, - // 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 + clone: function () { - this.makeEmpty(); - this.setFromPoints( points ); + return new THREE.Box3().copy( this ); - return this; + } - }; +}; - }(), +// File:src/math/Matrix3.js - translate: function ( offset ) { +/** + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ - this.min.add( offset ); - this.max.add( offset ); +THREE.Matrix3 = function () { - return this; + this.elements = new Float32Array( [ - }, + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - equals: function ( box ) { + ] ); - return box.min.equals( this.min ) && box.max.equals( this.max ); + if ( arguments.length > 0 ) { - }, + THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); - clone: function () { + } - return new THREE.Box3().copy( this ); +}; - } - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { +THREE.Matrix3.prototype = { - this.elements = new Float32Array(9); + constructor: THREE.Matrix3, - this.set( + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, - n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, - n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 + var te = this.elements; - ); -}; + te[ 0 ] = n11; te[ 3 ] = n12; te[ 6 ] = n13; + te[ 1 ] = n21; te[ 4 ] = n22; te[ 7 ] = n23; + te[ 2 ] = n31; te[ 5 ] = n32; te[ 8 ] = n33; -THREE.Matrix3.prototype = { + return this; - constructor: THREE.Matrix3, + }, - set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + identity: function () { - var te = this.elements; + this.set( - te[0] = n11; te[3] = n12; te[6] = n13; - te[1] = n21; te[4] = n22; te[7] = n23; - te[2] = n31; te[5] = n32; te[8] = n33; + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - return this; + ); - }, + return this; - identity: function () { + }, - this.set( + copy: function ( m ) { - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + var me = m.elements; - ); + this.set( - return this; + me[ 0 ], me[ 3 ], me[ 6 ], + me[ 1 ], me[ 4 ], me[ 7 ], + me[ 2 ], me[ 5 ], me[ 8 ] - }, + ); - copy: function ( m ) { + return this; - var me = m.elements; + }, - this.set( + multiplyVector3: function ( vector ) { - me[0], me[3], me[6], - me[1], me[4], me[7], - me[2], me[5], me[8] + THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); - ); + }, - return this; + multiplyVector3Array: function ( a ) { - }, + THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); - multiplyVector3: function ( vector ) { + }, - console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); + applyToVector3Array: function () { - }, + var v1 = new THREE.Vector3(); - multiplyVector3Array: function ( a ) { + return function ( array, offset, length ) { - console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); - return this.applyToVector3Array( a ); + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - }, + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - applyToVector3Array: function() { + v1.x = array[ j ]; + v1.y = array[ j + 1 ]; + v1.z = array[ j + 2 ]; - var v1 = new THREE.Vector3(); + v1.applyMatrix3( this ); - return function ( a ) { + array[ j ] = v1.x; + array[ j + 1 ] = v1.y; + array[ j + 2 ] = v1.z; - for ( var i = 0, il = a.length; i < il; i += 3 ) { + } - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; + return array; - v1.applyMatrix3( this ); + }; - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; + }(), - } + multiplyScalar: function ( s ) { - return a; + 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; - multiplyScalar: function ( s ) { + }, - var te = this.elements; + determinant: function () { - 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; + var te = this.elements; - return this; + 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; - determinant: function () { + }, - var te = this.elements; + getInverse: function ( matrix, throwOnInvertible ) { - 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]; + // input: THREE.Matrix4 + // ( based on http://code.google.com/p/webgl-mjs/ ) - return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; + var me = matrix.elements; + var te = this.elements; - }, + te[ 0 ] = me[ 10 ] * me[ 5 ] - me[ 6 ] * me[ 9 ]; + te[ 1 ] = - me[ 10 ] * me[ 1 ] + me[ 2 ] * me[ 9 ]; + te[ 2 ] = me[ 6 ] * me[ 1 ] - me[ 2 ] * me[ 5 ]; + te[ 3 ] = - me[ 10 ] * me[ 4 ] + me[ 6 ] * me[ 8 ]; + te[ 4 ] = me[ 10 ] * me[ 0 ] - me[ 2 ] * me[ 8 ]; + te[ 5 ] = - me[ 6 ] * me[ 0 ] + me[ 2 ] * me[ 4 ]; + te[ 6 ] = me[ 9 ] * me[ 4 ] - me[ 5 ] * me[ 8 ]; + te[ 7 ] = - me[ 9 ] * me[ 0 ] + me[ 1 ] * me[ 8 ]; + te[ 8 ] = me[ 5 ] * me[ 0 ] - me[ 1 ] * me[ 4 ]; - getInverse: function ( matrix, throwOnInvertible ) { + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; - // input: THREE.Matrix4 - // ( based on http://code.google.com/p/webgl-mjs/ ) + // no inverse - var me = matrix.elements; - var te = this.elements; + if ( det === 0 ) { - te[ 0 ] = me[10] * me[5] - me[6] * me[9]; - te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; - te[ 2 ] = me[6] * me[1] - me[2] * me[5]; - te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; - te[ 4 ] = me[10] * me[0] - me[2] * me[8]; - te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; - te[ 6 ] = me[9] * me[4] - me[5] * me[8]; - te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; - te[ 8 ] = me[5] * me[0] - me[1] * me[4]; + var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; - var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; + if ( throwOnInvertible || false ) { - // no inverse + throw new Error( msg ); - if ( det === 0 ) { + } else { - var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; + THREE.warn( msg ); - if ( throwOnInvertible || false ) { + } - throw new Error( msg ); + this.identity(); - } else { + return this; - console.warn( msg ); + } - } + this.multiplyScalar( 1.0 / det ); - this.identity(); + return this; - return this; + }, - } + transpose: function () { - this.multiplyScalar( 1.0 / det ); + var tmp, m = this.elements; - return this; + 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; - transpose: function () { + }, - var tmp, m = this.elements; + flattenToArrayOffset: function ( array, offset ) { - 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; + var te = this.elements; - return this; + 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 ]; - getNormalMatrix: function ( m ) { + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; - // input: THREE.Matrix4 + return array; - this.getInverse( m ).transpose(); + }, - return this; + getNormalMatrix: function ( m ) { - }, + // input: THREE.Matrix4 - transposeIntoArray: function ( r ) { + this.getInverse( m ).transpose(); - var m = this.elements; + return this; - 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; + transposeIntoArray: function ( r ) { - }, + var m = this.elements; - fromArray: function ( array ) { + 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 ]; - this.elements.set( array ); + return this; - return this; + }, - }, + fromArray: function ( array ) { - toArray: function () { + this.elements.set( array ); - var te = this.elements; + return this; - return [ - te[ 0 ], te[ 1 ], te[ 2 ], - te[ 3 ], te[ 4 ], te[ 5 ], - te[ 6 ], te[ 7 ], te[ 8 ] - ]; + }, - }, + toArray: function () { - clone: function () { + var te = this.elements; - var te = this.elements; + return [ + te[ 0 ], te[ 1 ], te[ 2 ], + te[ 3 ], te[ 4 ], te[ 5 ], + te[ 6 ], te[ 7 ], te[ 8 ] + ]; - return new THREE.Matrix3( + }, - te[0], te[3], te[6], - te[1], te[4], te[7], - te[2], te[5], te[8] + clone: function () { - ); + return new THREE.Matrix3().fromArray( this.elements ); - } + } }; +// File:src/math/Matrix4.js + /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -4368,1443 +4532,1508 @@ THREE.Matrix3.prototype = { * @author WestLangley / http://github.com/WestLangley */ +THREE.Matrix4 = function () { -THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + this.elements = new Float32Array( [ - this.elements = new Float32Array( 16 ); + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix - // we should not support semi specification of Matrix4, it is just weird. + ] ); - var te = this.elements; + if ( arguments.length > 0 ) { - te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; - te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; - te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; - te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; + THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); + + } }; THREE.Matrix4.prototype = { - constructor: THREE.Matrix4, - - set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + constructor: THREE.Matrix4, - var te = this.elements; + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - 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; + var te = this.elements; - return this; + 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( + identity: function () { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + this.set( - ); + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - return this; + ); - }, + return this; - copy: function ( m ) { + }, - this.elements.set( m.elements ); + copy: function ( m ) { - return this; + this.elements.set( m.elements ); - }, + return this; - extractPosition: function ( m ) { + }, - console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); + extractPosition: function ( m ) { - }, + THREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); - copyPosition: function ( m ) { + }, - var te = this.elements; - var me = m.elements; + copyPosition: function ( m ) { - te[12] = me[12]; - te[13] = me[13]; - te[14] = me[14]; + var te = this.elements; + var me = m.elements; - return this; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; - }, + return this; - extractRotation: function () { + }, - var v1 = new THREE.Vector3(); + extractBasis: function ( xAxis, yAxis, zAxis ) { + + var te = this.elements; + + xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] ); + yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] ); + zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] ); + + return this; + + }, + + makeBasis: function ( xAxis, yAxis, zAxis ) { - return function ( m ) { + 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 + ); - var te = this.elements; - var me = m.elements; + return this; - var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); - var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); - var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); + }, - te[0] = me[0] * scaleX; - te[1] = me[1] * scaleX; - te[2] = me[2] * scaleX; + extractRotation: function () { - te[4] = me[4] * scaleY; - te[5] = me[5] * scaleY; - te[6] = me[6] * scaleY; + var v1 = new THREE.Vector3(); - te[8] = me[8] * scaleZ; - te[9] = me[9] * scaleZ; - te[10] = me[10] * scaleZ; + return function ( m ) { - return this; + var te = this.elements; + var me = m.elements; - }; + var scaleX = 1 / v1.set( me[ 0 ], me[ 1 ], me[ 2 ] ).length(); + var scaleY = 1 / v1.set( me[ 4 ], me[ 5 ], me[ 6 ] ).length(); + var scaleZ = 1 / v1.set( me[ 8 ], me[ 9 ], me[ 10 ] ).length(); - }(), + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; - makeRotationFromEuler: function ( euler ) { + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; - if ( euler instanceof THREE.Euler === false ) { + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; - console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + return this; - } + }; - 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 ); + makeRotationFromEuler: function ( euler ) { - if ( euler.order === 'XYZ' ) { + if ( euler instanceof THREE.Euler === false ) { - var ae = a * e, af = a * f, be = b * e, bf = b * f; + THREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - 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; + var te = this.elements; - te[2] = bf - ae * d; - te[6] = be + af * d; - te[10] = a * c; + 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 ); - } else if ( euler.order === 'YXZ' ) { + if ( euler.order === 'XYZ' ) { - var ce = c * e, cf = c * f, de = d * e, df = d * f; + var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = ce + df * b; - te[4] = de * b - cf; - te[8] = a * d; + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - te[1] = a * f; - te[5] = a * e; - te[9] = - b; + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - te[2] = cf * b - de; - te[6] = df + ce * b; - te[10] = a * c; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - } else if ( euler.order === 'ZXY' ) { + } else if ( euler.order === 'YXZ' ) { - var ce = c * e, cf = c * f, de = d * e, df = d * f; + 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[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - te[1] = cf + de * b; - te[5] = a * e; - te[9] = df - ce * b; + te[ 1 ] = a * f; + te[ 5 ] = a * e; + te[ 9 ] = - b; - te[2] = - a * d; - te[6] = b; - te[10] = a * c; + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; - } else if ( euler.order === 'ZYX' ) { + } else if ( euler.order === 'ZXY' ) { - var ae = a * e, af = a * f, be = b * e, bf = b * f; + var ce = c * e, cf = c * f, de = d * e, df = d * f; - te[0] = c * e; - te[4] = be * d - af; - te[8] = ae * d + bf; + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - te[1] = c * f; - te[5] = bf * d + ae; - te[9] = af * d - be; + te[ 1 ] = cf + de * b; + te[ 5 ] = a * e; + te[ 9 ] = df - ce * b; - te[2] = - d; - te[6] = b * c; - te[10] = a * c; + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; - } else if ( euler.order === 'YZX' ) { + } else if ( euler.order === 'ZYX' ) { - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = c * e; - te[4] = bd - ac * f; - te[8] = bc * f + ad; + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - te[1] = f; - te[5] = a * e; - te[9] = - b * e; + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - te[2] = - d * e; - te[6] = ad * f + bc; - te[10] = ac - bd * f; + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - } else if ( euler.order === 'XZY' ) { + } else if ( euler.order === 'YZX' ) { - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + 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[ 0 ] = c * e; + te[ 4 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; - te[1] = ac * f + bd; - te[5] = a * e; - te[9] = ad * f - bc; + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - te[2] = bc * f - ad; - te[6] = b * e; - te[10] = bd * f + ac; + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - } + } else if ( euler.order === 'XZY' ) { - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - return this; + 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; - setRotationFromQuaternion: function ( q ) { + } - console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - return this.makeRotationFromQuaternion( q ); + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - }, + return this; - makeRotationFromQuaternion: function ( q ) { + }, - var te = this.elements; + setRotationFromQuaternion: function ( q ) { - 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; + THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - te[0] = 1 - ( yy + zz ); - te[4] = xy - wz; - te[8] = xz + wy; + return this.makeRotationFromQuaternion( q ); - 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 ); + makeRotationFromQuaternion: function ( q ) { - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + var te = this.elements; - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + 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; - return this; + 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; - lookAt: function() { + te[ 2 ] = xz - wy; + te[ 6 ] = yz + wx; + te[ 10 ] = 1 - ( xx + yy ); - var x = new THREE.Vector3(); - var y = new THREE.Vector3(); - var z = new THREE.Vector3(); + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - return function ( eye, target, up ) { + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - var te = this.elements; + return this; - z.subVectors( eye, target ).normalize(); + }, - if ( z.length() === 0 ) { + lookAt: function () { - z.z = 1; + var x = new THREE.Vector3(); + var y = new THREE.Vector3(); + var z = new THREE.Vector3(); - } + return function ( eye, target, up ) { - x.crossVectors( up, z ).normalize(); + var te = this.elements; - if ( x.length() === 0 ) { + z.subVectors( eye, target ).normalize(); - z.x += 0.0001; - x.crossVectors( up, z ).normalize(); + if ( z.length() === 0 ) { - } + z.z = 1; - y.crossVectors( z, x ); + } + x.crossVectors( up, z ).normalize(); - te[0] = x.x; te[4] = y.x; te[8] = z.x; - te[1] = x.y; te[5] = y.y; te[9] = z.y; - te[2] = x.z; te[6] = y.z; te[10] = z.z; + if ( x.length() === 0 ) { - return this; + z.x += 0.0001; + x.crossVectors( up, z ).normalize(); - }; + } - }(), + y.crossVectors( z, x ); - multiply: function ( m, n ) { - if ( n !== undefined ) { + 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; - console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); + return this; - } + }; - return this.multiplyMatrices( this, m ); + }(), - }, + multiply: function ( m, n ) { - multiplyMatrices: function ( a, b ) { + if ( n !== undefined ) { - var ae = a.elements; - var be = b.elements; - var te = this.elements; + THREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); - 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]; + return this.multiplyMatrices( this, m ); - 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; + multiplyMatrices: function ( a, b ) { - 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; + var ae = a.elements; + var be = b.elements; + var te = this.elements; - 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; + 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 ]; - return this; + 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; - multiplyToArray: function ( a, b, r ) { + 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; - var te = this.elements; + 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; - this.multiplyMatrices( a, b ); + 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; - 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; - return this; + }, - }, + multiplyToArray: function ( a, b, r ) { - multiplyScalar: function ( s ) { + var te = this.elements; - var te = this.elements; + this.multiplyMatrices( a, b ); - 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; + 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; + return this; - }, + }, - multiplyVector3: function ( vector ) { + multiplyScalar: function ( s ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); - return vector.applyProjection( this ); + 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; - multiplyVector4: function ( vector ) { + return this; - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + }, - }, + multiplyVector3: function ( vector ) { - multiplyVector3Array: function ( a ) { + THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + return vector.applyProjection( this ); - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); - return this.applyToVector3Array( a ); + }, - }, + multiplyVector4: function ( vector ) { - applyToVector3Array: function() { + THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - var v1 = new THREE.Vector3(); + }, - return function ( a ) { + multiplyVector3Array: function ( a ) { - for ( var i = 0, il = a.length; i < il; i += 3 ) { + THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; + }, - v1.applyMatrix4( this ); + applyToVector3Array: function () { - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; + var v1 = new THREE.Vector3(); - } + return function ( array, offset, length ) { - return a; + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - }; + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - }(), + v1.x = array[ j ]; + v1.y = array[ j + 1 ]; + v1.z = array[ j + 2 ]; - rotateAxis: function ( v ) { + v1.applyMatrix4( this ); - console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + array[ j ] = v1.x; + array[ j + 1 ] = v1.y; + array[ j + 2 ] = v1.z; - v.transformDirection( this ); + } - }, + return array; - crossVector: function ( vector ) { + }; - console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + }(), - }, + rotateAxis: function ( v ) { - determinant: function () { + THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - var te = this.elements; + v.transformDirection( this ); - 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 ) + crossVector: function ( vector ) { - 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 - ) + THREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - ); + }, - }, + determinant: function () { - transpose: function () { + var te = this.elements; - var te = this.elements; - var tmp; + 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 ]; - 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; + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - 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 ( + 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 + ) - return this; + ); - }, + }, - flattenToArray: function ( flat ) { + transpose: function () { - var te = this.elements; - flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; - flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; - flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; - flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; + var te = this.elements; + var tmp; - return flat; + 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; - flattenToArrayOffset: function( flat, offset ) { + return this; - var te = this.elements; - flat[ offset ] = te[0]; - flat[ offset + 1 ] = te[1]; - flat[ offset + 2 ] = te[2]; - flat[ offset + 3 ] = te[3]; + }, - flat[ offset + 4 ] = te[4]; - flat[ offset + 5 ] = te[5]; - flat[ offset + 6 ] = te[6]; - flat[ offset + 7 ] = te[7]; + flattenToArrayOffset: function ( array, offset ) { - flat[ offset + 8 ] = te[8]; - flat[ offset + 9 ] = te[9]; - flat[ offset + 10 ] = te[10]; - flat[ offset + 11 ] = te[11]; + var te = this.elements; - flat[ offset + 12 ] = te[12]; - flat[ offset + 13 ] = te[13]; - flat[ offset + 14 ] = te[14]; - flat[ offset + 15 ] = te[15]; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - return flat; + 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 ]; - getPosition: function() { + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - var v1 = new THREE.Vector3(); + return array; - return function () { + }, - console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + getPosition: function () { - var te = this.elements; - return v1.set( te[12], te[13], te[14] ); + var v1 = new THREE.Vector3(); - }; + return function () { - }(), + THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - setPosition: function ( v ) { + var te = this.elements; + return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); - var te = this.elements; + }; - te[12] = v.x; - te[13] = v.y; - te[14] = v.z; + }(), - return this; + setPosition: function ( v ) { - }, + var te = this.elements; - getInverse: function ( m, throwOnInvertible ) { + te[ 12 ] = v.x; + te[ 13 ] = v.y; + te[ 14 ] = v.z; - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements; - var me = m.elements; + return this; - var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; - var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; - var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; - var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; + }, - te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; - te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; - te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; - te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; - te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; - te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; - te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; - te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; - te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; - te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; - te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; - te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; - te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; - te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; - te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; - te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; + getInverse: function ( m, throwOnInvertible ) { - var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements; + var me = m.elements; - if ( det == 0 ) { + var n11 = me[ 0 ], n12 = me[ 4 ], n13 = me[ 8 ], n14 = me[ 12 ]; + var n21 = me[ 1 ], n22 = me[ 5 ], n23 = me[ 9 ], n24 = me[ 13 ]; + var n31 = me[ 2 ], n32 = me[ 6 ], n33 = me[ 10 ], n34 = me[ 14 ]; + var n41 = me[ 3 ], n42 = me[ 7 ], n43 = me[ 11 ], n44 = me[ 15 ]; - var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + te[ 0 ] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; + te[ 4 ] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; + te[ 8 ] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; + te[ 12 ] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + te[ 1 ] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44; + te[ 5 ] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44; + te[ 9 ] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44; + te[ 13 ] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34; + te[ 2 ] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44; + te[ 6 ] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44; + te[ 10 ] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44; + te[ 14 ] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34; + te[ 3 ] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43; + te[ 7 ] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43; + te[ 11 ] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43; + te[ 15 ] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33; - if ( throwOnInvertible || false ) { + var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; - throw new Error( msg ); + if ( det == 0 ) { - } else { + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; - console.warn( msg ); + if ( throwOnInvertible || false ) { - } + throw new Error( msg ); - this.identity(); + } else { - return this; - } + THREE.warn( msg ); - this.multiplyScalar( 1 / det ); + } - return this; + this.identity(); - }, + return this; + } - translate: function ( v ) { + this.multiplyScalar( 1 / det ); - console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); + return this; - }, + }, - rotateX: function ( angle ) { + translate: function ( v ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); + THREE.error( 'THREE.Matrix4: .translate() has been removed.' ); - }, + }, - rotateY: function ( angle ) { + rotateX: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - }, + }, - rotateZ: function ( angle ) { + rotateY: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - }, + }, - rotateByAxis: function ( axis, angle ) { + rotateZ: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - }, + }, - scale: function ( v ) { + rotateByAxis: function ( axis, angle ) { - var te = this.elements; - var x = v.x, y = v.y, z = v.z; + THREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - 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; + scale: function ( v ) { - }, + var te = this.elements; + var x = v.x, y = v.y, z = v.z; - getMaxScaleOnAxis: function () { + 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; - var te = this.elements; + return this; - var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; - var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; - var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; + }, - return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); + getMaxScaleOnAxis: function () { - }, + var te = this.elements; - makeTranslation: function ( x, y, z ) { + 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 ]; - this.set( + return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + }, - ); + makeTranslation: function ( x, y, z ) { - return this; + this.set( - }, + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 - makeRotationX: function ( theta ) { + ); - var c = Math.cos( theta ), s = Math.sin( theta ); + return this; - this.set( + }, - 1, 0, 0, 0, - 0, c, -s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + makeRotationX: function ( theta ) { - ); + var c = Math.cos( theta ), s = Math.sin( theta ); - return this; + this.set( - }, + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 - makeRotationY: function ( theta ) { + ); - var c = Math.cos( theta ), s = Math.sin( theta ); + return this; - this.set( + }, - c, 0, s, 0, - 0, 1, 0, 0, - -s, 0, c, 0, - 0, 0, 0, 1 + makeRotationY: function ( theta ) { - ); + var c = Math.cos( theta ), s = Math.sin( theta ); - return this; + this.set( - }, + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 - makeRotationZ: function ( theta ) { + ); - var c = Math.cos( theta ), s = Math.sin( theta ); + return this; - this.set( + }, - c, -s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + makeRotationZ: function ( theta ) { - ); + var c = Math.cos( theta ), s = Math.sin( theta ); - return this; + this.set( - }, + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - makeRotationAxis: function ( axis, angle ) { + ); - // Based on http://www.gamedev.net/reference/articles/article1199.asp + return this; - 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( + makeRotationAxis: function ( axis, angle ) { - 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 + // 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; - return this; + 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 - makeScale: function ( x, y, z ) { + ); - this.set( + return this; - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + }, - ); + makeScale: function ( x, y, z ) { - return this; + this.set( - }, + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - compose: function ( position, quaternion, scale ) { + ); - this.makeRotationFromQuaternion( quaternion ); - this.scale( scale ); - this.setPosition( position ); + return this; - return this; + }, - }, + compose: function ( position, quaternion, scale ) { - decompose: function () { + this.makeRotationFromQuaternion( quaternion ); + this.scale( scale ); + this.setPosition( position ); - var vector = new THREE.Vector3(); - var matrix = new THREE.Matrix4(); + return this; - return function ( position, quaternion, scale ) { + }, - var te = this.elements; + decompose: function () { - 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(); + var vector = new THREE.Vector3(); + var matrix = new THREE.Matrix4(); - // if determine is negative, we need to invert one scale - var det = this.determinant(); - if( det < 0 ) { - sx = -sx; - } + return function ( position, quaternion, scale ) { - position.x = te[12]; - position.y = te[13]; - position.z = te[14]; + var te = this.elements; - // scale the rotation part + 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(); - matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if ( det < 0 ) { + sx = - sx; + } - var invSX = 1 / sx; - var invSY = 1 / sy; - var invSZ = 1 / sz; + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - matrix.elements[0] *= invSX; - matrix.elements[1] *= invSX; - matrix.elements[2] *= invSX; + // scale the rotation part - matrix.elements[4] *= invSY; - matrix.elements[5] *= invSY; - matrix.elements[6] *= invSY; + matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() - matrix.elements[8] *= invSZ; - matrix.elements[9] *= invSZ; - matrix.elements[10] *= invSZ; + var invSX = 1 / sx; + var invSY = 1 / sy; + var invSZ = 1 / sz; - quaternion.setFromRotationMatrix( matrix ); + matrix.elements[ 0 ] *= invSX; + matrix.elements[ 1 ] *= invSX; + matrix.elements[ 2 ] *= invSX; - scale.x = sx; - scale.y = sy; - scale.z = sz; + matrix.elements[ 4 ] *= invSY; + matrix.elements[ 5 ] *= invSY; + matrix.elements[ 6 ] *= invSY; - return this; + matrix.elements[ 8 ] *= invSZ; + matrix.elements[ 9 ] *= invSZ; + matrix.elements[ 10 ] *= invSZ; - }; + quaternion.setFromRotationMatrix( matrix ); - }(), + scale.x = sx; + scale.y = sy; + scale.z = sz; - makeFrustum: function ( left, right, bottom, top, near, far ) { + return this; - 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; + makeFrustum: function ( left, right, bottom, top, near, far ) { - return this; + 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 ); - makePerspective: function ( fov, aspect, near, far ) { + 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; - var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); - var ymin = - ymax; - var xmin = ymin * aspect; - var xmax = ymax * aspect; + return this; - return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); + }, - }, + makePerspective: function ( fov, aspect, near, far ) { - makeOrthographic: function ( left, right, top, bottom, near, far ) { + var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); + var ymin = - ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; - var te = this.elements; - var w = right - left; - var h = top - bottom; - var p = far - near; + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); - 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; + makeOrthographic: function ( left, right, top, bottom, near, far ) { - return this; + var te = this.elements; + var w = right - left; + var h = top - bottom; + var p = far - near; - }, + var x = ( right + left ) / w; + var y = ( top + bottom ) / h; + var z = ( far + near ) / p; - fromArray: function ( array ) { + 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; - this.elements.set( array ); + return this; - return this; + }, - }, + fromArray: function ( array ) { - toArray: function () { + this.elements.set( array ); - var te = this.elements; + return this; - return [ - te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], - te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], - te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], - te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] - ]; + }, - }, + toArray: function () { - clone: function () { + var te = this.elements; - var te = this.elements; + return [ + te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], + te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], + te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], + te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] + ]; - return new THREE.Matrix4( + }, - te[0], te[4], te[8], te[12], - te[1], te[5], te[9], te[13], - te[2], te[6], te[10], te[14], - te[3], te[7], te[11], te[15] + clone: function () { - ); + return new THREE.Matrix4().fromArray( this.elements ); - } + } }; +// File:src/math/Ray.js + /** * @author bhouston / http://exocortex.com */ THREE.Ray = function ( origin, direction ) { - this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); - this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); + this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); + this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); }; THREE.Ray.prototype = { - constructor: THREE.Ray, + constructor: THREE.Ray, + + set: function ( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; - set: function ( origin, direction ) { + }, - this.origin.copy( origin ); - this.direction.copy( direction ); + at: function ( t, optionalTarget ) { - return this; + var result = optionalTarget || new THREE.Vector3(); - }, + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - copy: function ( ray ) { + }, - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + recast: function () { - return this; + var v1 = new THREE.Vector3(); - }, + return function ( t ) { - at: function ( t, optionalTarget ) { + this.origin.copy( this.at( t, v1 ) ); - var result = optionalTarget || new THREE.Vector3(); + return this; - return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + }; - }, + }(), - recast: function () { + closestPointToPoint: function ( point, optionalTarget ) { - var v1 = new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); + result.subVectors( point, this.origin ); + var directionDistance = result.dot( this.direction ); - return function ( t ) { + if ( directionDistance < 0 ) { - this.origin.copy( this.at( t, v1 ) ); + return result.copy( this.origin ); - return this; + } + + return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + }, + + distanceToPoint: function () { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + + // point behind the ray + + if ( directionDistance < 0 ) { + + return this.origin.distanceTo( point ); + + } + + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + return v1.distanceTo( point ); + + }; + + }(), + + distanceSqToSegment: function () { - }; + var segCenter = new THREE.Vector3(); + var segDir = new THREE.Vector3(); + var diff = new THREE.Vector3(); - }(), + return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - closestPointToPoint: function ( point, optionalTarget ) { + // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp + // 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 - var result = optionalTarget || new THREE.Vector3(); - result.subVectors( point, this.origin ); - var directionDistance = result.dot( this.direction ); + segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + segDir.copy( v1 ).sub( v0 ).normalize(); + diff.copy( this.origin ).sub( segCenter ); - if ( directionDistance < 0 ) { + 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; - return result.copy( this.origin ); + if ( det > 0 ) { - } + // The ray and segment are not parallel. - return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - }, + if ( s0 >= 0 ) { - distanceToPoint: function () { + if ( s1 >= - extDet ) { - var v1 = new THREE.Vector3(); + if ( s1 <= extDet ) { - return function ( point ) { + // region 0 + // Minimum at interior points of ray and segment. - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - // point behind the ray + } else { - if ( directionDistance < 0 ) { + // region 1 - return this.origin.distanceTo( point ); + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + } else { - return v1.distanceTo( point ); + // region 5 - }; + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - }(), + } - distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + } else { - // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp - // 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 + if ( s1 <= - extDet ) { - var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); - var segDir = v1.clone().sub( v0 ).normalize(); - var segExtent = v0.distanceTo( v1 ) * 0.5; - var diff = this.origin.clone().sub( segCenter ); - 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; + // region 4 - if ( det >= 0 ) { + 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; - // The ray and segment are not parallel. + } else if ( s1 <= extDet ) { - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + // region 3 - if ( s0 >= 0 ) { + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - if ( s1 >= - extDet ) { + } else { - if ( s1 <= extDet ) { + // region 2 - // region 0 - // Minimum at interior points of ray and segment. + 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; - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + } - } else { + } + + } 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 ); + + } - // region 1 + if ( optionalPointOnSegment ) { - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); - } + } - } else { + return sqrDist; - // region 5 + }; - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + }(), - } - } else { + isIntersectionSphere: function ( sphere ) { - if ( s1 <= - extDet) { + return this.distanceToPoint( sphere.center ) <= sphere.radius; - // 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; + intersectSphere: function () { - } else if ( s1 <= extDet ) { + // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/ - // region 3 + var v1 = new THREE.Vector3(); - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + return function ( sphere, optionalTarget ) { - } else { + v1.subVectors( sphere.center, this.origin ); - // region 2 + var tca = v1.dot( this.direction ); - 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; + var d2 = v1.dot( v1 ) - tca * tca; - } + var radius2 = sphere.radius * sphere.radius; - } + if ( d2 > radius2 ) return null; - } else { + var thc = Math.sqrt( radius2 - d2 ); - // Ray and segment are parallel. + // t0 = first intersect point - entrance on front of sphere + var t0 = tca - thc; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + // 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; - if ( optionalPointOnRay ) { + // 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 ); - optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, optionalTarget ); - } + } - if ( optionalPointOnSegment ) { + }(), - optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); + isIntersectionPlane: function ( plane ) { - } + // check if the ray lies on the plane first - return sqrDist; + var distToPoint = plane.distanceToPoint( this.origin ); - }, + if ( distToPoint === 0 ) { - isIntersectionSphere: function ( sphere ) { + return true; - return this.distanceToPoint( sphere.center ) <= sphere.radius; + } - }, + var denominator = plane.normal.dot( this.direction ); - isIntersectionPlane: function ( plane ) { + if ( denominator * distToPoint < 0 ) { - // check if the ray lies on the plane first + return true; - var distToPoint = plane.distanceToPoint( this.origin ); + } - if ( distToPoint === 0 ) { + // ray origin is behind the plane (and is pointing behind it) - return true; + return false; - } + }, - var denominator = plane.normal.dot( this.direction ); + distanceToPlane: function ( plane ) { - if ( denominator * distToPoint < 0 ) { + var denominator = plane.normal.dot( this.direction ); + if ( denominator == 0 ) { - return true + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) == 0 ) { - } + return 0; - // ray origin is behind the plane (and is pointing behind it) + } - return false; + // Null is preferable to undefined since undefined means.... it is undefined - }, + return null; - distanceToPlane: function ( plane ) { + } - var denominator = plane.normal.dot( this.direction ); - if ( denominator == 0 ) { + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - // line is coplanar, return origin - if( plane.distanceToPoint( this.origin ) == 0 ) { + // Return if the ray never intersects the plane - return 0; + return t >= 0 ? t : null; - } + }, - // Null is preferable to undefined since undefined means.... it is undefined + intersectPlane: function ( plane, optionalTarget ) { - return null; + var t = this.distanceToPlane( plane ); - } + if ( t === null ) { - var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + return null; + } - // Return if the ray never intersects the plane + return this.at( t, optionalTarget ); - return t >= 0 ? t : null; + }, - }, + isIntersectionBox: function () { - intersectPlane: function ( plane, optionalTarget ) { + var v = new THREE.Vector3(); - var t = this.distanceToPlane( plane ); + return function ( box ) { - if ( t === null ) { + return this.intersectBox( box, v ) !== null; - return null; - } + }; - return this.at( t, optionalTarget ); + }(), - }, + intersectBox: function ( box, optionalTarget ) { - isIntersectionBox: function () { - - var v = new THREE.Vector3(); + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - return function ( box ) { + var tmin,tmax,tymin,tymax,tzmin,tzmax; - return this.intersectBox( box, v ) !== null; + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + var origin = this.origin; - }(), + if ( invdirx >= 0 ) { - intersectBox: function ( box , optionalTarget ) { + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + } else { - var tmin,tmax,tymin,tymax,tzmin,tzmax; + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; + } - var invdirx = 1/this.direction.x, - invdiry = 1/this.direction.y, - invdirz = 1/this.direction.z; + if ( invdiry >= 0 ) { - var origin = this.origin; + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - if (invdirx >= 0) { - - tmin = (box.min.x - origin.x) * invdirx; - tmax = (box.max.x - origin.x) * invdirx; + } else { - } else { + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; + } - tmin = (box.max.x - origin.x) * invdirx; - tmax = (box.min.x - origin.x) * invdirx; - } + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - if (invdiry >= 0) { - - tymin = (box.min.y - origin.y) * invdiry; - tymax = (box.max.y - origin.y) * invdiry; + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN - } else { + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - tymin = (box.max.y - origin.y) * invdiry; - tymax = (box.min.y - origin.y) * invdiry; - } + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - if ((tmin > tymax) || (tymin > tmax)) return null; + if ( invdirz >= 0 ) { - // 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; + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - if (tymax < tmax || tmax !== tmax ) tmax = tymax; + } else { - if (invdirz >= 0) { - - tzmin = (box.min.z - origin.z) * invdirz; - tzmax = (box.max.z - origin.z) * invdirz; + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; + } - } else { + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - tzmin = (box.max.z - origin.z) * invdirz; - tzmax = (box.min.z - origin.z) * invdirz; - } + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - if ((tmin > tzmax) || (tzmin > tmax)) return null; + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - if (tzmin > tmin || tmin !== tmin ) tmin = tzmin; + //return point closest to the ray (positive side) - if (tzmax < tmax || tmax !== tmax ) tmax = tzmax; + if ( tmax < 0 ) return null; - //return point closest to the ray (positive side) + return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); - if ( tmax < 0 ) return null; + }, - return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); + intersectTriangle: function () { - }, + // Compute the offset origin, edges, and normal. + var diff = new THREE.Vector3(); + var edge1 = new THREE.Vector3(); + var edge2 = new THREE.Vector3(); + var normal = new THREE.Vector3(); - intersectTriangle: function() { + return function ( a, b, c, backfaceCulling, optionalTarget ) { - // Compute the offset origin, edges, and normal. - var diff = new THREE.Vector3(); - var edge1 = new THREE.Vector3(); - var edge2 = new THREE.Vector3(); - var normal = new THREE.Vector3(); + // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp - return function ( a, b, c, backfaceCulling, optionalTarget ) { + edge1.subVectors( b, a ); + edge2.subVectors( c, a ); + normal.crossVectors( edge1, edge2 ); - // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp + // 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; - edge1.subVectors( b, a ); - edge2.subVectors( c, a ); - normal.crossVectors( edge1, edge2 ); + if ( DdN > 0 ) { - // 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 ( backfaceCulling ) return null; + sign = 1; - if ( DdN > 0 ) { + } else if ( DdN < 0 ) { - if ( backfaceCulling ) return null; - sign = 1; + sign = - 1; + DdN = - DdN; - } else if ( DdN < 0 ) { + } else { - sign = - 1; - DdN = - DdN; + return null; - } 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 ) { - diff.subVectors( this.origin, a ); - var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); + return null; - // 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 ) { - var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); + return null; - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + } - return null; + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - } + 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 ) { - // Line intersects triangle, check if ray does. - var QdN = - sign * diff.dot( normal ); + return null; - // t < 0, no intersection - if ( QdN < 0 ) { + } - return null; + // Ray intersects triangle. + return this.at( QdN / DdN, optionalTarget ); - } + }; - // Ray intersects triangle. - return this.at( QdN / DdN, optionalTarget ); - - } - - }(), + }(), - applyMatrix4: function ( matrix4 ) { + applyMatrix4: function ( matrix4 ) { - this.direction.add( this.origin ).applyMatrix4( matrix4 ); - this.origin.applyMatrix4( matrix4 ); - this.direction.sub( this.origin ); - this.direction.normalize(); + this.direction.add( this.origin ).applyMatrix4( matrix4 ); + this.origin.applyMatrix4( matrix4 ); + this.direction.sub( this.origin ); + this.direction.normalize(); - return this; - }, + return this; + }, - equals: function ( ray ) { + equals: function ( ray ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - }, + }, - clone: function () { + clone: function () { - return new THREE.Ray().copy( this ); + return new THREE.Ray().copy( this ); - } + } }; +// File:src/math/Sphere.js + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -5812,153 +6041,154 @@ THREE.Ray.prototype = { THREE.Sphere = function ( center, radius ) { - this.center = ( center !== undefined ) ? center : new THREE.Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; + this.center = ( center !== undefined ) ? center : new THREE.Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; }; THREE.Sphere.prototype = { - constructor: THREE.Sphere, + constructor: THREE.Sphere, - set: function ( center, radius ) { + set: function ( center, radius ) { - this.center.copy( center ); - this.radius = radius; + this.center.copy( center ); + this.radius = radius; - return this; - }, + return this; + }, + setFromPoints: function () { - setFromPoints: function () { + var box = new THREE.Box3(); - var box = new THREE.Box3(); + return function ( points, optionalCenter ) { - return function ( points, optionalCenter ) { + var center = this.center; - var center = this.center; + if ( optionalCenter !== undefined ) { - if ( optionalCenter !== undefined ) { + center.copy( optionalCenter ); - center.copy( optionalCenter ); + } else { - } else { + box.setFromPoints( points ).center( center ); - box.setFromPoints( points ).center( center ); + } - } + var maxRadiusSq = 0; - var maxRadiusSq = 0; + for ( var i = 0, il = points.length; i < il; i ++ ) { - for ( var i = 0, il = points.length; i < il; i ++ ) { + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + } - } + this.radius = Math.sqrt( maxRadiusSq ); - this.radius = Math.sqrt( maxRadiusSq ); + return this; - return this; - - }; + }; - }(), + }(), - copy: function ( sphere ) { + copy: function ( sphere ) { - this.center.copy( sphere.center ); - this.radius = sphere.radius; + this.center.copy( sphere.center ); + this.radius = sphere.radius; - return this; + return this; - }, + }, - empty: function () { + empty: function () { - return ( this.radius <= 0 ); + return ( this.radius <= 0 ); - }, + }, - containsPoint: function ( point ) { + containsPoint: function ( point ) { - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - }, + }, - distanceToPoint: function ( point ) { + distanceToPoint: function ( point ) { - return ( point.distanceTo( this.center ) - this.radius ); + return ( point.distanceTo( this.center ) - this.radius ); - }, + }, - intersectsSphere: function ( sphere ) { + intersectsSphere: function ( sphere ) { - var radiusSum = this.radius + sphere.radius; + var radiusSum = this.radius + sphere.radius; - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - }, + }, - clampPoint: function ( point, optionalTarget ) { + clampPoint: function ( point, optionalTarget ) { - var deltaLengthSq = this.center.distanceToSquared( point ); + var deltaLengthSq = this.center.distanceToSquared( point ); - var result = optionalTarget || new THREE.Vector3(); - result.copy( point ); + var result = optionalTarget || new THREE.Vector3(); + result.copy( point ); - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - result.sub( this.center ).normalize(); - result.multiplyScalar( this.radius ).add( this.center ); + result.sub( this.center ).normalize(); + result.multiplyScalar( this.radius ).add( this.center ); - } + } - return result; + return result; - }, + }, - getBoundingBox: function ( optionalTarget ) { + getBoundingBox: function ( optionalTarget ) { - var box = optionalTarget || new THREE.Box3(); + var box = optionalTarget || new THREE.Box3(); - box.set( this.center, this.center ); - box.expandByScalar( this.radius ); + box.set( this.center, this.center ); + box.expandByScalar( this.radius ); - return box; + return box; - }, + }, - applyMatrix4: function ( matrix ) { + applyMatrix4: function ( matrix ) { - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - return this; + return this; - }, + }, - translate: function ( offset ) { + translate: function ( offset ) { - this.center.add( offset ); + this.center.add( offset ); - return this; + return this; - }, + }, - equals: function ( sphere ) { + equals: function ( sphere ) { - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - }, + }, - clone: function () { + clone: function () { - return new THREE.Sphere().copy( this ); + return new THREE.Sphere().copy( this ); - } + } }; +// File:src/math/Frustum.js + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -5967,401 +6197,405 @@ THREE.Sphere.prototype = { THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { - this.planes = [ + this.planes = [ - ( p0 !== undefined ) ? p0 : new THREE.Plane(), - ( p1 !== undefined ) ? p1 : new THREE.Plane(), - ( p2 !== undefined ) ? p2 : new THREE.Plane(), - ( p3 !== undefined ) ? p3 : new THREE.Plane(), - ( p4 !== undefined ) ? p4 : new THREE.Plane(), - ( p5 !== undefined ) ? p5 : new THREE.Plane() + ( p0 !== undefined ) ? p0 : new THREE.Plane(), + ( p1 !== undefined ) ? p1 : new THREE.Plane(), + ( p2 !== undefined ) ? p2 : new THREE.Plane(), + ( p3 !== undefined ) ? p3 : new THREE.Plane(), + ( p4 !== undefined ) ? p4 : new THREE.Plane(), + ( p5 !== undefined ) ? p5 : new THREE.Plane() - ]; + ]; }; THREE.Frustum.prototype = { - constructor: THREE.Frustum, + constructor: THREE.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; + + }, - set: function ( p0, p1, p2, p3, p4, p5 ) { + copy: function ( frustum ) { - var planes = this.planes; + 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 ); + for ( var i = 0; i < 6; i ++ ) { - return this; + planes[ i ].copy( frustum.planes[ i ] ); - }, + } + + return this; - copy: function ( frustum ) { + }, - var planes = this.planes; + setFromMatrix: function ( m ) { - for( var i = 0; i < 6; i ++ ) { + 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[i].copy( frustum.planes[i] ); + 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; - return this; + }, - }, + intersectsObject: function () { - setFromMatrix: function ( m ) { + var sphere = new THREE.Sphere(); - 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]; + return function ( object ) { - 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(); + var geometry = object.geometry; - return this; + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - }, + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); - intersectsObject: function () { + return this.intersectsSphere( sphere ); - var sphere = new THREE.Sphere(); + }; - return function ( object ) { + }(), - var geometry = object.geometry; + intersectsSphere: function ( sphere ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + var planes = this.planes; + var center = sphere.center; + var negRadius = - sphere.radius; - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); + for ( var i = 0; i < 6; i ++ ) { - return this.intersectsSphere( sphere ); + var distance = planes[ i ].distanceToPoint( center ); - }; + if ( distance < negRadius ) { - }(), + return false; - intersectsSphere: function ( sphere ) { + } - var planes = this.planes; - var center = sphere.center; - var negRadius = -sphere.radius; + } - for ( var i = 0; i < 6; i ++ ) { + return true; - var distance = planes[ i ].distanceToPoint( center ); + }, - if ( distance < negRadius ) { + intersectsBox: function () { - return false; + var p1 = new THREE.Vector3(), + p2 = new THREE.Vector3(); - } + return function ( box ) { - } + var planes = this.planes; - return true; + for ( var i = 0; i < 6 ; i ++ ) { - }, + var plane = planes[ i ]; - intersectsBox : function() { + 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 p1 = new THREE.Vector3(), - p2 = new THREE.Vector3(); + var d1 = plane.distanceToPoint( p1 ); + var d2 = plane.distanceToPoint( p2 ); - return function( box ) { + // if both outside plane, no intersection - 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; + if ( d1 < 0 && d2 < 0 ) { - var d1 = plane.distanceToPoint( p1 ); - var d2 = plane.distanceToPoint( p2 ); - - // if both outside plane, no intersection + return false; - if ( d1 < 0 && d2 < 0 ) { - - return false; - - } - } + } + } - return true; - }; + return true; + }; - }(), + }(), - containsPoint: function ( point ) { + containsPoint: function ( point ) { - var planes = this.planes; + var planes = this.planes; - for ( var i = 0; i < 6; i ++ ) { + for ( var i = 0; i < 6; i ++ ) { - if ( planes[ i ].distanceToPoint( point ) < 0 ) { + if ( planes[ i ].distanceToPoint( point ) < 0 ) { - return false; + return false; - } + } - } + } - return true; + return true; - }, + }, - clone: function () { + clone: function () { - return new THREE.Frustum().copy( this ); + return new THREE.Frustum().copy( this ); - } + } }; +// File:src/math/Plane.js + /** * @author bhouston / http://exocortex.com */ THREE.Plane = function ( normal, constant ) { - this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; + this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; }; THREE.Plane.prototype = { - constructor: THREE.Plane, + constructor: THREE.Plane, - set: function ( normal, constant ) { + set: function ( normal, constant ) { - this.normal.copy( normal ); - this.constant = constant; + this.normal.copy( normal ); + this.constant = constant; - return this; + return this; - }, + }, - setComponents: function ( x, y, z, w ) { + setComponents: function ( x, y, z, w ) { - this.normal.set( x, y, z ); - this.constant = w; + this.normal.set( x, y, z ); + this.constant = w; - return this; + return this; - }, + }, - setFromNormalAndCoplanarPoint: function ( normal, point ) { + 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 + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized - return this; + return this; - }, + }, - setFromCoplanarPoints: function() { + setFromCoplanarPoints: function () { - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - return function ( a, b, c ) { + return function ( a, b, c ) { - var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + 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)? + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - this.setFromNormalAndCoplanarPoint( normal, a ); + this.setFromNormalAndCoplanarPoint( normal, a ); - return this; + return this; - }; + }; - }(), + }(), - copy: function ( plane ) { + copy: function ( plane ) { - this.normal.copy( plane.normal ); - this.constant = plane.constant; + this.normal.copy( plane.normal ); + this.constant = plane.constant; - return this; + return this; - }, + }, - normalize: function () { + normalize: function () { - // Note: will lead to a divide by zero if the plane is invalid. + // 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; + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; - return this; + return this; - }, + }, - negate: function () { + negate: function () { - this.constant *= -1; - this.normal.negate(); + this.constant *= - 1; + this.normal.negate(); - return this; + return this; - }, + }, - distanceToPoint: function ( point ) { + distanceToPoint: function ( point ) { - return this.normal.dot( point ) + this.constant; + return this.normal.dot( point ) + this.constant; - }, + }, - distanceToSphere: function ( sphere ) { + distanceToSphere: function ( sphere ) { - return this.distanceToPoint( sphere.center ) - sphere.radius; + return this.distanceToPoint( sphere.center ) - sphere.radius; - }, + }, - projectPoint: function ( point, optionalTarget ) { + projectPoint: function ( point, optionalTarget ) { - return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); + return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); - }, + }, - orthoPoint: function ( point, optionalTarget ) { + orthoPoint: function ( point, optionalTarget ) { - var perpendicularMagnitude = this.distanceToPoint( point ); + var perpendicularMagnitude = this.distanceToPoint( point ); - var result = optionalTarget || new THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); - }, + }, - isIntersectionLine: function ( line ) { + isIntersectionLine: function ( line ) { - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + // 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 ); + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - }, + }, - intersectLine: function() { + intersectLine: function () { - var v1 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return function ( line, optionalTarget ) { + return function ( line, optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - var direction = line.delta( v1 ); + var direction = line.delta( v1 ); - var denominator = this.normal.dot( direction ); + var denominator = this.normal.dot( direction ); - if ( denominator == 0 ) { + if ( denominator == 0 ) { - // line is coplanar, return origin - if( this.distanceToPoint( line.start ) == 0 ) { + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) == 0 ) { - return result.copy( line.start ); + return result.copy( line.start ); + + } - } + // Unsure if this is the correct method to handle this case. + return undefined; - // Unsure if this is the correct method to handle this case. - return undefined; + } - } + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + if ( t < 0 || t > 1 ) { - if( t < 0 || t > 1 ) { + return undefined; - return undefined; + } - } + return result.copy( direction ).multiplyScalar( t ).add( line.start ); - return result.copy( direction ).multiplyScalar( t ).add( line.start ); + }; - }; + }(), - }(), + coplanarPoint: function ( optionalTarget ) { - coplanarPoint: function ( optionalTarget ) { + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); - var result = optionalTarget || new THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( - this.constant ); + }, - }, + applyMatrix4: function () { - applyMatrix4: function() { + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var m1 = new THREE.Matrix3(); - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var m1 = new THREE.Matrix3(); + return function ( matrix, optionalNormalMatrix ) { - return function ( matrix, optionalNormalMatrix ) { + // compute new normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); - // compute new normal based on theory here: - // http://www.songho.ca/opengl/gl_normaltransform.html - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); - var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); - - var newCoplanarPoint = this.coplanarPoint( v2 ); - newCoplanarPoint.applyMatrix4( matrix ); + var newCoplanarPoint = this.coplanarPoint( v2 ); + newCoplanarPoint.applyMatrix4( matrix ); - this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); + this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); - return this; + return this; - }; + }; - }(), + }(), - translate: function ( offset ) { + translate: function ( offset ) { - this.constant = this.constant - offset.dot( this.normal ); + this.constant = this.constant - offset.dot( this.normal ); - return this; + return this; - }, + }, - equals: function ( plane ) { + equals: function ( plane ) { - return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); + return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); - }, + }, - clone: function () { + clone: function () { - return new THREE.Plane().copy( this ); + return new THREE.Plane().copy( this ); - } + } }; +// File:src/math/Math.js + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -6369,161 +6603,171 @@ THREE.Plane.prototype = { THREE.Math = { - generateUUID: function () { + 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 () { + + for ( var i = 0; i < 36; i ++ ) { + + if ( i == 8 || i == 13 || i == 18 || i == 23 ) { + + uuid[ i ] = '-'; + + } else if ( i == 14 ) { - // http://www.broofa.com/Tools/Math.uuid.htm - - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); - var uuid = new Array(36); - var rnd = 0, r; + uuid[ i ] = '4'; - return function () { + } else { - for ( var i = 0; i < 36; i ++ ) { + if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[ i ] = chars[ ( i == 19 ) ? ( r & 0x3 ) | 0x8 : r ]; - 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( '' ); - } - } - - return uuid.join(''); + }; - }; + }(), - }(), + // Clamp value to range - // Clamp value to range + clamp: function ( x, a, b ) { - clamp: function ( x, a, b ) { + return ( x < a ) ? a : ( ( x > b ) ? b : x ); - return ( x < a ) ? a : ( ( x > b ) ? b : x ); + }, - }, + // Clamp value to range to range - // Linear mapping from range to range + mapLinear: function ( x, a1, a2, b1, b2 ) { - mapLinear: function ( x, a1, a2, b1, b2 ) { + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + }, - }, + // http://en.wikipedia.org/wiki/Smoothstep - // http://en.wikipedia.org/wiki/Smoothstep + smoothstep: function ( x, min, max ) { - smoothstep: function ( x, min, max ) { + if ( x <= min ) return 0; + if ( x >= max ) return 1; - if ( x <= min ) return 0; - if ( x >= max ) return 1; + x = ( x - min ) / ( max - min ); - x = ( x - min )/( max - min ); + return x * x * ( 3 - 2 * x ); - return x*x*(3 - 2*x); + }, - }, + smootherstep: function ( x, min, max ) { - smootherstep: function ( x, min, max ) { + if ( x <= min ) return 0; + if ( x >= max ) return 1; - if ( x <= min ) return 0; - if ( x >= max ) return 1; + x = ( x - min ) / ( max - min ); - x = ( x - min )/( max - min ); + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - return x*x*x*(x*(x*6 - 15) + 10); + }, - }, + // Random float from <0, 1> with 16 bits of randomness + // (standard Math.random() creates repetitive patterns when applied over larger space) - // Random float from <0, 1> with 16 bits of randomness - // (standard Math.random() creates repetitive patterns when applied over larger space) + random16: function () { - random16: function () { + return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; - return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; + }, - }, + // Random integer from interval - // Random integer from interval + randInt: function ( low, high ) { - randInt: function ( low, high ) { + return Math.floor( this.randFloat( low, high ) ); - return low + Math.floor( Math.random() * ( high - low + 1 ) ); + }, - }, + // Random float from interval - // Random float from interval + randFloat: function ( low, high ) { - randFloat: function ( low, high ) { + return low + Math.random() * ( high - low ); - return low + Math.random() * ( high - low ); + }, - }, + // Random float from <-range/2, range/2> interval - // Random float from <-range/2, range/2> interval + randFloatSpread: function ( range ) { - randFloatSpread: function ( range ) { + return range * ( 0.5 - Math.random() ); - return range * ( 0.5 - Math.random() ); + }, - }, + degToRad: function () { - sign: function ( x ) { + var degreeToRadiansFactor = Math.PI / 180; - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; + return function ( degrees ) { - }, + return degrees * degreeToRadiansFactor; - degToRad: function() { + }; - var degreeToRadiansFactor = Math.PI / 180; + }(), - return function ( degrees ) { + radToDeg: function () { - return degrees * degreeToRadiansFactor; + var radianToDegreesFactor = 180 / Math.PI; - }; + return function ( radians ) { - }(), + return radians * radianToDegreesFactor; - radToDeg: function() { + }; - var radianToDegreesFactor = 180 / Math.PI; + }(), - return function ( radians ) { + isPowerOfTwo: function ( value ) { - return radians * radianToDegreesFactor; + return ( value & ( value - 1 ) ) === 0 && value !== 0; - }; + }, - }(), + nextPowerOfTwo: function ( value ) { - isPowerOfTwo: function ( value ) { + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; - return ( value & ( value - 1 ) ) === 0 && value !== 0; + return value; - } + } }; +// File:src/math/Spline.js + /** * Spline from Tween.js, slightly optimized (and trashed) * http://sole.github.com/tween.js/examples/05_spline.html @@ -6534,173 +6778,175 @@ THREE.Math = { THREE.Spline = function ( points ) { - this.points = points; + this.points = points; - var c = [], v3 = { x: 0, y: 0, z: 0 }, - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; + var c = [], v3 = { x: 0, y: 0, z: 0 }, + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; - this.initFromArray = function( a ) { + this.initFromArray = function ( a ) { - this.points = []; + this.points = []; - for ( var i = 0; i < a.length; i++ ) { + for ( var i = 0; i < a.length; i ++ ) { - this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; + this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; - } + } - }; + }; - this.getPoint = function ( k ) { + this.getPoint = function ( k ) { - point = ( this.points.length - 1 ) * k; - intPoint = Math.floor( point ); - weight = point - intPoint; + point = ( this.points.length - 1 ) * k; + intPoint = Math.floor( point ); + weight = point - intPoint; - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; - pa = this.points[ c[ 0 ] ]; - pb = this.points[ c[ 1 ] ]; - pc = this.points[ c[ 2 ] ]; - pd = this.points[ c[ 3 ] ]; + pa = this.points[ c[ 0 ] ]; + pb = this.points[ c[ 1 ] ]; + pc = this.points[ c[ 2 ] ]; + pd = this.points[ c[ 3 ] ]; - w2 = weight * weight; - w3 = weight * w2; + w2 = weight * weight; + w3 = weight * w2; - v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); - v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); - v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); + v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); + v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); + v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); - return v3; + return v3; - }; + }; - this.getControlPointsArray = function () { + this.getControlPointsArray = function () { - var i, p, l = this.points.length, - coords = []; + var i, p, l = this.points.length, + coords = []; - for ( i = 0; i < l; i ++ ) { + for ( i = 0; i < l; i ++ ) { - p = this.points[ i ]; - coords[ i ] = [ p.x, p.y, p.z ]; + p = this.points[ i ]; + coords[ i ] = [ p.x, p.y, p.z ]; - } + } - return coords; + return coords; - }; + }; - // approximate length by summing linear segments + // approximate length by summing linear segments - this.getLength = function ( nSubDivisions ) { + this.getLength = function ( nSubDivisions ) { - var i, index, nSamples, position, - point = 0, intPoint = 0, oldIntPoint = 0, - oldPosition = new THREE.Vector3(), - tmpVec = new THREE.Vector3(), - chunkLengths = [], - totalLength = 0; + var i, index, nSamples, position, + point = 0, intPoint = 0, oldIntPoint = 0, + oldPosition = new THREE.Vector3(), + tmpVec = new THREE.Vector3(), + chunkLengths = [], + totalLength = 0; - // first point has 0 length + // first point has 0 length - chunkLengths[ 0 ] = 0; + chunkLengths[ 0 ] = 0; - if ( !nSubDivisions ) nSubDivisions = 100; + if ( ! nSubDivisions ) nSubDivisions = 100; - nSamples = this.points.length * nSubDivisions; + nSamples = this.points.length * nSubDivisions; - oldPosition.copy( this.points[ 0 ] ); + oldPosition.copy( this.points[ 0 ] ); - for ( i = 1; i < nSamples; i ++ ) { + for ( i = 1; i < nSamples; i ++ ) { - index = i / nSamples; + index = i / nSamples; - position = this.getPoint( index ); - tmpVec.copy( position ); + position = this.getPoint( index ); + tmpVec.copy( position ); - totalLength += tmpVec.distanceTo( oldPosition ); + totalLength += tmpVec.distanceTo( oldPosition ); - oldPosition.copy( position ); + oldPosition.copy( position ); - point = ( this.points.length - 1 ) * index; - intPoint = Math.floor( point ); + point = ( this.points.length - 1 ) * index; + intPoint = Math.floor( point ); - if ( intPoint != oldIntPoint ) { + if ( intPoint != oldIntPoint ) { - chunkLengths[ intPoint ] = totalLength; - oldIntPoint = intPoint; + chunkLengths[ intPoint ] = totalLength; + oldIntPoint = intPoint; - } + } - } + } - // last point ends with total length + // last point ends with total length - chunkLengths[ chunkLengths.length ] = totalLength; + chunkLengths[ chunkLengths.length ] = totalLength; - return { chunks: chunkLengths, total: totalLength }; + return { chunks: chunkLengths, total: totalLength }; - }; + }; - this.reparametrizeByArcLength = function ( samplingCoef ) { + this.reparametrizeByArcLength = function ( samplingCoef ) { - var i, j, - index, indexCurrent, indexNext, - linearDistance, realDistance, - sampling, position, - newpoints = [], - tmpVec = new THREE.Vector3(), - sl = this.getLength(); + var i, j, + index, indexCurrent, indexNext, + realDistance, + sampling, position, + newpoints = [], + tmpVec = new THREE.Vector3(), + sl = this.getLength(); - newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); + newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); - for ( i = 1; i < this.points.length; i++ ) { + for ( i = 1; i < this.points.length; i ++ ) { - //tmpVec.copy( this.points[ i - 1 ] ); - //linearDistance = tmpVec.distanceTo( this.points[ i ] ); + //tmpVec.copy( this.points[ i - 1 ] ); + //linearDistance = tmpVec.distanceTo( this.points[ i ] ); - realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; + realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; - sampling = Math.ceil( samplingCoef * realDistance / sl.total ); + sampling = Math.ceil( samplingCoef * realDistance / sl.total ); - indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); - indexNext = i / ( this.points.length - 1 ); + indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); + indexNext = i / ( this.points.length - 1 ); - for ( j = 1; j < sampling - 1; j++ ) { + for ( j = 1; j < sampling - 1; j ++ ) { - index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); + index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); - position = this.getPoint( index ); - newpoints.push( tmpVec.copy( position ).clone() ); + position = this.getPoint( index ); + newpoints.push( tmpVec.copy( position ).clone() ); - } + } - newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); + newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); - } + } - this.points = newpoints; + this.points = newpoints; - }; + }; - // Catmull-Rom + // Catmull-Rom - function interpolate( p0, p1, p2, p3, t, t2, t3 ) { + function interpolate( p0, p1, p2, p3, t, t2, t3 ) { - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - }; + }; }; +// File:src/math/Triangle.js + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -6708,211 +6954,191 @@ THREE.Spline = function ( points ) { THREE.Triangle = function ( a, b, c ) { - this.a = ( a !== undefined ) ? a : new THREE.Vector3(); - this.b = ( b !== undefined ) ? b : new THREE.Vector3(); - this.c = ( c !== undefined ) ? c : new THREE.Vector3(); + this.a = ( a !== undefined ) ? a : new THREE.Vector3(); + this.b = ( b !== undefined ) ? b : new THREE.Vector3(); + this.c = ( c !== undefined ) ? c : new THREE.Vector3(); }; -THREE.Triangle.normal = function() { +THREE.Triangle.normal = function () { - var v0 = new THREE.Vector3(); + var v0 = new THREE.Vector3(); - return function ( a, b, c, optionalTarget ) { + return function ( a, b, c, optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - result.subVectors( c, b ); - v0.subVectors( a, b ); - result.cross( v0 ); + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); - var resultLengthSq = result.lengthSq(); - if( resultLengthSq > 0 ) { + var resultLengthSq = result.lengthSq(); + if ( resultLengthSq > 0 ) { - return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); - } + } - return result.set( 0, 0, 0 ); + return result.set( 0, 0, 0 ); - }; + }; }(); // static/instance method to calculate barycoordinates // based on: http://www.blackpawn.com/texts/pointinpoly/default.html -THREE.Triangle.barycoordFromPoint = function() { +THREE.Triangle.barycoordFromPoint = function () { - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - return function ( point, a, b, c, optionalTarget ) { + return function ( point, a, b, c, optionalTarget ) { - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); + 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 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 denom = ( dot00 * dot11 - dot01 * dot01 ); - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - // colinear 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 ); - } + // colinear 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; + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - // barycoordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); + // barycoordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); - }; + }; }(); -THREE.Triangle.containsPoint = function() { +THREE.Triangle.containsPoint = function () { - var v1 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return function ( point, a, b, c ) { + return function ( point, a, b, c ) { - var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); + var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - }; + }; }(); THREE.Triangle.prototype = { - constructor: THREE.Triangle, - - set: function ( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + constructor: THREE.Triangle, - return this; + set: function ( a, b, c ) { - }, + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - setFromPointsAndIndices: function ( points, i0, i1, i2 ) { + return this; - this.a.copy( points[i0] ); - this.b.copy( points[i1] ); - this.c.copy( points[i2] ); + }, - return this; + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - }, + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); - copy: function ( triangle ) { + return this; - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + }, - return this; + copy: function ( triangle ) { - }, + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - area: function() { + return this; - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); + }, - return function () { + area: function () { - v0.subVectors( this.c, this.b ); - v1.subVectors( this.a, this.b ); + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return v0.cross( v1 ).length() * 0.5; + return function () { - }; + 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 THREE.Vector3(); - return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + }(), - }, + midpoint: function ( optionalTarget ) { - normal: function ( optionalTarget ) { + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); + }, - }, + normal: function ( optionalTarget ) { - plane: function ( optionalTarget ) { + return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); - var result = optionalTarget || new THREE.Plane(); + }, - return result.setFromCoplanarPoints( this.a, this.b, this.c ); + plane: function ( optionalTarget ) { - }, + var result = optionalTarget || new THREE.Plane(); - barycoordFromPoint: function ( point, optionalTarget ) { + return result.setFromCoplanarPoints( this.a, this.b, this.c ); - return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + }, - }, + barycoordFromPoint: function ( point, optionalTarget ) { - containsPoint: function ( point ) { + return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); - return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); + }, - }, + containsPoint: function ( point ) { - equals: function ( triangle ) { + return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + }, - }, + equals: function ( triangle ) { - clone: function () { + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - return new THREE.Triangle().copy( this ); + }, - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ + clone: function () { -THREE.Vertex = function ( v ) { + return new THREE.Triangle().copy( this ); - console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') - return v; + } }; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.UV = function ( u, v ) { - - console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') - return new THREE.Vector2( u, v ); - -}; +// File:src/core/Clock.js /** * @author alteredq / http://alteredqualia.com/ @@ -6920,73 +7146,75 @@ THREE.UV = function ( u, v ) { THREE.Clock = function ( autoStart ) { - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - this.running = false; + this.running = false; }; THREE.Clock.prototype = { - constructor: THREE.Clock, + constructor: THREE.Clock, - start: function () { + start: function () { - this.startTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + this.startTime = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); - this.oldTime = this.startTime; - this.running = true; - }, + this.oldTime = this.startTime; + this.running = true; + }, - stop: function () { + stop: function () { - this.getElapsedTime(); - this.running = false; + this.getElapsedTime(); + this.running = false; - }, + }, - getElapsedTime: function () { + getElapsedTime: function () { - this.getDelta(); - return this.elapsedTime; + this.getDelta(); + return this.elapsedTime; - }, + }, - getDelta: function () { + getDelta: function () { - var diff = 0; + var diff = 0; - if ( this.autoStart && ! this.running ) { + if ( this.autoStart && ! this.running ) { - this.start(); + this.start(); - } + } - if ( this.running ) { + if ( this.running ) { - var newTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + var newTime = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); - diff = 0.001 * ( newTime - this.oldTime ); - this.oldTime = newTime; + diff = 0.001 * ( newTime - this.oldTime ); + this.oldTime = newTime; - this.elapsedTime += diff; + this.elapsedTime += diff; - } + } - return diff; + return diff; - } + } }; +// File:src/core/EventDispatcher.js + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -6995,106 +7223,108 @@ THREE.EventDispatcher = function () {} THREE.EventDispatcher.prototype = { - constructor: THREE.EventDispatcher, + constructor: THREE.EventDispatcher, - apply: function ( object ) { + apply: function ( object ) { - object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; - object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; - object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; - object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; + object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; + object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; + object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; + object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; - }, + }, - addEventListener: function ( type, listener ) { + addEventListener: function ( type, listener ) { - if ( this._listeners === undefined ) this._listeners = {}; + if ( this._listeners === undefined ) this._listeners = {}; - var listeners = this._listeners; + var listeners = this._listeners; - if ( listeners[ type ] === undefined ) { + if ( listeners[ type ] === undefined ) { - listeners[ type ] = []; + listeners[ type ] = []; - } + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { - if ( listeners[ type ].indexOf( listener ) === - 1 ) { + listeners[ type ].push( listener ); - listeners[ type ].push( listener ); + } - } + }, - }, + hasEventListener: function ( type, listener ) { - hasEventListener: function ( type, listener ) { + if ( this._listeners === undefined ) return false; - if ( this._listeners === undefined ) return false; + var listeners = this._listeners; - var listeners = this._listeners; + if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { - if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { + return true; - return true; + } - } + return false; - return false; + }, - }, + removeEventListener: function ( type, listener ) { - removeEventListener: function ( type, listener ) { + if ( this._listeners === undefined ) return; - if ( this._listeners === undefined ) return; + var listeners = this._listeners; + var listenerArray = listeners[ type ]; - var listeners = this._listeners; - var listenerArray = listeners[ type ]; + if ( listenerArray !== undefined ) { - if ( listenerArray !== undefined ) { + var index = listenerArray.indexOf( listener ); - var index = listenerArray.indexOf( listener ); + if ( index !== - 1 ) { - if ( index !== - 1 ) { + listenerArray.splice( index, 1 ); - listenerArray.splice( index, 1 ); + } - } + } - } + }, - }, + dispatchEvent: function ( event ) { - dispatchEvent: function ( event ) { - - if ( this._listeners === undefined ) return; + if ( this._listeners === undefined ) return; - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; - if ( listenerArray !== undefined ) { + if ( listenerArray !== undefined ) { - event.target = this; + event.target = this; - var array = []; - var length = listenerArray.length; + var array = []; + var length = listenerArray.length; - for ( var i = 0; i < length; i ++ ) { + for ( var i = 0; i < length; i ++ ) { - array[ i ] = listenerArray[ i ]; + array[ i ] = listenerArray[ i ]; - } + } - for ( var i = 0; i < length; i ++ ) { + for ( var i = 0; i < length; i ++ ) { - array[ i ].call( this, event ); + array[ i ].call( this, event ); - } + } - } + } - } + } }; +// File:src/core/Raycaster.js + /** * @author mrdoob / http://mrdoob.com/ * @author bhouston / http://exocortex.com/ @@ -7103,1019 +7333,1002 @@ THREE.EventDispatcher.prototype = { ( function ( THREE ) { - THREE.Raycaster = function ( origin, direction, near, far ) { + THREE.Raycaster = function ( origin, direction, near, far ) { + + this.ray = new THREE.Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near || 0; + this.far = far || Infinity; + + this.params = { + Sprite: {}, + Mesh: {}, + PointCloud: { threshold: 1 }, + LOD: {}, + Line: {} + }; + + }; + + var descSort = function ( a, b ) { - this.ray = new THREE.Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) + return a.distance - b.distance; - this.near = near || 0; - this.far = far || Infinity; + }; - }; + var intersectObject = function ( object, raycaster, intersects, recursive ) { - var sphere = new THREE.Sphere(); - var localRay = new THREE.Ray(); - var facePlane = new THREE.Plane(); - var intersectPoint = new THREE.Vector3(); - var matrixPosition = new THREE.Vector3(); + object.raycast( raycaster, intersects ); - var inverseMatrix = new THREE.Matrix4(); + if ( recursive === true ) { - var descSort = function ( a, b ) { + var children = object.children; - return a.distance - b.distance; + for ( var i = 0, l = children.length; i < l; i ++ ) { - }; + intersectObject( children[ i ], raycaster, intersects, true ); - var vA = new THREE.Vector3(); - var vB = new THREE.Vector3(); - var vC = new THREE.Vector3(); + } - var intersectObject = function ( object, raycaster, intersects ) { + } - if ( object instanceof THREE.Sprite ) { + }; - matrixPosition.setFromMatrixPosition( object.matrixWorld ); - - var distance = raycaster.ray.distanceToPoint( matrixPosition ); + // - if ( distance > object.scale.x ) { + THREE.Raycaster.prototype = { - return intersects; + constructor: THREE.Raycaster, - } + precision: 0.0001, + linePrecision: 1, - intersects.push( { + set: function ( origin, direction ) { - distance: distance, - point: object.position, - face: null, - object: object + // direction is assumed to be normalized (for accurate distance calculations) - } ); + this.ray.set( origin, direction ); - } else if ( object instanceof THREE.LOD ) { + }, - matrixPosition.setFromMatrixPosition( object.matrixWorld ); - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + setFromCamera: function ( coords, camera ) { - intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); + // camera is assumed _not_ to be a child of a transformed object - } else if ( object instanceof THREE.Mesh ) { + if ( camera instanceof THREE.PerspectiveCamera ) { - var geometry = object.geometry; + this.ray.origin.copy( camera.position ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( camera.position ).normalize(); - // Checking boundingSphere distance to ray + } else if ( camera instanceof THREE.OrthographicCamera ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); + } else { - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + THREE.error( 'THREE.Raycaster: Unsupported camera type.' ); - return intersects; + } - } + }, - // Check boundingBox before continuing - - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + intersectObject: function ( object, recursive ) { - if ( geometry.boundingBox !== null ) { + var intersects = []; - if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { + intersectObject( object, this, intersects, recursive ); - return intersects; + intersects.sort( descSort ); - } + return intersects; - } + }, - if ( geometry instanceof THREE.BufferGeometry ) { + intersectObjects: function ( objects, recursive ) { - var material = object.material; + var intersects = []; - if ( material === undefined ) return intersects; + if ( objects instanceof Array === false ) { - var attributes = geometry.attributes; + THREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; - var a, b, c; - var precision = raycaster.precision; + } - if ( attributes.index !== undefined ) { + for ( var i = 0, l = objects.length; i < l; i ++ ) { - var indices = attributes.index.array; - var positions = attributes.position.array; - var offsets = geometry.offsets; + intersectObject( objects[ i ], this, intersects, recursive ); - if ( offsets.length === 0 ) { + } - offsets = [ { start: 0, count: positions.length, index: 0 } ]; + intersects.sort( descSort ); - } + return intersects; - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + } - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; + }; - for ( var i = start, il = start + count; i < il; i += 3 ) { +}( THREE ) ); - a = index + indices[ i ]; - b = index + indices[ i + 1 ]; - c = index + indices[ i + 2 ]; +// File:src/core/Object3D.js - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + */ - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); +THREE.Object3D = function () { - } else { + Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } ); - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + this.uuid = THREE.Math.generateUUID(); - } + this.name = ''; + this.type = 'Object3D'; - if ( intersectionPoint === null ) continue; + this.parent = undefined; + this.children = []; - intersectionPoint.applyMatrix4( object.matrixWorld ); + this.up = THREE.Object3D.DefaultUp.clone(); - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + var position = new THREE.Vector3(); + var rotation = new THREE.Euler(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3( 1, 1, 1 ); - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + var onRotationChange = function () { + quaternion.setFromEuler( rotation, false ); + }; - intersects.push( { + var onQuaternionChange = function () { + rotation.setFromQuaternion( quaternion, undefined, false ); + }; - distance: distance, - point: intersectionPoint, - indices: [a, b, c], - face: null, - faceIndex: null, - object: object + rotation.onChange( onRotationChange ); + quaternion.onChange( onQuaternionChange ); - } ); + Object.defineProperties( this, { + position: { + enumerable: true, + configurable: true, + value: position + }, + rotation: { + enumerable: true, + configurable: true, + value: rotation + }, + quaternion: { + enumerable: true, + configurable: true, + value: quaternion + }, + scale: { + enumerable: true, + configurable: true, + value: scale + } + } ); - } + this.rotationAutoUpdate = true; - } + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); - } else { + this.matrixAutoUpdate = true; + this.matrixWorldNeedsUpdate = false; - var offsets = geometry.offsets; - var positions = attributes.position.array; + this.visible = true; - for ( var i = 0, il = attributes.position.array.length; i < il; i += 3 ) { + this.castShadow = false; + this.receiveShadow = false; - a = i; - b = i + 1; - c = i + 2; + this.frustumCulled = true; + this.renderOrder = 0; - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); + this.userData = {}; - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); +}; - } else { +THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 ); - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); +THREE.Object3D.prototype = { - } + constructor: THREE.Object3D, - if ( intersectionPoint === null ) continue; + get eulerOrder () { - intersectionPoint.applyMatrix4( object.matrixWorld ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + return this.rotation.order; - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + }, - intersects.push( { + set eulerOrder ( value ) { - distance: distance, - point: intersectionPoint, - indices: [a, b, c], - face: null, - faceIndex: null, - object: object + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - } ); + this.rotation.order = value; - } + }, - } + get useQuaternion () { - } else if ( geometry instanceof THREE.Geometry ) { + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - var objectMaterials = isFaceMaterial === true ? object.material.materials : null; + }, - var a, b, c, d; - var precision = raycaster.precision; + set useQuaternion ( value ) { - var vertices = geometry.vertices; + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + }, - var face = geometry.faces[ f ]; + applyMatrix: function ( matrix ) { - var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; + this.matrix.multiplyMatrices( matrix, this.matrix ); - if ( material === undefined ) continue; + this.matrix.decompose( this.position, this.quaternion, this.scale ); - a = vertices[ face.a ]; - b = vertices[ face.b ]; - c = vertices[ face.c ]; + }, - if ( material.morphTargets === true ) { + setRotationFromAxisAngle: function ( axis, angle ) { - var morphTargets = geometry.morphTargets; - var morphInfluences = object.morphTargetInfluences; + // assumes axis is normalized - vA.set( 0, 0, 0 ); - vB.set( 0, 0, 0 ); - vC.set( 0, 0, 0 ); + this.quaternion.setFromAxisAngle( axis, angle ); - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + }, - var influence = morphInfluences[ t ]; + setRotationFromEuler: function ( euler ) { - if ( influence === 0 ) continue; + this.quaternion.setFromEuler( euler, true ); - var targets = morphTargets[ t ].vertices; + }, - vA.x += ( targets[ face.a ].x - a.x ) * influence; - vA.y += ( targets[ face.a ].y - a.y ) * influence; - vA.z += ( targets[ face.a ].z - a.z ) * influence; + setRotationFromMatrix: function ( m ) { - vB.x += ( targets[ face.b ].x - b.x ) * influence; - vB.y += ( targets[ face.b ].y - b.y ) * influence; - vB.z += ( targets[ face.b ].z - b.z ) * influence; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - vC.x += ( targets[ face.c ].x - c.x ) * influence; - vC.y += ( targets[ face.c ].y - c.y ) * influence; - vC.z += ( targets[ face.c ].z - c.z ) * influence; + this.quaternion.setFromRotationMatrix( m ); - } + }, - vA.add( a ); - vB.add( b ); - vC.add( c ); + setRotationFromQuaternion: function ( q ) { - a = vA; - b = vB; - c = vC; + // assumes q is normalized - } + this.quaternion.copy( q ); - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); + }, - } else { - - var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); + rotateOnAxis: function () { - } + // rotate object on axis in object space + // axis is assumed to be normalized - if ( intersectionPoint === null ) continue; + var q1 = new THREE.Quaternion(); - intersectionPoint.applyMatrix4( object.matrixWorld ); + return function ( axis, angle ) { - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + q1.setFromAxisAngle( axis, angle ); - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + this.quaternion.multiply( q1 ); - intersects.push( { + return this; - distance: distance, - point: intersectionPoint, - face: face, - faceIndex: f, - object: object + } - } ); + }(), - } + rotateX: function () { - } + var v1 = new THREE.Vector3( 1, 0, 0 ); - } else if ( object instanceof THREE.Line ) { + return function ( angle ) { - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; + return this.rotateOnAxis( v1, angle ); - var geometry = object.geometry; + }; - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + }(), - // Checking boundingSphere distance to ray + rotateY: function () { - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + var v1 = new THREE.Vector3( 0, 1, 0 ); - return intersects; + return function ( angle ) { - } - - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + return this.rotateOnAxis( v1, angle ); - /* if ( geometry instanceof THREE.BufferGeometry ) { + }; - } else */ if ( geometry instanceof THREE.Geometry ) { + }(), - var vertices = geometry.vertices; - var nbVertices = vertices.length; - var interSegment = new THREE.Vector3(); - var interRay = new THREE.Vector3(); - var step = object.type === THREE.LineStrip ? 1 : 2; + rotateZ: function () { - for ( var i = 0; i < nbVertices - 1; i = i + step ) { + var v1 = new THREE.Vector3( 0, 0, 1 ); - var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); + return function ( angle ) { - if ( distSq > precisionSq ) continue; + return this.rotateOnAxis( v1, angle ); - var distance = localRay.origin.distanceTo( interRay ); + }; - if ( distance < raycaster.near || distance > raycaster.far ) continue; + }(), - intersects.push( { + translateOnAxis: function () { - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( object.matrixWorld ), - face: null, - faceIndex: null, - object: object + // translate object by distance along axis in object space + // axis is assumed to be normalized - } ); + var v1 = new THREE.Vector3(); - } + return function ( axis, distance ) { - } + v1.copy( axis ).applyQuaternion( this.quaternion ); - } + this.position.add( v1.multiplyScalar( distance ) ); - }; + return this; - var intersectDescendants = function ( object, raycaster, intersects ) { + } - var descendants = object.getDescendants(); + }(), - for ( var i = 0, l = descendants.length; i < l; i ++ ) { + translate: function ( distance, axis ) { - intersectObject( descendants[ i ], raycaster, intersects ); + THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + return this.translateOnAxis( axis, distance ); - } - }; + }, - // + translateX: function () { - THREE.Raycaster.prototype.precision = 0.0001; - THREE.Raycaster.prototype.linePrecision = 1; + var v1 = new THREE.Vector3( 1, 0, 0 ); - THREE.Raycaster.prototype.set = function ( origin, direction ) { + return function ( distance ) { - this.ray.set( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) + return this.translateOnAxis( v1, distance ); - }; + }; - THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { + }(), - var intersects = []; + translateY: function () { - if ( recursive === true ) { + var v1 = new THREE.Vector3( 0, 1, 0 ); - intersectDescendants( object, this, intersects ); + return function ( distance ) { - } + return this.translateOnAxis( v1, distance ); - intersectObject( object, this, intersects ); + }; - intersects.sort( descSort ); + }(), - return intersects; + translateZ: function () { - }; + var v1 = new THREE.Vector3( 0, 0, 1 ); - THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { + return function ( distance ) { - var intersects = []; + return this.translateOnAxis( v1, distance ); - for ( var i = 0, l = objects.length; i < l; i ++ ) { + }; - intersectObject( objects[ i ], this, intersects ); + }(), - if ( recursive === true ) { + localToWorld: function ( vector ) { - intersectDescendants( objects[ i ], this, intersects ); + return vector.applyMatrix4( this.matrixWorld ); - } + }, - } + worldToLocal: function () { - intersects.sort( descSort ); + var m1 = new THREE.Matrix4(); - return intersects; + return function ( vector ) { - }; + return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); -}( THREE ) ); + }; -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - */ + }(), -THREE.Object3D = function () { + lookAt: function () { - this.id = THREE.Object3DIdCount ++; - this.uuid = THREE.Math.generateUUID(); + // This routine does not support objects with rotated and/or translated parent(s) - this.name = ''; + var m1 = new THREE.Matrix4(); - this.parent = undefined; - this.children = []; + return function ( vector ) { - this.up = new THREE.Vector3( 0, 1, 0 ); + m1.lookAt( vector, this.position, this.up ); - this.position = new THREE.Vector3(); - this._rotation = new THREE.Euler(); - this._quaternion = new THREE.Quaternion(); - this.scale = new THREE.Vector3( 1, 1, 1 ); + this.quaternion.setFromRotationMatrix( m1 ); - // keep rotation and quaternion in sync + }; - this._rotation._quaternion = this.quaternion; - this._quaternion._euler = this.rotation; + }(), - this.renderDepth = null; + add: function ( object ) { - this.rotationAutoUpdate = true; + if ( arguments.length > 1 ) { - this.matrix = new THREE.Matrix4(); - this.matrixWorld = new THREE.Matrix4(); + for ( var i = 0; i < arguments.length; i ++ ) { - this.matrixAutoUpdate = true; - this.matrixWorldNeedsUpdate = false; + this.add( arguments[ i ] ); - this.visible = true; + } - this.castShadow = false; - this.receiveShadow = false; + return this; - this.frustumCulled = true; + }; - this.userData = {}; + if ( object === this ) { -}; + THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; + } -THREE.Object3D.prototype = { + if ( object instanceof THREE.Object3D ) { - constructor: THREE.Object3D, - - get rotation () { - return this._rotation; - }, + if ( object.parent !== undefined ) { - set rotation ( value ) { - - this._rotation = value; - this._rotation._quaternion = this._quaternion; - this._quaternion._euler = this._rotation; - this._rotation._updateQuaternion(); - - }, + object.parent.remove( object ); - get quaternion () { - return this._quaternion; - }, - - set quaternion ( value ) { - - this._quaternion = value; - this._quaternion._euler = this._rotation; - this._rotation._quaternion = this._quaternion; - this._quaternion._updateEuler(); - - }, + } - get eulerOrder () { + object.parent = this; + object.dispatchEvent( { type: 'added' } ); - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + this.children.push( object ); - return this.rotation.order; + } else { - }, + THREE.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - set eulerOrder ( value ) { + } + + return this; + + }, + + remove: function ( object ) { - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + if ( arguments.length > 1 ) { - this.rotation.order = value; + for ( var i = 0; i < arguments.length; i ++ ) { - }, + this.remove( arguments[ i ] ); - get useQuaternion () { + } - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + }; - }, + var index = this.children.indexOf( object ); - set useQuaternion ( value ) { + if ( index !== - 1 ) { - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + object.parent = undefined; + + object.dispatchEvent( { type: 'removed' } ); + + this.children.splice( index, 1 ); + + } - }, + }, - applyMatrix: function ( matrix ) { + getChildByName: function ( name ) { - this.matrix.multiplyMatrices( matrix, this.matrix ); + THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); - this.matrix.decompose( this.position, this.quaternion, this.scale ); + }, - }, + getObjectById: function ( id ) { - setRotationFromAxisAngle: function ( axis, angle ) { + return this.getObjectByProperty( 'id', id ); - // assumes axis is normalized + }, - this.quaternion.setFromAxisAngle( axis, angle ); + getObjectByName: function ( name ) { - }, + return this.getObjectByProperty( 'name', name ); - setRotationFromEuler: function ( euler ) { + }, - this.quaternion.setFromEuler( euler, true ); + getObjectByProperty: function ( name, value ) { - }, + if ( this[ name ] === value ) return this; - setRotationFromMatrix: function ( m ) { + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); - this.quaternion.setFromRotationMatrix( m ); + if ( object !== undefined ) { - }, + return object; - setRotationFromQuaternion: function ( q ) { + } - // assumes q is normalized + } - this.quaternion.copy( q ); + return undefined; - }, + }, - rotateOnAxis: function() { + getWorldPosition: function ( optionalTarget ) { - // rotate object on axis in object space - // axis is assumed to be normalized + var result = optionalTarget || new THREE.Vector3(); - var q1 = new THREE.Quaternion(); + this.updateMatrixWorld( true ); - return function ( axis, angle ) { + return result.setFromMatrixPosition( this.matrixWorld ); - q1.setFromAxisAngle( axis, angle ); + }, - this.quaternion.multiply( q1 ); + getWorldQuaternion: function () { - return this; + var position = new THREE.Vector3(); + var scale = new THREE.Vector3(); - } + return function ( optionalTarget ) { - }(), + var result = optionalTarget || new THREE.Quaternion(); - rotateX: function () { + this.updateMatrixWorld( true ); - var v1 = new THREE.Vector3( 1, 0, 0 ); + this.matrixWorld.decompose( position, result, scale ); - return function ( angle ) { + return result; - return this.rotateOnAxis( v1, angle ); + } - }; + }(), - }(), + getWorldRotation: function () { - rotateY: function () { + var quaternion = new THREE.Quaternion(); - var v1 = new THREE.Vector3( 0, 1, 0 ); + return function ( optionalTarget ) { - return function ( angle ) { + var result = optionalTarget || new THREE.Euler(); - return this.rotateOnAxis( v1, angle ); + this.getWorldQuaternion( quaternion ); - }; + return result.setFromQuaternion( quaternion, this.rotation.order, false ); - }(), + } - rotateZ: function () { + }(), - var v1 = new THREE.Vector3( 0, 0, 1 ); + getWorldScale: function () { - return function ( angle ) { + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); - return this.rotateOnAxis( v1, angle ); + return function ( optionalTarget ) { - }; + var result = optionalTarget || new THREE.Vector3(); - }(), + this.updateMatrixWorld( true ); - translateOnAxis: function () { + this.matrixWorld.decompose( position, quaternion, result ); - // translate object by distance along axis in object space - // axis is assumed to be normalized + return result; - var v1 = new THREE.Vector3(); + } - return function ( axis, distance ) { + }(), - v1.copy( axis ); + getWorldDirection: function () { - v1.applyQuaternion( this.quaternion ); + var quaternion = new THREE.Quaternion(); - this.position.add( v1.multiplyScalar( distance ) ); + return function ( optionalTarget ) { - return this; + var result = optionalTarget || new THREE.Vector3(); - } + this.getWorldQuaternion( quaternion ); - }(), + return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); - translate: function ( distance, axis ) { + } - console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); - return this.translateOnAxis( axis, distance ); + }(), - }, + raycast: function () {}, - translateX: function () { + traverse: function ( callback ) { - var v1 = new THREE.Vector3( 1, 0, 0 ); + callback( this ); - return function ( distance ) { + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - return this.translateOnAxis( v1, distance ); + this.children[ i ].traverse( callback ); - }; + } - }(), + }, - translateY: function () { + traverseVisible: function ( callback ) { - var v1 = new THREE.Vector3( 0, 1, 0 ); + if ( this.visible === false ) return; - return function ( distance ) { + callback( this ); - return this.translateOnAxis( v1, distance ); + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - }; + this.children[ i ].traverseVisible( callback ); - }(), + } - translateZ: function () { + }, - var v1 = new THREE.Vector3( 0, 0, 1 ); + traverseAncestors: function ( callback ) { - return function ( distance ) { + if ( this.parent ) { - return this.translateOnAxis( v1, distance ); + callback( this.parent ); - }; + this.parent.traverseAncestors( callback ); - }(), + } - localToWorld: function ( vector ) { + }, - return vector.applyMatrix4( this.matrixWorld ); + updateMatrix: function () { - }, + this.matrix.compose( this.position, this.quaternion, this.scale ); - worldToLocal: function () { + this.matrixWorldNeedsUpdate = true; - var m1 = new THREE.Matrix4(); + }, - return function ( vector ) { + updateMatrixWorld: function ( force ) { - return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); + if ( this.matrixAutoUpdate === true ) this.updateMatrix(); - }; + if ( this.matrixWorldNeedsUpdate === true || force === true ) { - }(), + if ( this.parent === undefined ) { - lookAt: function () { + this.matrixWorld.copy( this.matrix ); - // This routine does not support objects with rotated and/or translated parent(s) + } else { - var m1 = new THREE.Matrix4(); + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - return function ( vector ) { + } - m1.lookAt( vector, this.position, this.up ); + this.matrixWorldNeedsUpdate = false; - this.quaternion.setFromRotationMatrix( m1 ); + force = true; - }; + } - }(), + // update children - add: function ( object ) { + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - if ( object === this ) { + this.children[ i ].updateMatrixWorld( force ); - console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); - return; + } - } + }, - if ( object instanceof THREE.Object3D ) { + toJSON: function () { - if ( object.parent !== undefined ) { + var output = { + metadata: { + version: 4.3, + type: 'Object', + generator: 'ObjectExporter' + } + }; - object.parent.remove( object ); + // - } + var geometries = {}; - object.parent = this; - object.dispatchEvent( { type: 'added' } ); + var parseGeometry = function ( geometry ) { - this.children.push( object ); + if ( output.geometries === undefined ) { - // add to scene + output.geometries = []; - var scene = this; + } - while ( scene.parent !== undefined ) { + if ( geometries[ geometry.uuid ] === undefined ) { - scene = scene.parent; + var json = geometry.toJSON(); - } + delete json.metadata; - if ( scene !== undefined && scene instanceof THREE.Scene ) { + geometries[ geometry.uuid ] = json; - scene.__addObject( object ); + output.geometries.push( json ); - } + } - } + return geometry.uuid; - }, + }; - remove: function ( object ) { + // - var index = this.children.indexOf( object ); + var materials = {}; - if ( index !== - 1 ) { + var parseMaterial = function ( material ) { - object.parent = undefined; - object.dispatchEvent( { type: 'removed' } ); + if ( output.materials === undefined ) { - this.children.splice( index, 1 ); + output.materials = []; - // remove from scene + } - var scene = this; + if ( materials[ material.uuid ] === undefined ) { - while ( scene.parent !== undefined ) { + var json = material.toJSON(); - scene = scene.parent; + delete json.metadata; - } + materials[ material.uuid ] = json; - if ( scene !== undefined && scene instanceof THREE.Scene ) { + output.materials.push( json ); - scene.__removeObject( object ); + } - } + return material.uuid; - } + }; - }, + // - traverse: function ( callback ) { + var parseObject = function ( object ) { - callback( this ); + var data = {}; - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + data.uuid = object.uuid; + data.type = object.type; - this.children[ i ].traverse( callback ); + if ( object.name !== '' ) data.name = object.name; + if ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData; + if ( object.visible !== true ) data.visible = object.visible; - } + if ( object instanceof THREE.PerspectiveCamera ) { - }, + data.fov = object.fov; + data.aspect = object.aspect; + data.near = object.near; + data.far = object.far; - getObjectById: function ( id, recursive ) { + } else if ( object instanceof THREE.OrthographicCamera ) { - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + data.left = object.left; + data.right = object.right; + data.top = object.top; + data.bottom = object.bottom; + data.near = object.near; + data.far = object.far; - var child = this.children[ i ]; + } else if ( object instanceof THREE.AmbientLight ) { - if ( child.id === id ) { + data.color = object.color.getHex(); - return child; + } else if ( object instanceof THREE.DirectionalLight ) { - } + data.color = object.color.getHex(); + data.intensity = object.intensity; - if ( recursive === true ) { + } else if ( object instanceof THREE.PointLight ) { - child = child.getObjectById( id, recursive ); + data.color = object.color.getHex(); + data.intensity = object.intensity; + data.distance = object.distance; + data.decay = object.decay; - if ( child !== undefined ) { + } else if ( object instanceof THREE.SpotLight ) { - return child; + data.color = object.color.getHex(); + data.intensity = object.intensity; + data.distance = object.distance; + data.angle = object.angle; + data.exponent = object.exponent; + data.decay = object.decay; - } + } else if ( object instanceof THREE.HemisphereLight ) { - } + data.color = object.color.getHex(); + data.groundColor = object.groundColor.getHex(); - } + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { - return undefined; + data.geometry = parseGeometry( object.geometry ); + data.material = parseMaterial( object.material ); - }, + if ( object instanceof THREE.Line ) data.mode = object.mode; - getObjectByName: function ( name, recursive ) { + } else if ( object instanceof THREE.Sprite ) { - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + data.material = parseMaterial( object.material ); - var child = this.children[ i ]; + } - if ( child.name === name ) { + data.matrix = object.matrix.toArray(); - return child; + if ( object.children.length > 0 ) { - } + data.children = []; - if ( recursive === true ) { + for ( var i = 0; i < object.children.length; i ++ ) { - child = child.getObjectByName( name, recursive ); + data.children.push( parseObject( object.children[ i ] ) ); - if ( child !== undefined ) { + } - return child; + } - } + return data; - } + } - } + output.object = parseObject( this ); - return undefined; + return output; - }, + }, - getChildByName: function ( name, recursive ) { + clone: function ( object, recursive ) { - console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name, recursive ); + if ( object === undefined ) object = new THREE.Object3D(); + if ( recursive === undefined ) recursive = true; - }, + object.name = this.name; - getDescendants: function ( array ) { + object.up.copy( this.up ); - if ( array === undefined ) array = []; + object.position.copy( this.position ); + object.quaternion.copy( this.quaternion ); + object.scale.copy( this.scale ); - Array.prototype.push.apply( array, this.children ); + object.rotationAutoUpdate = this.rotationAutoUpdate; - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + object.matrix.copy( this.matrix ); + object.matrixWorld.copy( this.matrixWorld ); - this.children[ i ].getDescendants( array ); + object.matrixAutoUpdate = this.matrixAutoUpdate; + object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; - } + object.visible = this.visible; - return array; + object.castShadow = this.castShadow; + object.receiveShadow = this.receiveShadow; - }, + object.frustumCulled = this.frustumCulled; - updateMatrix: function () { + object.userData = JSON.parse( JSON.stringify( this.userData ) ); - this.matrix.compose( this.position, this.quaternion, this.scale ); + if ( recursive === true ) { - this.matrixWorldNeedsUpdate = true; + for ( var i = 0; i < this.children.length; i ++ ) { - }, + var child = this.children[ i ]; + object.add( child.clone() ); - updateMatrixWorld: function ( force ) { + } - if ( this.matrixAutoUpdate === true ) this.updateMatrix(); + } - if ( this.matrixWorldNeedsUpdate === true || force === true ) { + return object; - if ( this.parent === undefined ) { + }, - this.matrixWorld.copy( this.matrix ); + bindPosition: function( position ) { - } else { + delete this.position; + Object.defineProperty( this, "position", { + enumerable: true, + configurable: true, + value: position + }); - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + }, - } + bindQuaternion: function( quaternion ) { - this.matrixWorldNeedsUpdate = false; + delete this.quaternion; + Object.defineProperty( this, "quaternion", { + enumerable: true, + configurable: true, + value: quaternion + }); - force = true; + var rotation = this.rotation; - } + quaternion.onChange( function () { - // update children + rotation.setFromQuaternion( quaternion, undefined, false ); - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + } ); - this.children[ i ].updateMatrixWorld( force ); + rotation.onChange( function () { - } + quaternion.setFromEuler( rotation, false ); - }, + } ); - clone: function ( object, recursive ) { - if ( object === undefined ) object = new THREE.Object3D(); - if ( recursive === undefined ) recursive = true; + }, - object.name = this.name; + bindRotation: function( rotation ) { - object.up.copy( this.up ); + delete this.rotation; + Object.defineProperty( this, "rotation", { + enumerable: true, + configurable: true, + value: rotation + }); - object.position.copy( this.position ); - object.quaternion.copy( this.quaternion ); - object.scale.copy( this.scale ); + var quaternion = this.quaternion; - object.renderDepth = this.renderDepth; + // Remember the last callback, since Object3D needs this to keep this.quaternion in sync + var lastcallback = rotation.onChangeCallback; - object.rotationAutoUpdate = this.rotationAutoUpdate; + rotation.onChange( function () { - object.matrix.copy( this.matrix ); - object.matrixWorld.copy( this.matrixWorld ); + quaternion.setFromEuler( rotation, false ); + lastcallback(); - object.matrixAutoUpdate = this.matrixAutoUpdate; - object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + } ); - object.visible = this.visible; + quaternion.onChange( function () { - object.castShadow = this.castShadow; - object.receiveShadow = this.receiveShadow; + rotation.setFromQuaternion( quaternion, undefined, false ); - object.frustumCulled = this.frustumCulled; + } ); - object.userData = JSON.parse( JSON.stringify( this.userData ) ); + }, - if ( recursive === true ) { + bindObjectRotation: function( object ) { - for ( var i = 0; i < this.children.length; i ++ ) { + delete this.rotation; + delete this.quaternion; - var child = this.children[ i ]; - object.add( child.clone() ); + Object.defineProperty( this, "rotation", { + enumerable: true, + configurable: true, + value: object.rotation + }); + Object.defineProperty( this, "quaternion", { + enumerable: true, + configurable: true, + value: object.quaternion + }); - } + }, - } + bindScale: function( scale ) { - return object; + delete this.scale; + Object.defineProperty( this, "scale", { + enumerable: true, + configurable: true, + value: scale + }); - } + } }; @@ -8123,2648 +8336,2474 @@ THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); THREE.Object3DIdCount = 0; +// File:src/core/Face3.js + /** * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author julianwa / https://github.com/julianwa + * @author alteredq / http://alteredqualia.com/ */ -THREE.Projector = function () { +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { - var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, - _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, - _face, _faceCount, _facePool = [], _facePoolLength = 0, - _line, _lineCount, _linePool = [], _linePoolLength = 0, - _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + this.a = a; + this.b = b; + this.c = c; - _renderData = { objects: [], lights: [], elements: [] }, + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : []; - _vA = new THREE.Vector3(), - _vB = new THREE.Vector3(), - _vC = new THREE.Vector3(), + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; - _vector3 = new THREE.Vector3(), - _vector4 = new THREE.Vector4(), + this.vertexTangents = []; - _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), - _boundingBox = new THREE.Box3(), - _points3 = new Array( 3 ), - _points4 = new Array( 4 ), + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - _viewMatrix = new THREE.Matrix4(), - _viewProjectionMatrix = new THREE.Matrix4(), +}; - _modelMatrix, - _modelViewProjectionMatrix = new THREE.Matrix4(), +THREE.Face3.prototype = { - _normalMatrix = new THREE.Matrix3(), + constructor: THREE.Face3, - _frustum = new THREE.Frustum(), + clone: function () { - _clippedVertex1PositionScreen = new THREE.Vector4(), - _clippedVertex2PositionScreen = new THREE.Vector4(); + var face = new THREE.Face3( this.a, this.b, this.c ); - this.projectVector = function ( vector, camera ) { + face.normal.copy( this.normal ); + face.color.copy( this.color ); - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + face.materialIndex = this.materialIndex; - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) { - return vector.applyProjection( _viewProjectionMatrix ); + face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - }; + } - this.unprojectVector = function () { + for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) { - var projectionMatrixInverse = new THREE.Matrix4(); + face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - return function ( vector, camera ) { + } - projectionMatrixInverse.getInverse( camera.projectionMatrix ); - _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse ); + for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) { - return vector.applyProjection( _viewProjectionMatrix ); + face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); - }; + } - }(); + return face; - this.pickingRay = function ( vector, camera ) { + } - // set two vectors with opposing z values - vector.z = -1.0; - var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); +}; - this.unprojectVector( vector, camera ); - this.unprojectVector( end, camera ); +// File:src/core/Face4.js - // find direction from vector to end - end.sub( vector ).normalize(); +/** + * @author mrdoob / http://mrdoob.com/ + */ - return new THREE.Raycaster( vector, end ); +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - }; + THREE.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ) + return new THREE.Face3( a, b, c, normal, color, materialIndex ); - var projectObject = function ( object ) { +}; - if ( object.visible === false ) return; +// File:src/core/BufferAttribute.js - if ( object instanceof THREE.Light ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - _renderData.lights.push( object ); +THREE.BufferAttribute = function ( array, itemSize ) { - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { + this.array = array; + this.itemSize = itemSize; - if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + this.needsUpdate = false; - _object = getNextObjectInPool(); - _object.id = object.id; - _object.object = object; +}; - if ( object.renderDepth !== null ) { +THREE.BufferAttribute.prototype = { - _object.z = object.renderDepth; + constructor: THREE.BufferAttribute, - } else { + get length () { - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyProjection( _viewProjectionMatrix ); - _object.z = _vector3.z; + return this.array.length; - } + }, - _renderData.objects.push( _object ); + copyAt: function ( index1, attribute, index2 ) { - } + index1 *= this.itemSize; + index2 *= attribute.itemSize; - } + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - for ( var i = 0, l = object.children.length; i < l; i ++ ) { + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - projectObject( object.children[ i ] ); + } - } + return this; - }; + }, - var projectGraph = function ( root, sortObjects ) { + set: function ( value, offset ) { - _objectCount = 0; + if ( offset === undefined ) offset = 0; - _renderData.objects.length = 0; - _renderData.lights.length = 0; + this.array.set( value, offset ); - projectObject( root ); + return this; - if ( sortObjects === true ) { + }, - _renderData.objects.sort( painterSort ); + setX: function ( index, x ) { - } + this.array[ index * this.itemSize ] = x; - }; + return this; - var RenderList = function () { + }, - var normals = []; - var uvs = []; + setY: function ( index, y ) { - var object = null; - var material = null; + this.array[ index * this.itemSize + 1 ] = y; - var normalMatrix = new THREE.Matrix3(); + return this; - var setObject = function ( value ) { + }, - object = value; - material = object.material; + setZ: function ( index, z ) { - normalMatrix.getNormalMatrix( object.matrixWorld ); + this.array[ index * this.itemSize + 2 ] = z; - normals.length = 0; - uvs.length = 0; + return this; - }; + }, - var projectVertex = function ( vertex ) { + setXY: function ( index, x, y ) { - var position = vertex.position; - var positionWorld = vertex.positionWorld; - var positionScreen = vertex.positionScreen; + index *= this.itemSize; - positionWorld.copy( position ).applyMatrix4( _modelMatrix ); - positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); + this.array[ index ] = x; + this.array[ index + 1 ] = y; - var invW = 1 / positionScreen.w; + return this; - positionScreen.x *= invW; - positionScreen.y *= invW; - positionScreen.z *= invW; + }, - vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && - positionScreen.y >= -1 && positionScreen.y <= 1 && - positionScreen.z >= -1 && positionScreen.z <= 1; + setXYZ: function ( index, x, y, z ) { - }; + index *= this.itemSize; - var pushVertex = function ( x, y, z ) { + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; - _vertex = getNextVertexInPool(); - _vertex.position.set( x, y, z ); + return this; - projectVertex( _vertex ); + }, - }; + setXYZW: function ( index, x, y, z, w ) { - var pushNormal = function ( x, y, z ) { + index *= this.itemSize; - normals.push( x, y, z ); + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; - }; + return this; - var pushUv = function ( x, y ) { + }, - uvs.push( x, y ); + clone: function () { - }; + return new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - var checkTriangleVisibility = function ( v1, v2, v3 ) { + } - if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; +}; - _points3[ 0 ] = v1.positionScreen; - _points3[ 1 ] = v2.positionScreen; - _points3[ 2 ] = v3.positionScreen; +// - return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ); +THREE.Int8Attribute = function ( data, itemSize ) { - }; + THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var checkBackfaceCulling = function ( v1, v2, v3 ) { +}; - return ( ( v3.positionScreen.x - v1.positionScreen.x ) * - ( v2.positionScreen.y - v1.positionScreen.y ) - - ( v3.positionScreen.y - v1.positionScreen.y ) * - ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; +THREE.Uint8Attribute = function ( data, itemSize ) { - }; + THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var pushLine = function ( a, b ) { +}; - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; +THREE.Uint8ClampedAttribute = function ( data, itemSize ) { - _line = getNextLineInPool(); + THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - _line.id = object.id; - _line.v1.copy( v1 ); - _line.v2.copy( v2 ); - _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; - _line.material = object.material; +}; - _renderData.elements.push( _line ); +THREE.Int16Attribute = function ( data, itemSize ) { - }; + THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var pushTriangle = function ( a, b, c ) { +}; - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; - var v3 = _vertexPool[ c ]; +THREE.Uint16Attribute = function ( data, itemSize ) { - if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; + THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { +}; - _face = getNextFaceInPool(); +THREE.Int32Attribute = function ( data, itemSize ) { - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - for ( var i = 0; i < 3; i ++ ) { +}; - var offset = arguments[ i ] * 3; - var normal = _face.vertexNormalsModel[ i ]; +THREE.Uint32Attribute = function ( data, itemSize ) { - normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] ); - normal.applyMatrix3( normalMatrix ).normalize(); + THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var offset2 = arguments[ i ] * 2; +}; - var uv = _face.uvs[ i ]; - uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] ); +THREE.Float32Attribute = function ( data, itemSize ) { - } + THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - _face.vertexNormalsLength = 3; +}; - _face.material = object.material; +THREE.Float64Attribute = function ( data, itemSize ) { - _renderData.elements.push( _face ); + THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - } +}; - }; +// File:src/core/DynamicBufferAttribute.js - return { - setObject: setObject, - projectVertex: projectVertex, - checkTriangleVisibility: checkTriangleVisibility, - checkBackfaceCulling: checkBackfaceCulling, - pushVertex: pushVertex, - pushNormal: pushNormal, - pushUv: pushUv, - pushLine: pushLine, - pushTriangle: pushTriangle - } +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author mrdoob / http://mrdoob.com/ + */ - }; +THREE.DynamicBufferAttribute = function ( array, itemSize ) { - var renderList = new RenderList(); + THREE.BufferAttribute.call( this, array, itemSize ); - this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + this.updateRange = { offset: 0, count: -1 }; - var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, - isFaceMaterial, objectMaterials; +}; - _faceCount = 0; - _lineCount = 0; - _spriteCount = 0; +THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); +THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; - _renderData.elements.length = 0; +THREE.DynamicBufferAttribute.prototype.clone = function () { - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - if ( camera.parent === undefined ) camera.updateMatrixWorld(); + return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); +}; - _frustum.setFromMatrix( _viewProjectionMatrix ); +// File:src/core/BufferGeometry.js - projectGraph( scene, sortObjects ); +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { +THREE.BufferGeometry = function () { - object = _renderData.objects[ o ].object; - geometry = object.geometry; + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - renderList.setObject( object ); + this.uuid = THREE.Math.generateUUID(); - _modelMatrix = object.matrixWorld; + this.name = ''; + this.type = 'BufferGeometry'; - _vertexCount = 0; + this.attributes = {}; + this.attributesKeys = []; - if ( object instanceof THREE.Mesh ) { + this.drawcalls = []; + this.offsets = this.drawcalls; // backwards compatibility - if ( geometry instanceof THREE.BufferGeometry ) { + this.boundingBox = null; + this.boundingSphere = null; - var attributes = geometry.attributes; - var offsets = geometry.offsets; +}; - if ( attributes.position === undefined ) continue; +THREE.BufferGeometry.prototype = { - var positions = attributes.position.array; + constructor: THREE.BufferGeometry, - for ( var i = 0, l = positions.length; i < l; i += 3 ) { + addAttribute: function ( name, attribute ) { - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + if ( attribute instanceof THREE.BufferAttribute === false ) { - } + THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - if ( attributes.normal !== undefined ) { + this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; - var normals = attributes.normal.array; + return; - for ( var i = 0, l = normals.length; i < l; i += 3 ) { + } - renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); + this.attributes[ name ] = attribute; + this.attributesKeys = Object.keys( this.attributes ); - } + }, - } + getAttribute: function ( name ) { - if ( attributes.uv !== undefined ) { + return this.attributes[ name ]; - var uvs = attributes.uv.array; + }, - for ( var i = 0, l = uvs.length; i < l; i += 2 ) { + addDrawCall: function ( start, count, indexOffset ) { - renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); + this.drawcalls.push( { - } + start: start, + count: count, + index: indexOffset !== undefined ? indexOffset : 0 - } + } ); - if ( attributes.index !== undefined ) { + }, - var indices = attributes.index.array; + applyMatrix: function ( matrix ) { - if ( offsets.length > 0 ) { + var position = this.attributes.position; - for ( var o = 0; o < offsets.length; o ++ ) { + if ( position !== undefined ) { - var offset = offsets[ o ]; - var index = offset.index; + matrix.applyToVector3Array( position.array ); + position.needsUpdate = true; - for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { + } - renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); + var normal = this.attributes.normal; - } + if ( normal !== undefined ) { - } + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - } else { + normalMatrix.applyToVector3Array( normal.array ); + normal.needsUpdate = true; - for ( var i = 0, l = indices.length; i < l; i += 3 ) { + } - renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + if ( this.boundingBox !== null ) { - } + this.computeBoundingBox(); - } + } - } else { + if ( this.boundingSphere !== null ) { - for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { + this.computeBoundingSphere(); - renderList.pushTriangle( i, i + 1, i + 2 ); + } - } + }, - } + center: function () { - } else if ( geometry instanceof THREE.Geometry ) { + this.computeBoundingBox(); - vertices = geometry.vertices; - faces = geometry.faces; - faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + var offset = this.boundingBox.center().negate(); - _normalMatrix.getNormalMatrix( _modelMatrix ); + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - objectMaterials = isFaceMaterial === true ? object.material : null; + return offset; - for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { + }, - var vertex = vertices[ v ]; - renderList.pushVertex( vertex.x, vertex.y, vertex.z ); + fromGeometry: function ( geometry, settings ) { - } + settings = settings || { 'vertexColors': THREE.NoColors }; - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + var vertices = geometry.vertices; + var faces = geometry.faces; + var faceVertexUvs = geometry.faceVertexUvs; + var vertexColors = settings.vertexColors; + var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3; - face = faces[ f ]; + var positions = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); - var material = isFaceMaterial === true - ? objectMaterials.materials[ face.materialIndex ] - : object.material; + var normals = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); - if ( material === undefined ) continue; + if ( vertexColors !== THREE.NoColors ) { - var side = material.side; + var colors = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - var v1 = _vertexPool[ face.a ]; - var v2 = _vertexPool[ face.b ]; - var v3 = _vertexPool[ face.c ]; + } - if ( material.morphTargets === true ) { + if ( hasFaceVertexUv === true ) { - var morphTargets = geometry.morphTargets; - var morphInfluences = object.morphTargetInfluences; + var uvs = new Float32Array( faces.length * 3 * 2 ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - var v1p = v1.position; - var v2p = v2.position; - var v3p = v3.position; + } - _vA.set( 0, 0, 0 ); - _vB.set( 0, 0, 0 ); - _vC.set( 0, 0, 0 ); + for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) { - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + var face = faces[ i ]; - var influence = morphInfluences[ t ]; + var a = vertices[ face.a ]; + var b = vertices[ face.b ]; + var c = vertices[ face.c ]; - if ( influence === 0 ) continue; + positions[ i3 ] = a.x; + positions[ i3 + 1 ] = a.y; + positions[ i3 + 2 ] = a.z; - var targets = morphTargets[ t ].vertices; + positions[ i3 + 3 ] = b.x; + positions[ i3 + 4 ] = b.y; + positions[ i3 + 5 ] = b.z; - _vA.x += ( targets[ face.a ].x - v1p.x ) * influence; - _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; - _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; + positions[ i3 + 6 ] = c.x; + positions[ i3 + 7 ] = c.y; + positions[ i3 + 8 ] = c.z; - _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; - _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; - _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; + if ( hasFaceVertexNormals === true ) { - _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; - _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; - _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; + var na = face.vertexNormals[ 0 ]; + var nb = face.vertexNormals[ 1 ]; + var nc = face.vertexNormals[ 2 ]; - } + normals[ i3 ] = na.x; + normals[ i3 + 1 ] = na.y; + normals[ i3 + 2 ] = na.z; - v1.position.add( _vA ); - v2.position.add( _vB ); - v3.position.add( _vC ); + normals[ i3 + 3 ] = nb.x; + normals[ i3 + 4 ] = nb.y; + normals[ i3 + 5 ] = nb.z; - renderList.projectVertex( v1 ); - renderList.projectVertex( v2 ); - renderList.projectVertex( v3 ); + normals[ i3 + 6 ] = nc.x; + normals[ i3 + 7 ] = nc.y; + normals[ i3 + 8 ] = nc.z; - } + } else { - if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; + var n = face.normal; - var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); + normals[ i3 ] = n.x; + normals[ i3 + 1 ] = n.y; + normals[ i3 + 2 ] = n.z; - if ( side !== THREE.DoubleSide ) { - if ( side === THREE.FrontSide && visible === false ) continue; - if ( side === THREE.BackSide && visible === true ) continue; - } + normals[ i3 + 3 ] = n.x; + normals[ i3 + 4 ] = n.y; + normals[ i3 + 5 ] = n.z; - _face = getNextFaceInPool(); + normals[ i3 + 6 ] = n.x; + normals[ i3 + 7 ] = n.y; + normals[ i3 + 8 ] = n.z; - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); + } - _face.normalModel.copy( face.normal ); + if ( vertexColors === THREE.FaceColors ) { - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + var fc = face.color; - _face.normalModel.negate(); + colors[ i3 ] = fc.r; + colors[ i3 + 1 ] = fc.g; + colors[ i3 + 2 ] = fc.b; - } + colors[ i3 + 3 ] = fc.r; + colors[ i3 + 4 ] = fc.g; + colors[ i3 + 5 ] = fc.b; - _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); + colors[ i3 + 6 ] = fc.r; + colors[ i3 + 7 ] = fc.g; + colors[ i3 + 8 ] = fc.b; - faceVertexNormals = face.vertexNormals; + } else if ( vertexColors === THREE.VertexColors ) { - for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { + var vca = face.vertexColors[ 0 ]; + var vcb = face.vertexColors[ 1 ]; + var vcc = face.vertexColors[ 2 ]; - var normalModel = _face.vertexNormalsModel[ n ]; - normalModel.copy( faceVertexNormals[ n ] ); + colors[ i3 ] = vca.r; + colors[ i3 + 1 ] = vca.g; + colors[ i3 + 2 ] = vca.b; - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + colors[ i3 + 3 ] = vcb.r; + colors[ i3 + 4 ] = vcb.g; + colors[ i3 + 5 ] = vcb.b; - normalModel.negate(); + colors[ i3 + 6 ] = vcc.r; + colors[ i3 + 7 ] = vcc.g; + colors[ i3 + 8 ] = vcc.b; - } + } - normalModel.applyMatrix3( _normalMatrix ).normalize(); + if ( hasFaceVertexUv === true ) { - } + var uva = faceVertexUvs[ 0 ][ i ][ 0 ]; + var uvb = faceVertexUvs[ 0 ][ i ][ 1 ]; + var uvc = faceVertexUvs[ 0 ][ i ][ 2 ]; - _face.vertexNormalsLength = faceVertexNormals.length; + uvs[ i2 ] = uva.x; + uvs[ i2 + 1 ] = uva.y; - var vertexUvs = faceVertexUvs[ f ]; + uvs[ i2 + 2 ] = uvb.x; + uvs[ i2 + 3 ] = uvb.y; - if ( vertexUvs !== undefined ) { + uvs[ i2 + 4 ] = uvc.x; + uvs[ i2 + 5 ] = uvc.y; - for ( var u = 0; u < 3; u ++ ) { + } - _face.uvs[ u ].copy( vertexUvs[ u ] ); + } - } + this.computeBoundingSphere() - } + return this; - _face.color = face.color; - _face.material = material; + }, - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + computeBoundingBox: function () { - _renderData.elements.push( _face ); + var vector = new THREE.Vector3(); - } + return function () { - } + if ( this.boundingBox === null ) { - } else if ( object instanceof THREE.Line ) { + this.boundingBox = new THREE.Box3(); - if ( geometry instanceof THREE.BufferGeometry ) { + } - var attributes = geometry.attributes; + var positions = this.attributes.position.array; - if ( attributes.position !== undefined ) { + if ( positions ) { - var positions = attributes.position.array; + var bb = this.boundingBox; + bb.makeEmpty(); - for ( var i = 0, l = positions.length; i < l; i += 3 ) { + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + bb.expandByPoint( vector ); - } + } - if ( attributes.index !== undefined ) { + } - var indices = attributes.index.array; + if ( positions === undefined || positions.length === 0 ) { - for ( var i = 0, l = indices.length; i < l; i += 2 ) { + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); - renderList.pushLine( indices[ i ], indices[ i + 1 ] ); + } - } + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - } else { + THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); - for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i ++ ) { + } - renderList.pushLine( i, i + 1 ); + } - } + }(), - } + computeBoundingSphere: function () { - } + var box = new THREE.Box3(); + var vector = new THREE.Vector3(); - } else if ( geometry instanceof THREE.Geometry ) { + return function () { - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + if ( this.boundingSphere === null ) { - vertices = object.geometry.vertices; + this.boundingSphere = new THREE.Sphere(); - if ( vertices.length === 0 ) continue; + } - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + var positions = this.attributes.position.array; - // Handle LineStrip and LinePieces - var step = object.type === THREE.LinePieces ? 2 : 1; + if ( positions ) { - for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { + box.makeEmpty(); - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + var center = this.boundingSphere.center; - if ( ( v + 1 ) % step > 0 ) continue; + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - v2 = _vertexPool[ _vertexCount - 2 ]; + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + box.expandByPoint( vector ); - _clippedVertex1PositionScreen.copy( v1.positionScreen ); - _clippedVertex2PositionScreen.copy( v2.positionScreen ); + } - if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + box.center( center ); - // Perform the perspective divide - _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); - _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + // hoping to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - _line = getNextLineInPool(); + var maxRadiusSq = 0; - _line.id = object.id; - _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); - _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - _line.material = object.material; + } - if ( object.material.vertexColors === THREE.VertexColors ) { + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); - _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); + if ( isNaN( this.boundingSphere.radius ) ) { - } + THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); - _renderData.elements.push( _line ); + } - } + } - } + } - } + }(), - } else if ( object instanceof THREE.Sprite ) { + computeFaceNormals: function () { - _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); - _vector4.applyMatrix4( _viewProjectionMatrix ); + // backwards compatibility - var invW = 1 / _vector4.w; + }, - _vector4.z *= invW; + computeVertexNormals: function () { - if ( _vector4.z >= -1 && _vector4.z <= 1 ) { + var attributes = this.attributes; - _sprite = getNextSpriteInPool(); - _sprite.id = object.id; - _sprite.x = _vector4.x * invW; - _sprite.y = _vector4.y * invW; - _sprite.z = _vector4.z; - _sprite.object = object; + if ( attributes.position ) { - _sprite.rotation = object.rotation; + var positions = attributes.position.array; - _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); - _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); + if ( attributes.normal === undefined ) { - _sprite.material = object.material; + this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) ); - _renderData.elements.push( _sprite ); + } else { - } + // reset existing normals to zero - } + var normals = attributes.normal.array; - } + for ( var i = 0, il = normals.length; i < il; i ++ ) { - if ( sortElements === true ) _renderData.elements.sort( painterSort ); + normals[ i ] = 0; - return _renderData; + } - }; + } - // Pools + var normals = attributes.normal.array; - function getNextObjectInPool() { + var vA, vB, vC, - if ( _objectCount === _objectPoolLength ) { + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), - var object = new THREE.RenderableObject(); - _objectPool.push( object ); - _objectPoolLength ++; - _objectCount ++; - return object; + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); - } + // indexed elements - return _objectPool[ _objectCount ++ ]; + if ( attributes.index ) { - } + var indices = attributes.index.array; - function getNextVertexInPool() { + var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] ); - if ( _vertexCount === _vertexPoolLength ) { + for ( var j = 0, jl = offsets.length; j < jl; ++ j ) { - var vertex = new THREE.RenderableVertex(); - _vertexPool.push( vertex ); - _vertexPoolLength ++; - _vertexCount ++; - return vertex; + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; - } + for ( var i = start, il = start + count; i < il; i += 3 ) { - return _vertexPool[ _vertexCount ++ ]; + vA = ( index + indices[ i ] ) * 3; + vB = ( index + indices[ i + 1 ] ) * 3; + vC = ( index + indices[ i + 2 ] ) * 3; - } + pA.fromArray( positions, vA ); + pB.fromArray( positions, vB ); + pC.fromArray( positions, vC ); - function getNextFaceInPool() { + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - if ( _faceCount === _facePoolLength ) { + normals[ vA ] += cb.x; + normals[ vA + 1 ] += cb.y; + normals[ vA + 2 ] += cb.z; - var face = new THREE.RenderableFace(); - _facePool.push( face ); - _facePoolLength ++; - _faceCount ++; - return face; + 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; - return _facePool[ _faceCount ++ ]; + } + } - } + } else { - function getNextLineInPool() { + // non-indexed elements (unconnected triangle soup) - if ( _lineCount === _linePoolLength ) { + for ( var i = 0, il = positions.length; i < il; i += 9 ) { - var line = new THREE.RenderableLine(); - _linePool.push( line ); - _linePoolLength ++; - _lineCount ++ - return line; + 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 ); - return _linePool[ _lineCount ++ ]; + 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; - function getNextSpriteInPool() { + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; - if ( _spriteCount === _spritePoolLength ) { + } - var sprite = new THREE.RenderableSprite(); - _spritePool.push( sprite ); - _spritePoolLength ++; - _spriteCount ++ - return sprite; + } - } + this.normalizeNormals(); - return _spritePool[ _spriteCount ++ ]; + attributes.normal.needsUpdate = true; - } + } - // + }, - function painterSort( a, b ) { + computeTangents: function () { - if ( a.z !== b.z ) { + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) - return b.z - a.z; + if ( this.attributes.index === undefined || + this.attributes.position === undefined || + this.attributes.normal === undefined || + this.attributes.uv === undefined ) { - } else if ( a.id !== b.id ) { + THREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); + return; - return a.id - b.id; + } - } else { + var indices = this.attributes.index.array; + var positions = this.attributes.position.array; + var normals = this.attributes.normal.array; + var uvs = this.attributes.uv.array; - return 0; + var nVertices = positions.length / 3; - } + if ( this.attributes.tangent === undefined ) { - } + this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - function clipLine( s1, s2 ) { + } - var alpha1 = 0, alpha2 = 1, + var tangents = this.attributes.tangent.array; - // Calculate the boundary coordinate of each vertex for the near and far clip planes, - // Z = -1 and Z = +1, respectively. - bc1near = s1.z + s1.w, - bc2near = s2.z + s2.w, - bc1far = - s1.z + s1.w, - bc2far = - s2.z + s2.w; + var tan1 = [], tan2 = []; - if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { + for ( var k = 0; k < nVertices; k ++ ) { - // Both vertices lie entirely within all clip planes. - return true; + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); - } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { + } - // Both vertices lie entirely outside one of the clip planes. - return false; + var vA = new THREE.Vector3(), + vB = new THREE.Vector3(), + vC = new THREE.Vector3(), - } else { + uvA = new THREE.Vector2(), + uvB = new THREE.Vector2(), + uvC = new THREE.Vector2(), - // The line segment spans at least one clip plane. + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r; - if ( bc1near < 0 ) { + var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); - // v1 lies outside the near plane, v2 inside - alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + function handleTriangle( a, b, c ) { - } else if ( bc2near < 0 ) { + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - // v2 lies outside the near plane, v1 inside - alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); - } + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; - if ( bc1far < 0 ) { + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; - // v1 lies outside the far plane, v2 inside - alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; - } else if ( bc2far < 0 ) { + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; - // v2 lies outside the far plane, v2 inside - alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; - } + r = 1.0 / ( s1 * t2 - s2 * t1 ); - if ( alpha2 < alpha1 ) { + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); - // The line segment spans two boundaries, but is outside both of them. - // (This can't happen when we're only clipping against just near/far but good - // to leave the check here for future usage if other clip planes are added.) - return false; + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); - } else { + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); - // Update the s1 and s2 vertices to match the clipped line segment. - s1.lerp( s2, alpha1 ); - s2.lerp( s1, 1 - alpha2 ); + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); - return true; + } - } + var i, il; + var j, jl; + var iA, iB, iC; - } + if ( this.drawcalls.length === 0 ) { - } + this.addDrawCall( 0, indices.length, 0 ); -}; + } -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + var drawcalls = this.drawcalls; -THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { + for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { - this.a = a; - this.b = b; - this.c = c; + var start = drawcalls[ j ].start; + var count = drawcalls[ j ].count; + var index = drawcalls[ j ].index; - this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); - this.vertexNormals = normal instanceof Array ? normal : [ ]; + for ( i = start, il = start + count; i < il; i += 3 ) { - this.color = color instanceof THREE.Color ? color : new THREE.Color(); - this.vertexColors = color instanceof Array ? color : []; + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; - this.vertexTangents = []; + handleTriangle( iA, iB, iC ); - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + } -}; - -THREE.Face3.prototype = { - - constructor: THREE.Face3, - - clone: function () { - - var face = new THREE.Face3( this.a, this.b, this.c ); + } - face.normal.copy( this.normal ); - face.color.copy( this.color ); + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; - face.materialIndex = this.materialIndex; + function handleVertex( v ) { - var i, il; - for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + n.fromArray( normals, v * 3 ); + n2.copy( n ); - return face; + t = tan1[ v ]; - } + // Gram-Schmidt orthogonalize -}; + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); -/** - * @author mrdoob / http://mrdoob.com/ - */ + // Calculate handedness -THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; - console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; - return new THREE.Face3( a, b, c, normal, color, materialIndex ); + } -}; + for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var start = drawcalls[ j ].start; + var count = drawcalls[ j ].count; + var index = drawcalls[ j ].index; -THREE.BufferAttribute = function () {}; + for ( i = start, il = start + count; i < il; i += 3 ) { -THREE.BufferAttribute.prototype = { + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; - constructor: THREE.BufferAttribute, + handleVertex( iA ); + handleVertex( iB ); + handleVertex( iC ); - get length () { + } - return this.array.length; + } - }, + }, + + /* + Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. + This method will effectively rewrite the index buffer and remap all attributes to match the new indices. + WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. + size - Defaults to 65535, but allows for larger or smaller chunks. + */ + computeOffsets: function ( size ) { + + if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit. + + var indices = this.attributes.index.array; + var vertices = this.attributes.position.array; + + var facesCount = ( indices.length / 3 ); + + /* + console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); + console.log("Faces to process: "+(indices.length/3)); + console.log("Reordering "+verticesCount+" vertices."); + */ + + var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers + var indexPtr = 0; + var vertexPtr = 0; + + var offsets = [ { start:0, count:0, index:0 } ]; + var offset = offsets[ 0 ]; + + var duplicatedVertices = 0; + var newVerticeMaps = 0; + var faceVertices = new Int32Array( 6 ); + var vertexMap = new Int32Array( vertices.length ); + var revVertexMap = new Int32Array( vertices.length ); + for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; } + + /* + Traverse every face and reorder vertices in the proper offsets of 65k. + We can have more than 65k entries in the index buffer per offset, but only reference 65k values. + */ + for ( var findex = 0; findex < facesCount; findex ++ ) { + newVerticeMaps = 0; + + for ( var vo = 0; vo < 3; vo ++ ) { + var vid = indices[ findex * 3 + vo ]; + if ( vertexMap[ vid ] == - 1 ) { + //Unmapped vertice + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = - 1; + newVerticeMaps ++; + } else if ( vertexMap[ vid ] < offset.index ) { + //Reused vertices from previous block (duplicate) + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = - 1; + duplicatedVertices ++; + } else { + //Reused vertice in the current block + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ]; + } + } + + var faceMax = vertexPtr + newVerticeMaps; + if ( faceMax > ( offset.index + size ) ) { + var new_offset = { start:indexPtr, count:0, index:vertexPtr }; + offsets.push( new_offset ); + offset = new_offset; + + //Re-evaluate reused vertices in light of new offset. + for ( var v = 0; v < 6; v += 2 ) { + var new_vid = faceVertices[ v + 1 ]; + if ( new_vid > - 1 && new_vid < offset.index ) + faceVertices[ v + 1 ] = - 1; + } + } - set: function ( value ) { + //Reindex the face. + for ( var v = 0; v < 6; v += 2 ) { + var vid = faceVertices[ v ]; + var new_vid = faceVertices[ v + 1 ]; - this.array.set( value ); + if ( new_vid === - 1 ) + new_vid = vertexPtr ++; - }, + vertexMap[ vid ] = new_vid; + revVertexMap[ new_vid ] = vid; + sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit + offset.count ++; + } + } - setX: function ( index, x ) { + /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ + this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr ); + this.offsets = offsets; // TODO: Deprecate + this.drawcalls = offsets; - this.array[ index * this.itemSize ] = x; + /* + var orderTime = Date.now(); + console.log("Reorder time: "+(orderTime-s)+"ms"); + console.log("Duplicated "+duplicatedVertices+" vertices."); + console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); + console.log("Draw offsets: "+offsets.length); + */ - }, + return offsets; - setY: function ( index, y ) { + }, - this.array[ index * this.itemSize + 1 ] = y; + merge: function ( geometry, offset ) { - }, + if ( geometry instanceof THREE.BufferGeometry === false ) { - setZ: function ( index, z ) { + THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; - this.array[ index * this.itemSize + 2 ] = z; + } - }, + if ( offset === undefined ) offset = 0; - setXY: function ( index, x, y ) { + var attributes = this.attributes; - index *= this.itemSize; + for ( var key in attributes ) { - this.array[ index ] = x; - this.array[ index + 1 ] = y; + if ( geometry.attributes[ key ] === undefined ) continue; - }, + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; - setXYZ: function ( index, x, y, z ) { + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; - index *= this.itemSize; + var attributeSize = attribute2.itemSize; - this.array[ index ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; + for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { - }, + attributeArray1[ j ] = attributeArray2[ i ]; - setXYZW: function ( index, x, y, z, w ) { + } - index *= this.itemSize; + } - this.array[ index ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; + return this; - } + }, -}; + normalizeNormals: function () { -// + var normals = this.attributes.normal.array; -THREE.Int8Attribute = function ( size, itemSize ) { + var x, y, z, n; - this.array = new Int8Array( size * itemSize ); - this.itemSize = itemSize; + for ( var i = 0, il = normals.length; i < il; i += 3 ) { -}; + x = normals[ i ]; + y = normals[ i + 1 ]; + z = normals[ i + 2 ]; -THREE.Int8Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + n = 1.0 / Math.sqrt( x * x + y * y + z * z ); -THREE.Uint8Attribute = function ( size, itemSize ) { + normals[ i ] *= n; + normals[ i + 1 ] *= n; + normals[ i + 2 ] *= n; - this.array = new Uint8Array( size * itemSize ); - this.itemSize = itemSize; + } -}; + }, + + /* + reoderBuffers: + Reorder attributes based on a new indexBuffer and indexMap. + indexBuffer - Uint16Array of the new ordered indices. + indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. + vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). + */ + reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) { + + /* Create a copy of all attributes for reordering. */ + var sortedAttributes = {}; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + var sourceArray = this.attributes[ attr ].array; + sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount ); + } -THREE.Uint8Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + /* Move attribute positions based on the new index map */ + for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) { + var vid = indexMap[ new_vid ]; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + var attrArray = this.attributes[ attr ].array; + var attrSize = this.attributes[ attr ].itemSize; + var sortedAttr = sortedAttributes[ attr ]; + for ( var k = 0; k < attrSize; k ++ ) + sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; + } + } -THREE.Uint8ClampedAttribute = function ( size, itemSize ) { + /* Carry the new sorted buffers locally */ + this.attributes[ 'index' ].array = indexBuffer; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + this.attributes[ attr ].array = sortedAttributes[ attr ]; + this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount; + } + }, - this.array = new Uint8ClampedArray( size * itemSize ); - this.itemSize = itemSize; + toJSON: function () { -}; + var output = { + metadata: { + version: 4.0, + type: 'BufferGeometry', + generator: 'BufferGeometryExporter' + }, + uuid: this.uuid, + type: this.type, + data: { + attributes: {} + } + }; -THREE.Uint8ClampedAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + var attributes = this.attributes; + var offsets = this.offsets; + var boundingSphere = this.boundingSphere; -THREE.Int16Attribute = function ( size, itemSize ) { + for ( var key in attributes ) { - this.array = new Int16Array( size * itemSize ); - this.itemSize = itemSize; + var attribute = attributes[ key ]; -}; + var array = Array.prototype.slice.call( attribute.array ); -THREE.Int16Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + output.data.attributes[ key ] = { + itemSize: attribute.itemSize, + type: attribute.array.constructor.name, + array: array + } -THREE.Uint16Attribute = function ( size, itemSize ) { + } - this.array = new Uint16Array( size * itemSize ); - this.itemSize = itemSize; + if ( offsets.length > 0 ) { -}; + output.data.offsets = JSON.parse( JSON.stringify( offsets ) ); -THREE.Uint16Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + } -THREE.Int32Attribute = function ( size, itemSize ) { + if ( boundingSphere !== null ) { - this.array = new Int32Array( size * itemSize ); - this.itemSize = itemSize; + output.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + } -}; + } -THREE.Int32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + return output; -THREE.Uint32Attribute = function ( size, itemSize ) { + }, - this.array = new Uint32Array( size * itemSize ); - this.itemSize = itemSize; + clone: function () { -}; + var geometry = new THREE.BufferGeometry(); -THREE.Uint32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + for ( var attr in this.attributes ) { -THREE.Float32Attribute = function ( size, itemSize ) { + var sourceAttr = this.attributes[ attr ]; + geometry.addAttribute( attr, sourceAttr.clone() ); - this.array = new Float32Array( size * itemSize ); - this.itemSize = itemSize; + } -}; + for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { -THREE.Float32Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); + var offset = this.offsets[ i ]; -THREE.Float64Attribute = function ( size, itemSize ) { + geometry.offsets.push( { - this.array = new Float64Array( size * itemSize ); - this.itemSize = itemSize; + start: offset.start, + index: offset.index, + count: offset.count -}; + } ); -THREE.Float64Attribute.prototype = Object.create( THREE.BufferAttribute.prototype ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.BufferGeometry = function () { + return geometry; - this.id = THREE.GeometryIdCount ++; - this.uuid = THREE.Math.generateUUID(); + }, - this.name = ''; + dispose: function () { - this.attributes = {}; - this.drawcalls = []; - this.offsets = this.drawcalls; // backwards compatibility + this.dispatchEvent( { type: 'dispose' } ); - this.boundingBox = null; - this.boundingSphere = null; + } }; -THREE.BufferGeometry.prototype = { - - constructor: THREE.BufferGeometry, - - addAttribute: function ( name, attribute ) { - - if ( attribute instanceof THREE.BufferAttribute === false ) { - - console.warn( 'DEPRECATED: BufferGeometry\'s addAttribute() now expects ( name, attribute ).' ); - - this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; - - return; - - } - - this.attributes[ name ] = attribute; - - }, - - getAttribute: function ( name ) { - - return this.attributes[ name ]; - - }, - - addDrawCall: function ( start, count, indexOffset ) { - - this.drawcalls.push( { - - start: start, - count: count, - index: indexOffset !== undefined ? indexOffset : 0 - - } ); - - }, - - applyMatrix: function ( matrix ) { - - var position = this.attributes.position; - - if ( position !== undefined ) { - - matrix.applyToVector3Array( position.array ); - position.needsUpdate = true; - - } - - var normal = this.attributes.normal; - - if ( normal !== undefined ) { - - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - - normalMatrix.applyToVector3Array( normal.array ); - normal.needsUpdate = true; - - } - - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new THREE.Box3(); - - } - - var positions = this.attributes[ "position" ].array; - - if ( positions ) { - - var bb = this.boundingBox; - - if( positions.length >= 3 ) { - bb.min.x = bb.max.x = positions[ 0 ]; - bb.min.y = bb.max.y = positions[ 1 ]; - bb.min.z = bb.max.z = positions[ 2 ]; - } - - for ( var i = 3, il = positions.length; i < il; i += 3 ) { - - var x = positions[ i ]; - var y = positions[ i + 1 ]; - var z = positions[ i + 2 ]; - - // bounding box - - if ( x < bb.min.x ) { - - bb.min.x = x; - - } else if ( x > bb.max.x ) { - - bb.max.x = x; - - } - - if ( y < bb.min.y ) { - - bb.min.y = y; - - } else if ( y > bb.max.y ) { - - bb.max.y = y; - - } - - if ( z < bb.min.z ) { - - bb.min.z = z; - - } else if ( z > bb.max.z ) { +THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); - bb.max.z = z; +// File:src/core/Geometry.js - } +/** + * @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://exocortex.com + */ - } +THREE.Geometry = function () { - } + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - if ( positions === undefined || positions.length === 0 ) { + this.uuid = THREE.Math.generateUUID(); - this.boundingBox.min.set( 0, 0, 0 ); - this.boundingBox.max.set( 0, 0, 0 ); + this.name = ''; + this.type = 'Geometry'; - } + this.vertices = []; + this.colors = []; // one-to-one vertex colors, used in Points and Line - }, + this.faces = []; - computeBoundingSphere: function () { + this.faceVertexUvs = [ [] ]; - var box = new THREE.Box3(); - var vector = new THREE.Vector3(); + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; - return function () { + this.skinWeights = []; + this.skinIndices = []; - if ( this.boundingSphere === null ) { + this.lineDistances = []; - this.boundingSphere = new THREE.Sphere(); + this.boundingBox = null; + this.boundingSphere = null; - } + this.hasTangents = false; - var positions = this.attributes[ "position" ].array; + this.dynamic = true; // the intermediate typed arrays will be deleted when set to false - if ( positions ) { + // update flags - box.makeEmpty(); + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.tangentsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; - var center = this.boundingSphere.center; + this.groupsNeedUpdate = false; - for ( var i = 0, il = positions.length; i < il; i += 3 ) { +}; - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - box.addPoint( vector ); +THREE.Geometry.prototype = { - } + constructor: THREE.Geometry, - box.center( center ); + applyMatrix: function ( matrix ) { - var maxRadiusSq = 0; + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - for ( var i = 0, il = positions.length; i < il; i += 3 ) { + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); - } + } - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + 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(); - computeFaceNormals: function () { + } - // backwards compatibility + } - }, + if ( this.boundingBox !== null ) { - computeVertexNormals: function () { + this.computeBoundingBox(); - if ( this.attributes[ "position" ] ) { + } - var i, il; - var j, jl; + if ( this.boundingSphere !== null ) { - var nVertexElements = this.attributes[ "position" ].array.length; + this.computeBoundingSphere(); - if ( this.attributes[ "normal" ] === undefined ) { + } - this.attributes[ "normal" ] = { + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; - itemSize: 3, - array: new Float32Array( nVertexElements ) + }, - }; + fromBufferGeometry: function ( geometry ) { - } else { + var scope = this; - // reset existing normals to zero + var attributes = geometry.attributes; - for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { + var vertices = attributes.position.array; + var indices = attributes.index !== undefined ? attributes.index.array : undefined; + 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; - this.attributes[ "normal" ].array[ i ] = 0; + var tempNormals = []; + var tempUVs = []; - } + for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) { - } + scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; + if ( normals !== undefined ) { - var vA, vB, vC, x, y, z, + tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); - pA = new THREE.Vector3(), - pB = new THREE.Vector3(), - pC = new THREE.Vector3(), + } - cb = new THREE.Vector3(), - ab = new THREE.Vector3(); + if ( colors !== undefined ) { - // indexed elements + scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); - if ( this.attributes[ "index" ] ) { + } - var indices = this.attributes[ "index" ].array; + if ( uvs !== undefined ) { - var offsets = this.offsets; + tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) ); - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + } - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + } - for ( i = start, il = start + count; i < il; i += 3 ) { + var addFace = function ( a, b, c ) { - vA = index + indices[ i ]; - vB = index + indices[ i + 1 ]; - vC = index + indices[ i + 2 ]; + 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() ] : []; - x = positions[ vA * 3 ]; - y = positions[ vA * 3 + 1 ]; - z = positions[ vA * 3 + 2 ]; - pA.set( x, y, z ); + scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) ); - x = positions[ vB * 3 ]; - y = positions[ vB * 3 + 1 ]; - z = positions[ vB * 3 + 2 ]; - pB.set( x, y, z ); + if ( uvs !== undefined ) { - x = positions[ vC * 3 ]; - y = positions[ vC * 3 + 1 ]; - z = positions[ vC * 3 + 2 ]; - pC.set( x, y, z ); + scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + } - normals[ vA * 3 ] += cb.x; - normals[ vA * 3 + 1 ] += cb.y; - normals[ vA * 3 + 2 ] += cb.z; + }; - normals[ vB * 3 ] += cb.x; - normals[ vB * 3 + 1 ] += cb.y; - normals[ vB * 3 + 2 ] += cb.z; + if ( indices !== undefined ) { - normals[ vC * 3 ] += cb.x; - normals[ vC * 3 + 1 ] += cb.y; - normals[ vC * 3 + 2 ] += cb.z; + var drawcalls = geometry.drawcalls; - } + if ( drawcalls.length > 0 ) { - } + for ( var i = 0; i < drawcalls.length; i ++ ) { - // non-indexed elements (unconnected triangle soup) + var drawcall = drawcalls[ i ]; - } else { + var start = drawcall.start; + var count = drawcall.count; + var index = drawcall.index; - for ( i = 0, il = positions.length; i < il; i += 9 ) { + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - x = positions[ i ]; - y = positions[ i + 1 ]; - z = positions[ i + 2 ]; - pA.set( x, y, z ); + addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] ); - x = positions[ i + 3 ]; - y = positions[ i + 4 ]; - z = positions[ i + 5 ]; - pB.set( x, y, z ); + } - x = positions[ i + 6 ]; - y = positions[ i + 7 ]; - z = positions[ i + 8 ]; - pC.set( x, y, z ); + } - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + } else { - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; + for ( var i = 0; i < indices.length; i += 3 ) { - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; + } - } + } - } + } else { - this.normalizeNormals(); + for ( var i = 0; i < vertices.length / 3; i += 3 ) { - this.normalsNeedUpdate = true; + addFace( i, i + 1, i + 2 ); - } + } - }, + } - normalizeNormals: function () { + this.computeFaceNormals(); - var normals = this.attributes[ "normal" ].array; + if ( geometry.boundingBox !== null ) { - var x, y, z, n; + this.boundingBox = geometry.boundingBox.clone(); - for ( var i = 0, il = normals.length; i < il; i += 3 ) { + } - x = normals[ i ]; - y = normals[ i + 1 ]; - z = normals[ i + 2 ]; + if ( geometry.boundingSphere !== null ) { - n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + this.boundingSphere = geometry.boundingSphere.clone(); - normals[ i ] *= n; - normals[ i + 1 ] *= n; - normals[ i + 2 ] *= n; + } - } + return this; - }, + }, - computeTangents: function () { + center: function () { - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) + this.computeBoundingBox(); - if ( this.attributes[ "index" ] === undefined || - this.attributes[ "position" ] === undefined || - this.attributes[ "normal" ] === undefined || - this.attributes[ "uv" ] === undefined ) { + var offset = this.boundingBox.center().negate(); - console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); - return; + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - } + return offset; - var indices = this.attributes[ "index" ].array; - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; - var uvs = this.attributes[ "uv" ].array; + }, - var nVertices = positions.length / 3; + computeFaceNormals: function () { - if ( this.attributes[ "tangent" ] === undefined ) { + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - var nTangentElements = 4 * nVertices; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.attributes[ "tangent" ] = { + var face = this.faces[ f ]; - itemSize: 4, - array: new Float32Array( nTangentElements ) + 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(); - var tangents = this.attributes[ "tangent" ].array; + face.normal.copy( cb ); - var tan1 = [], tan2 = []; + } - for ( var k = 0; k < nVertices; k ++ ) { + }, - tan1[ k ] = new THREE.Vector3(); - tan2[ k ] = new THREE.Vector3(); + computeVertexNormals: function ( areaWeighted ) { - } + var v, vl, f, fl, face, vertices; - var xA, yA, zA, - xB, yB, zB, - xC, yC, zC, + vertices = new Array( this.vertices.length ); - uA, vA, - uB, vB, - uC, vC, + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r; + vertices[ v ] = new THREE.Vector3(); - var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + } - function handleTriangle( a, b, c ) { + if ( areaWeighted ) { - xA = positions[ a * 3 ]; - yA = positions[ a * 3 + 1 ]; - zA = positions[ a * 3 + 2 ]; + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm - xB = positions[ b * 3 ]; - yB = positions[ b * 3 + 1 ]; - zB = positions[ b * 3 + 2 ]; + var vA, vB, vC; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - xC = positions[ c * 3 ]; - yC = positions[ c * 3 + 1 ]; - zC = positions[ c * 3 + 2 ]; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - uA = uvs[ a * 2 ]; - vA = uvs[ a * 2 + 1 ]; + face = this.faces[ f ]; - uB = uvs[ b * 2 ]; - vB = uvs[ b * 2 + 1 ]; + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; - uC = uvs[ c * 2 ]; - vC = uvs[ c * 2 + 1 ]; + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - x1 = xB - xA; - x2 = xC - xA; + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); - y1 = yB - yA; - y2 = yC - yA; + } - z1 = zB - zA; - z2 = zC - zA; + } else { - s1 = uB - uA; - s2 = uC - uA; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - t1 = vB - vA; - t2 = vC - vA; + face = this.faces[ f ]; - r = 1.0 / ( s1 * t2 - s2 * t1 ); + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); - sdir.set( - ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r - ); + } - tdir.set( - ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r - ); + } - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); + vertices[ v ].normalize(); - } + } - var i, il; - var j, jl; - var iA, iB, iC; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - var offsets = this.offsets; + face = this.faces[ f ]; - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); + face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); + face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + } - for ( i = start, il = start + count; i < il; i += 3 ) { + }, - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; + computeMorphNormals: function () { - handleTriangle( iA, iB, iC ); + 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 ++ ) { - var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); - var n = new THREE.Vector3(), n2 = new THREE.Vector3(); - var w, t, test; + face = this.faces[ f ]; - function handleVertex( v ) { + if ( ! face.__originalFaceNormal ) { - n.x = normals[ v * 3 ]; - n.y = normals[ v * 3 + 1 ]; - n.z = normals[ v * 3 + 2 ]; + face.__originalFaceNormal = face.normal.clone(); - n2.copy( n ); + } else { - t = tan1[ v ]; + face.__originalFaceNormal.copy( face.normal ); - // Gram-Schmidt orthogonalize + } - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - // Calculate handedness + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - tmp2.crossVectors( n2, t ); - test = tmp2.dot( tan2[ v ] ); - w = ( test < 0.0 ) ? -1.0 : 1.0; + if ( ! face.__originalVertexNormals[ i ] ) { - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - } + } else { - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + } - for ( i = start, il = start + count; i < il; i += 3 ) { + } - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; + } - handleVertex( iA ); - handleVertex( iB ); - handleVertex( iC ); + // use temp geometry to compute face and vertex normals for each morph - } + var tmpGeo = new THREE.Geometry(); + tmpGeo.faces = this.faces; - } + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - }, + // create on first access - /* - computeOffsets - Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. - This method will effectively rewrite the index buffer and remap all attributes to match the new indices. - WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. - indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks. - */ - computeOffsets: function(indexBufferSize) { + if ( ! this.morphNormals[ i ] ) { - var size = indexBufferSize; - if(indexBufferSize === undefined) - size = 65535; //WebGL limits type of index buffer values to 16-bit. + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; - var s = Date.now(); + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - var indices = this.attributes['index'].array; - var vertices = this.attributes['position'].array; - - var verticesCount = (vertices.length/3); - var facesCount = (indices.length/3); - - /* - console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); - console.log("Faces to process: "+(indices.length/3)); - console.log("Reordering "+verticesCount+" vertices."); - */ - - var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers - var indexPtr = 0; - var vertexPtr = 0; - - var offsets = [ { start:0, count:0, index:0 } ]; - var offset = offsets[0]; - - var duplicatedVertices = 0; - var newVerticeMaps = 0; - var faceVertices = new Int32Array(6); - var vertexMap = new Int32Array( vertices.length ); - var revVertexMap = new Int32Array( vertices.length ); - for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; } - - /* - Traverse every face and reorder vertices in the proper offsets of 65k. - We can have more than 65k entries in the index buffer per offset, but only reference 65k values. - */ - for(var findex = 0; findex < facesCount; findex++) { - newVerticeMaps = 0; - - for(var vo = 0; vo < 3; vo++) { - var vid = indices[ findex*3 + vo ]; - if(vertexMap[vid] == -1) { - //Unmapped vertice - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = -1; - newVerticeMaps++; - } else if(vertexMap[vid] < offset.index) { - //Reused vertices from previous block (duplicate) - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = -1; - duplicatedVertices++; - } else { - //Reused vertice in the current block - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = vertexMap[vid]; - } - } - - var faceMax = vertexPtr + newVerticeMaps; - if(faceMax > (offset.index + size)) { - var new_offset = { start:indexPtr, count:0, index:vertexPtr }; - offsets.push(new_offset); - offset = new_offset; - - //Re-evaluate reused vertices in light of new offset. - for(var v = 0; v < 6; v+=2) { - var new_vid = faceVertices[v+1]; - if(new_vid > -1 && new_vid < offset.index) - faceVertices[v+1] = -1; - } - } - - //Reindex the face. - for(var v = 0; v < 6; v+=2) { - var vid = faceVertices[v]; - var new_vid = faceVertices[v+1]; - - if(new_vid === -1) - new_vid = vertexPtr++; - - vertexMap[vid] = new_vid; - revVertexMap[new_vid] = vid; - sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit - offset.count++; - } - } - - /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ - this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr); - this.offsets = offsets; - - /* - var orderTime = Date.now(); - console.log("Reorder time: "+(orderTime-s)+"ms"); - console.log("Duplicated "+duplicatedVertices+" vertices."); - console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); - console.log("Draw offsets: "+offsets.length); - */ - - return offsets; - }, - - /* - reoderBuffers: - Reorder attributes based on a new indexBuffer and indexMap. - indexBuffer - Uint16Array of the new ordered indices. - indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. - vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). - */ - reorderBuffers: function(indexBuffer, indexMap, vertexCount) { - - /* Create a copy of all attributes for reordering. */ - var sortedAttributes = {}; - var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; - for( var attr in this.attributes ) { - if(attr == 'index') - continue; - var sourceArray = this.attributes[attr].array; - for ( var i = 0, il = types.length; i < il; i++ ) { - var type = types[i]; - if (sourceArray instanceof type) { - sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount ); - break; - } - } - } - - /* Move attribute positions based on the new index map */ - for(var new_vid = 0; new_vid < vertexCount; new_vid++) { - var vid = indexMap[new_vid]; - for ( var attr in this.attributes ) { - if(attr == 'index') - continue; - var attrArray = this.attributes[attr].array; - var attrSize = this.attributes[attr].itemSize; - var sortedAttr = sortedAttributes[attr]; - for(var k = 0; k < attrSize; k++) - sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; - } - } - - /* Carry the new sorted buffers locally */ - this.attributes['index'].array = indexBuffer; - for ( var attr in this.attributes ) { - if(attr == 'index') - continue; - this.attributes[attr].array = sortedAttributes[attr]; - this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount; - } - }, + var faceNormal, vertexNormals; - clone: function () { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - var geometry = new THREE.BufferGeometry(); + faceNormal = new THREE.Vector3(); + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; - var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); - for ( var attr in this.attributes ) { + } - var sourceAttr = this.attributes[ attr ]; - var sourceArray = sourceAttr.array; + } - var attribute = { + var morphNormals = this.morphNormals[ i ]; - itemSize: sourceAttr.itemSize, - array: null + // set vertices to morph target - }; + tmpGeo.vertices = this.morphTargets[ i ].vertices; - for ( var i = 0, il = types.length; i < il; i ++ ) { + // compute morph normals - var type = types[ i ]; + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); - if ( sourceArray instanceof type ) { + // store morph normals - attribute.array = new type( sourceArray ); - break; + var faceNormal, vertexNormals; - } + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - } + face = this.faces[ f ]; - geometry.attributes[ attr ] = attribute; + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; - } + faceNormal.copy( face.normal ); - for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); - var offset = this.offsets[ i ]; + } - geometry.offsets.push( { + } - start: offset.start, - index: offset.index, - count: offset.count + // restore original normals - } ); + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - } + face = this.faces[ f ]; - return geometry; + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; - }, + } - dispose: function () { + }, - this.dispatchEvent( { type: 'dispose' } ); + computeTangents: function () { - } + // based on http://www.terathon.com/code/tangent.html + // tangents go to vertices -}; + var f, fl, v, vl, i, vertexIndex, + face, uv, vA, vB, vC, uvA, uvB, uvC, + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r, t, test, + tan1 = [], tan2 = [], + sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), + tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), + n = new THREE.Vector3(), w; -THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + tan1[ v ] = new THREE.Vector3(); + tan2[ v ] = new THREE.Vector3(); -THREE.BufferGeometryManipulator = function ( bufferGeometry ) { + } - this.vertices = []; - this.normals = []; - this.uvs = []; + function handleTriangle( context, a, b, c, ua, ub, uc ) { - var attributes = bufferGeometry.attributes; - var length = attributes.position.array.length / 3; + vA = context.vertices[ a ]; + vB = context.vertices[ b ]; + vC = context.vertices[ c ]; - for ( var i = 0; i < length; i ++ ) { + uvA = uv[ ua ]; + uvB = uv[ ub ]; + uvC = uv[ uc ]; - this.vertices.push( new THREE.TypedVector3( attributes.position.array, i * 3 ) ); - this.normals.push( new THREE.TypedVector3( attributes.normal.array, i * 3 ) ); - this.uvs.push( new THREE.TypedVector2( attributes.uv.array, i * 2 ) ); + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; - } + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; -}; -/** - * @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://exocortex.com - */ + r = 1.0 / ( s1 * t2 - s2 * t1 ); + sdir.set( ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r ); + tdir.set( ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r ); -THREE.Geometry = function () { + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); - this.id = THREE.GeometryIdCount ++; - this.uuid = THREE.Math.generateUUID(); + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); - this.name = ''; + } - this.vertices = []; - this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.faces = []; + face = this.faces[ f ]; + uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents - this.faceVertexUvs = [[]]; + handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; + } - this.skinWeights = []; - this.skinIndices = []; + var faceIndex = [ 'a', 'b', 'c', 'd' ]; - this.lineDistances = []; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.boundingBox = null; - this.boundingSphere = null; + face = this.faces[ f ]; - this.hasTangents = false; + for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) { - this.dynamic = true; // the intermediate typed arrays will be deleted when set to false + n.copy( face.vertexNormals[ i ] ); - // update flags + vertexIndex = face[ faceIndex[ i ] ]; - this.verticesNeedUpdate = false; - this.elementsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.tangentsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; + t = tan1[ vertexIndex ]; - this.buffersNeedUpdate = false; + // Gram-Schmidt orthogonalize -}; + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); -THREE.Geometry.prototype = { + // Calculate handedness - constructor: THREE.Geometry, + tmp2.crossVectors( face.vertexNormals[ i ], t ); + test = tmp2.dot( tan2[ vertexIndex ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; - applyMatrix: function ( matrix ) { + face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + } - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + } - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); + this.hasTangents = true; - } + }, - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + computeLineDistances: function () { - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); + var d = 0; + var vertices = this.vertices; - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + if ( i > 0 ) { - } + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); - } + } - if ( this.boundingBox instanceof THREE.Box3 ) { + this.lineDistances[ i ] = d; - this.computeBoundingBox(); + } - } + }, - if ( this.boundingSphere instanceof THREE.Sphere ) { + computeBoundingBox: function () { - this.computeBoundingSphere(); + if ( this.boundingBox === null ) { - } + this.boundingBox = new THREE.Box3(); - }, + } - computeFaceNormals: function () { + this.boundingBox.setFromPoints( this.vertices ); - var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + }, - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + computeBoundingSphere: function () { - var face = this.faces[ f ]; + if ( this.boundingSphere === null ) { - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; + this.boundingSphere = new THREE.Sphere(); - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + } - cb.normalize(); + this.boundingSphere.setFromPoints( this.vertices ); - face.normal.copy( cb ); + }, - } + merge: function ( geometry, matrix, materialIndexOffset ) { - }, + if ( geometry instanceof THREE.Geometry === false ) { - computeVertexNormals: function ( areaWeighted ) { + THREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; - var v, vl, f, fl, face, vertices; + } - vertices = new Array( this.vertices.length ); + 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 ]; - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - vertices[ v ] = new THREE.Vector3(); + if ( matrix !== undefined ) { - } + normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - if ( areaWeighted ) { + } - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm + // vertices - var vA, vB, vC, vD; - var cb = new THREE.Vector3(), ab = new THREE.Vector3(), - db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var vertex = vertices2[ i ]; - face = this.faces[ f ]; + var vertexCopy = vertex.clone(); - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; + if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + vertices1.push( vertexCopy ); - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); + } - } + // faces - } else { + for ( i = 0, il = faces2.length; i < il; i ++ ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; - face = this.faces[ f ]; + faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); + if ( normalMatrix !== undefined ) { - } + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - } + } - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - vertices[ v ].normalize(); + normal = faceVertexNormals[ j ].clone(); - } + if ( normalMatrix !== undefined ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + normal.applyMatrix3( normalMatrix ).normalize(); - face = this.faces[ f ]; + } - face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); - face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); - face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); + faceCopy.vertexNormals.push( normal ); - } + } - }, + faceCopy.color.copy( face.color ); - computeMorphNormals: function () { + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { - var i, il, f, fl, face; + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); - // 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 ++ ) { + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - face = this.faces[ f ]; + faces1.push( faceCopy ); - if ( ! face.__originalFaceNormal ) { + } - face.__originalFaceNormal = face.normal.clone(); + // uvs - } else { + for ( i = 0, il = uvs2.length; i < il; i ++ ) { - face.__originalFaceNormal.copy( face.normal ); + var uv = uvs2[ i ], uvCopy = []; - } + if ( uv === undefined ) { - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + continue; - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + } - if ( ! face.__originalVertexNormals[ i ] ) { + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + uvCopy.push( uv[ j ].clone() ); - } else { + } - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + uvs1.push( uvCopy ); - } + } - } + }, - } + mergeMesh: function ( mesh ) { - // use temp geometry to compute face and vertex normals for each morph + if ( mesh instanceof THREE.Mesh === false ) { - var tmpGeo = new THREE.Geometry(); - tmpGeo.faces = this.faces; + THREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + } - // create on first access + mesh.matrixAutoUpdate && mesh.updateMatrix(); - if ( ! this.morphNormals[ i ] ) { + this.merge( mesh.geometry, mesh.matrix ); - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; + }, - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ - var faceNormal, vertexNormals; + mergeVertices: function () { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) + var unique = [], changes = []; - face = this.faces[ f ]; + var v, key; + var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i, il, face; + var indices, j, jl; - faceNormal = new THREE.Vector3(); - vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); + 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; - var morphNormals = this.morphNormals[ i ]; + } else { - // set vertices to morph target + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; - tmpGeo.vertices = this.morphTargets[ i ].vertices; + } - // compute morph normals + }; - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); - // store morph normals + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; - var faceNormal, vertexNormals; + for ( i = 0, il = this.faces.length; i < il; i ++ ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + face = this.faces[ i ]; - face = this.faces[ f ]; + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; + indices = [ face.a, face.b, face.c ]; - faceNormal.copy( face.normal ); + var dupIndex = - 1; - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + // 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 ] ) { - } + dupIndex = n; + faceIndicesToRemove.push( i ); + break; - } + } + } - // restore original normals + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + var idx = faceIndicesToRemove[ i ]; - face = this.faces[ f ]; + this.faces.splice( idx, 1 ); - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - } + this.faceVertexUvs[ j ].splice( idx, 1 ); - }, + } - computeTangents: function () { + } - // based on http://www.terathon.com/code/tangent.html - // tangents go to vertices + // Use unique set of vertices - var f, fl, v, vl, i, il, vertexIndex, - face, uv, vA, vB, vC, uvA, uvB, uvC, - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r, t, test, - tan1 = [], tan2 = [], - sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), - tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), - n = new THREE.Vector3(), w; + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + }, - tan1[ v ] = new THREE.Vector3(); - tan2[ v ] = new THREE.Vector3(); + toJSON: function () { - } + var output = { + metadata: { + version: 4.0, + type: 'BufferGeometry', + generator: 'BufferGeometryExporter' + }, + uuid: this.uuid, + type: this.type + }; - function handleTriangle( context, a, b, c, ua, ub, uc ) { + if ( this.name !== "" ) output.name = this.name; - vA = context.vertices[ a ]; - vB = context.vertices[ b ]; - vC = context.vertices[ c ]; + if ( this.parameters !== undefined ) { - uvA = uv[ ua ]; - uvB = uv[ ub ]; - uvC = uv[ uc ]; + var parameters = this.parameters; - x1 = vB.x - vA.x; - x2 = vC.x - vA.x; - y1 = vB.y - vA.y; - y2 = vC.y - vA.y; - z1 = vB.z - vA.z; - z2 = vC.z - vA.z; + for ( var key in parameters ) { - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; + if ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ]; - r = 1.0 / ( s1 * t2 - s2 * t1 ); - sdir.set( ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r ); - tdir.set( ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r ); + } - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); + return output; - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); + } - } + var vertices = []; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + for ( var i = 0; i < this.vertices.length; i ++ ) { - face = this.faces[ f ]; - uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); + } - } + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; - var faceIndex = [ 'a', 'b', 'c', 'd' ]; + for ( var i = 0; i < this.faces.length; i ++ ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var face = this.faces[ i ]; - face = this.faces[ f ]; + var hasMaterial = false; // face.materialIndex !== undefined; + 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; - for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { + var faceType = 0; - n.copy( face.vertexNormals[ i ] ); + faceType = setBit( faceType, 0, 0 ); + 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 ); - vertexIndex = face[ faceIndex[ i ] ]; + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); - t = tan1[ vertexIndex ]; - // Gram-Schmidt orthogonalize + /* + if ( hasMaterial ) { - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + faces.push( face.materialIndex ); - // Calculate handedness + } + */ - tmp2.crossVectors( face.vertexNormals[ i ], t ); - test = tmp2.dot( tan2[ vertexIndex ] ); - w = (test < 0.0) ? -1.0 : 1.0; + if ( hasFaceVertexUv ) { - face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; - } + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); - } + } - this.hasTangents = true; + if ( hasFaceNormal ) { - }, + faces.push( getNormalIndex( face.normal ) ); - computeLineDistances: function ( ) { + } - var d = 0; - var vertices = this.vertices; + if ( hasFaceVertexNormal ) { - for ( var i = 0, il = vertices.length; i < il; i ++ ) { + var vertexNormals = face.vertexNormals; - if ( i > 0 ) { + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); - d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); + } - } + if ( hasFaceColor ) { - this.lineDistances[ i ] = d; + faces.push( getColorIndex( face.color ) ); - } + } - }, + if ( hasFaceVertexColor ) { - computeBoundingBox: function () { + var vertexColors = face.vertexColors; - if ( this.boundingBox === null ) { + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); - this.boundingBox = new THREE.Box3(); + } - } + } - this.boundingBox.setFromPoints( this.vertices ); + function setBit( value, position, enabled ) { - }, + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) ); - computeBoundingSphere: function () { + } - if ( this.boundingSphere === null ) { + function getNormalIndex( normal ) { - this.boundingSphere = new THREE.Sphere(); + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); - } + if ( normalsHash[ hash ] !== undefined ) { - this.boundingSphere.setFromPoints( this.vertices ); + return normalsHash[ hash ]; - }, + } - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); - mergeVertices: function () { + return normalsHash[ hash ]; - var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) - var unique = [], changes = []; + } - var v, key; - var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 - var precision = Math.pow( 10, precisionPoints ); - var i,il, face; - var indices, k, j, jl, u; + function getColorIndex( color ) { - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + var hash = color.r.toString() + color.g.toString() + color.b.toString(); - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + if ( colorsHash[ hash ] !== undefined ) { - if ( verticesMap[ key ] === undefined ) { + return colorsHash[ hash ]; - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; + } - } else { + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; + return colorsHash[ hash ]; - } + } - }; + function getUvIndex( uv ) { + var hash = uv.x.toString() + uv.y.toString(); - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; + if ( uvsHash[ hash ] !== undefined ) { - for( i = 0, il = this.faces.length; i < il; i ++ ) { + return uvsHash[ hash ]; - face = this.faces[ i ]; + } - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); - indices = [ face.a, face.b, face.c ]; + return uvsHash[ hash ]; - var dupIndex = -1; + } - // 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 ] ) { + output.data = {}; - dupIndex = n; - faceIndicesToRemove.push( i ); - break; + output.data.vertices = vertices; + output.data.normals = normals; + if ( colors.length > 0 ) output.data.colors = colors; + if ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility + output.data.faces = faces; - } - } + // - } + return output; - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - var idx = faceIndicesToRemove[ i ]; + }, - this.faces.splice( idx, 1 ); + clone: function () { - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + var geometry = new THREE.Geometry(); - this.faceVertexUvs[ j ].splice( idx, 1 ); + var vertices = this.vertices; - } + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - } + geometry.vertices.push( vertices[ i ].clone() ); - // Use unique set of vertices + } - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; + var faces = this.faces; - }, + for ( var i = 0, il = faces.length; i < il; i ++ ) { - // Geometry splitting + geometry.faces.push( faces[ i ].clone() ); - makeGroups: ( function () { + } - var geometryGroupCounter = 0; - - return function ( usesFaceMaterial, maxVerticesInGroup ) { + for ( var i = 0, il = this.faceVertexUvs.length; i < il; i ++ ) { - var f, fl, face, materialIndex, - groupHash, hash_map = {}; + var faceVertexUvs = this.faceVertexUvs[ i ]; - var numMorphTargets = this.morphTargets.length; - var numMorphNormals = this.morphNormals.length; + if ( geometry.faceVertexUvs[ i ] === undefined ) { - this.geometryGroups = {}; + geometry.faceVertexUvs[ i ] = []; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } - face = this.faces[ f ]; - materialIndex = usesFaceMaterial ? face.materialIndex : 0; + for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - if ( ! ( materialIndex in hash_map ) ) { + var uvs = faceVertexUvs[ j ], uvsCopy = []; - hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; + for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { - } + var uv = uvs[ k ]; - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + uvsCopy.push( uv.clone() ); - if ( ! ( groupHash in this.geometryGroups ) ) { + } - this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + geometry.faceVertexUvs[ i ].push( uvsCopy ); - } + } - if ( this.geometryGroups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { + } - hash_map[ materialIndex ].counter += 1; - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + return geometry; - if ( ! ( groupHash in this.geometryGroups ) ) { + }, - this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + dispose: function () { - } + this.dispatchEvent( { type: 'dispose' } ); - } + } - this.geometryGroups[ groupHash ].faces3.push( f ); - this.geometryGroups[ groupHash ].vertices += 3; +}; - } +THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - this.geometryGroupsList = []; +THREE.GeometryIdCount = 0; - for ( var g in this.geometryGroups ) { +// File:src/cameras/Camera.js - this.geometryGroups[ g ].id = geometryGroupCounter ++; +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ - this.geometryGroupsList.push( this.geometryGroups[ g ] ); +THREE.Camera = function () { - } + THREE.Object3D.call( this ); - }; - - } )(), + this.type = 'Camera'; - clone: function () { + this.matrixWorldInverse = new THREE.Matrix4(); + this.projectionMatrix = new THREE.Matrix4(); - var geometry = new THREE.Geometry(); +}; - var vertices = this.vertices; +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Camera.prototype.constructor = THREE.Camera; - for ( var i = 0, il = vertices.length; i < il; i ++ ) { +THREE.Camera.prototype.getWorldDirection = function () { - geometry.vertices.push( vertices[ i ].clone() ); + var quaternion = new THREE.Quaternion(); - } + return function ( optionalTarget ) { - var faces = this.faces; + var result = optionalTarget || new THREE.Vector3(); - for ( var i = 0, il = faces.length; i < il; i ++ ) { + this.getWorldQuaternion( quaternion ); - geometry.faces.push( faces[ i ].clone() ); + return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - } + } - var uvs = this.faceVertexUvs[ 0 ]; +}(); - for ( var i = 0, il = uvs.length; i < il; i ++ ) { +THREE.Camera.prototype.lookAt = function () { - var uv = uvs[ i ], uvCopy = []; + // This routine does not support cameras with rotated and/or translated parent(s) - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + var m1 = new THREE.Matrix4(); - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + return function ( vector ) { - } + m1.lookAt( this.position, vector, this.up ); - geometry.faceVertexUvs[ 0 ].push( uvCopy ); + this.quaternion.setFromRotationMatrix( m1 ); - } + }; - return geometry; +}(); - }, +THREE.Camera.prototype.clone = function ( camera ) { - dispose: function () { + if ( camera === undefined ) camera = new THREE.Camera(); - this.dispatchEvent( { type: 'dispose' } ); + THREE.Object3D.prototype.clone.call( this, camera ); - } + camera.matrixWorldInverse.copy( this.matrixWorldInverse ); + camera.projectionMatrix.copy( this.projectionMatrix ); + return camera; }; -THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - -THREE.GeometryIdCount = 0; +// File:src/cameras/CubeCamera.js /** - * @author mrdoob / http://mrdoob.com/ + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ */ -THREE.Geometry2 = function ( vertices, normals, uvs ) { - - THREE.BufferGeometry.call( this ); - - this.attributes[ 'position' ] = { array: vertices, itemSize: 3 }; - this.attributes[ 'normal' ] = { array: normals, itemSize: 3 }; - this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 }; - -}; +THREE.CubeCamera = function ( near, far, cubeResolution ) { -THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + THREE.Object3D.call( this ); -THREE.IndexedGeometry2 = function ( indices, vertices, normals, uvs ) { + this.type = 'CubeCamera'; - THREE.BufferGeometry.call( this ); + var fov = 90, aspect = 1; - this.attributes[ 'index' ] = { array: indices, itemSize: 1 }; - this.attributes[ 'position' ] = { array: vertices, itemSize: 3 }; - this.attributes[ 'normal' ] = { array: normals, itemSize: 3 }; - this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 }; + var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); -}; + var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) ); + this.add( cameraNX ); -THREE.IndexedGeometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ + var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); -THREE.Camera = function () { + var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) ); + this.add( cameraNY ); - THREE.Object3D.call( this ); + var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, - 1, 0 ); + cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); - this.matrixWorldInverse = new THREE.Matrix4(); - this.projectionMatrix = new THREE.Matrix4(); + var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) ); + this.add( cameraNZ ); -}; + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); -THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); + this.updateCubeMap = function ( renderer, scene ) { -THREE.Camera.prototype.lookAt = function () { + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; - // This routine does not support cameras with rotated and/or translated parent(s) + renderTarget.generateMipmaps = false; - var m1 = new THREE.Matrix4(); + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); - return function ( vector ) { + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); - m1.lookAt( this.position, vector, this.up ); + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); - this.quaternion.setFromRotationMatrix( m1 ); + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); - }; + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); -}(); + renderTarget.generateMipmaps = generateMipmaps; -THREE.Camera.prototype.clone = function (camera) { + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); - if ( camera === undefined ) camera = new THREE.Camera(); + }; - THREE.Object3D.prototype.clone.call( this, camera ); +}; - camera.matrixWorldInverse.copy( this.matrixWorldInverse ); - camera.projectionMatrix.copy( this.projectionMatrix ); +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; - return camera; -}; +// File:src/cameras/OrthographicCamera.js /** * @author alteredq / http://alteredqualia.com/ @@ -10772,45 +10811,61 @@ THREE.Camera.prototype.clone = function (camera) { THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { - THREE.Camera.call( this ); + THREE.Camera.call( this ); - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + this.type = 'OrthographicCamera'; - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; + this.zoom = 1; - this.updateProjectionMatrix(); + 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(); }; THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { - this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + 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; + + this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far ); }; THREE.OrthographicCamera.prototype.clone = function () { - var camera = new THREE.OrthographicCamera(); + var camera = new THREE.OrthographicCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); - THREE.Camera.prototype.clone.call( this, camera ); + camera.zoom = this.zoom; - camera.left = this.left; - camera.right = this.right; - camera.top = this.top; - camera.bottom = this.bottom; - - camera.near = this.near; - camera.far = this.far; + camera.left = this.left; + camera.right = this.right; + camera.top = this.top; + camera.bottom = this.bottom; - return camera; + camera.near = this.near; + camera.far = this.far; + + camera.projectionMatrix.copy( this.projectionMatrix ); + + return camera; }; +// File:src/cameras/PerspectiveCamera.js + /** * @author mrdoob / http://mrdoob.com/ * @author greggman / http://games.greggman.com/ @@ -10819,18 +10874,23 @@ THREE.OrthographicCamera.prototype.clone = function () { THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { - THREE.Camera.call( this ); + THREE.Camera.call( this ); + + this.type = 'PerspectiveCamera'; - this.fov = fov !== undefined ? fov : 50; - this.aspect = aspect !== undefined ? aspect : 1; - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; + this.zoom = 1; - this.updateProjectionMatrix(); + this.fov = fov !== undefined ? fov : 50; + this.aspect = aspect !== undefined ? aspect : 1; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + + this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; /** @@ -10841,10 +10901,10 @@ THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { - if ( frameHeight === undefined ) frameHeight = 24; + if ( frameHeight === undefined ) frameHeight = 24; - this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); - this.updateProjectionMatrix(); + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); } @@ -10887,110 +10947,129 @@ THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { - this.fullWidth = fullWidth; - this.fullHeight = fullHeight; - this.x = x; - this.y = y; - this.width = width; - this.height = height; + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; - this.updateProjectionMatrix(); + this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { - if ( this.fullWidth ) { + var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) ); + + if ( this.fullWidth ) { - var aspect = this.fullWidth / this.fullHeight; - var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; - var bottom = -top; - var left = aspect * bottom; - var right = aspect * top; - var width = Math.abs( right - left ); - var height = Math.abs( top - bottom ); + var aspect = this.fullWidth / this.fullHeight; + var top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near; + var bottom = - top; + var left = aspect * bottom; + var right = aspect * top; + var width = Math.abs( right - left ); + var height = Math.abs( top - bottom ); - this.projectionMatrix.makeFrustum( - left + this.x * width / this.fullWidth, - left + ( this.x + this.width ) * width / this.fullWidth, - top - ( this.y + this.height ) * height / this.fullHeight, - top - this.y * height / this.fullHeight, - this.near, - this.far - ); + this.projectionMatrix.makeFrustum( + left + this.x * width / this.fullWidth, + left + ( this.x + this.width ) * width / this.fullWidth, + top - ( this.y + this.height ) * height / this.fullHeight, + top - this.y * height / this.fullHeight, + this.near, + this.far + ); - } else { + } else { - this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); + this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far ); - } + } }; THREE.PerspectiveCamera.prototype.clone = function () { - var camera = new THREE.PerspectiveCamera(); + var camera = new THREE.PerspectiveCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); + + camera.zoom = this.zoom; - THREE.Camera.prototype.clone.call( this, camera ); + camera.fov = this.fov; + camera.aspect = this.aspect; + camera.near = this.near; + camera.far = this.far; - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; + camera.projectionMatrix.copy( this.projectionMatrix ); + + return camera; - return camera; }; +// File:src/lights/Light.js + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ - + THREE.Light = function ( color ) { - THREE.Object3D.call( this ); + THREE.Object3D.call( this ); - this.color = new THREE.Color( color ); + this.type = 'Light'; + + this.color = new THREE.Color( color ); }; THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Light.prototype.constructor = THREE.Light; THREE.Light.prototype.clone = function ( light ) { - if ( light === undefined ) light = new THREE.Light(); + if ( light === undefined ) light = new THREE.Light(); - THREE.Object3D.prototype.clone.call( this, light ); + THREE.Object3D.prototype.clone.call( this, light ); - light.color.copy( this.color ); + light.color.copy( this.color ); - return light; + return light; }; +// File:src/lights/AmbientLight.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.AmbientLight = function ( color ) { - THREE.Light.call( this, color ); + THREE.Light.call( this, color ); + + this.type = 'AmbientLight'; }; THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; THREE.AmbientLight.prototype.clone = function () { - var light = new THREE.AmbientLight(); + var light = new THREE.AmbientLight(); - THREE.Light.prototype.clone.call( this, light ); + THREE.Light.prototype.clone.call( this, light ); - return light; + return light; }; +// File:src/lights/AreaLight.js + /** * @author MPanknin / http://www.redplant.de/ * @author alteredq / http://alteredqualia.com/ @@ -10998,25 +11077,30 @@ THREE.AmbientLight.prototype.clone = function () { THREE.AreaLight = function ( color, intensity ) { - THREE.Light.call( this, color ); + THREE.Light.call( this, color ); + + this.type = 'AreaLight'; - this.normal = new THREE.Vector3( 0, -1, 0 ); - this.right = new THREE.Vector3( 1, 0, 0 ); + this.normal = new THREE.Vector3( 0, - 1, 0 ); + this.right = new THREE.Vector3( 1, 0, 0 ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.width = 1.0; - this.height = 1.0; + this.width = 1.0; + this.height = 1.0; - this.constantAttenuation = 1.5; - this.linearAttenuation = 0.5; - this.quadraticAttenuation = 0.1; + this.constantAttenuation = 1.5; + this.linearAttenuation = 0.5; + this.quadraticAttenuation = 0.1; }; THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AreaLight.prototype.constructor = THREE.AreaLight; +// File:src/lights/DirectionalLight.js + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -11024,885 +11108,904 @@ THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); THREE.DirectionalLight = function ( color, intensity ) { - THREE.Light.call( this, color ); + THREE.Light.call( this, color ); + + this.type = 'DirectionalLight'; - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.castShadow = false; - this.onlyShadow = false; + this.castShadow = false; + this.onlyShadow = false; - // + // - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; - this.shadowCameraLeft = -500; - this.shadowCameraRight = 500; - this.shadowCameraTop = 500; - this.shadowCameraBottom = -500; + this.shadowCameraLeft = - 500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = - 500; - this.shadowCameraVisible = false; + this.shadowCameraVisible = false; - this.shadowBias = 0; - this.shadowDarkness = 0.5; + this.shadowBias = 0; + this.shadowDarkness = 0.5; - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - // + // - this.shadowCascade = false; + this.shadowCascade = false; - this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); - this.shadowCascadeCount = 2; + this.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 ); + this.shadowCascadeCount = 2; - this.shadowCascadeBias = [ 0, 0, 0 ]; - this.shadowCascadeWidth = [ 512, 512, 512 ]; - this.shadowCascadeHeight = [ 512, 512, 512 ]; + this.shadowCascadeBias = [ 0, 0, 0 ]; + this.shadowCascadeWidth = [ 512, 512, 512 ]; + this.shadowCascadeHeight = [ 512, 512, 512 ]; - this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; - this.shadowCascadeArray = []; + this.shadowCascadeArray = []; - // + // - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; }; THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); +THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; THREE.DirectionalLight.prototype.clone = function () { - var light = new THREE.DirectionalLight(); + var light = new THREE.DirectionalLight(); - THREE.Light.prototype.clone.call( this, light ); + THREE.Light.prototype.clone.call( this, light ); - light.target = this.target.clone(); + light.target = this.target.clone(); - light.intensity = this.intensity; + light.intensity = this.intensity; - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; - // + // - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; - light.shadowCameraLeft = this.shadowCameraLeft; - light.shadowCameraRight = this.shadowCameraRight; - light.shadowCameraTop = this.shadowCameraTop; - light.shadowCameraBottom = this.shadowCameraBottom; + light.shadowCameraLeft = this.shadowCameraLeft; + light.shadowCameraRight = this.shadowCameraRight; + light.shadowCameraTop = this.shadowCameraTop; + light.shadowCameraBottom = this.shadowCameraBottom; - light.shadowCameraVisible = this.shadowCameraVisible; + light.shadowCameraVisible = this.shadowCameraVisible; - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; - // + // - light.shadowCascade = this.shadowCascade; + light.shadowCascade = this.shadowCascade; - light.shadowCascadeOffset.copy( this.shadowCascadeOffset ); - light.shadowCascadeCount = this.shadowCascadeCount; + light.shadowCascadeOffset.copy( this.shadowCascadeOffset ); + light.shadowCascadeCount = this.shadowCascadeCount; - light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 ); - light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 ); - light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 ); + light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 ); + light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 ); + light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 ); - light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 ); - light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 ); + light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 ); + light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 ); - return light; + return light; }; +// File:src/lights/HemisphereLight.js + /** * @author alteredq / http://alteredqualia.com/ */ THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { - THREE.Light.call( this, skyColor ); + THREE.Light.call( this, skyColor ); + + this.type = 'HemisphereLight'; - this.position.set( 0, 100, 0 ); + this.position.set( 0, 100, 0 ); - this.groundColor = new THREE.Color( groundColor ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.groundColor = new THREE.Color( groundColor ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; }; THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); +THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; THREE.HemisphereLight.prototype.clone = function () { - var light = new THREE.HemisphereLight(); + var light = new THREE.HemisphereLight(); - THREE.Light.prototype.clone.call( this, light ); + THREE.Light.prototype.clone.call( this, light ); - light.groundColor.copy( this.groundColor ); - light.intensity = this.intensity; + light.groundColor.copy( this.groundColor ); + light.intensity = this.intensity; - return light; + return light; }; +// File:src/lights/PointLight.js + /** * @author mrdoob / http://mrdoob.com/ */ -THREE.PointLight = function ( color, intensity, distance ) { +THREE.PointLight = function ( color, intensity, distance, decay ) { + + THREE.Light.call( this, color ); - THREE.Light.call( this, color ); + this.type = 'PointLight'; - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. }; THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); +THREE.PointLight.prototype.constructor = THREE.PointLight; THREE.PointLight.prototype.clone = function () { - var light = new THREE.PointLight(); + var light = new THREE.PointLight(); - THREE.Light.prototype.clone.call( this, light ); + THREE.Light.prototype.clone.call( this, light ); - light.intensity = this.intensity; - light.distance = this.distance; + light.intensity = this.intensity; + light.distance = this.distance; + light.decay = this.decay; - return light; + return light; }; +// File:src/lights/SpotLight.js + /** * @author alteredq / http://alteredqualia.com/ */ -THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { + + THREE.Light.call( this, color ); - THREE.Light.call( this, color ); + this.type = 'SpotLight'; - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.exponent = ( exponent !== undefined ) ? exponent : 10; + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.exponent = ( exponent !== undefined ) ? exponent : 10; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - this.castShadow = false; - this.onlyShadow = false; + this.castShadow = false; + this.onlyShadow = false; - // + // - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - this.shadowCameraFov = 50; + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; - this.shadowCameraVisible = false; + this.shadowCameraVisible = false; - this.shadowBias = 0; - this.shadowDarkness = 0.5; + this.shadowBias = 0; + this.shadowDarkness = 0.5; - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - // + // - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; }; THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); +THREE.SpotLight.prototype.constructor = THREE.SpotLight; THREE.SpotLight.prototype.clone = function () { - var light = new THREE.SpotLight(); + var light = new THREE.SpotLight(); - THREE.Light.prototype.clone.call( this, light ); + THREE.Light.prototype.clone.call( this, light ); - light.target = this.target.clone(); + light.target = this.target.clone(); - light.intensity = this.intensity; - light.distance = this.distance; - light.angle = this.angle; - light.exponent = this.exponent; + light.intensity = this.intensity; + light.distance = this.distance; + light.angle = this.angle; + light.exponent = this.exponent; + light.decay = this.decay; - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; - // + // - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; - light.shadowCameraFov = this.shadowCameraFov; + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; + light.shadowCameraFov = this.shadowCameraFov; - light.shadowCameraVisible = this.shadowCameraVisible; + light.shadowCameraVisible = this.shadowCameraVisible; - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; - return light; + return light; }; +// File:src/loaders/Cache.js + /** * @author mrdoob / http://mrdoob.com/ */ -THREE.Cache = function () { - - this.files = {}; +THREE.Cache = { -}; + files: {}, -THREE.Cache.prototype = { + add: function ( key, file ) { - constructor: THREE.Cache, + // console.log( 'THREE.Cache', 'Adding key:', key ); - add: function ( key, file ) { + this.files[ key ] = file; - // console.log( 'THREE.Cache', 'Adding key:', key ); + }, - this.files[ key ] = file; + get: function ( key ) { - }, + // console.log( 'THREE.Cache', 'Checking key:', key ); - get: function ( key ) { + return this.files[ key ]; - // console.log( 'THREE.Cache', 'Checking key:', key ); + }, - return this.files[ key ]; + remove: function ( key ) { - }, + delete this.files[ key ]; - remove: function ( key ) { + }, - delete this.files[ key ]; + clear: function () { - }, + this.files = {} - clear: function () { + } - this.files = {} +}; - } +// File:src/loaders/Loader.js -}; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Loader = function ( showStatus ) { - this.showStatus = showStatus; - this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + this.showStatus = showStatus; + this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; - this.imageLoader = new THREE.ImageLoader(); + this.imageLoader = new THREE.ImageLoader(); - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; }; THREE.Loader.prototype = { - constructor: THREE.Loader, + constructor: THREE.Loader, - crossOrigin: undefined, + crossOrigin: undefined, - addStatusElement: function () { + addStatusElement: function () { - var e = document.createElement( "div" ); + var e = document.createElement( 'div' ); - e.style.position = "absolute"; - e.style.right = "0px"; - e.style.top = "0px"; - e.style.fontSize = "0.8em"; - e.style.textAlign = "left"; - e.style.background = "rgba(0,0,0,0.25)"; - e.style.color = "#fff"; - e.style.width = "120px"; - e.style.padding = "0.5em 0.5em 0.5em 0.5em"; - e.style.zIndex = 1000; + e.style.position = 'absolute'; + e.style.right = '0px'; + e.style.top = '0px'; + e.style.fontSize = '0.8em'; + e.style.textAlign = 'left'; + e.style.background = 'rgba(0,0,0,0.25)'; + e.style.color = '#fff'; + e.style.width = '120px'; + e.style.padding = '0.5em 0.5em 0.5em 0.5em'; + e.style.zIndex = 1000; - e.innerHTML = "Loading ..."; + e.innerHTML = 'Loading ...'; - return e; + return e; - }, + }, - updateProgress: function ( progress ) { + updateProgress: function ( progress ) { - var message = "Loaded "; + var message = 'Loaded '; - if ( progress.total ) { + if ( progress.total ) { - message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; + message += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%'; - } else { + } else { - message += ( progress.loaded / 1024 ).toFixed(2) + " KB"; + message += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB'; - } + } - this.statusDomElement.innerHTML = message; + this.statusDomElement.innerHTML = message; - }, + }, - extractUrlBase: function ( url ) { + extractUrlBase: function ( url ) { - var parts = url.split( '/' ); + var parts = url.split( '/' ); - if ( parts.length === 1 ) return './'; + if ( parts.length === 1 ) return './'; - parts.pop(); + parts.pop(); - return parts.join( '/' ) + '/'; + return parts.join( '/' ) + '/'; - }, + }, - initMaterials: function ( materials, texturePath ) { + initMaterials: function ( materials, texturePath ) { - var array = []; + var array = []; - for ( var i = 0; i < materials.length; ++ i ) { + for ( var i = 0; i < materials.length; ++ i ) { - array[ i ] = this.createMaterial( materials[ i ], texturePath ); + array[ i ] = this.createMaterial( materials[ i ], texturePath ); - } + } - return array; + return array; - }, + }, - needsTangents: function ( materials ) { + needsTangents: function ( materials ) { - for( var i = 0, il = materials.length; i < il; i ++ ) { + for ( var i = 0, il = materials.length; i < il; i ++ ) { - var m = materials[ i ]; + var m = materials[ i ]; - if ( m instanceof THREE.ShaderMaterial ) return true; + if ( m instanceof THREE.ShaderMaterial ) return true; - } + } - return false; + return false; - }, + }, - createMaterial: function ( m, texturePath ) { + createMaterial: function ( m, texturePath ) { - var scope = this; + var scope = this; - function nearest_pow2( n ) { + function nearest_pow2( n ) { - var l = Math.log( n ) / Math.LN2; - return Math.pow( 2, Math.round( l ) ); + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); - } - - function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - - var isCompressed = /\.dds$/i.test( sourceFile ); + } - var fullPath = texturePath + sourceFile; + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - if ( isCompressed ) { + var fullPath = texturePath + sourceFile; - var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); + var texture; - where[ name ] = texture; + var loader = THREE.Loader.Handlers.get( fullPath ); - } else { + if ( loader !== null ) { - var texture = document.createElement( 'canvas' ); + texture = loader.load( fullPath ); - where[ name ] = new THREE.Texture( texture ); + } else { - } + texture = new THREE.Texture(); - where[ name ].sourceFile = sourceFile; + loader = scope.imageLoader; + loader.crossOrigin = scope.crossOrigin; + loader.load( fullPath, function ( image ) { - if( repeat ) { + if ( THREE.Math.isPowerOfTwo( image.width ) === false || + THREE.Math.isPowerOfTwo( image.height ) === false ) { - where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); + var width = nearest_pow2( image.width ); + var height = nearest_pow2( image.height ); - if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - } + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, width, height ); - if ( offset ) { + texture.image = canvas; - where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); + } else { - } + texture.image = image; - if ( wrap ) { + } - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } + texture.needsUpdate = true; - if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; - if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; + } ); - } + } - if ( anisotropy ) { + texture.sourceFile = sourceFile; - where[ name ].anisotropy = anisotropy; + if ( repeat ) { - } + texture.repeat.set( repeat[ 0 ], repeat[ 1 ] ); - if ( ! isCompressed ) { + if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - var texture = where[ name ]; + } - scope.imageLoader.crossOrigin = scope.crossOrigin; - scope.imageLoader.load( fullPath, function ( image ) { + if ( offset ) { - if ( THREE.Math.isPowerOfTwo( image.width ) === false || - THREE.Math.isPowerOfTwo( image.height ) === false ) { + texture.offset.set( offset[ 0 ], offset[ 1 ] ); - var width = nearest_pow2( image.width ); - var height = nearest_pow2( image.height ); + } - texture.image.width = width; - texture.image.height = height; - texture.image.getContext( '2d' ).drawImage( image, 0, 0, width, height ); + if ( wrap ) { - } else { + var wrapMap = { + 'repeat': THREE.RepeatWrapping, + 'mirror': THREE.MirroredRepeatWrapping + } - texture.image = image; + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ]; - } + } - texture.needsUpdate = true; + if ( anisotropy ) { - } ); + texture.anisotropy = anisotropy; - } + } - } + where[ name ] = texture; - function rgb2hex( rgb ) { + } - return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; + function rgb2hex( rgb ) { - } + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; - // defaults + } - var mtype = "MeshLambertMaterial"; - var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; + // defaults - // parameters from model file + var mtype = 'MeshLambertMaterial'; + var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; - if ( m.shading ) { + // parameters from model file - var shading = m.shading.toLowerCase(); + if ( m.shading ) { - if ( shading === "phong" ) mtype = "MeshPhongMaterial"; - else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + var shading = m.shading.toLowerCase(); - } + if ( shading === 'phong' ) mtype = 'MeshPhongMaterial'; + else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial'; - if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { + } - mpars.blending = THREE[ m.blending ]; + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { - } + mpars.blending = THREE[ m.blending ]; - if ( m.transparent !== undefined || m.opacity < 1.0 ) { + } - mpars.transparent = m.transparent; + if ( m.transparent !== undefined ) { - } + mpars.transparent = m.transparent; - if ( m.depthTest !== undefined ) { + } - mpars.depthTest = m.depthTest; + if ( m.opacity !== undefined && m.opacity < 1.0 ) { - } + mpars.transparent = true; - if ( m.depthWrite !== undefined ) { + } - mpars.depthWrite = m.depthWrite; + if ( m.depthTest !== undefined ) { - } + mpars.depthTest = m.depthTest; - if ( m.visible !== undefined ) { + } - mpars.visible = m.visible; + if ( m.depthWrite !== undefined ) { - } + mpars.depthWrite = m.depthWrite; - if ( m.flipSided !== undefined ) { + } - mpars.side = THREE.BackSide; + if ( m.visible !== undefined ) { - } + mpars.visible = m.visible; - if ( m.doubleSided !== undefined ) { + } - mpars.side = THREE.DoubleSide; + if ( m.flipSided !== undefined ) { - } + mpars.side = THREE.BackSide; - if ( m.wireframe !== undefined ) { + } - mpars.wireframe = m.wireframe; + if ( m.doubleSided !== undefined ) { - } + mpars.side = THREE.DoubleSide; - if ( m.vertexColors !== undefined ) { + } - if ( m.vertexColors === "face" ) { + if ( m.wireframe !== undefined ) { - mpars.vertexColors = THREE.FaceColors; + mpars.wireframe = m.wireframe; - } else if ( m.vertexColors ) { + } - mpars.vertexColors = THREE.VertexColors; + if ( m.vertexColors !== undefined ) { - } + if ( m.vertexColors === 'face' ) { - } + mpars.vertexColors = THREE.FaceColors; - // colors + } else if ( m.vertexColors ) { - if ( m.colorDiffuse ) { + mpars.vertexColors = THREE.VertexColors; - mpars.color = rgb2hex( m.colorDiffuse ); + } - } else if ( m.DbgColor ) { + } - mpars.color = m.DbgColor; + // colors - } + if ( m.colorDiffuse ) { - if ( m.colorSpecular ) { + mpars.color = rgb2hex( m.colorDiffuse ); - mpars.specular = rgb2hex( m.colorSpecular ); + } else if ( m.DbgColor ) { - } + mpars.color = m.DbgColor; - if ( m.colorAmbient ) { + } - mpars.ambient = rgb2hex( m.colorAmbient ); + if ( m.colorSpecular ) { - } + mpars.specular = rgb2hex( m.colorSpecular ); - // modifiers + } - if ( m.transparency ) { + if ( m.colorEmissive ) { - mpars.opacity = m.transparency; + mpars.emissive = rgb2hex( m.colorEmissive ); - } + } - if ( m.specularCoef ) { + // modifiers - mpars.shininess = m.specularCoef; + if ( m.transparency !== undefined ) { - } + console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); + m.opacity = m.transparency; - // textures + } - if ( m.mapDiffuse && texturePath ) { + if ( m.opacity !== undefined ) { - create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + mpars.opacity = m.opacity; - } + } - if ( m.mapLight && texturePath ) { + if ( m.specularCoef ) { - create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + mpars.shininess = m.specularCoef; - } + } - if ( m.mapBump && texturePath ) { + // textures - create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + if ( m.mapDiffuse && texturePath ) { - } + create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - if ( m.mapNormal && texturePath ) { + } - create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + if ( m.mapLight && texturePath ) { - } + create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - if ( m.mapSpecular && texturePath ) { + } - create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + if ( m.mapBump && texturePath ) { - } + create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - // + } - if ( m.mapBumpScale ) { + if ( m.mapNormal && texturePath ) { - mpars.bumpScale = m.mapBumpScale; + create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - } + } - // special case for normal mapped material + if ( m.mapSpecular && texturePath ) { - if ( m.mapNormal ) { + create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + } - uniforms[ "tNormal" ].value = mpars.normalMap; + if ( m.mapAlpha && texturePath ) { - if ( m.mapNormalFactor ) { + create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); + } - } + // - if ( mpars.map ) { + if ( m.mapBumpScale ) { - uniforms[ "tDiffuse" ].value = mpars.map; - uniforms[ "enableDiffuse" ].value = true; + mpars.bumpScale = m.mapBumpScale; - } + } - if ( mpars.specularMap ) { + if ( m.mapNormalFactor ) { - uniforms[ "tSpecular" ].value = mpars.specularMap; - uniforms[ "enableSpecular" ].value = true; + mpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor ); - } + } - if ( mpars.lightMap ) { + var material = new THREE[ mtype ]( mpars ); - uniforms[ "tAO" ].value = mpars.lightMap; - uniforms[ "enableAO" ].value = true; + if ( m.DbgName !== undefined ) material.name = m.DbgName; - } + return material; - // for the moment don't handle displacement texture + } - uniforms[ "diffuse" ].value.setHex( mpars.color ); - uniforms[ "specular" ].value.setHex( mpars.specular ); - uniforms[ "ambient" ].value.setHex( mpars.ambient ); +}; - uniforms[ "shininess" ].value = mpars.shininess; +THREE.Loader.Handlers = { - if ( mpars.opacity !== undefined ) { + handlers: [], - uniforms[ "opacity" ].value = mpars.opacity; + add: function ( regex, loader ) { - } + this.handlers.push( regex, loader ); - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - var material = new THREE.ShaderMaterial( parameters ); + }, - if ( mpars.transparent ) { + get: function ( file ) { - material.transparent = true; + for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) { - } + var regex = this.handlers[ i ]; + var loader = this.handlers[ i + 1 ]; - } else { + if ( regex.test( file ) ) { - var material = new THREE[ mtype ]( mpars ); + return loader; - } + } - if ( m.DbgName !== undefined ) material.name = m.DbgName; + } - return material; + return null; - } + } }; +// File:src/loaders/XHRLoader.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.XHRLoader = function ( manager ) { - this.cache = new THREE.Cache(); - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.XHRLoader.prototype = { - constructor: THREE.XHRLoader, + constructor: THREE.XHRLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; - load: function ( url, onLoad, onProgress, onError ) { + var cached = THREE.Cache.get( url ); - var scope = this; + if ( cached !== undefined ) { - var cached = scope.cache.get( url ); + if ( onLoad ) onLoad( cached ); + return; - if ( cached !== undefined ) { + } - onLoad( cached ); - return; + var request = new XMLHttpRequest(); + request.open( 'GET', url, true ); - } + request.addEventListener( 'load', function ( event ) { - var request = new XMLHttpRequest(); + THREE.Cache.add( url, this.response ); - if ( onLoad !== undefined ) { + if ( onLoad ) onLoad( this.response ); - request.addEventListener( 'load', function ( event ) { + scope.manager.itemEnd( url ); - scope.cache.add( url, event.target.responseText ); + }, false ); - onLoad( event.target.responseText ); - scope.manager.itemEnd( url ); + if ( onProgress !== undefined ) { - }, false ); + request.addEventListener( 'progress', function ( event ) { - } + onProgress( event ); - if ( onProgress !== undefined ) { + }, false ); - request.addEventListener( 'progress', function ( event ) { + } - onProgress( event ); + if ( onError !== undefined ) { - }, false ); + request.addEventListener( 'error', function ( event ) { - } + onError( event ); - if ( onError !== undefined ) { + }, false ); - request.addEventListener( 'error', function ( event ) { + } - onError( event ); + if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + if ( this.responseType !== undefined ) request.responseType = this.responseType; - }, false ); + request.send( null ); - } + scope.manager.itemStart( url ); - if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + }, - request.open( 'GET', url, true ); - request.send( null ); + setResponseType: function ( value ) { - scope.manager.itemStart( url ); + this.responseType = value; - }, + }, - setCrossOrigin: function ( value ) { + setCrossOrigin: function ( value ) { - this.crossOrigin = value; + this.crossOrigin = value; - } + } }; +// File:src/loaders/ImageLoader.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.ImageLoader = function ( manager ) { - this.cache = new THREE.Cache(); - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.ImageLoader.prototype = { - constructor: THREE.ImageLoader, + constructor: THREE.ImageLoader, - load: function ( url, onLoad, onProgress, onError ) { + load: function ( url, onLoad, onProgress, onError ) { - var scope = this; + var scope = this; - var cached = scope.cache.get( url ); + var cached = THREE.Cache.get( url ); - if ( cached !== undefined ) { + if ( cached !== undefined ) { - onLoad( cached ); - return; + onLoad( cached ); + return; - } - - var image = document.createElement( 'img' ); - - if ( onLoad !== undefined ) { + } - image.addEventListener( 'load', function ( event ) { + var image = document.createElement( 'img' ); - scope.cache.add( url, this ); + image.addEventListener( 'load', function ( event ) { - onLoad( this ); - scope.manager.itemEnd( url ); + THREE.Cache.add( url, this ); - }, false ); + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); - } + }, false ); - if ( onProgress !== undefined ) { + if ( onProgress !== undefined ) { - image.addEventListener( 'progress', function ( event ) { + image.addEventListener( 'progress', function ( event ) { - onProgress( event ); + onProgress( event ); - }, false ); + }, false ); - } + } - if ( onError !== undefined ) { + if ( onError !== undefined ) { - image.addEventListener( 'error', function ( event ) { + image.addEventListener( 'error', function ( event ) { - onError( event ); + onError( event ); - }, false ); + }, false ); - } + } - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - image.src = url; + image.src = url; - scope.manager.itemStart( url ); + scope.manager.itemStart( url ); - return image; + return image; - }, + }, - setCrossOrigin: function ( value ) { + setCrossOrigin: function ( value ) { - this.crossOrigin = value; + this.crossOrigin = value; - } + } } +// File:src/loaders/JSONLoader.js + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -11910,2488 +12013,2200 @@ THREE.ImageLoader.prototype = { THREE.JSONLoader = function ( showStatus ) { - THREE.Loader.call( this, showStatus ); + THREE.Loader.call( this, showStatus ); - this.withCredentials = false; + this.withCredentials = false; }; THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); +THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { - var scope = this; + // todo: unify load API to for easier SceneLoader use - // todo: unify load API to for easier SceneLoader use + texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url ); - texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); - - this.onLoadStart(); - this.loadAjaxJSON( this, url, callback, texturePath ); + this.onLoadStart(); + this.loadAjaxJSON( this, url, callback, texturePath ); }; THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { - var xhr = new XMLHttpRequest(); + var xhr = new XMLHttpRequest(); + + var length = 0; - var length = 0; + xhr.onreadystatechange = function () { - xhr.onreadystatechange = function () { + if ( xhr.readyState === xhr.DONE ) { - if ( xhr.readyState === xhr.DONE ) { + if ( xhr.status === 200 || xhr.status === 0 ) { - if ( xhr.status === 200 || xhr.status === 0 ) { + if ( xhr.responseText ) { - if ( xhr.responseText ) { + var json = JSON.parse( xhr.responseText ); + var metadata = json.metadata; - var json = JSON.parse( xhr.responseText ); + if ( metadata !== undefined ) { - if ( json.metadata !== undefined && json.metadata.type === 'scene' ) { + if ( metadata.type === 'object' ) { - console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); - return; + THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; - } + } - var result = context.parse( json, texturePath ); - callback( result.geometry, result.materials ); + if ( metadata.type === 'scene' ) { - } else { + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; - console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); + } - } + } - // in context of more complex asset initialization - // do not block on single failed file - // maybe should go even one more level up + var result = context.parse( json, texturePath ); + callback( result.geometry, result.materials ); - context.onLoadComplete(); + } else { - } else { + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' ); - console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + } + + // in context of more complex asset initialization + // do not block on single failed file + // maybe should go even one more level up + + context.onLoadComplete(); + + } else { - } + THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' ); - } else if ( xhr.readyState === xhr.LOADING ) { + } - if ( callbackProgress ) { + } else if ( xhr.readyState === xhr.LOADING ) { - if ( length === 0 ) { + if ( callbackProgress ) { - length = xhr.getResponseHeader( 'Content-Length' ); + if ( length === 0 ) { - } + length = xhr.getResponseHeader( 'Content-Length' ); - callbackProgress( { total: length, loaded: xhr.responseText.length } ); + } + + callbackProgress( { total: length, loaded: xhr.responseText.length } ); - } + } - } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { + } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { - if ( callbackProgress !== undefined ) { + if ( callbackProgress !== undefined ) { - length = xhr.getResponseHeader( "Content-Length" ); + length = xhr.getResponseHeader( 'Content-Length' ); - } + } - } + } - }; + }; - xhr.open( "GET", url, true ); - xhr.withCredentials = this.withCredentials; - xhr.send( null ); + xhr.open( 'GET', url, true ); + xhr.withCredentials = this.withCredentials; + xhr.send( null ); }; THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - var scope = this, - geometry = new THREE.Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + var geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); - parseModel( scale ); + parseSkin(); + parseMorphing( scale ); - parseSkin(); - parseMorphing( scale ); + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + function parseModel( scale ) { - function parseModel( scale ) { + function isBitSet( value, position ) { - function isBitSet( value, position ) { + return value & ( 1 << position ); - return value & ( 1 << position ); + } - } + var i, j, fi, - var i, j, fi, + offset, zLength, - offset, zLength, + colorIndex, normalIndex, uvIndex, materialIndex, - colorIndex, normalIndex, uvIndex, materialIndex, + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + vertex, face, faceA, faceB, hex, normal, - vertex, face, faceA, faceB, color, hex, normal, + uvLayer, uv, u, v, - uvLayer, uv, u, v, + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + nUvLayers = 0; - nUvLayers = 0; + if ( json.uvs !== undefined ) { - if ( json.uvs !== undefined ) { + // disregard empty arrays - // disregard empty arrays + for ( i = 0; i < json.uvs.length; i ++ ) { - for ( i = 0; i < json.uvs.length; i++ ) { + if ( json.uvs[ i ].length ) nUvLayers ++; - if ( json.uvs[ i ].length ) nUvLayers ++; + } - } + for ( i = 0; i < nUvLayers; i ++ ) { - for ( i = 0; i < nUvLayers; i++ ) { + geometry.faceVertexUvs[ i ] = []; - geometry.faceVertexUvs[ i ] = []; + } - } + } - } + offset = 0; + zLength = vertices.length; - offset = 0; - zLength = vertices.length; + while ( offset < zLength ) { - while ( offset < zLength ) { + vertex = new THREE.Vector3(); - vertex = new THREE.Vector3(); + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; + geometry.vertices.push( vertex ); - geometry.vertices.push( vertex ); + } - } + offset = 0; + zLength = faces.length; - offset = 0; - zLength = faces.length; + while ( offset < zLength ) { - while ( offset < zLength ) { + type = faces[ offset ++ ]; - 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 ); - 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); - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + if ( isQuad ) { - if ( isQuad ) { + faceA = new THREE.Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; - faceA = new THREE.Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; + faceB = new THREE.Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; - faceB = new THREE.Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; + offset += 4; - offset += 4; + if ( hasMaterial ) { - if ( hasMaterial ) { + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; + } - } + // to get face <=> uv index correspondence - // to get face <=> uv index correspondence + fi = geometry.faces.length; - fi = geometry.faces.length; + if ( hasFaceVertexUv ) { - if ( hasFaceVertexUv ) { + for ( i = 0; i < nUvLayers; i ++ ) { - for ( i = 0; i < nUvLayers; i++ ) { + uvLayer = json.uvs[ i ]; - uvLayer = json.uvs[ i ]; + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = [] - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = [] + for ( j = 0; j < 4; j ++ ) { - for ( j = 0; j < 4; j ++ ) { + uvIndex = faces[ offset ++ ]; - uvIndex = faces[ offset ++ ]; + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + uv = new THREE.Vector2( u, v ); - uv = new THREE.Vector2( u, v ); + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + } - } + } - } + } - } + if ( hasFaceNormal ) { - if ( hasFaceNormal ) { + normalIndex = faces[ offset ++ ] * 3; - normalIndex = faces[ offset ++ ] * 3; + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + faceB.normal.copy( faceA.normal ); - faceB.normal.copy( faceA.normal ); + } - } + if ( hasFaceVertexNormal ) { - if ( hasFaceVertexNormal ) { + for ( i = 0; i < 4; i ++ ) { - for ( i = 0; i < 4; i++ ) { + normalIndex = faces[ offset ++ ] * 3; - normalIndex = faces[ offset ++ ] * 3; + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + } - } + } - } + if ( hasFaceColor ) { - if ( hasFaceColor ) { + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + } - } + if ( hasFaceVertexColor ) { - if ( hasFaceVertexColor ) { + for ( i = 0; i < 4; i ++ ) { - for ( i = 0; i < 4; i++ ) { + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); - if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); + } - } + } - } + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + } else { - } else { + face = new THREE.Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; - face = new THREE.Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + if ( hasMaterial ) { - if ( hasMaterial ) { + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + } - } + // to get face <=> uv index correspondence - // to get face <=> uv index correspondence + fi = geometry.faces.length; - fi = geometry.faces.length; + if ( hasFaceVertexUv ) { - if ( hasFaceVertexUv ) { + for ( i = 0; i < nUvLayers; i ++ ) { - for ( i = 0; i < nUvLayers; i++ ) { + uvLayer = json.uvs[ i ]; - uvLayer = json.uvs[ i ]; + geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi ] = []; + for ( j = 0; j < 3; j ++ ) { - for ( j = 0; j < 3; j ++ ) { + uvIndex = faces[ offset ++ ]; - uvIndex = faces[ offset ++ ]; + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + uv = new THREE.Vector2( u, v ); - uv = new THREE.Vector2( u, v ); + geometry.faceVertexUvs[ i ][ fi ].push( uv ); - geometry.faceVertexUvs[ i ][ fi ].push( uv ); + } - } + } - } + } - } + if ( hasFaceNormal ) { - if ( hasFaceNormal ) { + normalIndex = faces[ offset ++ ] * 3; - normalIndex = faces[ offset ++ ] * 3; + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + } - } + if ( hasFaceVertexNormal ) { - if ( hasFaceVertexNormal ) { + for ( i = 0; i < 3; i ++ ) { - for ( i = 0; i < 3; i++ ) { + normalIndex = faces[ offset ++ ] * 3; - normalIndex = faces[ offset ++ ] * 3; + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + face.vertexNormals.push( normal ); - face.vertexNormals.push( normal ); + } - } + } - } + if ( hasFaceColor ) { - if ( hasFaceColor ) { + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); + } - } + if ( hasFaceVertexColor ) { - if ( hasFaceVertexColor ) { + for ( i = 0; i < 3; i ++ ) { - for ( i = 0; i < 3; i++ ) { + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); + } - } + } - } + geometry.faces.push( face ); - geometry.faces.push( face ); + } - } + } - } + }; - }; + function parseSkin() { + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; - function parseSkin() { - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + if ( json.skinWeights ) { - if ( json.skinWeights ) { + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - 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; - 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 THREE.Vector4( x, y, z, w ) ); - geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); + } - } + } - } + if ( json.skinIndices ) { - if ( json.skinIndices ) { + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - 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; - 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 THREE.Vector4( a, b, c, d ) ); - geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); + } - } + } - } + geometry.bones = json.bones; - geometry.bones = json.bones; + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + THREE.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + } - } + // could change this to json.animations[0] or remove completely - // could change this to json.animations[0] or remove completely - - geometry.animation = json.animation; - geometry.animations = json.animations; + geometry.animation = json.animation; + geometry.animations = json.animations; - }; + }; - function parseMorphing( scale ) { + function parseMorphing( scale ) { - if ( json.morphTargets !== undefined ) { + if ( json.morphTargets !== undefined ) { - var i, l, v, vl, dstVertices, srcVertices; + var i, l, v, vl, dstVertices, srcVertices; - for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; - dstVertices = geometry.morphTargets[ i ].vertices; - srcVertices = json.morphTargets [ i ].vertices; + dstVertices = geometry.morphTargets[ i ].vertices; + srcVertices = json.morphTargets [ i ].vertices; - for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - var vertex = new THREE.Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + var vertex = new THREE.Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; - dstVertices.push( vertex ); + dstVertices.push( vertex ); - } + } - } + } - } + } - if ( json.morphColors !== undefined ) { + if ( json.morphColors !== undefined ) { - var i, l, c, cl, dstColors, srcColors, color; + var i, l, c, cl, dstColors, srcColors, color; - for ( i = 0, l = json.morphColors.length; i < l; i++ ) { + for ( i = 0, l = json.morphColors.length; i < l; i ++ ) { - geometry.morphColors[ i ] = {}; - geometry.morphColors[ i ].name = json.morphColors[ i ].name; - geometry.morphColors[ i ].colors = []; + geometry.morphColors[ i ] = {}; + geometry.morphColors[ i ].name = json.morphColors[ i ].name; + geometry.morphColors[ i ].colors = []; - dstColors = geometry.morphColors[ i ].colors; - srcColors = json.morphColors [ i ].colors; + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors [ i ].colors; - for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { - color = new THREE.Color( 0xffaa00 ); - color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); - dstColors.push( color ); + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); - } + } - } + } - } + } - }; + }; - if ( json.materials === undefined || json.materials.length === 0 ) { + if ( json.materials === undefined || json.materials.length === 0 ) { - return { geometry: geometry }; + return { geometry: geometry }; - } else { + } else { - var materials = this.initMaterials( json.materials, texturePath ); + var materials = this.initMaterials( json.materials, texturePath ); - if ( this.needsTangents( materials ) ) { + if ( this.needsTangents( materials ) ) { - geometry.computeTangents(); + geometry.computeTangents(); - } + } - return { geometry: geometry, materials: materials }; + return { geometry: geometry, materials: materials }; - } + } }; +// File:src/loaders/LoadingManager.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.LoadingManager = function ( onLoad, onProgress, onError ) { - var scope = this; + var scope = this; - var loaded = 0, total = 0; + var loaded = 0, total = 0; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; - this.itemStart = function ( url ) { + this.itemStart = function ( url ) { - total ++; + total ++; - }; + }; - this.itemEnd = function ( url ) { + this.itemEnd = function ( url ) { - loaded ++; + loaded ++; - if ( scope.onProgress !== undefined ) { + if ( scope.onProgress !== undefined ) { - scope.onProgress( url, loaded, total ); + scope.onProgress( url, loaded, total ); - } + } - if ( loaded === total && scope.onLoad !== undefined ) { + if ( loaded === total && scope.onLoad !== undefined ) { - scope.onLoad(); + scope.onLoad(); - } + } - }; + }; }; THREE.DefaultLoadingManager = new THREE.LoadingManager(); +// File:src/loaders/BufferGeometryLoader.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.BufferGeometryLoader = function ( manager ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.BufferGeometryLoader.prototype = { - constructor: THREE.BufferGeometryLoader, + constructor: THREE.BufferGeometryLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); - load: function ( url, onLoad, onProgress, onError ) { + }, onProgress, onError ); - var scope = this; + }, - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { + setCrossOrigin: function ( value ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + this.crossOrigin = value; - } ); + }, - }, + parse: function ( json ) { - setCrossOrigin: function ( value ) { + var geometry = new THREE.BufferGeometry(); - this.crossOrigin = value; + var attributes = json.data.attributes; - }, + for ( var key in attributes ) { - parse: function ( json ) { + var attribute = attributes[ key ]; + var typedArray = new self[ attribute.type ]( attribute.array ); - var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) ); - var attributes = json.attributes; - var offsets = json.offsets; - var boundingSphere = json.boundingSphere; + } + + var offsets = json.data.offsets; - for ( var key in attributes ) { + if ( offsets !== undefined ) { - var attribute = attributes[ key ]; + geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); + + } - geometry.attributes[ key ] = { - itemSize: attribute.itemSize, - array: new self[ attribute.type ]( attribute.array ) - } + var boundingSphere = json.data.boundingSphere; - } + if ( boundingSphere !== undefined ) { - if ( offsets !== undefined ) { + var center = new THREE.Vector3(); - geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); + if ( boundingSphere.center !== undefined ) { - } + center.fromArray( boundingSphere.center ); - if ( boundingSphere !== undefined ) { + } - geometry.boundingSphere = new THREE.Sphere( - new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), - boundingSphere.radius - ); + geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius ); - } + } - return geometry; + return geometry; - } + } }; +// File:src/loaders/MaterialLoader.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.MaterialLoader = function ( manager ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.MaterialLoader.prototype = { - constructor: THREE.MaterialLoader, + constructor: THREE.MaterialLoader, - load: function ( url, onLoad, onProgress, onError ) { + load: function ( url, onLoad, onProgress, onError ) { - var scope = this; + var scope = this; - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + onLoad( scope.parse( JSON.parse( text ) ) ); - } ); + }, onProgress, onError ); - }, + }, - setCrossOrigin: function ( value ) { + setCrossOrigin: function ( value ) { - this.crossOrigin = value; + this.crossOrigin = value; - }, + }, - parse: function ( json ) { + parse: function ( json ) { - var material = new THREE[ json.type ]; + var material = new THREE[ json.type ]; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); - 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.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - 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.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.color !== undefined ) material.color.setHex( json.color ); + 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.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.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.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.materials !== undefined ) { + // for PointCloudMaterial + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - for ( var i = 0, l = json.materials.length; i < l; i ++ ) { + if ( json.materials !== undefined ) { - material.materials.push( this.parse( json.materials[ i ] ) ); + for ( var i = 0, l = json.materials.length; i < l; i ++ ) { - } + material.materials.push( this.parse( json.materials[ i ] ) ); - } + } + + } - return material; + return material; - } + } }; +// File:src/loaders/ObjectLoader.js + /** * @author mrdoob / http://mrdoob.com/ */ THREE.ObjectLoader = function ( manager ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.texturePath = ''; }; THREE.ObjectLoader.prototype = { - constructor: THREE.ObjectLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { + constructor: THREE.ObjectLoader, - onLoad( scope.parse( JSON.parse( text ) ) ); + load: function ( url, onLoad, onProgress, onError ) { - } ); + if ( this.texturePath === '' ) { - }, + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; + } - }, + var scope = this; - parse: function ( json ) { + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - var geometries = this.parseGeometries( json.geometries ); - var materials = this.parseMaterials( json.materials ); - var object = this.parseObject( json.object, geometries, materials ); + scope.parse( JSON.parse( text ), onLoad ); - return object; + }, onProgress, onError ); - }, + }, - parseGeometries: function ( json ) { + setTexturePath: function ( value ) { - var geometries = {}; + this.texturePath = value; - if ( json !== undefined ) { + }, - var geometryLoader = new THREE.JSONLoader(); - var bufferGeometryLoader = new THREE.BufferGeometryLoader(); + setCrossOrigin: function ( value ) { - for ( var i = 0, l = json.length; i < l; i ++ ) { + this.crossOrigin = value; - var geometry; - var data = json[ i ]; + }, - switch ( data.type ) { + parse: function ( json, onLoad ) { - case 'PlaneGeometry': + var geometries = this.parseGeometries( json.geometries ); - geometry = new THREE.PlaneGeometry( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); + var images = this.parseImages( json.images, function () { - break; + if ( onLoad !== undefined ) onLoad( object ); - case 'BoxGeometry': - case 'CubeGeometry': // DEPRECATED + } ); + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); + var object = this.parseObject( json.object, geometries, materials ); - geometry = new THREE.BoxGeometry( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + if ( json.images === undefined || json.images.length === 0 ) { - break; + if ( onLoad !== undefined ) onLoad( object ); - case 'CircleGeometry': + } - geometry = new THREE.CircleGeometry( - data.radius, - data.segments - ); + return object; - break; + }, - case 'CylinderGeometry': + parseGeometries: function ( json ) { - geometry = new THREE.CylinderGeometry( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded - ); + var geometries = {}; - break; + if ( json !== undefined ) { - case 'SphereGeometry': + var geometryLoader = new THREE.JSONLoader(); + var bufferGeometryLoader = new THREE.BufferGeometryLoader(); - geometry = new THREE.SphereGeometry( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); + for ( var i = 0, l = json.length; i < l; i ++ ) { - break; + var geometry; + var data = json[ i ]; - case 'IcosahedronGeometry': + switch ( data.type ) { - geometry = new THREE.IcosahedronGeometry( - data.radius, - data.detail - ); + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - break; + geometry = new THREE[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); - case 'TorusGeometry': + break; - geometry = new THREE.TorusGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); + case 'BoxGeometry': + case 'CubeGeometry': // backwards compatible - break; + geometry = new THREE.BoxGeometry( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); - case 'TorusKnotGeometry': + break; - geometry = new THREE.TorusKnotGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.p, - data.q, - data.heightScale - ); + case 'CircleGeometry': - break; + geometry = new THREE.CircleGeometry( + data.radius, + data.segments + ); - case 'BufferGeometry': + break; - geometry = bufferGeometryLoader.parse( data.data ); + case 'CylinderGeometry': - break; + geometry = new THREE.CylinderGeometry( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded + ); - case 'Geometry': + break; - geometry = geometryLoader.parse( data.data ).geometry; + case 'SphereGeometry': - break; + geometry = new THREE.SphereGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); - } + break; - geometry.uuid = data.uuid; + case 'IcosahedronGeometry': - if ( data.name !== undefined ) geometry.name = data.name; + geometry = new THREE.IcosahedronGeometry( + data.radius, + data.detail + ); - geometries[ data.uuid ] = geometry; + break; - } + case 'TorusGeometry': - } + geometry = new THREE.TorusGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - return geometries; + break; - }, + case 'TorusKnotGeometry': - parseMaterials: function ( json ) { + geometry = new THREE.TorusKnotGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.p, + data.q, + data.heightScale + ); - var materials = {}; + break; - if ( json !== undefined ) { + case 'BufferGeometry': - var loader = new THREE.MaterialLoader(); + geometry = bufferGeometryLoader.parse( data ); - for ( var i = 0, l = json.length; i < l; i ++ ) { + break; - var data = json[ i ]; - var material = loader.parse( data ); + case 'Geometry': - material.uuid = data.uuid; + geometry = geometryLoader.parse( data.data ).geometry; - if ( data.name !== undefined ) material.name = data.name; + break; - materials[ data.uuid ] = material; + } - } + geometry.uuid = data.uuid; - } + if ( data.name !== undefined ) geometry.name = data.name; - return materials; + geometries[ data.uuid ] = geometry; - }, + } - parseObject: function () { + } - var matrix = new THREE.Matrix4(); + return geometries; - return function ( data, geometries, materials ) { + }, - var object; + parseMaterials: function ( json, textures ) { - switch ( data.type ) { + var materials = {}; - case 'Scene': + if ( json !== undefined ) { - object = new THREE.Scene(); + var getTexture = function ( name ) { - break; + if ( textures[ name ] === undefined ) { - case 'PerspectiveCamera': + THREE.warn( 'THREE.ObjectLoader: Undefined texture', name ); - object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + } - break; + return textures[ name ]; - case 'OrthographicCamera': + }; - object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + var loader = new THREE.MaterialLoader(); - break; + for ( var i = 0, l = json.length; i < l; i ++ ) { - case 'AmbientLight': + var data = json[ i ]; + var material = loader.parse( data ); - object = new THREE.AmbientLight( data.color ); + material.uuid = data.uuid; - break; + if ( data.name !== undefined ) material.name = data.name; - case 'DirectionalLight': + if ( data.map !== undefined ) { - object = new THREE.DirectionalLight( data.color, data.intensity ); + material.map = getTexture( data.map ); - break; + } - case 'PointLight': + if ( data.bumpMap !== undefined ) { - object = new THREE.PointLight( data.color, data.intensity, data.distance ); + material.bumpMap = getTexture( data.bumpMap ); + if ( data.bumpScale ) { + material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale ); + } - break; + } - case 'SpotLight': + if ( data.alphaMap !== undefined ) { - object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent ); + material.alphaMap = getTexture( data.alphaMap ); - break; + } - case 'HemisphereLight': + if ( data.envMap !== undefined ) { - object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); + material.envMap = getTexture( data.envMap ); - break; + } - case 'Mesh': + if ( data.normalMap !== undefined ) { - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; + material.normalMap = getTexture( data.normalMap ); + if ( data.normalScale ) { + material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale ); + } - if ( geometry === undefined ) { + } - console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); + if ( data.lightMap !== undefined ) { - } + material.lightMap = getTexture( data.lightMap ); - if ( material === undefined ) { + } - console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + if ( data.specularMap !== undefined ) { - } + material.specularMap = getTexture( data.specularMap ); - object = new THREE.Mesh( geometry, material ); + } - break; + materials[ data.uuid ] = material; - case 'Sprite': + } - var material = materials[ data.material ]; + } - if ( material === undefined ) { + return materials; - console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + }, - } + parseImages: function ( json, onLoad ) { - object = new THREE.Sprite( material ); + var scope = this; + var images = {}; - break; + if ( json !== undefined && json.length > 0 ) { - default: + var manager = new THREE.LoadingManager( onLoad ); - object = new THREE.Object3D(); + var loader = new THREE.ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + var loadImage = function ( url ) { - object.uuid = data.uuid; + scope.manager.itemStart( url ); - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { + return loader.load( url, function () { - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); + scope.manager.itemEnd( url ); - } else { + } ); - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + }; - } + for ( var i = 0, l = json.length; i < l; i ++ ) { - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; - if ( data.children !== undefined ) { + images[ image.uuid ] = loadImage( path ); - for ( var child in data.children ) { + } - object.add( this.parseObject( data.children[ child ], geometries, materials ) ); + } - } + return images; - } + }, - return object; + parseTextures: function ( json, images ) { - } + var textures = {}; - }() + if ( json !== undefined ) { -}; + for ( var i = 0, l = json.length; i < l; i ++ ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + var data = json[ i ]; -THREE.SceneLoader = function () { + if ( data.image === undefined ) { - this.onLoadStart = function () {}; - this.onLoadProgress = function() {}; - this.onLoadComplete = function () {}; + THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid ); - this.callbackSync = function () {}; - this.callbackProgress = function () {}; + } - this.geometryHandlers = {}; - this.hierarchyHandlers = {}; + if ( images[ data.image ] === undefined ) { - this.addGeometryHandler( "ascii", THREE.JSONLoader ); + THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image ); -}; + } -THREE.SceneLoader.prototype = { + var texture = new THREE.Texture( images[ data.image ] ); + texture.needsUpdate = true; - constructor: THREE.SceneLoader, + texture.uuid = data.uuid; - load: function ( url, onLoad, onProgress, onError ) { + if ( data.name !== undefined ) texture.name = data.name; + if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); + if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ]; + if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ]; + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + if ( data.wrap instanceof Array ) { - var scope = this; + texture.wrapS = THREE[ data.wrap[ 0 ] ]; + texture.wrapT = THREE[ data.wrap[ 1 ] ]; - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { + } - scope.parse( JSON.parse( text ), onLoad, url ); + textures[ data.uuid ] = texture; - } ); + } - }, + } - setCrossOrigin: function ( value ) { + return textures; - this.crossOrigin = value; + }, - }, + parseObject: function () { - addGeometryHandler: function ( typeID, loaderClass ) { + var matrix = new THREE.Matrix4(); - this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; + return function ( data, geometries, materials ) { - }, + var object; - addHierarchyHandler: function ( typeID, loaderClass ) { + var getGeometry = function ( name ) { - this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; + if ( geometries[ name ] === undefined ) { - }, + THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - parse: function ( json, callbackFinished, url ) { + } - var scope = this; + return geometries[ name ]; - var urlBase = THREE.Loader.prototype.extractUrlBase( url ); + }; - var geometry, material, camera, fog, - texture, images, color, - light, hex, intensity, - counter_models, counter_textures, - total_models, total_textures, - result; + var getMaterial = function ( name ) { - var target_array = []; + if ( materials[ name ] === undefined ) { - var data = json; + THREE.warn( 'THREE.ObjectLoader: Undefined material', name ); - // async geometry loaders + } - for ( var typeID in this.geometryHandlers ) { + return materials[ name ]; - var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; - this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + }; - } + switch ( data.type ) { - // async hierachy loaders + case 'Scene': - for ( var typeID in this.hierarchyHandlers ) { + object = new THREE.Scene(); - var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; - this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + break; - } + case 'PerspectiveCamera': - counter_models = 0; - counter_textures = 0; + object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - result = { + break; - scene: new THREE.Scene(), - geometries: {}, - face_materials: {}, - materials: {}, - textures: {}, - objects: {}, - cameras: {}, - lights: {}, - fogs: {}, - empties: {}, - groups: {} + case 'OrthographicCamera': - }; + object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - if ( data.transform ) { + break; - var position = data.transform.position, - rotation = data.transform.rotation, - scale = data.transform.scale; + case 'AmbientLight': - if ( position ) { + object = new THREE.AmbientLight( data.color ); - result.scene.position.fromArray( position ); + break; - } + case 'DirectionalLight': - if ( rotation ) { + object = new THREE.DirectionalLight( data.color, data.intensity ); - result.scene.rotation.fromArray( rotation ); + break; - } + case 'PointLight': - if ( scale ) { + object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay ); - result.scene.scale.fromArray( scale ); + break; - } + case 'SpotLight': - if ( position || rotation || scale ) { + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay ); - result.scene.updateMatrix(); - result.scene.updateMatrixWorld(); + break; - } + case 'HemisphereLight': - } + object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); - function get_url( source_url, url_type ) { + break; - if ( url_type == "relativeToHTML" ) { + case 'Mesh': - return source_url; + object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); - } else { + break; - return urlBase + source_url; + case 'Line': - } + object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - }; + break; - // toplevel loader function, delegates to handle_children + case 'PointCloud': - function handle_objects() { + object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) ); - handle_children( result.scene, data.objects ); + break; - } + case 'Sprite': - // handle all the children from the loaded json and attach them to given parent + object = new THREE.Sprite( getMaterial( data.material ) ); - function handle_children( parent, children ) { + break; - var mat, dst, pos, rot, scl, quat; + case 'Group': - for ( var objID in children ) { + object = new THREE.Group(); - // check by id if child has already been handled, - // if not, create new object + break; - var object = result.objects[ objID ]; - var objJSON = children[ objID ]; + default: - if ( object === undefined ) { + object = new THREE.Object3D(); - // meshes + } - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + object.uuid = data.uuid; - if ( objJSON.loading === undefined ) { + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { - var reservedTypes = { - "type": 1, "url": 1, "material": 1, - "position": 1, "rotation": 1, "scale" : 1, - "visible": 1, "children": 1, "userData": 1, - "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 - }; + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); - var loaderParameters = {}; + } else { - for ( var parType in objJSON ) { + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - if ( ! ( parType in reservedTypes ) ) { + } - loaderParameters[ parType ] = objJSON[ parType ]; + 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 ) { - material = result.materials[ objJSON.material ]; + object.add( this.parseObject( data.children[ child ], geometries, materials ) ); - objJSON.loading = true; + } - var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; + } - // ColladaLoader + return object; - if ( loader.options ) { + } - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); + }() - // UTF8Loader - // OBJLoader +}; - } else { +// File:src/loaders/TextureLoader.js - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.TextureLoader = function ( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - } else if ( objJSON.geometry !== undefined ) { +}; - geometry = result.geometries[ objJSON.geometry ]; +THREE.TextureLoader.prototype = { - // geometry already loaded + constructor: THREE.TextureLoader, - if ( geometry ) { + load: function ( url, onLoad, onProgress, onError ) { - var needsTangents = false; + var scope = this; - material = result.materials[ objJSON.material ]; - needsTangents = material instanceof THREE.ShaderMaterial; + var loader = new THREE.ImageLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( image ) { - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - mat = objJSON.matrix; - quat = objJSON.quaternion; + var texture = new THREE.Texture( image ); + texture.needsUpdate = true; - // use materials from the model file - // if there is no material specified in the object + if ( onLoad !== undefined ) { - if ( ! objJSON.material ) { + onLoad( texture ); - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + } - } + }, onProgress, onError ); - // use materials from the model file - // if there is just empty face material - // (must create new material as each model has its own face material) + }, - if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { + setCrossOrigin: function ( value ) { - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + this.crossOrigin = value; - } + } - if ( material instanceof THREE.MeshFaceMaterial ) { +}; - for ( var i = 0; i < material.materials.length; i ++ ) { +// File:src/loaders/BinaryTextureLoader.js - needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); +/** + * @author Nikos M. / https://github.com/foo123/ + * + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + */ - } +THREE.DataTextureLoader = THREE.BinaryTextureLoader = function () { - } + // override in sub classes + this._parser = null; - if ( needsTangents ) { +}; - geometry.computeTangents(); +THREE.BinaryTextureLoader.prototype = { - } + constructor: THREE.BinaryTextureLoader, - if ( objJSON.skin ) { + load: function ( url, onLoad, onProgress, onError ) { - object = new THREE.SkinnedMesh( geometry, material ); + var scope = this; - } else if ( objJSON.morph ) { + var texture = new THREE.DataTexture( ); - object = new THREE.MorphAnimMesh( geometry, material ); + var loader = new THREE.XHRLoader(); + loader.setResponseType( 'arraybuffer' ); - if ( objJSON.duration !== undefined ) { + loader.load( url, function ( buffer ) { - object.duration = objJSON.duration; + var texData = scope._parser( buffer ); - } + if ( !texData ) return; - if ( objJSON.time !== undefined ) { + if ( undefined !== texData.image ) { - object.time = objJSON.time; + texture.image = texData.image; - } + } else if ( undefined !== texData.data ) { - if ( objJSON.mirroredLoop !== undefined ) { + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - object.mirroredLoop = objJSON.mirroredLoop; + } - } + texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping; + texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; - if ( material.morphNormals ) { + texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; + texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter; - geometry.computeMorphNormals(); + texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; - } + if ( undefined !== texData.format ) { - } else { + texture.format = texData.format; - object = new THREE.Mesh( geometry, material ); + } + if ( undefined !== texData.type ) { - } + texture.type = texData.type; - object.name = objID; + } - if ( mat ) { + if ( undefined !== texData.mipmaps ) { - object.matrixAutoUpdate = false; - object.matrix.set( - mat[0], mat[1], mat[2], mat[3], - mat[4], mat[5], mat[6], mat[7], - mat[8], mat[9], mat[10], mat[11], - mat[12], mat[13], mat[14], mat[15] - ); + texture.mipmaps = texData.mipmaps; - } else { + } - object.position.fromArray( pos ); + if ( 1 === texData.mipmapCount ) { - if ( quat ) { + texture.minFilter = THREE.LinearFilter; - object.quaternion.fromArray( quat ); + } - } else { + texture.needsUpdate = true; - object.rotation.fromArray( rot ); + if ( onLoad ) onLoad( texture, texData ); - } + }, onProgress, onError ); - object.scale.fromArray( scl ); - } + return texture; - object.visible = objJSON.visible; - object.castShadow = objJSON.castShadow; - object.receiveShadow = objJSON.receiveShadow; + } - parent.add( object ); +}; - result.objects[ objID ] = object; +// File:src/loaders/CompressedTextureLoader.js - } +/** + * @author mrdoob / http://mrdoob.com/ + * + * Abstract Base class to block based textures loader (dds, pvr, ...) + */ - // lights +THREE.CompressedTextureLoader = function () { - } else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" || - objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" || - objJSON.type === "HemisphereLight" || objJSON.type === "AreaLight" ) { + // override in sub classes + this._parser = null; - var color = objJSON.color; - var intensity = objJSON.intensity; - var distance = objJSON.distance; - var position = objJSON.position; - var rotation = objJSON.rotation; +}; - switch ( objJSON.type ) { - case 'AmbientLight': - light = new THREE.AmbientLight( color ); - break; +THREE.CompressedTextureLoader.prototype = { - case 'PointLight': - light = new THREE.PointLight( color, intensity, distance ); - light.position.fromArray( position ); - break; + constructor: THREE.CompressedTextureLoader, - case 'DirectionalLight': - light = new THREE.DirectionalLight( color, intensity ); - light.position.fromArray( objJSON.direction ); - break; + load: function ( url, onLoad, onError ) { - case 'SpotLight': - light = new THREE.SpotLight( color, intensity, distance, 1 ); - light.angle = objJSON.angle; - light.position.fromArray( position ); - light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); - light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); - break; + var scope = this; - case 'HemisphereLight': - light = new THREE.DirectionalLight( color, intensity, distance ); - light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); - light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); - break; + var images = []; - case 'AreaLight': - light = new THREE.AreaLight(color, intensity); - light.position.fromArray( position ); - light.width = objJSON.size; - light.height = objJSON.size_y; - break; + var texture = new THREE.CompressedTexture(); + texture.image = images; - } + var loader = new THREE.XHRLoader(); + loader.setResponseType( 'arraybuffer' ); - parent.add( light ); + if ( url instanceof Array ) { - light.name = objID; - result.lights[ objID ] = light; - result.objects[ objID ] = light; + var loaded = 0; - // cameras + var loadTexture = function ( i ) { - } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { + loader.load( url[ i ], function ( buffer ) { - pos = objJSON.position; - rot = objJSON.rotation; - quat = objJSON.quaternion; + var texDatas = scope._parser( buffer, true ); - if ( objJSON.type === "PerspectiveCamera" ) { + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); + loaded += 1; - } else if ( objJSON.type === "OrthographicCamera" ) { + if ( loaded === 6 ) { - camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); + if (texDatas.mipmapCount == 1) + texture.minFilter = THREE.LinearFilter; - } + texture.format = texDatas.format; + texture.needsUpdate = true; - camera.name = objID; - camera.position.fromArray( pos ); + if ( onLoad ) onLoad( texture ); - if ( quat !== undefined ) { + } - camera.quaternion.fromArray( quat ); + } ); - } else if ( rot !== undefined ) { + }; - camera.rotation.fromArray( rot ); + for ( var i = 0, il = url.length; i < il; ++ i ) { - } + loadTexture( i ); - parent.add( camera ); + } - result.cameras[ objID ] = camera; - result.objects[ objID ] = camera; + } else { - // pure Object3D + // compressed cubemap texture stored in a single DDS file - } else { + loader.load( url, function ( buffer ) { - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - quat = objJSON.quaternion; + var texDatas = scope._parser( buffer, true ); - object = new THREE.Object3D(); - object.name = objID; - object.position.fromArray( pos ); + if ( texDatas.isCubemap ) { - if ( quat ) { + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - object.quaternion.fromArray( quat ); + for ( var f = 0; f < faces; f ++ ) { - } else { + images[ f ] = { mipmaps : [] }; - object.rotation.fromArray( rot ); + 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; - object.scale.fromArray( scl ); - object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; + } - parent.add( object ); + } - result.objects[ objID ] = object; - result.empties[ objID ] = object; + } else { - } + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - if ( object ) { + } - if ( objJSON.userData !== undefined ) { + if ( texDatas.mipmapCount === 1 ) { - for ( var key in objJSON.userData ) { + texture.minFilter = THREE.LinearFilter; - var value = objJSON.userData[ key ]; - object.userData[ key ] = value; + } - } + texture.format = texDatas.format; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); - if ( objJSON.groups !== undefined ) { + } ); - for ( var i = 0; i < objJSON.groups.length; i ++ ) { + } - var groupID = objJSON.groups[ i ]; + return texture; - if ( result.groups[ groupID ] === undefined ) { + } - result.groups[ groupID ] = []; +}; - } +// File:src/materials/Material.js - result.groups[ groupID ].push( objID ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.Material = function () { - } + Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } ); - } + this.uuid = THREE.Math.generateUUID(); - } + this.name = ''; + this.type = 'Material'; - if ( object !== undefined && objJSON.children !== undefined ) { + this.side = THREE.FrontSide; - handle_children( object, objJSON.children ); + this.opacity = 1; + this.transparent = false; - } + this.blending = THREE.NormalBlending; - } + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - }; + this.depthTest = true; + this.depthWrite = true; - function handle_mesh( geo, mat, id ) { + this.colorWrite = true; - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; - handle_objects(); + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - }; + this.alphaTest = 0; - function handle_hierarchy( node, id, parent, material, obj ) { + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - var p = obj.position; - var r = obj.rotation; - var q = obj.quaternion; - var s = obj.scale; + this.visible = true; - node.position.fromArray( p ); + this._needsUpdate = true; - if ( q ) { +}; - node.quaternion.fromArray( q ); +THREE.Material.prototype = { - } else { + constructor: THREE.Material, - node.rotation.fromArray( r ); + get needsUpdate () { - } + return this._needsUpdate; - node.scale.fromArray( s ); + }, - // override children materials - // if object material was specified in JSON explicitly + set needsUpdate ( value ) { - if ( material ) { + if ( value === true ) this.update(); - node.traverse( function ( child ) { + this._needsUpdate = value; - child.material = material; + }, - } ); + setValues: function ( values ) { - } + if ( values === undefined ) return; - // override children visibility - // with root node visibility as specified in JSON + for ( var key in values ) { - var visible = ( obj.visible !== undefined ) ? obj.visible : true; + var newValue = values[ key ]; - node.traverse( function ( child ) { + if ( newValue === undefined ) { - child.visible = visible; + THREE.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + continue; - } ); + } - parent.add( node ); + if ( key in this ) { - node.name = id; + var currentValue = this[ key ]; - result.objects[ id ] = node; - handle_objects(); + if ( currentValue instanceof THREE.Color ) { - }; + currentValue.set( newValue ); - function create_callback_geometry( id ) { + } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { - return function ( geo, mat ) { + currentValue.copy( newValue ); - geo.name = id; + } else if ( key == 'overdraw' ) { - handle_mesh( geo, mat, id ); + // ensure overdraw is backwards-compatable with legacy boolean type + this[ key ] = Number( newValue ); - counter_models -= 1; + } else { - scope.onLoadComplete(); + this[ key ] = newValue; - async_callback_gate(); + } - } + } - }; + } - function create_callback_hierachy( id, parent, material, obj ) { + }, - return function ( event ) { + toJSON: function () { - var result; + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type + }; - // loaders which use EventDispatcher + if ( this.name !== "" ) output.name = this.name; - if ( event.content ) { + if ( this instanceof THREE.MeshBasicMaterial ) { - result = event.content; + output.color = this.color.getHex(); + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - // ColladaLoader + } else if ( this instanceof THREE.MeshLambertMaterial ) { - } else if ( event.dae ) { + output.color = this.color.getHex(); + output.emissive = this.emissive.getHex(); + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - result = event.scene; + } else if ( this instanceof THREE.MeshPhongMaterial ) { + output.color = this.color.getHex(); + output.emissive = this.emissive.getHex(); + output.specular = this.specular.getHex(); + output.shininess = this.shininess; + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - // UTF8Loader + } else if ( this instanceof THREE.MeshNormalMaterial ) { - } else { + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - result = event; + } else if ( this instanceof THREE.MeshDepthMaterial ) { - } + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - handle_hierarchy( result, id, parent, material, obj ); + } else if ( this instanceof THREE.PointCloudMaterial ) { - counter_models -= 1; + output.size = this.size; + output.sizeAttenuation = this.sizeAttenuation; + output.color = this.color.getHex(); - scope.onLoadComplete(); + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - async_callback_gate(); + } else if ( this instanceof THREE.ShaderMaterial ) { - } + output.uniforms = this.uniforms; + output.vertexShader = this.vertexShader; + output.fragmentShader = this.fragmentShader; - }; + } else if ( this instanceof THREE.SpriteMaterial ) { - function create_callback_embed( id ) { + output.color = this.color.getHex(); - return function ( geo, mat ) { + } - geo.name = id; + if ( this.opacity < 1 ) output.opacity = this.opacity; + if ( this.transparent !== false ) output.transparent = this.transparent; + if ( this.wireframe !== false ) output.wireframe = this.wireframe; - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; + return output; - } + }, - }; + clone: function ( material ) { - function async_callback_gate() { + if ( material === undefined ) material = new THREE.Material(); - var progress = { + material.name = this.name; - totalModels : total_models, - totalTextures : total_textures, - loadedModels : total_models - counter_models, - loadedTextures : total_textures - counter_textures + material.side = this.side; - }; + material.opacity = this.opacity; + material.transparent = this.transparent; - scope.callbackProgress( progress, result ); + material.blending = this.blending; - scope.onLoadProgress(); + material.blendSrc = this.blendSrc; + material.blendDst = this.blendDst; + material.blendEquation = this.blendEquation; + material.blendSrcAlpha = this.blendSrcAlpha; + material.blendDstAlpha = this.blendDstAlpha; + material.blendEquationAlpha = this.blendEquationAlpha; - if ( counter_models === 0 && counter_textures === 0 ) { + material.depthTest = this.depthTest; + material.depthWrite = this.depthWrite; - finalize(); - callbackFinished( result ); + material.polygonOffset = this.polygonOffset; + material.polygonOffsetFactor = this.polygonOffsetFactor; + material.polygonOffsetUnits = this.polygonOffsetUnits; - } + material.alphaTest = this.alphaTest; - }; + material.overdraw = this.overdraw; - function finalize() { + material.visible = this.visible; - // take care of targets which could be asynchronously loaded objects + return material; - for ( var i = 0; i < target_array.length; i ++ ) { + }, - var ta = target_array[ i ]; + update: function () { - var target = result.objects[ ta.targetName ]; + this.dispatchEvent( { type: 'update' } ); - if ( target ) { + }, - ta.object.target = target; + dispose: function () { - } else { + this.dispatchEvent( { type: 'dispose' } ); - // if there was error and target of specified name doesn't exist in the scene file - // create instead dummy target - // (target must be added to scene explicitly as parent is already added) + } - ta.object.target = new THREE.Object3D(); - result.scene.add( ta.object.target ); +}; - } +THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - ta.object.target.userData.targetInverse = ta.object; +THREE.MaterialIdCount = 0; - } +// File:src/materials/LineBasicMaterial.js - }; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round", + * + * vertexColors: + * + * fog: + * } + */ - var callbackTexture = function ( count ) { +THREE.LineBasicMaterial = function ( parameters ) { - counter_textures -= count; - async_callback_gate(); + THREE.Material.call( this ); - scope.onLoadComplete(); + this.type = 'LineBasicMaterial'; - }; + this.color = new THREE.Color( 0xffffff ); - // must use this instead of just directly calling callbackTexture - // because of closure in the calling context loop + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - var generateTextureCallback = function ( count ) { + this.vertexColors = THREE.NoColors; - return function () { + this.fog = true; - callbackTexture( count ); + this.setValues( parameters ); - }; +}; - }; +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; - function traverse_json_hierarchy( objJSON, callback ) { +THREE.LineBasicMaterial.prototype.clone = function () { - callback( objJSON ); + var material = new THREE.LineBasicMaterial(); - if ( objJSON.children !== undefined ) { + THREE.Material.prototype.clone.call( this, material ); - for ( var objChildID in objJSON.children ) { + material.color.copy( this.color ); - traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); + material.linewidth = this.linewidth; + material.linecap = this.linecap; + material.linejoin = this.linejoin; - } + material.vertexColors = this.vertexColors; - } + material.fog = this.fog; - }; + return material; - // first go synchronous elements +}; - // fogs +// File:src/materials/LineDashedMaterial.js - var fogID, fogJSON; +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: , + * + * vertexColors: + * + * fog: + * } + */ - for ( fogID in data.fogs ) { +THREE.LineDashedMaterial = function ( parameters ) { - fogJSON = data.fogs[ fogID ]; + THREE.Material.call( this ); - if ( fogJSON.type === "linear" ) { + this.type = 'LineDashedMaterial'; - fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); + this.color = new THREE.Color( 0xffffff ); - } else if ( fogJSON.type === "exp2" ) { + this.linewidth = 1; - fog = new THREE.FogExp2( 0x000000, fogJSON.density ); + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; - } + this.vertexColors = false; - color = fogJSON.color; - fog.color.setRGB( color[0], color[1], color[2] ); + this.fog = true; - result.fogs[ fogID ] = fog; + this.setValues( parameters ); - } +}; - // now come potentially asynchronous elements +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial; - // geometries +THREE.LineDashedMaterial.prototype.clone = function () { - // count how many geometries will be loaded asynchronously + var material = new THREE.LineDashedMaterial(); - var geoID, geoJSON; + THREE.Material.prototype.clone.call( this, material ); - for ( geoID in data.geometries ) { + material.color.copy( this.color ); - geoJSON = data.geometries[ geoID ]; + material.linewidth = this.linewidth; - if ( geoJSON.type in this.geometryHandlers ) { + material.scale = this.scale; + material.dashSize = this.dashSize; + material.gapSize = this.gapSize; - counter_models += 1; + material.vertexColors = this.vertexColors; - scope.onLoadStart(); + material.fog = this.fog; - } + return material; - } +}; - // count how many hierarchies will be loaded asynchronously +// File:src/materials/MeshBasicMaterial.js - for ( var objID in data.objects ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * lightMap: 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: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * + * fog: + * } + */ - traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { +THREE.MeshBasicMaterial = function ( parameters ) { - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + THREE.Material.call( this ); - counter_models += 1; + this.type = 'MeshBasicMaterial'; - scope.onLoadStart(); + this.color = new THREE.Color( 0xffffff ); // emissive - } + this.map = null; - }); + this.lightMap = null; - } + this.specularMap = null; - total_models = counter_models; + this.alphaMap = null; - for ( geoID in data.geometries ) { + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - geoJSON = data.geometries[ geoID ]; + this.fog = true; - if ( geoJSON.type === "cube" ) { + this.shading = THREE.SmoothShading; - geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - } else if ( geoJSON.type === "plane" ) { + this.vertexColors = THREE.NoColors; - geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; + this.skinning = false; + this.morphTargets = false; - } else if ( geoJSON.type === "sphere" ) { + this.setValues( parameters ); - geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; +}; - } else if ( geoJSON.type === "cylinder" ) { +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; - geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; +THREE.MeshBasicMaterial.prototype.clone = function () { - } else if ( geoJSON.type === "torus" ) { + var material = new THREE.MeshBasicMaterial(); - geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; + THREE.Material.prototype.clone.call( this, material ); - } else if ( geoJSON.type === "icosahedron" ) { + material.color.copy( this.color ); - geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; + material.map = this.map; - } else if ( geoJSON.type in this.geometryHandlers ) { + material.lightMap = this.lightMap; - var loaderParameters = {}; + material.specularMap = this.specularMap; - for ( var parType in geoJSON ) { + material.alphaMap = this.alphaMap; - if ( parType !== "type" && parType !== "url" ) { + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - loaderParameters[ parType ] = geoJSON[ parType ]; + material.fog = this.fog; - } + material.shading = this.shading; - } + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; - loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); + material.vertexColors = this.vertexColors; - } else if ( geoJSON.type === "embedded" ) { + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; - var modelJson = data.embeds[ geoJSON.id ], - texture_path = ""; + return material; - // pass metadata along to jsonLoader so it knows the format version +}; - modelJson.metadata = data.metadata; - - if ( modelJson ) { - - var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; - var model = jsonLoader.parse( modelJson, texture_path ); - create_callback_embed( geoID )( model.geometry, model.materials ); - - } - - } - - } - - // textures - - // count how many textures will be loaded asynchronously - - var textureID, textureJSON; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.url instanceof Array ) { - - counter_textures += textureJSON.url.length; - - for( var n = 0; n < textureJSON.url.length; n ++ ) { - - scope.onLoadStart(); - - } - - } else { - - counter_textures += 1; - - scope.onLoadStart(); - - } - - } - - total_textures = counter_textures; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { - - textureJSON.mapping = new THREE[ textureJSON.mapping ](); - - } - - if ( textureJSON.url instanceof Array ) { - - var count = textureJSON.url.length; - var url_array = []; - - for( var i = 0; i < count; i ++ ) { - - url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); - - } - - var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } else { - - texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } - - } else { - - var isCompressed = /\.dds$/i.test( textureJSON.url ); - var fullUrl = get_url( textureJSON.url, data.urlBaseType ); - var textureCallback = generateTextureCallback( 1 ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } else { - - texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } - - if ( THREE[ textureJSON.minFilter ] !== undefined ) - texture.minFilter = THREE[ textureJSON.minFilter ]; - - if ( THREE[ textureJSON.magFilter ] !== undefined ) - texture.magFilter = THREE[ textureJSON.magFilter ]; - - if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; - - if ( textureJSON.repeat ) { - - texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); - - if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; - if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - - } - - if ( textureJSON.offset ) { - - texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); - - } - - // handle wrap after repeat so that default repeat can be overriden - - if ( textureJSON.wrap ) { - - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } - - if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; - if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; - - } - - } - - result.textures[ textureID ] = texture; - - } - - // materials - - var matID, matJSON; - var parID; - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - for ( parID in matJSON.parameters ) { - - if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { - - matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; - - } else if ( parID === "shading" ) { - - matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; - - } else if ( parID === "side" ) { - - if ( matJSON.parameters[ parID ] == "double" ) { - - matJSON.parameters[ parID ] = THREE.DoubleSide; - - } else if ( matJSON.parameters[ parID ] == "back" ) { - - matJSON.parameters[ parID ] = THREE.BackSide; - - } else { - - matJSON.parameters[ parID ] = THREE.FrontSide; - - } - - } else if ( parID === "blending" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; - - } else if ( parID === "combine" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; - - } else if ( parID === "vertexColors" ) { - - if ( matJSON.parameters[ parID ] == "face" ) { - - matJSON.parameters[ parID ] = THREE.FaceColors; - - // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false - - } else if ( matJSON.parameters[ parID ] ) { - - matJSON.parameters[ parID ] = THREE.VertexColors; - - } - - } else if ( parID === "wrapRGB" ) { - - var v3 = matJSON.parameters[ parID ]; - matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); - - } - - } - - if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { - - matJSON.parameters.transparent = true; - - } - - if ( matJSON.parameters.normalMap ) { - - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - var diffuse = matJSON.parameters.color; - var specular = matJSON.parameters.specular; - var ambient = matJSON.parameters.ambient; - var shininess = matJSON.parameters.shininess; - - uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; - - if ( matJSON.parameters.normalScale ) { - - uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); - - } - - if ( matJSON.parameters.map ) { - - uniforms[ "tDiffuse" ].value = matJSON.parameters.map; - uniforms[ "enableDiffuse" ].value = true; - - } - - if ( matJSON.parameters.envMap ) { - - uniforms[ "tCube" ].value = matJSON.parameters.envMap; - uniforms[ "enableReflection" ].value = true; - uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity; - - } - - if ( matJSON.parameters.lightMap ) { - - uniforms[ "tAO" ].value = matJSON.parameters.lightMap; - uniforms[ "enableAO" ].value = true; - - } - - if ( matJSON.parameters.specularMap ) { - - uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; - uniforms[ "enableSpecular" ].value = true; - - } - - if ( matJSON.parameters.displacementMap ) { - - uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; - uniforms[ "enableDisplacement" ].value = true; - - uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; - uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; - - } - - uniforms[ "diffuse" ].value.setHex( diffuse ); - uniforms[ "specular" ].value.setHex( specular ); - uniforms[ "ambient" ].value.setHex( ambient ); - - uniforms[ "shininess" ].value = shininess; - - if ( matJSON.parameters.opacity ) { - - uniforms[ "opacity" ].value = matJSON.parameters.opacity; - - } - - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - - material = new THREE.ShaderMaterial( parameters ); - - } else { - - material = new THREE[ matJSON.type ]( matJSON.parameters ); - - } - - material.name = matID; - - result.materials[ matID ] = material; - - } - - // second pass through all materials to initialize MeshFaceMaterials - // that could be referring to other materials out of order - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - if ( matJSON.parameters.materials ) { - - var materialArray = []; - - for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { - - var label = matJSON.parameters.materials[ i ]; - materialArray.push( result.materials[ label ] ); - - } - - result.materials[ matID ].materials = materialArray; - - } - - } - - // objects ( synchronous init of procedural primitives ) - - handle_objects(); - - // defaults - - if ( result.cameras && data.defaults.camera ) { - - result.currentCamera = result.cameras[ data.defaults.camera ]; - - } - - if ( result.fogs && data.defaults.fog ) { - - result.scene.fog = result.fogs[ data.defaults.fog ]; - - } - - // synchronous callback - - scope.callbackSync( result ); - - // just in case there are no async elements - - async_callback_gate(); - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.TextureLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.TextureLoader.prototype = { - - constructor: THREE.TextureLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.ImageLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( image ) { - - var texture = new THREE.Texture( image ); - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; +// File:src/materials/MeshLambertMaterial.js /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * emissive: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: 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: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } */ -THREE.Material = function () { - - this.id = THREE.MaterialIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.side = THREE.FrontSide; - - this.opacity = 1; - this.transparent = false; - - this.blending = THREE.NormalBlending; - - this.blendSrc = THREE.SrcAlphaFactor; - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - - this.depthTest = true; - this.depthWrite = true; - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.alphaTest = 0; - - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - - this.visible = true; - - this.needsUpdate = true; - -}; - -THREE.Material.prototype = { - - constructor: THREE.Material, - - setValues: function ( values ) { - - if ( values === undefined ) return; - - for ( var key in values ) { - - var newValue = values[ key ]; - - if ( newValue === undefined ) { +THREE.MeshLambertMaterial = function ( parameters ) { - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); - continue; + THREE.Material.call( this ); - } + this.type = 'MeshLambertMaterial'; - if ( key in this ) { + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); - var currentValue = this[ key ]; + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - if ( currentValue instanceof THREE.Color ) { + this.map = null; - currentValue.set( newValue ); + this.lightMap = null; - } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { + this.specularMap = null; - currentValue.copy( newValue ); + this.alphaMap = null; - } else if ( key == 'overdraw') { + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - // ensure overdraw is backwards-compatable with legacy boolean type - this[ key ] = Number(newValue); + this.fog = true; - } else { + this.shading = THREE.SmoothShading; - this[ key ] = newValue; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - } + this.vertexColors = THREE.NoColors; - } + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - } + this.setValues( parameters ); - }, +}; - clone: function ( material ) { +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial; - if ( material === undefined ) material = new THREE.Material(); +THREE.MeshLambertMaterial.prototype.clone = function () { - material.name = this.name; + var material = new THREE.MeshLambertMaterial(); - material.side = this.side; + THREE.Material.prototype.clone.call( this, material ); - material.opacity = this.opacity; - material.transparent = this.transparent; + material.color.copy( this.color ); + material.emissive.copy( this.emissive ); - material.blending = this.blending; + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); - material.blendSrc = this.blendSrc; - material.blendDst = this.blendDst; - material.blendEquation = this.blendEquation; + material.map = this.map; - material.depthTest = this.depthTest; - material.depthWrite = this.depthWrite; + material.lightMap = this.lightMap; - material.polygonOffset = this.polygonOffset; - material.polygonOffsetFactor = this.polygonOffsetFactor; - material.polygonOffsetUnits = this.polygonOffsetUnits; + material.specularMap = this.specularMap; - material.alphaTest = this.alphaTest; + material.alphaMap = this.alphaMap; - material.overdraw = this.overdraw; + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - material.visible = this.visible; + material.fog = this.fog; - return material; + material.shading = this.shading; - }, + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - dispose: function () { + material.vertexColors = this.vertexColors; - this.dispatchEvent( { type: 'dispose' } ); + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - } + return material; }; -THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - -THREE.MaterialIdCount = 0; +// File:src/materials/MeshPhongMaterial.js /** * @author mrdoob / http://mrdoob.com/ @@ -14399,373 +14214,9 @@ THREE.MaterialIdCount = 0; * * parameters = { * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round", - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineBasicMaterial.prototype.clone = function () { - - var material = new THREE.LineBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - material.linecap = this.linecap; - material.linejoin = this.linejoin; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: , - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineDashedMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineDashedMaterial.prototype.clone = function () { - - var material = new THREE.LineDashedMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - - material.scale = this.scale; - material.dashSize = this.dashSize; - material.gapSize = this.gapSize; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * - * fog: - * } - */ - -THREE.MeshBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshBasicMaterial.prototype.clone = function () { - - var material = new THREE.MeshBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * ambient: , - * emissive: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshLambertMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); - this.emissive = new THREE.Color( 0x000000 ); - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshLambertMaterial.prototype.clone = function () { - - var material = new THREE.MeshLambertMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * ambient: , - * emissive: , - * specular: , - * shininess: , + * emissive: , + * specular: , + * shininess: , * opacity: , * * map: new THREE.Texture( ), @@ -14773,5975 +14224,3726 @@ THREE.MeshLambertMaterial.prototype.clone = function () { * lightMap: new THREE.Texture( ), * * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshPhongMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); - this.emissive = new THREE.Color( 0x000000 ); - this.specular = new THREE.Color( 0x111111 ); - this.shininess = 30; - - this.metal = false; - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - - this.lightMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new THREE.Vector2( 1, 1 ); - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshPhongMaterial.prototype.clone = function () { - - var material = new THREE.MeshPhongMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); - material.specular.copy( this.specular ); - material.shininess = this.shininess; - - material.metal = this.metal; - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; - - material.normalMap = this.normalMap; - material.normalScale.copy( this.normalScale ); - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshDepthMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.setValues( parameters ); - -}; - -THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshDepthMaterial.prototype.clone = function () { - - var material = new THREE.MeshDepthMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * opacity: , - * - * shading: THREE.FlatShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshNormalMaterial = function ( parameters ) { - - THREE.Material.call( this, parameters ); - - this.shading = THREE.FlatShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshNormalMaterial.prototype.clone = function () { - - var material = new THREE.MeshNormalMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MeshFaceMaterial = function ( materials ) { - - this.materials = materials instanceof Array ? materials : []; - -}; - -THREE.MeshFaceMaterial.prototype.clone = function () { - - var material = new THREE.MeshFaceMaterial(); - - for ( var i = 0; i < this.materials.length; i ++ ) { - - material.materials.push( this.materials[ i ].clone() ); - - } - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * vertexColors: , - * - * fog: - * } - */ - -THREE.ParticleSystemMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.map = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.ParticleSystemMaterial.prototype.clone = function () { - - var material = new THREE.ParticleSystemMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.size = this.size; - material.sizeAttenuation = this.sizeAttenuation; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -// backwards compatibility - -THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * fragmentShader: , - * vertexShader: , - * - * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, - * - * defines: { "label" : "value" }, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.ShaderMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.fragmentShader = "void main() {}"; - this.vertexShader = "void main() {}"; - this.uniforms = {}; - this.defines = {}; - this.attributes = null; - - this.shading = THREE.SmoothShading; - - 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.vertexColors = THREE.NoColors; // set to use "color" attribute stream - - 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 - - // 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; - - this.setValues( parameters ); - -}; - -THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.ShaderMaterial.prototype.clone = function () { - - var material = new THREE.ShaderMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.fragmentShader = this.fragmentShader; - material.vertexShader = this.vertexShader; - - material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); - - material.attributes = this.attributes; - material.defines = this.defines; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - material.fog = this.fog; - - material.lights = this.lights; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RawShaderMaterial = function ( parameters ) { - - THREE.ShaderMaterial.call( this, parameters ); - -}; - -THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); - -THREE.RawShaderMaterial.prototype.clone = function () { - - var material = new THREE.RawShaderMaterial(); - - THREE.ShaderMaterial.prototype.clone.call( this, material ); - - return material; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2(), - * - * fog: - * } - */ - -THREE.SpriteMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - // defaults - - this.color = new THREE.Color( 0xffffff ); - this.map = null; - - this.rotation = 0; - - this.fog = false; - - // set parameters - - this.setValues( parameters ); - -}; - -THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.SpriteMaterial.prototype.clone = function () { - - var material = new THREE.SpriteMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.map = this.map; - - material.rotation = this.rotation; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * color: , - * program: , - * opacity: , - * blending: THREE.NormalBlending - * } - */ - -THREE.SpriteCanvasMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - this.program = function ( context, color ) {}; - - this.setValues( parameters ); - -}; - -THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.SpriteCanvasMaterial.prototype.clone = function () { - - var material = new THREE.SpriteCanvasMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.program = this.program; - - return material; - -}; - -// backwards compatibility - -THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ - -THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - this.id = THREE.TextureIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.image = image; - this.mipmaps = []; - - this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); - - this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; - - this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; - - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - - this.format = format !== undefined ? format : THREE.RGBAFormat; - this.type = type !== undefined ? type : THREE.UnsignedByteType; - - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.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) - - this._needsUpdate = false; - this.onUpdate = null; - -}; - -THREE.Texture.prototype = { - - constructor: THREE.Texture, - - get needsUpdate () { - - return this._needsUpdate; - - }, - - set needsUpdate ( value ) { - - if ( value === true ) this.update(); - - this._needsUpdate = value; - - }, - - clone: function ( texture ) { - - if ( texture === undefined ) texture = new THREE.Texture(); - - texture.image = this.image; - texture.mipmaps = this.mipmaps.slice(0); - - texture.mapping = this.mapping; - - texture.wrapS = this.wrapS; - texture.wrapT = this.wrapT; - - texture.magFilter = this.magFilter; - texture.minFilter = this.minFilter; - - texture.anisotropy = this.anisotropy; - - texture.format = this.format; - texture.type = this.type; - - texture.offset.copy( this.offset ); - texture.repeat.copy( this.repeat ); - - texture.generateMipmaps = this.generateMipmaps; - texture.premultiplyAlpha = this.premultiplyAlpha; - texture.flipY = this.flipY; - texture.unpackAlignment = this.unpackAlignment; - - return texture; - - }, - - update: function () { - - this.dispatchEvent( { type: 'update' } ); - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); - -THREE.TextureIdCount = 0; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file - -}; - -THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); - -THREE.CompressedTexture.prototype.clone = function () { - - var texture = new THREE.CompressedTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { data: data, width: width, height: height }; - -}; - -THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); - -THREE.DataTexture.prototype.clone = function () { - - var texture = new THREE.DataTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ParticleSystem = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); - - this.sortParticles = false; - this.frustumCulled = false; - -}; - -THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.ParticleSystem.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); - - object.sortParticles = this.sortParticles; - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Line = function ( geometry, material, type ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.type = ( type !== undefined ) ? type : THREE.LineStrip; - -}; - -THREE.LineStrip = 0; -THREE.LinePieces = 1; - -THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Line.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ - -THREE.Mesh = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.updateMorphTargets(); - -}; - -THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Mesh.prototype.updateMorphTargets = function () { - - if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - - this.morphTargetBase = -1; - this.morphTargetForcedOrder = []; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - - } - - } - -}; - -THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - - if ( this.morphTargetDictionary[ name ] !== undefined ) { - - return this.morphTargetDictionary[ name ]; - - } - - console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); - - return 0; - -}; - -THREE.Mesh.prototype.clone = function ( object, recursive ) { - - if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); - - THREE.Object3D.prototype.clone.call( this, object, recursive ); - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Bone = function( belongsToSkin ) { - - THREE.Object3D.call( this ); - - this.skin = belongsToSkin; - this.skinMatrix = new THREE.Matrix4(); - -}; - -THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { - - // update local - - if ( this.matrixAutoUpdate ) { - - forceUpdate |= this.updateMatrix(); - - } - - // update skin matrix - - if ( forceUpdate || this.matrixWorldNeedsUpdate ) { - - if ( parentSkinMatrix ) { - - this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); - - } else { - - this.skinMatrix.copy( this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - forceUpdate = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].update( this.skinMatrix, forceUpdate ); - - } - -}; - - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - - THREE.Mesh.call( this, geometry, material ); - - // - - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - - // init bones - - this.identityMatrix = new THREE.Matrix4(); - - this.bones = []; - this.boneMatrices = []; - - var b, bone, gbone, p, q, s; - - if ( this.geometry && this.geometry.bones !== undefined ) { - - for ( b = 0; b < this.geometry.bones.length; b ++ ) { - - gbone = this.geometry.bones[ b ]; - - p = gbone.pos; - q = gbone.rotq; - s = gbone.scl; - - bone = this.addBone(); - - bone.name = gbone.name; - bone.position.set( p[0], p[1], p[2] ); - bone.quaternion.set( q[0], q[1], q[2], q[3] ); - - if ( s !== undefined ) { - - bone.scale.set( s[0], s[1], s[2] ); - - } else { - - bone.scale.set( 1, 1, 1 ); - - } - - } - - for ( b = 0; b < this.bones.length; b ++ ) { - - gbone = this.geometry.bones[ b ]; - bone = this.bones[ b ]; - - if ( gbone.parent === -1 ) { - - this.add( bone ); - - } else { - - this.bones[ gbone.parent ].add( bone ); - - } - - } - - // - - var nBones = this.bones.length; - - if ( this.useVertexTexture ) { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones (8 * 8 / 4) - // 16x16 pixel texture max 64 bones (16 * 16 / 4) - // 32x32 pixel texture max 256 bones (32 * 32 / 4) - // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - - var size; - - if ( nBones > 256 ) - size = 64; - else if ( nBones > 64 ) - size = 32; - else if ( nBones > 16 ) - size = 16; - else - size = 8; - - this.boneTextureWidth = size; - this.boneTextureHeight = size; - - this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel - this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); - this.boneTexture.minFilter = THREE.NearestFilter; - this.boneTexture.magFilter = THREE.NearestFilter; - this.boneTexture.generateMipmaps = false; - this.boneTexture.flipY = false; - - } else { - - this.boneMatrices = new Float32Array( 16 * nBones ); - - } - - this.pose(); - - } - -}; - -THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.SkinnedMesh.prototype.addBone = function( bone ) { - - if ( bone === undefined ) { - - bone = new THREE.Bone( this ); - - } - - this.bones.push( bone ); - - return bone; - -}; - -THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { - - var offsetMatrix = new THREE.Matrix4(); - - return function ( force ) { - - this.matrixAutoUpdate && this.updateMatrix(); - - // update matrixWorld - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent ) { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } else { - - this.matrixWorld.copy( this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; - - if ( child instanceof THREE.Bone ) { - - child.update( this.identityMatrix, false ); - - } else { - - child.updateMatrixWorld( true ); - - } - - } - - // make a snapshot of the bones' rest position - - if ( this.boneInverses == undefined ) { - - this.boneInverses = []; - - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - - var inverse = new THREE.Matrix4(); - - inverse.getInverse( this.bones[ b ].skinMatrix ); - - this.boneInverses.push( inverse ); - - } - - } - - // 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; - - // TODO: we could get rid of this multiplication step if the skinMatrix - // was already representing the offset; however, this requires some - // major changes to the animation system - - offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); - offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); - - } - - if ( this.useVertexTexture ) { - - this.boneTexture.needsUpdate = true; - - } - - }; - -}(); - -THREE.SkinnedMesh.prototype.pose = function () { - - this.updateMatrixWorld( true ); - - this.normalizeSkinWeights(); - -}; - -THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - - if ( this.geometry instanceof THREE.Geometry ) { - - for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - - var sw = this.geometry.skinWeights[ i ]; - - var scale = 1.0 / sw.lengthManhattan(); - - if ( scale !== Infinity ) { - - sw.multiplyScalar( scale ); - - } else { - - sw.set( 1 ); // this will be normalized by the shader anyway - - } - - } - - } else { - - // skinning weights assumed to be normalized for THREE.BufferGeometry - - } - -}; - -THREE.SkinnedMesh.prototype.clone = function ( object ) { - - if ( object === undefined ) { - - object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); - - } - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphAnimMesh = function ( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); - - // API - - this.duration = 1000; // milliseconds - this.mirroredLoop = false; - this.time = 0; - - // internals - - this.lastKeyframe = 0; - this.currentKeyframe = 0; - - this.direction = 1; - this.directionBackwards = false; - - this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); - -}; - -THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { - - this.startKeyframe = start; - this.endKeyframe = end; - - this.length = this.endKeyframe - this.startKeyframe + 1; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - - this.direction = 1; - this.directionBackwards = false; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - - this.direction = -1; - this.directionBackwards = true; - -}; - -THREE.MorphAnimMesh.prototype.parseAnimations = function () { - - var geometry = this.geometry; - - if ( ! geometry.animations ) geometry.animations = {}; - - var firstAnimation, animations = geometry.animations; - - var pattern = /([a-z]+)(\d+)/; - - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - - var morph = geometry.morphTargets[ i ]; - var parts = morph.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - var label = parts[ 1 ]; - var num = parts[ 2 ]; - - if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; - - var animation = animations[ label ]; - - if ( i < animation.start ) animation.start = i; - if ( i > animation.end ) animation.end = i; - - if ( ! firstAnimation ) firstAnimation = label; - - } - - } - - geometry.firstAnimation = firstAnimation; - -}; - -THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { - - if ( ! this.geometry.animations ) this.geometry.animations = {}; - - this.geometry.animations[ label ] = { start: start, end: end }; - -}; - -THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { - - var animation = this.geometry.animations[ label ]; - - if ( animation ) { - - this.setFrameRange( animation.start, animation.end ); - this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); - this.time = 0; - - } else { - - console.warn( "animation[" + label + "] undefined" ); - - } - -}; - -THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { - - var frameTime = this.duration / this.length; - - this.time += this.direction * delta; - - if ( this.mirroredLoop ) { - - if ( this.time > this.duration || this.time < 0 ) { - - this.direction *= -1; - - if ( this.time > this.duration ) { - - this.time = this.duration; - this.directionBackwards = true; - - } - - if ( this.time < 0 ) { - - this.time = 0; - this.directionBackwards = false; - - } - - } - - } else { - - this.time = this.time % this.duration; - - if ( this.time < 0 ) this.time += this.duration; - - } - - var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); - - if ( keyframe !== this.currentKeyframe ) { - - this.morphTargetInfluences[ this.lastKeyframe ] = 0; - this.morphTargetInfluences[ this.currentKeyframe ] = 1; - - this.morphTargetInfluences[ keyframe ] = 0; - - this.lastKeyframe = this.currentKeyframe; - this.currentKeyframe = keyframe; - - } - - var mix = ( this.time % frameTime ) / frameTime; - - if ( this.directionBackwards ) { - - mix = 1 - mix; - - } - - this.morphTargetInfluences[ this.currentKeyframe ] = mix; - this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; - -}; - -THREE.MorphAnimMesh.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); - - object.duration = this.duration; - object.mirroredLoop = this.mirroredLoop; - object.time = this.time; - - object.lastKeyframe = this.lastKeyframe; - object.currentKeyframe = this.currentKeyframe; - - object.direction = this.direction; - object.directionBackwards = this.directionBackwards; - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LOD = function () { - - THREE.Object3D.call( this ); - - this.objects = []; - -}; - - -THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.LOD.prototype.addLevel = function ( object, distance ) { - - if ( distance === undefined ) distance = 0; - - distance = Math.abs( distance ); - - for ( var l = 0; l < this.objects.length; l ++ ) { - - if ( distance < this.objects[ l ].distance ) { - - break; - - } - - } - - this.objects.splice( l, 0, { distance: distance, object: object } ); - this.add( object ); - -}; - -THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance < this.objects[ i ].distance ) { - - break; - - } - - } - - return this.objects[ i - 1 ].object; - -}; - -THREE.LOD.prototype.update = function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( camera ) { - - if ( this.objects.length > 1 ) { - - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); - - var distance = v1.distanceTo( v2 ); - - this.objects[ 0 ].object.visible = true; - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance >= this.objects[ i ].distance ) { - - this.objects[ i - 1 ].object.visible = false; - this.objects[ i ].object.visible = true; - - } else { - - break; - - } - - } - - for( ; i < l; i ++ ) { - - this.objects[ i ].object.visible = false; - - } - - } - - }; - -}(); - -THREE.LOD.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.LOD(); - - THREE.Object3D.prototype.clone.call( this, object ); - - for ( var i = 0, l = this.objects.length; i < l; i ++ ) { - var x = this.objects[i].object.clone(); - x.visible = i === 0; - object.addLevel( x, this.objects[i].distance ); - } - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Sprite = ( function () { - - var vertices = new THREE.Float32Attribute( 3, 3 ); - vertices.set( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] ); - - var geometry = new THREE.BufferGeometry(); - geometry.addAttribute( 'position', vertices ); - - return function ( material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry; - this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - - }; - -} )(); - -THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); - -/* - * Custom update matrix - */ - -THREE.Sprite.prototype.updateMatrix = function () { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - -}; - -THREE.Sprite.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Sprite( this.material ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -// Backwards compatibility - -THREE.Particle = THREE.Sprite; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Scene = function () { - - THREE.Object3D.call( this ); - - this.fog = null; - this.overrideMaterial = null; - - this.autoUpdate = true; // checked by the renderer - this.matrixAutoUpdate = false; - - this.__lights = []; - - this.__objectsAdded = []; - this.__objectsRemoved = []; - -}; - -THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Scene.prototype.__addObject = function ( object ) { - - if ( object instanceof THREE.Light ) { - - if ( this.__lights.indexOf( object ) === - 1 ) { - - this.__lights.push( object ); - - } - - if ( object.target && object.target.parent === undefined ) { - - this.add( object.target ); - - } - - } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { - - this.__objectsAdded.push( object ); - - // check if previously removed - - var i = this.__objectsRemoved.indexOf( object ); - - if ( i !== -1 ) { - - this.__objectsRemoved.splice( i, 1 ); - - } - - } - - this.dispatchEvent( { type: 'objectAdded', object: object } ); - object.dispatchEvent( { type: 'addedToScene', scene: this } ); - - for ( var c = 0; c < object.children.length; c ++ ) { - - this.__addObject( object.children[ c ] ); - - } - -}; - -THREE.Scene.prototype.__removeObject = function ( object ) { - - if ( object instanceof THREE.Light ) { - - var i = this.__lights.indexOf( object ); - - if ( i !== -1 ) { - - this.__lights.splice( i, 1 ); - - } - - if ( object.shadowCascadeArray ) { - - for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { - - this.__removeObject( object.shadowCascadeArray[ x ] ); - - } - - } - - } else if ( !( object instanceof THREE.Camera ) ) { - - this.__objectsRemoved.push( object ); - - // check if previously added - - var i = this.__objectsAdded.indexOf( object ); - - if ( i !== -1 ) { - - this.__objectsAdded.splice( i, 1 ); - - } - - } - - this.dispatchEvent( { type: 'objectRemoved', object: object } ); - object.dispatchEvent( { type: 'removedFromScene', scene: this } ); - - for ( var c = 0; c < object.children.length; c ++ ) { - - this.__removeObject( object.children[ c ] ); - - } - -}; - -THREE.Scene.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Scene(); - - THREE.Object3D.prototype.clone.call(this, object); - - if ( this.fog !== null ) object.fog = this.fog.clone(); - if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); - - object.autoUpdate = this.autoUpdate; - object.matrixAutoUpdate = this.matrixAutoUpdate; - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Fog = function ( color, near, far ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; - -}; - -THREE.Fog.prototype.clone = function () { - - return new THREE.Fog( this.color.getHex(), this.near, this.far ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.FogExp2 = function ( color, density ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; - -}; - -THREE.FogExp2.prototype.clone = function () { - - return new THREE.FogExp2( this.color.getHex(), this.density ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CanvasRenderer = function ( parameters ) { - - console.log( 'THREE.CanvasRenderer', THREE.REVISION ); - - var smoothstep = THREE.Math.smoothstep; - - parameters = parameters || {}; - - var _this = this, - _renderData, _elements, _lights, - _projector = new THREE.Projector(), - - _canvas = parameters.canvas !== undefined - ? parameters.canvas - : document.createElement( 'canvas' ), - - _canvasWidth = _canvas.width, - _canvasHeight = _canvas.height, - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), - - _context = _canvas.getContext( '2d', { - alpha: parameters.alpha === true - } ), - - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0, - - _contextGlobalAlpha = 1, - _contextGlobalCompositeOperation = 0, - _contextStrokeStyle = null, - _contextFillStyle = null, - _contextLineWidth = null, - _contextLineCap = null, - _contextLineJoin = null, - _contextDashSize = null, - _contextGapSize = 0, - - _camera, - - _v1, _v2, _v3, _v4, - _v5 = new THREE.RenderableVertex(), - _v6 = new THREE.RenderableVertex(), - - _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, - _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, - - _color = new THREE.Color(), - _color1 = new THREE.Color(), - _color2 = new THREE.Color(), - _color3 = new THREE.Color(), - _color4 = new THREE.Color(), - - _diffuseColor = new THREE.Color(), - _emissiveColor = new THREE.Color(), - - _lightColor = new THREE.Color(), - - _patterns = {}, - - _image, _uvs, - _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, - - _clipBox = new THREE.Box2(), - _clearBox = new THREE.Box2(), - _elemBox = new THREE.Box2(), - - _ambientLight = new THREE.Color(), - _directionalLights = new THREE.Color(), - _pointLights = new THREE.Color(), - - _vector3 = new THREE.Vector3(), // Needed for PointLight - _centroid = new THREE.Vector3(), - _normal = new THREE.Vector3(), - _normalViewMatrix = new THREE.Matrix3(); - - // dash+gap fallbacks for Firefox and everything else - - if ( _context.setLineDash === undefined ) { - - if ( _context.mozDash !== undefined ) { - - _context.setLineDash = function ( values ) { - - _context.mozDash = values[ 0 ] !== null ? values : null; - - } - - } else { - - _context.setLineDash = function () {} - - } - - } - - this.domElement = _canvas; - - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; - - this.autoClear = true; - this.sortObjects = true; - this.sortElements = true; - - this.info = { - - render: { - - vertices: 0, - faces: 0 - - } - - } - - // WebGLRenderer compatibility - - this.supportsVertexTextures = function () {}; - this.setFaceCulling = function () {}; - - this.setSize = function ( width, height, updateStyle ) { - - _canvasWidth = width * this.devicePixelRatio; - _canvasHeight = height * this.devicePixelRatio; - - _canvas.width = _canvasWidth; - _canvas.height = _canvasHeight; - - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); - - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { - - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; - - } - - _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ), - _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); - _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - _contextGlobalAlpha = 1; - _contextGlobalCompositeOperation = 0; - _contextStrokeStyle = null; - _contextFillStyle = null; - _contextLineWidth = null; - _contextLineCap = null; - _contextLineJoin = null; - - this.setViewport( 0, 0, width, height ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - _context.setTransform( width / _canvasWidth, 0, 0, - height / _canvasHeight, x, _canvasHeight - y ); - _context.translate( _canvasWidthHalf, _canvasHeightHalf ); - - }; - - this.setScissor = function () {}; - this.enableScissorTest = function () {}; - - this.setClearColor = function ( color, alpha ) { - - _clearColor.set( color ); - _clearAlpha = alpha !== undefined ? alpha : 1; - - _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); - _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - }; - - this.setClearColorHex = function ( hex, alpha ) { - - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); - - }; - - this.getMaxAnisotropy = function () { - - return 0; - - }; - - this.clear = function () { - - if ( _clearBox.empty() === false ) { - - _clearBox.intersect( _clipBox ); - _clearBox.expandByScalar( 2 ); - - if ( _clearAlpha < 1 ) { - - _context.clearRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); - - } - - if ( _clearAlpha > 0 ) { - - setBlending( THREE.NormalBlending ); - setOpacity( 1 ); - - setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); - - _context.fillRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); - - } - - _clearBox.makeEmpty(); - - } - - }; - - // compatibility - - this.clearColor = function () {}; - this.clearDepth = function () {}; - this.clearStencil = function () {}; - - this.render = function ( scene, camera ) { - - if ( camera instanceof THREE.Camera === false ) { - - console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - if ( this.autoClear === true ) this.clear(); - - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - - _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); - _elements = _renderData.elements; - _lights = _renderData.lights; - _camera = camera; - - _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); - - /* DEBUG - setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); - _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); - */ - - calculateLights(); - - for ( var e = 0, el = _elements.length; e < el; e ++ ) { - - var element = _elements[ e ]; - - var material = element.material; - - if ( material === undefined || material.visible === false ) continue; - - _elemBox.makeEmpty(); - - if ( element instanceof THREE.RenderableSprite ) { - - _v1 = element; - _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; - - renderSprite( _v1, element, material ); - - } else if ( element instanceof THREE.RenderableLine ) { - - _v1 = element.v1; _v2 = element.v2; - - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; - - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen - ] ); - - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { - - renderLine( _v1, _v2, element, material ); - - } - - } else if ( element instanceof THREE.RenderableFace ) { - - _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; - - if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; - if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; - if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; - - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; - _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; - - if ( material.overdraw > 0 ) { - - expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); - expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); - expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); - - } - - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen, - _v3.positionScreen - ] ); - - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { - - renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); - - } - - } - - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); - _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); - */ - - _clearBox.union( _elemBox ); - - } - - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); - _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); - */ - - // _context.setTransform( 1, 0, 0, 1, 0, 0 ); - - }; - - // - - function calculateLights() { - - _ambientLight.setRGB( 0, 0, 0 ); - _directionalLights.setRGB( 0, 0, 0 ); - _pointLights.setRGB( 0, 0, 0 ); - - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { - - var light = _lights[ l ]; - var lightColor = light.color; - - if ( light instanceof THREE.AmbientLight ) { - - _ambientLight.add( lightColor ); - - } else if ( light instanceof THREE.DirectionalLight ) { - - // for sprites - - _directionalLights.add( lightColor ); - - } else if ( light instanceof THREE.PointLight ) { - - // for sprites - - _pointLights.add( lightColor ); - - } - - } - - } - - function calculateLight( position, normal, color ) { - - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { - - var light = _lights[ l ]; - - _lightColor.copy( light.color ); - - if ( light instanceof THREE.DirectionalLight ) { - - var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); - - var amount = normal.dot( lightPosition ); - - if ( amount <= 0 ) continue; - - amount *= light.intensity; - - color.add( _lightColor.multiplyScalar( amount ) ); - - } else if ( light instanceof THREE.PointLight ) { - - var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); - - var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); - - if ( amount <= 0 ) continue; - - amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); - - if ( amount == 0 ) continue; - - amount *= light.intensity; - - color.add( _lightColor.multiplyScalar( amount ) ); - - } - - } - - } - - function renderSprite( v1, element, material ) { - - setOpacity( material.opacity ); - setBlending( material.blending ); - - var scaleX = element.scale.x * _canvasWidthHalf; - var scaleY = element.scale.y * _canvasHeightHalf; - - var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite - _elemBox.min.set( v1.x - dist, v1.y - dist ); - _elemBox.max.set( v1.x + dist, v1.y + dist ); - - if ( material instanceof THREE.SpriteMaterial || - material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility - - var texture = material.map; - - if ( texture !== null ) { - - if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { - - if ( texture.image !== undefined && texture.image.width > 0 ) { - - textureToPattern( texture ); - - } - - texture.addEventListener( 'update', onTextureUpdate ); - - } - - var pattern = _patterns[ texture.id ]; - - if ( pattern !== undefined ) { - - setFillStyle( pattern ); - - } else { - - setFillStyle( 'rgba( 0, 0, 0, 1 )' ); - - } - - // - - var bitmap = texture.image; - - var ox = bitmap.width * texture.offset.x; - var oy = bitmap.height * texture.offset.y; - - var sx = bitmap.width * texture.repeat.x; - var sy = bitmap.height * texture.repeat.y; - - var cx = scaleX / sx; - var cy = scaleY / sy; - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.translate( - scaleX / 2, - scaleY / 2 ); - _context.scale( cx, cy ); - _context.translate( - ox, - oy ); - _context.fillRect( ox, oy, sx, sy ); - _context.restore(); - - } else { // no texture - - setFillStyle( material.color.getStyle() ); - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.scale( scaleX, - scaleY ); - _context.fillRect( - 0.5, - 0.5, 1, 1 ); - _context.restore(); - - } - - } else if ( material instanceof THREE.SpriteCanvasMaterial ) { - - setStrokeStyle( material.color.getStyle() ); - setFillStyle( material.color.getStyle() ); - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.scale( scaleX, scaleY ); - - material.program( _context ); - - _context.restore(); - - } - - /* DEBUG - setStrokeStyle( 'rgb(255,255,0)' ); - _context.beginPath(); - _context.moveTo( v1.x - 10, v1.y ); - _context.lineTo( v1.x + 10, v1.y ); - _context.moveTo( v1.x, v1.y - 10 ); - _context.lineTo( v1.x, v1.y + 10 ); - _context.stroke(); - */ - - } - - function renderLine( v1, v2, element, material ) { - - setOpacity( material.opacity ); - setBlending( material.blending ); - - _context.beginPath(); - _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); - _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); - - if ( material instanceof THREE.LineBasicMaterial ) { - - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); - - if ( material.vertexColors !== THREE.VertexColors ) { - - setStrokeStyle( material.color.getStyle() ); - - } else { - - var colorStyle1 = element.vertexColors[0].getStyle(); - var colorStyle2 = element.vertexColors[1].getStyle(); - - if ( colorStyle1 === colorStyle2 ) { - - setStrokeStyle( colorStyle1 ); - - } else { - - try { - - var grad = _context.createLinearGradient( - v1.positionScreen.x, - v1.positionScreen.y, - v2.positionScreen.x, - v2.positionScreen.y - ); - grad.addColorStop( 0, colorStyle1 ); - grad.addColorStop( 1, colorStyle2 ); - - } catch ( exception ) { - - grad = colorStyle1; - - } - - setStrokeStyle( grad ); - - } - - } - - _context.stroke(); - _elemBox.expandByScalar( material.linewidth * 2 ); - - } else if ( material instanceof THREE.LineDashedMaterial ) { - - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); - setStrokeStyle( material.color.getStyle() ); - setDashAndGap( material.dashSize, material.gapSize ); - - _context.stroke(); - - _elemBox.expandByScalar( material.linewidth * 2 ); - - setDashAndGap( null, null ); - - } - - } - - function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { - - _this.info.render.vertices += 3; - _this.info.render.faces ++; - - setOpacity( material.opacity ); - setBlending( material.blending ); - - _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; - _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; - _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; - - drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); - - if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { - - _diffuseColor.copy( material.color ); - _emissiveColor.copy( material.emissive ); - - if ( material.vertexColors === THREE.FaceColors ) { - - _diffuseColor.multiply( element.color ); - - } - - _color.copy( _ambientLight ); - - _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 ); - - calculateLight( _centroid, element.normalModel, _color ); - - _color.multiply( _diffuseColor ).add( _emissiveColor ); + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * 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, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); +THREE.MeshPhongMaterial = function ( parameters ) { - } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + THREE.Material.call( this ); - if ( material.map !== null ) { + this.type = 'MeshPhongMaterial'; - if ( material.map.mapping instanceof THREE.UVMapping ) { + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0x111111 ); + this.shininess = 30; - _uvs = element.uvs; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); + this.metal = false; - } + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - } else if ( material.envMap !== null ) { + this.map = null; - if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { + this.lightMap = null; - _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); - _uv1x = 0.5 * _normal.x + 0.5; - _uv1y = 0.5 * _normal.y + 0.5; + this.bumpMap = null; + this.bumpScale = 1; - _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); - _uv2x = 0.5 * _normal.x + 0.5; - _uv2y = 0.5 * _normal.y + 0.5; + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); - _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); - _uv3x = 0.5 * _normal.x + 0.5; - _uv3y = 0.5 * _normal.y + 0.5; + this.specularMap = null; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + this.alphaMap = null; - } else if ( material.envMap.mapping instanceof THREE.SphericalRefractionMapping ) { + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); - _uv1x = - 0.5 * _normal.x + 0.5; - _uv1y = - 0.5 * _normal.y + 0.5; + this.fog = true; - _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); - _uv2x = - 0.5 * _normal.x + 0.5; - _uv2y = - 0.5 * _normal.y + 0.5; + this.shading = THREE.SmoothShading; - _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); - _uv3x = - 0.5 * _normal.x + 0.5; - _uv3y = - 0.5 * _normal.y + 0.5; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + this.vertexColors = THREE.NoColors; - } + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + this.setValues( parameters ); - } else { +}; - _color.copy( material.color ); +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; - if ( material.vertexColors === THREE.FaceColors ) { +THREE.MeshPhongMaterial.prototype.clone = function () { - _color.multiply( element.color ); + var material = new THREE.MeshPhongMaterial(); - } + THREE.Material.prototype.clone.call( this, material ); - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); + material.color.copy( this.color ); + material.emissive.copy( this.emissive ); + material.specular.copy( this.specular ); + material.shininess = this.shininess; - } + material.metal = this.metal; - } else if ( material instanceof THREE.MeshDepthMaterial ) { + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); - _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far ); + material.map = this.map; - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); + material.lightMap = this.lightMap; - } else if ( material instanceof THREE.MeshNormalMaterial ) { + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; - _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); - _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + material.specularMap = this.specularMap; - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); + material.alphaMap = this.alphaMap; - } else { + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - _color.setRGB( 1, 1, 1 ); + material.fog = this.fog; - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); + material.shading = this.shading; - } + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - } + material.vertexColors = this.vertexColors; - // + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - function drawTriangle( x0, y0, x1, y1, x2, y2 ) { + return material; - _context.beginPath(); - _context.moveTo( x0, y0 ); - _context.lineTo( x1, y1 ); - _context.lineTo( x2, y2 ); - _context.closePath(); +}; - } +// File:src/materials/MeshDepthMaterial.js - function strokePath( color, linewidth, linecap, linejoin ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ - setLineWidth( linewidth ); - setLineCap( linecap ); - setLineJoin( linejoin ); - setStrokeStyle( color.getStyle() ); +THREE.MeshDepthMaterial = function ( parameters ) { - _context.stroke(); + THREE.Material.call( this ); - _elemBox.expandByScalar( linewidth * 2 ); + this.type = 'MeshDepthMaterial'; - } + this.morphTargets = false; + this.wireframe = false; + this.wireframeLinewidth = 1; - function fillPath( color ) { + this.setValues( parameters ); - setFillStyle( color.getStyle() ); - _context.fill(); +}; - } +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial; - function onTextureUpdate ( event ) { +THREE.MeshDepthMaterial.prototype.clone = function () { - textureToPattern( event.target ); + var material = new THREE.MeshDepthMaterial(); - } + THREE.Material.prototype.clone.call( this, material ); - function textureToPattern( texture ) { + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - var repeatX = texture.wrapS === THREE.RepeatWrapping; - var repeatY = texture.wrapT === THREE.RepeatWrapping; + return material; - var image = texture.image; +}; - var canvas = document.createElement( 'canvas' ); - canvas.width = image.width; - canvas.height = image.height; +// File:src/materials/MeshNormalMaterial.js - var context = canvas.getContext( '2d' ); - context.setTransform( 1, 0, 0, - 1, 0, image.height ); - context.drawImage( image, 0, 0 ); +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: , + * + * shading: THREE.FlatShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ - _patterns[ texture.id ] = _context.createPattern( - canvas, repeatX === true && repeatY === true - ? 'repeat' - : repeatX === true && repeatY === false - ? 'repeat-x' - : repeatX === false && repeatY === true - ? 'repeat-y' - : 'no-repeat' - ); +THREE.MeshNormalMaterial = function ( parameters ) { - } + THREE.Material.call( this, parameters ); - function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { + this.type = 'MeshNormalMaterial'; - if ( texture instanceof THREE.DataTexture ) return; + this.wireframe = false; + this.wireframeLinewidth = 1; - if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { + this.morphTargets = false; - if ( texture.image !== undefined && texture.image.width > 0 ) { + this.setValues( parameters ); - textureToPattern( texture ); +}; - } +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial; - texture.addEventListener( 'update', onTextureUpdate ); +THREE.MeshNormalMaterial.prototype.clone = function () { - } + var material = new THREE.MeshNormalMaterial(); - var pattern = _patterns[ texture.id ]; + THREE.Material.prototype.clone.call( this, material ); - if ( pattern !== undefined ) { + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - setFillStyle( pattern ); + return material; - } else { +}; - setFillStyle( 'rgba(0,0,0,1)' ); - _context.fill(); +// File:src/materials/MeshFaceMaterial.js - return; +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.MeshFaceMaterial = function ( materials ) { - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + this.uuid = THREE.Math.generateUUID(); - var a, b, c, d, e, f, det, idet, - offsetX = texture.offset.x / texture.repeat.x, - offsetY = texture.offset.y / texture.repeat.y, - width = texture.image.width * texture.repeat.x, - height = texture.image.height * texture.repeat.y; + this.type = 'MeshFaceMaterial'; + + this.materials = materials instanceof Array ? materials : []; - u0 = ( u0 + offsetX ) * width; - v0 = ( v0 + offsetY ) * height; +}; - u1 = ( u1 + offsetX ) * width; - v1 = ( v1 + offsetY ) * height; +THREE.MeshFaceMaterial.prototype = { - u2 = ( u2 + offsetX ) * width; - v2 = ( v2 + offsetY ) * height; + constructor: THREE.MeshFaceMaterial, - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; + toJSON: function () { - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type, + materials: [] + }; - det = u1 * v2 - u2 * v1; + for ( var i = 0, l = this.materials.length; i < l; i ++ ) { - if ( det === 0 ) return; + output.materials.push( this.materials[ i ].toJSON() ); - idet = 1 / det; + } - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; + return output; - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; + }, - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.fill(); - _context.restore(); + clone: function () { - } + var material = new THREE.MeshFaceMaterial(); - function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { + for ( var i = 0; i < this.materials.length; i ++ ) { - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + material.materials.push( this.materials[ i ].clone() ); - var a, b, c, d, e, f, det, idet, - width = image.width - 1, - height = image.height - 1; + } - u0 *= width; v0 *= height; - u1 *= width; v1 *= height; - u2 *= width; v2 *= height; + return material; - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; + } - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; +}; - det = u1 * v2 - u2 * v1; +// File:src/materials/PointCloudMaterial.js - idet = 1 / det; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * size: , + * sizeAttenuation: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * vertexColors: , + * + * fog: + * } + */ - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; +THREE.PointCloudMaterial = function ( parameters ) { - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; + THREE.Material.call( this ); - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.clip(); - _context.drawImage( image, 0, 0 ); - _context.restore(); + this.type = 'PointCloudMaterial'; - } + this.color = new THREE.Color( 0xffffff ); - // Hide anti-alias gaps + this.map = null; - function expand( v1, v2, pixels ) { + this.size = 1; + this.sizeAttenuation = true; - var x = v2.x - v1.x, y = v2.y - v1.y, - det = x * x + y * y, idet; + this.vertexColors = THREE.NoColors; - if ( det === 0 ) return; + this.fog = true; - idet = pixels / Math.sqrt( det ); + this.setValues( parameters ); - x *= idet; y *= idet; +}; - v2.x += x; v2.y += y; - v1.x -= x; v1.y -= y; +THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial; - } +THREE.PointCloudMaterial.prototype.clone = function () { - // Context cached methods. + var material = new THREE.PointCloudMaterial(); - function setOpacity( value ) { + THREE.Material.prototype.clone.call( this, material ); - if ( _contextGlobalAlpha !== value ) { + material.color.copy( this.color ); - _context.globalAlpha = value; - _contextGlobalAlpha = value; + material.map = this.map; - } + material.size = this.size; + material.sizeAttenuation = this.sizeAttenuation; - } + material.vertexColors = this.vertexColors; - function setBlending( value ) { + material.fog = this.fog; - if ( _contextGlobalCompositeOperation !== value ) { + return material; - if ( value === THREE.NormalBlending ) { +}; - _context.globalCompositeOperation = 'source-over'; +// backwards compatibility - } else if ( value === THREE.AdditiveBlending ) { +THREE.ParticleBasicMaterial = function ( parameters ) { - _context.globalCompositeOperation = 'lighter'; + THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); + return new THREE.PointCloudMaterial( parameters ); - } else if ( value === THREE.SubtractiveBlending ) { +}; - _context.globalCompositeOperation = 'darker'; +THREE.ParticleSystemMaterial = function ( parameters ) { - } + THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); + return new THREE.PointCloudMaterial( parameters ); - _contextGlobalCompositeOperation = value; +}; - } +// File:src/materials/ShaderMaterial.js - } +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * defines: { "label" : "value" }, + * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, + * + * fragmentShader: , + * vertexShader: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * lights: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ - function setLineWidth( value ) { +THREE.ShaderMaterial = function ( parameters ) { - if ( _contextLineWidth !== value ) { + THREE.Material.call( this ); - _context.lineWidth = value; - _contextLineWidth = value; + this.type = 'ShaderMaterial'; - } + this.defines = {}; + this.uniforms = {}; + this.attributes = null; - } + 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}'; - function setLineCap( value ) { + this.shading = THREE.SmoothShading; - // "butt", "round", "square" + this.linewidth = 1; - if ( _contextLineCap !== value ) { + this.wireframe = false; + this.wireframeLinewidth = 1; - _context.lineCap = value; - _contextLineCap = value; + this.fog = false; // set to use scene fog - } + this.lights = false; // set to use scene lights - } + this.vertexColors = THREE.NoColors; // set to use "color" attribute stream - function setLineJoin( value ) { + this.skinning = false; // set to use skinning attribute streams - // "round", "bevel", "miter" + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals - if ( _contextLineJoin !== value ) { + // 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 ] + }; - _context.lineJoin = value; - _contextLineJoin = value; + this.index0AttributeName = undefined; - } + this.setValues( parameters ); - } +}; - function setStrokeStyle( value ) { +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial; - if ( _contextStrokeStyle !== value ) { +THREE.ShaderMaterial.prototype.clone = function () { - _context.strokeStyle = value; - _contextStrokeStyle = value; + var material = new THREE.ShaderMaterial(); - } + THREE.Material.prototype.clone.call( this, material ); - } + material.fragmentShader = this.fragmentShader; + material.vertexShader = this.vertexShader; - function setFillStyle( value ) { + material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); - if ( _contextFillStyle !== value ) { + material.attributes = this.attributes; + material.defines = this.defines; - _context.fillStyle = value; - _contextFillStyle = value; + material.shading = this.shading; - } + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - } + material.fog = this.fog; - function setDashAndGap( dashSizeValue, gapSizeValue ) { + material.lights = this.lights; - if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { + material.vertexColors = this.vertexColors; - _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); - _contextDashSize = dashSizeValue; - _contextGapSize = gapSizeValue; + material.skinning = this.skinning; - } + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - } + return material; }; +// File:src/materials/RawShaderMaterial.js + /** - * Shader chunks for WebLG Shader library - * - * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ */ -THREE.ShaderChunk = { - - // FOG - - fog_pars_fragment: [ - - "#ifdef USE_FOG", - - " uniform vec3 fogColor;", - - " #ifdef FOG_EXP2", - - " uniform float fogDensity;", - - " #else", - - " uniform float fogNear;", - " uniform float fogFar;", - - " #endif", - - "#endif" - - ].join("\n"), - - fog_fragment: [ - - "#ifdef USE_FOG", - - " #ifdef USE_LOGDEPTHBUF_EXT", - - " float depth = gl_FragDepthEXT / gl_FragCoord.w;", - - " #else", - - " float depth = gl_FragCoord.z / gl_FragCoord.w;", - - " #endif", - - " #ifdef FOG_EXP2", - - " const float LOG2 = 1.442695;", - " float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", - " fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", - - " #else", - - " float fogFactor = smoothstep( fogNear, fogFar, depth );", +THREE.RawShaderMaterial = function ( parameters ) { - " #endif", + THREE.ShaderMaterial.call( this, parameters ); - " gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + this.type = 'RawShaderMaterial'; - "#endif" +}; - ].join("\n"), +THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); +THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial; - // ENVIRONMENT MAP +THREE.RawShaderMaterial.prototype.clone = function () { - envmap_pars_fragment: [ + var material = new THREE.RawShaderMaterial(); - "#ifdef USE_ENVMAP", + THREE.ShaderMaterial.prototype.clone.call( this, material ); - " uniform float reflectivity;", - " uniform samplerCube envMap;", - " uniform float flipEnvMap;", - " uniform int combine;", + return material; - " #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", +}; - " uniform bool useRefract;", - " uniform float refractionRatio;", +// File:src/materials/SpriteMaterial.js - " #else", +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: + * } + */ - " varying vec3 vReflect;", +THREE.SpriteMaterial = function ( parameters ) { - " #endif", + THREE.Material.call( this ); - "#endif" + this.type = 'SpriteMaterial'; - ].join("\n"), + this.color = new THREE.Color( 0xffffff ); + this.map = null; - envmap_fragment: [ + this.rotation = 0; - "#ifdef USE_ENVMAP", + this.fog = false; - " vec3 reflectVec;", + // set parameters - " #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + this.setValues( parameters ); - " vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", +}; - // http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations - // "Transforming Normal Vectors with the Inverse Transformation" +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; - " vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );", +THREE.SpriteMaterial.prototype.clone = function () { - " if ( useRefract ) {", + var material = new THREE.SpriteMaterial(); - " reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );", + THREE.Material.prototype.clone.call( this, material ); - " } else { ", + material.color.copy( this.color ); + material.map = this.map; - " reflectVec = reflect( cameraToVertex, worldNormal );", + material.rotation = this.rotation; - " }", + material.fog = this.fog; - " #else", + return material; - " reflectVec = vReflect;", +}; - " #endif", +// File:src/textures/Texture.js - " #ifdef DOUBLE_SIDED", +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ - " float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - " vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - " #else", + Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } ); - " vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + this.uuid = THREE.Math.generateUUID(); - " #endif", + this.name = ''; + this.sourceFile = ''; - " #ifdef GAMMA_INPUT", + this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; + this.mipmaps = []; - " cubeColor.xyz *= cubeColor.xyz;", + this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; - " #endif", + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; - " if ( combine == 1 ) {", + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; - " gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - " } else if ( combine == 2 ) {", + this.format = format !== undefined ? format : THREE.RGBAFormat; + this.type = type !== undefined ? type : THREE.UnsignedByteType; - " gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); - " } else {", + 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) - " gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", + this._needsUpdate = false; + this.onUpdate = null; - " }", +}; - "#endif" +THREE.Texture.DEFAULT_IMAGE = undefined; +THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; - ].join("\n"), +THREE.Texture.prototype = { - envmap_pars_vertex: [ + constructor: THREE.Texture, - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + get needsUpdate () { - " varying vec3 vReflect;", + return this._needsUpdate; - " uniform float refractionRatio;", - " uniform bool useRefract;", + }, - "#endif" + set needsUpdate ( value ) { - ].join("\n"), + if ( value === true ) this.update(); - worldpos_vertex : [ + this._needsUpdate = value; - "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", + }, - " #ifdef USE_SKINNING", + clone: function ( texture ) { - " vec4 worldPosition = modelMatrix * skinned;", + if ( texture === undefined ) texture = new THREE.Texture(); - " #endif", + texture.image = this.image; + texture.mipmaps = this.mipmaps.slice( 0 ); - " #if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + texture.mapping = this.mapping; - " vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", + texture.wrapS = this.wrapS; + texture.wrapT = this.wrapT; - " #endif", + texture.magFilter = this.magFilter; + texture.minFilter = this.minFilter; - " #if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + texture.anisotropy = this.anisotropy; - " vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + texture.format = this.format; + texture.type = this.type; - " #endif", + texture.offset.copy( this.offset ); + texture.repeat.copy( this.repeat ); - "#endif" + texture.generateMipmaps = this.generateMipmaps; + texture.premultiplyAlpha = this.premultiplyAlpha; + texture.flipY = this.flipY; + texture.unpackAlignment = this.unpackAlignment; - ].join("\n"), + return texture; - envmap_vertex : [ + }, - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + update: function () { - " vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", - " worldNormal = normalize( worldNormal );", + this.dispatchEvent( { type: 'update' } ); - " vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", + }, - " if ( useRefract ) {", + dispose: function () { - " vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", + this.dispatchEvent( { type: 'dispose' } ); - " } else {", + } - " vReflect = reflect( cameraToVertex, worldNormal );", +}; - " }", +THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); - "#endif" +THREE.TextureIdCount = 0; - ].join("\n"), +// File:src/textures/CubeTexture.js - // COLOR MAP (particles) +/** + * @author mrdoob / http://mrdoob.com/ + */ - map_particle_pars_fragment: [ +THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - "#ifdef USE_MAP", + mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; + + THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - " uniform sampler2D map;", + this.images = images; - "#endif" +}; - ].join("\n"), +THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; +THREE.CubeTexture.clone = function ( texture ) { - map_particle_fragment: [ + if ( texture === undefined ) texture = new THREE.CubeTexture(); - "#ifdef USE_MAP", + THREE.Texture.prototype.clone.call( this, texture ); - " gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", + texture.images = this.images; - "#endif" + return texture; - ].join("\n"), +}; - // COLOR MAP (triangles) +// File:src/textures/CompressedTexture.js - map_pars_vertex: [ +/** + * @author alteredq / http://alteredqualia.com/ + */ - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - " varying vec2 vUv;", - " uniform vec4 offsetRepeat;", + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "#endif" + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; - ].join("\n"), + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) - map_pars_fragment: [ + this.flipY = false; - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files - " varying vec2 vUv;", + this.generateMipmaps = false; - "#endif", +}; - "#ifdef USE_MAP", +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture; - " uniform sampler2D map;", +THREE.CompressedTexture.prototype.clone = function () { - "#endif" + var texture = new THREE.CompressedTexture(); - ].join("\n"), + THREE.Texture.prototype.clone.call( this, texture ); - map_vertex: [ + return texture; - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", +}; - " vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", +// File:src/textures/DataTexture.js - "#endif" +/** + * @author alteredq / http://alteredqualia.com/ + */ - ].join("\n"), +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - map_fragment: [ + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "#ifdef USE_MAP", + this.image = { data: data, width: width, height: height }; - " vec4 texelColor = texture2D( map, vUv );", +}; - " #ifdef GAMMA_INPUT", +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.DataTexture.prototype.constructor = THREE.DataTexture; - " texelColor.xyz *= texelColor.xyz;", +THREE.DataTexture.prototype.clone = function () { - " #endif", + var texture = new THREE.DataTexture(); - " gl_FragColor = gl_FragColor * texelColor;", + THREE.Texture.prototype.clone.call( this, texture ); - "#endif" + return texture; - ].join("\n"), +}; - // LIGHT MAP +// File:src/textures/VideoTexture.js - lightmap_pars_fragment: [ +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#ifdef USE_LIGHTMAP", +THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - " varying vec2 vUv2;", - " uniform sampler2D lightMap;", + THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "#endif" + this.generateMipmaps = false; - ].join("\n"), + var scope = this; - lightmap_pars_vertex: [ + var update = function () { - "#ifdef USE_LIGHTMAP", + requestAnimationFrame( update ); - " varying vec2 vUv2;", + if ( video.readyState === video.HAVE_ENOUGH_DATA ) { - "#endif" + scope.needsUpdate = true; - ].join("\n"), + } - lightmap_fragment: [ + }; - "#ifdef USE_LIGHTMAP", + update(); - " gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", +}; - "#endif" +THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; - ].join("\n"), +// File:src/objects/Group.js - lightmap_vertex: [ +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#ifdef USE_LIGHTMAP", +THREE.Group = function () { - " vUv2 = uv2;", + THREE.Object3D.call( this ); - "#endif" + this.type = 'Group'; - ].join("\n"), +}; - // BUMP MAP +THREE.Group.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Group.prototype.constructor = THREE.Group; - bumpmap_pars_fragment: [ +// File:src/objects/PointCloud.js - "#ifdef USE_BUMPMAP", +/** + * @author alteredq / http://alteredqualia.com/ + */ - " uniform sampler2D bumpMap;", - " uniform float bumpScale;", +THREE.PointCloud = function ( geometry, material ) { - // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen - // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + THREE.Object3D.call( this ); - // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + this.type = 'PointCloud'; - " vec2 dHdxy_fwd() {", + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } ); - " vec2 dSTdx = dFdx( vUv );", - " vec2 dSTdy = dFdy( vUv );", +}; - " float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", - " float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", - " float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", +THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype ); +THREE.PointCloud.prototype.constructor = THREE.PointCloud; - " return vec2( dBx, dBy );", +THREE.PointCloud.prototype.raycast = ( function () { - " }", + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); - " vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", + return function ( raycaster, intersects ) { - " vec3 vSigmaX = dFdx( surf_pos );", - " vec3 vSigmaY = dFdy( surf_pos );", - " vec3 vN = surf_norm;", // normalized + var object = this; + var geometry = object.geometry; + var threshold = raycaster.params.PointCloud.threshold; - " vec3 R1 = cross( vSigmaY, vN );", - " vec3 R2 = cross( vN, vSigmaX );", + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - " float fDet = dot( vSigmaX, R1 );", + if ( geometry.boundingBox !== null ) { - " vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", - " return normalize( abs( fDet ) * surf_norm - vGrad );", + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - " }", + return; - "#endif" + } - ].join("\n"), + } - // NORMAL MAP + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var position = new THREE.Vector3(); - normalmap_pars_fragment: [ + var testPoint = function ( point, index ) { - "#ifdef USE_NORMALMAP", + var rayPointDistance = ray.distanceToPoint( point ); - " uniform sampler2D normalMap;", - " uniform vec2 normalScale;", + if ( rayPointDistance < localThreshold ) { - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + var intersectPoint = ray.closestPointToPoint( point ); + intersectPoint.applyMatrix4( object.matrixWorld ); - " vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - " vec3 q0 = dFdx( eye_pos.xyz );", - " vec3 q1 = dFdy( eye_pos.xyz );", - " vec2 st0 = dFdx( vUv.st );", - " vec2 st1 = dFdy( vUv.st );", + intersects.push( { - " vec3 S = normalize( q0 * st1.t - q1 * st0.t );", - " vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", - " vec3 N = normalize( surf_norm );", + distance: distance, + distanceToRay: rayPointDistance, + point: intersectPoint.clone(), + index: index, + face: null, + object: object - " vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", - " mapN.xy = normalScale * mapN.xy;", - " mat3 tsn = mat3( S, T, N );", - " return normalize( tsn * mapN );", + } ); - " }", + } - "#endif" + }; - ].join("\n"), + if ( geometry instanceof THREE.BufferGeometry ) { - // SPECULAR MAP + var attributes = geometry.attributes; + var positions = attributes.position.array; - specularmap_pars_fragment: [ + if ( attributes.index !== undefined ) { - "#ifdef USE_SPECULARMAP", + var indices = attributes.index.array; + var offsets = geometry.offsets; - " uniform sampler2D specularMap;", + if ( offsets.length === 0 ) { - "#endif" + var offset = { + start: 0, + count: indices.length, + index: 0 + }; - ].join("\n"), + offsets = [ offset ]; - specularmap_fragment: [ + } - "float specularStrength;", + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - "#ifdef USE_SPECULARMAP", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - " vec4 texelSpecular = texture2D( specularMap, vUv );", - " specularStrength = texelSpecular.r;", + for ( var i = start, il = start + count; i < il; i ++ ) { - "#else", + var a = index + indices[ i ]; - " specularStrength = 1.0;", + position.fromArray( positions, a * 3 ); - "#endif" + testPoint( position, a ); - ].join("\n"), + } - // LIGHTS LAMBERT + } - lights_lambert_pars_vertex: [ + } else { - "uniform vec3 ambient;", - "uniform vec3 diffuse;", - "uniform vec3 emissive;", + var pointCount = positions.length / 3; - "uniform vec3 ambientLightColor;", + for ( var i = 0; i < pointCount; i ++ ) { - "#if MAX_DIR_LIGHTS > 0", + position.set( + positions[ 3 * i ], + positions[ 3 * i + 1 ], + positions[ 3 * i + 2 ] + ); - " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + testPoint( position, i ); - "#endif", + } - "#if MAX_HEMI_LIGHTS > 0", + } - " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + } else { - "#endif", + var vertices = this.geometry.vertices; - "#if MAX_POINT_LIGHTS > 0", + for ( var i = 0; i < vertices.length; i ++ ) { - " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + testPoint( vertices[ i ], i ); - "#endif", + } - "#if MAX_SPOT_LIGHTS > 0", + } - " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + }; - "#endif", +}() ); - "#ifdef WRAP_AROUND", +THREE.PointCloud.prototype.clone = function ( object ) { - " uniform vec3 wrapRGB;", + if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material ); - "#endif" + THREE.Object3D.prototype.clone.call( this, object ); - ].join("\n"), + return object; - lights_lambert_vertex: [ +}; - "vLightFront = vec3( 0.0 );", +// Backwards compatibility - "#ifdef DOUBLE_SIDED", +THREE.ParticleSystem = function ( geometry, material ) { - " vLightBack = vec3( 0.0 );", + THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); + return new THREE.PointCloud( geometry, material ); - "#endif", +}; - "transformedNormal = normalize( transformedNormal );", +// File:src/objects/Line.js - "#if MAX_DIR_LIGHTS > 0", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", +THREE.Line = function ( geometry, material, mode ) { - " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - " vec3 dirVector = normalize( lDirection.xyz );", + THREE.Object3D.call( this ); - " float dotProduct = dot( transformedNormal, dirVector );", - " vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", + this.type = 'Line'; - " #ifdef DOUBLE_SIDED", + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - " vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + this.mode = mode !== undefined ? mode : THREE.LineStrip; - " #ifdef WRAP_AROUND", +}; - " vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", +THREE.LineStrip = 0; +THREE.LinePieces = 1; - " #endif", +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Line.prototype.constructor = THREE.Line; - " #endif", +THREE.Line.prototype.raycast = ( function () { - " #ifdef WRAP_AROUND", + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - " vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - " directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", + return function ( raycaster, intersects ) { - " #ifdef DOUBLE_SIDED", + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; - " directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", + var geometry = this.geometry; - " #endif", + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - " #endif", + // Checking boundingSphere distance to ray - " vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - " #ifdef DOUBLE_SIDED", + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - " vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", + return; - " #endif", + } - "}", + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - "#endif", + var vStart = new THREE.Vector3(); + var vEnd = new THREE.Vector3(); + var interSegment = new THREE.Vector3(); + var interRay = new THREE.Vector3(); + var step = this.mode === THREE.LineStrip ? 1 : 2; - "#if MAX_POINT_LIGHTS > 0", + if ( geometry instanceof THREE.BufferGeometry ) { - " for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + var attributes = geometry.attributes; - " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - " vec3 lVector = lPosition.xyz - mvPosition.xyz;", + if ( attributes.index !== undefined ) { - " float lDistance = 1.0;", - " if ( pointLightDistance[ i ] > 0.0 )", - " lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + var indices = attributes.index.array; + var positions = attributes.position.array; + var offsets = geometry.offsets; - " lVector = normalize( lVector );", - " float dotProduct = dot( transformedNormal, lVector );", + if ( offsets.length === 0 ) { - " vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", + offsets = [ { start: 0, count: indices.length, index: 0 } ]; - " #ifdef DOUBLE_SIDED", + } - " vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + for ( var oi = 0; oi < offsets.length; oi ++) { - " #ifdef WRAP_AROUND", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - " vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + for ( var i = start; i < start + count - 1; i += step ) { - " #endif", + var a = index + indices[ i ]; + var b = index + indices[ i + 1 ]; - " #endif", + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); - " #ifdef WRAP_AROUND", + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - " vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - " pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", + if ( distSq > precisionSq ) continue; - " #ifdef DOUBLE_SIDED", + var distance = ray.origin.distanceTo( interRay ); - " pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - " #endif", + intersects.push( { - " #endif", + 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, + offsetIndex: oi, + face: null, + faceIndex: null, + object: this - " vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", + } ); - " #ifdef DOUBLE_SIDED", + } - " vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", + } - " #endif", + } else { - " }", + var positions = attributes.position.array; - "#endif", + for ( var i = 0; i < positions.length / 3 - 1; i += step ) { - "#if MAX_SPOT_LIGHTS > 0", + vStart.fromArray( positions, 3 * i ); + vEnd.fromArray( positions, 3 * i + 3 ); - " for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - " vec3 lVector = lPosition.xyz - mvPosition.xyz;", + if ( distSq > precisionSq ) continue; - " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", + var distance = ray.origin.distanceTo( interRay ); - " if ( spotEffect > spotLightAngleCos[ i ] ) {", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + intersects.push( { - " float lDistance = 1.0;", - " if ( spotLightDistance[ i ] > 0.0 )", - " lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + 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 - " lVector = normalize( lVector );", + } ); - " float dotProduct = dot( transformedNormal, lVector );", - " vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", + } - " #ifdef DOUBLE_SIDED", + } - " vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + } else if ( geometry instanceof THREE.Geometry ) { - " #ifdef WRAP_AROUND", + var vertices = geometry.vertices; + var nbVertices = vertices.length; - " vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + for ( var i = 0; i < nbVertices - 1; i += step ) { - " #endif", + var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - " #endif", + if ( distSq > precisionSq ) continue; - " #ifdef WRAP_AROUND", + var distance = ray.origin.distanceTo( interRay ); - " vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - " spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - " #ifdef DOUBLE_SIDED", + intersects.push( { - " spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", + 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 - " #endif", + } ); - " #endif", + } - " vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", + } - " #ifdef DOUBLE_SIDED", + }; - " vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", +}() ); - " #endif", +THREE.Line.prototype.clone = function ( object ) { - " }", + if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode ); - " }", + THREE.Object3D.prototype.clone.call( this, object ); - "#endif", + return object; - "#if MAX_HEMI_LIGHTS > 0", +}; - " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", +// File:src/objects/Mesh.js - " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - " vec3 lVector = normalize( lDirection.xyz );", +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ - " float dotProduct = dot( transformedNormal, lVector );", +THREE.Mesh = function ( geometry, material ) { - " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - " float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", + THREE.Object3D.call( this ); - " vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + this.type = 'Mesh'; + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - " #ifdef DOUBLE_SIDED", + this.updateMorphTargets(); - " vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", +}; - " #endif", +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Mesh.prototype.constructor = THREE.Mesh; - " }", +THREE.Mesh.prototype.updateMorphTargets = function () { - "#endif", + if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", + this.morphTargetBase = - 1; + this.morphTargetForcedOrder = []; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - "#ifdef DOUBLE_SIDED", + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - " vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - "#endif" + } - ].join("\n"), + } - // LIGHTS PHONG +}; - lights_phong_pars_vertex: [ +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + if ( this.morphTargetDictionary[ name ] !== undefined ) { - " varying vec3 vWorldPosition;", + return this.morphTargetDictionary[ name ]; - "#endif" + } - ].join("\n"), + THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); + return 0; - lights_phong_vertex: [ +}; - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", - " vWorldPosition = worldPosition.xyz;", +THREE.Mesh.prototype.raycast = ( function () { - "#endif" + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - ].join("\n"), + var vA = new THREE.Vector3(); + var vB = new THREE.Vector3(); + var vC = new THREE.Vector3(); - lights_phong_pars_fragment: [ + return function ( raycaster, intersects ) { - "uniform vec3 ambientLightColor;", + var geometry = this.geometry; - "#if MAX_DIR_LIGHTS > 0", + // Checking boundingSphere distance to ray - " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - "#endif", + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - "#if MAX_HEMI_LIGHTS > 0", + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + return; - "#endif", + } - "#if MAX_POINT_LIGHTS > 0", + // Check boundingBox before continuing - " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + if ( geometry.boundingBox !== null ) { - "#endif", + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - "#if MAX_SPOT_LIGHTS > 0", + return; - " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + } - " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + } - "#endif", + if ( geometry instanceof THREE.BufferGeometry ) { - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + var material = this.material; - " varying vec3 vWorldPosition;", + if ( material === undefined ) return; - "#endif", + var attributes = geometry.attributes; - "#ifdef WRAP_AROUND", + var a, b, c; + var precision = raycaster.precision; - " uniform vec3 wrapRGB;", + if ( attributes.index !== undefined ) { - "#endif", + var indices = attributes.index.array; + var positions = attributes.position.array; + var offsets = geometry.offsets; - "varying vec3 vViewPosition;", - "varying vec3 vNormal;" + if ( offsets.length === 0 ) { - ].join("\n"), + offsets = [ { start: 0, count: indices.length, index: 0 } ]; - lights_phong_fragment: [ + } - "vec3 normal = normalize( vNormal );", - "vec3 viewPosition = normalize( vViewPosition );", + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - "#ifdef DOUBLE_SIDED", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - " normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + for ( var i = start, il = start + count; i < il; i += 3 ) { - "#endif", + a = index + indices[ i ]; + b = index + indices[ i + 1 ]; + c = index + indices[ i + 2 ]; - "#ifdef USE_NORMALMAP", + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - " normal = perturbNormal2Arb( -vViewPosition, normal );", + if ( material.side === THREE.BackSide ) { - "#elif defined( USE_BUMPMAP )", + var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - " normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + } else { - "#endif", + var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - "#if MAX_POINT_LIGHTS > 0", + } - " vec3 pointDiffuse = vec3( 0.0 );", - " vec3 pointSpecular = vec3( 0.0 );", + if ( intersectionPoint === null ) continue; - " for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + intersectionPoint.applyMatrix4( this.matrixWorld ); - " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - " vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - " float lDistance = 1.0;", - " if ( pointLightDistance[ i ] > 0.0 )", - " lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - " lVector = normalize( lVector );", + intersects.push( { - // diffuse + distance: distance, + point: intersectionPoint, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + faceIndex: null, + object: this - " float dotProduct = dot( normal, lVector );", + } ); - " #ifdef WRAP_AROUND", + } - " float pointDiffuseWeightFull = max( dotProduct, 0.0 );", - " float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + } - " vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + } else { - " #else", + var positions = attributes.position.array; - " float pointDiffuseWeight = max( dotProduct, 0.0 );", + for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) { - " #endif", + a = i; + b = i + 1; + c = i + 2; - " pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", + vA.fromArray( positions, j ); + vB.fromArray( positions, j + 3 ); + vC.fromArray( positions, j + 6 ); - // specular + if ( material.side === THREE.BackSide ) { - " vec3 pointHalfVector = normalize( lVector + viewPosition );", - " float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - " float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - // 2.0 => 2.0001 is hack to work around ANGLE bug + } else { - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", - " pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", + } - " }", + if ( intersectionPoint === null ) continue; - "#endif", + intersectionPoint.applyMatrix4( this.matrixWorld ); - "#if MAX_SPOT_LIGHTS > 0", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - " vec3 spotDiffuse = vec3( 0.0 );", - " vec3 spotSpecular = vec3( 0.0 );", + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - " for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + intersects.push( { - " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - " vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + distance: distance, + point: intersectionPoint, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + faceIndex: null, + object: this - " float lDistance = 1.0;", - " if ( spotLightDistance[ i ] > 0.0 )", - " lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + } ); - " lVector = normalize( lVector );", + } - " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + } - " if ( spotEffect > spotLightAngleCos[ i ] ) {", + } else if ( geometry instanceof THREE.Geometry ) { - " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? this.material.materials : null; - // diffuse + var a, b, c; + var precision = raycaster.precision; - " float dotProduct = dot( normal, lVector );", + var vertices = geometry.vertices; - " #ifdef WRAP_AROUND", + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - " float spotDiffuseWeightFull = max( dotProduct, 0.0 );", - " float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + var face = geometry.faces[ f ]; - " vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material; - " #else", + if ( material === undefined ) continue; - " float spotDiffuseWeight = max( dotProduct, 0.0 );", + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; - " #endif", + if ( material.morphTargets === true ) { - " spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", + var morphTargets = geometry.morphTargets; + var morphInfluences = this.morphTargetInfluences; - // specular + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); - " vec3 spotHalfVector = normalize( lVector + viewPosition );", - " float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - " float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - // 2.0 => 2.0001 is hack to work around ANGLE bug + var influence = morphInfluences[ t ]; - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + if ( influence === 0 ) continue; - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", - " spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", + var targets = morphTargets[ t ].vertices; - " }", + vA.x += ( targets[ face.a ].x - a.x ) * influence; + vA.y += ( targets[ face.a ].y - a.y ) * influence; + vA.z += ( targets[ face.a ].z - a.z ) * influence; - " }", + vB.x += ( targets[ face.b ].x - b.x ) * influence; + vB.y += ( targets[ face.b ].y - b.y ) * influence; + vB.z += ( targets[ face.b ].z - b.z ) * influence; - "#endif", + vC.x += ( targets[ face.c ].x - c.x ) * influence; + vC.y += ( targets[ face.c ].y - c.y ) * influence; + vC.z += ( targets[ face.c ].z - c.z ) * influence; - "#if MAX_DIR_LIGHTS > 0", + } - " vec3 dirDiffuse = vec3( 0.0 );", - " vec3 dirSpecular = vec3( 0.0 );" , + vA.add( a ); + vB.add( b ); + vC.add( c ); - " for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + a = vA; + b = vB; + c = vC; - " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - " vec3 dirVector = normalize( lDirection.xyz );", + } - // diffuse + if ( material.side === THREE.BackSide ) { - " float dotProduct = dot( normal, dirVector );", + var intersectionPoint = ray.intersectTriangle( c, b, a, true ); - " #ifdef WRAP_AROUND", + } else { - " float dirDiffuseWeightFull = max( dotProduct, 0.0 );", - " float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); - " vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", + } - " #else", + if ( intersectionPoint === null ) continue; - " float dirDiffuseWeight = max( dotProduct, 0.0 );", + intersectionPoint.applyMatrix4( this.matrixWorld ); - " #endif", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - " dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - // specular + intersects.push( { - " vec3 dirHalfVector = normalize( dirVector + viewPosition );", - " float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - " float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + distance: distance, + point: intersectionPoint, + face: face, + faceIndex: f, + object: this - /* - // fresnel term from skin shader - " const float F0 = 0.128;", + } ); - " float base = 1.0 - dot( viewPosition, dirHalfVector );", - " float exponential = pow( base, 5.0 );", + } - " float fresnel = exponential + F0 * ( 1.0 - exponential );", - */ + } - /* - // fresnel term from fresnel shader - " const float mFresnelBias = 0.08;", - " const float mFresnelScale = 0.3;", - " const float mFresnelPower = 5.0;", + }; - " float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", - */ +}() ); - // 2.0 => 2.0001 is hack to work around ANGLE bug +THREE.Mesh.prototype.clone = function ( object, recursive ) { - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); - //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", + THREE.Object3D.prototype.clone.call( this, object, recursive ); - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );", - " dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + return object; +}; - " }", +// File:src/objects/Bone.js - "#endif", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - "#if MAX_HEMI_LIGHTS > 0", +THREE.Bone = function ( skin ) { - " vec3 hemiDiffuse = vec3( 0.0 );", - " vec3 hemiSpecular = vec3( 0.0 );" , + THREE.Object3D.call( this ); - " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + this.type = 'Bone'; - " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - " vec3 lVector = normalize( lDirection.xyz );", + this.skin = skin; - // diffuse +}; - " float dotProduct = dot( normal, lVector );", - " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Bone.prototype.constructor = THREE.Bone; - " vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", +// File:src/objects/Skeleton.js - " hemiDiffuse += diffuse * hemiColor;", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author michael guerrero / http://realitymeltdown.com + * @author ikerr / http://verold.com + */ - // specular (sky light) +THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { - " vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", - " float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - " float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - // specular (ground light) + this.identityMatrix = new THREE.Matrix4(); - " vec3 lVectorGround = -lVector;", + // copy the bone array - " vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", - " float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - " float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + bones = bones || []; - " float dotProductGround = dot( normal, lVectorGround );", + this.bones = bones.slice( 0 ); - // 2.0 => 2.0001 is hack to work around ANGLE bug + // create a bone texture or an array of floats - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + if ( this.useVertexTexture ) { - " vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );", - " vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );", - " hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones (8 * 8 / 4) + // 16x16 pixel texture max 64 bones (16 * 16 / 4) + // 32x32 pixel texture max 256 bones (32 * 32 / 4) + // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - " }", + var size; - "#endif", + if ( this.bones.length > 256 ) + size = 64; + else if ( this.bones.length > 64 ) + size = 32; + else if ( this.bones.length > 16 ) + size = 16; + else + size = 8; - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", + this.boneTextureWidth = size; + this.boneTextureHeight = size; - "#if MAX_DIR_LIGHTS > 0", + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); + this.boneTexture.minFilter = THREE.NearestFilter; + this.boneTexture.magFilter = THREE.NearestFilter; + this.boneTexture.generateMipmaps = false; + this.boneTexture.flipY = false; - " totalDiffuse += dirDiffuse;", - " totalSpecular += dirSpecular;", + } else { - "#endif", + this.boneMatrices = new Float32Array( 16 * this.bones.length ); - "#if MAX_HEMI_LIGHTS > 0", + } - " totalDiffuse += hemiDiffuse;", - " totalSpecular += hemiSpecular;", + // use the supplied bone inverses or calculate the inverses - "#endif", + if ( boneInverses === undefined ) { - "#if MAX_POINT_LIGHTS > 0", + this.calculateInverses(); - " totalDiffuse += pointDiffuse;", - " totalSpecular += pointSpecular;", + } else { - "#endif", + if ( this.bones.length === boneInverses.length ) { - "#if MAX_SPOT_LIGHTS > 0", + this.boneInverses = boneInverses.slice( 0 ); - " totalDiffuse += spotDiffuse;", - " totalSpecular += spotSpecular;", + } else { - "#endif", + THREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); - "#ifdef METAL", + this.boneInverses = []; - " gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#else", + this.boneInverses.push( new THREE.Matrix4() ); - " gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + } - "#endif" + } - ].join("\n"), + } - // VERTEX COLORS +}; - color_pars_fragment: [ +THREE.Skeleton.prototype.calculateInverses = function () { - "#ifdef USE_COLOR", + this.boneInverses = []; - " varying vec3 vColor;", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#endif" + var inverse = new THREE.Matrix4(); - ].join("\n"), + if ( this.bones[ b ] ) { + inverse.getInverse( this.bones[ b ].matrixWorld ); - color_fragment: [ + } - "#ifdef USE_COLOR", + this.boneInverses.push( inverse ); - " gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", + } - "#endif" +}; - ].join("\n"), +THREE.Skeleton.prototype.pose = function () { - color_pars_vertex: [ + var bone; - "#ifdef USE_COLOR", + // recover the bind-time world matrices - " varying vec3 vColor;", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#endif" + bone = this.bones[ b ]; - ].join("\n"), + if ( bone ) { + bone.matrixWorld.getInverse( this.boneInverses[ b ] ); - color_vertex: [ + } - "#ifdef USE_COLOR", + } - " #ifdef GAMMA_INPUT", + // compute the local matrices, positions, rotations and scales - " vColor = color * color;", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - " #else", + bone = this.bones[ b ]; - " vColor = color;", + if ( bone ) { - " #endif", + if ( bone.parent ) { - "#endif" + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( bone.matrixWorld ); - ].join("\n"), + } else { - // SKINNING + bone.matrix.copy( bone.matrixWorld ); - skinning_pars_vertex: [ + } - "#ifdef USE_SKINNING", + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - " #ifdef BONE_TEXTURE", + } - " uniform sampler2D boneTexture;", - " uniform int boneTextureWidth;", - " uniform int boneTextureHeight;", + } - " mat4 getBoneMatrix( const in float i ) {", +}; - " float j = i * 4.0;", - " float x = mod( j, float( boneTextureWidth ) );", - " float y = floor( j / float( boneTextureWidth ) );", +THREE.Skeleton.prototype.update = ( function () { - " float dx = 1.0 / float( boneTextureWidth );", - " float dy = 1.0 / float( boneTextureHeight );", + var offsetMatrix = new THREE.Matrix4(); + + return function () { - " y = dy * ( y + 0.5 );", + // flatten bone matrices to array - " vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", - " vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", - " vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", - " vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - " mat4 bone = mat4( v1, v2, v3, v4 );", + // compute the offset between the current and the original transform - " return bone;", + var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; - " }", + offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); + offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); - " #else", + } - " uniform mat4 boneGlobalMatrices[ MAX_BONES ];", + if ( this.useVertexTexture ) { - " mat4 getBoneMatrix( const in float i ) {", + this.boneTexture.needsUpdate = true; - " mat4 bone = boneGlobalMatrices[ int(i) ];", - " return bone;", + } + + }; - " }", +} )(); - " #endif", - "#endif" +// File:src/objects/SkinnedMesh.js - ].join("\n"), +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - skinbase_vertex: [ +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - "#ifdef USE_SKINNING", + THREE.Mesh.call( this, geometry, material ); - " mat4 boneMatX = getBoneMatrix( skinIndex.x );", - " mat4 boneMatY = getBoneMatrix( skinIndex.y );", - " mat4 boneMatZ = getBoneMatrix( skinIndex.z );", - " mat4 boneMatW = getBoneMatrix( skinIndex.w );", + this.type = 'SkinnedMesh'; - "#endif" + this.bindMode = "attached"; + this.bindMatrix = new THREE.Matrix4(); + this.bindMatrixInverse = new THREE.Matrix4(); - ].join("\n"), + // init bones - skinning_vertex: [ + // TODO: remove bone creation as there is no reason (other than + // convenience) for THREE.SkinnedMesh to do this. - "#ifdef USE_SKINNING", + var bones = []; - " #ifdef USE_MORPHTARGETS", + if ( this.geometry && this.geometry.bones !== undefined ) { - " vec4 skinVertex = vec4( morphed, 1.0 );", + var bone, gbone, p, q, s; - " #else", + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - " vec4 skinVertex = vec4( position, 1.0 );", + gbone = this.geometry.bones[ b ]; - " #endif", + p = gbone.pos; + q = gbone.rotq; + s = gbone.scl; - " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - " skinned += boneMatY * skinVertex * skinWeight.y;", - " skinned += boneMatZ * skinVertex * skinWeight.z;", - " skinned += boneMatW * skinVertex * skinWeight.w;", + bone = new THREE.Bone( this ); + bones.push( bone ); - "#endif" + bone.name = gbone.name; + bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] ); + bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] ); - ].join("\n"), + if ( s !== undefined ) { - // MORPHING + bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] ); - morphtarget_pars_vertex: [ + } else { - "#ifdef USE_MORPHTARGETS", + bone.scale.set( 1, 1, 1 ); - " #ifndef USE_MORPHNORMALS", + } - " uniform float morphTargetInfluences[ 8 ];", + } - " #else", + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - " uniform float morphTargetInfluences[ 4 ];", + gbone = this.geometry.bones[ b ]; - " #endif", + if ( gbone.parent !== - 1 ) { - "#endif" + bones[ gbone.parent ].add( bones[ b ] ); - ].join("\n"), + } else { - morphtarget_vertex: [ + this.add( bones[ b ] ); - "#ifdef USE_MORPHTARGETS", + } - " vec3 morphed = vec3( 0.0 );", - " morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", - " morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", - " morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", - " morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", + } - " #ifndef USE_MORPHNORMALS", + } - " morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", - " morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", - " morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", - " morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", + this.normalizeSkinWeights(); - " #endif", + this.updateMatrixWorld( true ); + this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) ); - " morphed += position;", +}; - "#endif" - ].join("\n"), +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; - default_vertex : [ +THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { - "vec4 mvPosition;", + this.skeleton = skeleton; - "#ifdef USE_SKINNING", + if ( bindMatrix === undefined ) { - " mvPosition = modelViewMatrix * skinned;", + this.updateMatrixWorld( true ); - "#endif", + bindMatrix = this.matrixWorld; - "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", + } - " mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); - "#endif", +}; - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", +THREE.SkinnedMesh.prototype.pose = function () { - " mvPosition = modelViewMatrix * vec4( position, 1.0 );", + this.skeleton.pose(); - "#endif", +}; - "gl_Position = projectionMatrix * mvPosition;" +THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - ].join("\n"), + if ( this.geometry instanceof THREE.Geometry ) { - morphnormal_vertex: [ + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - "#ifdef USE_MORPHNORMALS", + var sw = this.geometry.skinWeights[ i ]; - " vec3 morphedNormal = vec3( 0.0 );", + var scale = 1.0 / sw.lengthManhattan(); - " morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", - " morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", - " morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", - " morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", + if ( scale !== Infinity ) { - " morphedNormal += normal;", + sw.multiplyScalar( scale ); - "#endif" + } else { - ].join("\n"), + sw.set( 1 ); // this will be normalized by the shader anyway - skinnormal_vertex: [ + } - "#ifdef USE_SKINNING", + } - " mat4 skinMatrix = skinWeight.x * boneMatX;", - " skinMatrix += skinWeight.y * boneMatY;", - " skinMatrix += skinWeight.z * boneMatZ;", - " skinMatrix += skinWeight.w * boneMatW;", + } else { - " #ifdef USE_MORPHNORMALS", + // skinning weights assumed to be normalized for THREE.BufferGeometry - " vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", + } - " #else", +}; - " vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", +THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { - " #endif", + THREE.Mesh.prototype.updateMatrixWorld.call( this, true ); - "#endif" + if ( this.bindMode === "attached" ) { - ].join("\n"), + this.bindMatrixInverse.getInverse( this.matrixWorld ); - defaultnormal_vertex: [ + } else if ( this.bindMode === "detached" ) { - "vec3 objectNormal;", + this.bindMatrixInverse.getInverse( this.bindMatrix ); - "#ifdef USE_SKINNING", + } else { - " objectNormal = skinnedNormal.xyz;", + THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); - "#endif", + } - "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", +}; - " objectNormal = morphedNormal;", +THREE.SkinnedMesh.prototype.clone = function( object ) { - "#endif", + if ( object === undefined ) { - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", + object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); - " objectNormal = normal;", + } - "#endif", + THREE.Mesh.prototype.clone.call( this, object ); - "#ifdef FLIP_SIDED", + return object; - " objectNormal = -objectNormal;", +}; - "#endif", - "vec3 transformedNormal = normalMatrix * objectNormal;" +// File:src/objects/MorphAnimMesh.js - ].join("\n"), +/** + * @author alteredq / http://alteredqualia.com/ + */ - // SHADOW MAP +THREE.MorphAnimMesh = function ( geometry, material ) { - // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples - // http://spidergl.org/example.php?id=6 - // http://fabiensanglard.net/shadowmapping + THREE.Mesh.call( this, geometry, material ); - shadowmap_pars_fragment: [ + this.type = 'MorphAnimMesh'; - "#ifdef USE_SHADOWMAP", + // API - " uniform sampler2D shadowMap[ MAX_SHADOWS ];", - " uniform vec2 shadowMapSize[ MAX_SHADOWS ];", + this.duration = 1000; // milliseconds + this.mirroredLoop = false; + this.time = 0; - " uniform float shadowDarkness[ MAX_SHADOWS ];", - " uniform float shadowBias[ MAX_SHADOWS ];", + // internals - " varying vec4 vShadowCoord[ MAX_SHADOWS ];", + this.lastKeyframe = 0; + this.currentKeyframe = 0; - " float unpackDepth( const in vec4 rgba_depth ) {", + this.direction = 1; + this.directionBackwards = false; - " const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", - " float depth = dot( rgba_depth, bit_shift );", - " return depth;", + this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); - " }", +}; - "#endif" +THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.MorphAnimMesh.prototype.constructor = THREE.MorphAnimMesh; - ].join("\n"), +THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { - shadowmap_fragment: [ + this.startKeyframe = start; + this.endKeyframe = end; - "#ifdef USE_SHADOWMAP", + this.length = this.endKeyframe - this.startKeyframe + 1; - " #ifdef SHADOWMAP_DEBUG", +}; - " vec3 frustumColors[3];", - " frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", - " frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", - " frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", +THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - " #endif", + this.direction = 1; + this.directionBackwards = false; - " #ifdef SHADOWMAP_CASCADE", +}; - " int inFrustumCount = 0;", +THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - " #endif", + this.direction = - 1; + this.directionBackwards = true; - " float fDepth;", - " vec3 shadowColor = vec3( 1.0 );", +}; - " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", +THREE.MorphAnimMesh.prototype.parseAnimations = function () { - " vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", + var geometry = this.geometry; - // "if ( something && something )" breaks ATI OpenGL shader compiler - // "if ( all( something, something ) )" using this instead + if ( ! geometry.animations ) geometry.animations = {}; - " bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", - " bool inFrustum = all( inFrustumVec );", + var firstAnimation, animations = geometry.animations; - // don't shadow pixels outside of light frustum - // use just first frustum (for cascades) - // don't shadow pixels behind far plane of light frustum + var pattern = /([a-z]+)_?(\d+)/; - " #ifdef SHADOWMAP_CASCADE", + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - " inFrustumCount += int( inFrustum );", - " bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", + var morph = geometry.morphTargets[ i ]; + var parts = morph.name.match( pattern ); - " #else", + if ( parts && parts.length > 1 ) { - " bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", + var label = parts[ 1 ]; - " #endif", + if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity }; - " bool frustumTest = all( frustumTestVec );", + var animation = animations[ label ]; - " if ( frustumTest ) {", + if ( i < animation.start ) animation.start = i; + if ( i > animation.end ) animation.end = i; - " shadowCoord.z += shadowBias[ i ];", + if ( ! firstAnimation ) firstAnimation = label; - " #if defined( SHADOWMAP_TYPE_PCF )", + } - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ + } - " float shadow = 0.0;", + geometry.firstAnimation = firstAnimation; - /* - // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL - // must enroll loop manually +}; - " for ( float y = -1.25; y <= 1.25; y += 1.25 )", - " for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", +THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { - " vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", + if ( ! this.geometry.animations ) this.geometry.animations = {}; - // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup - //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", + this.geometry.animations[ label ] = { start: start, end: end }; - " float fDepth = unpackDepth( rgbaDepth );", +}; - " if ( fDepth < shadowCoord.z )", - " shadow += 1.0;", +THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { - " }", + var animation = this.geometry.animations[ label ]; - " shadow /= 9.0;", + if ( animation ) { - */ + this.setFrameRange( animation.start, animation.end ); + this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); + this.time = 0; - " const float shadowDelta = 1.0 / 9.0;", + } else { - " float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - " float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' ); - " float dx0 = -1.25 * xPixelOffset;", - " float dy0 = -1.25 * yPixelOffset;", - " float dx1 = 1.25 * xPixelOffset;", - " float dy1 = 1.25 * yPixelOffset;", + } - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", +}; - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", +THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + var frameTime = this.duration / this.length; - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + this.time += this.direction * delta; - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + if ( this.mirroredLoop ) { - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + if ( this.time > this.duration || this.time < 0 ) { - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + this.direction *= - 1; - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + if ( this.time > this.duration ) { - " fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", - " if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + this.time = this.duration; + this.directionBackwards = true; - " shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + } - " #elif defined( SHADOWMAP_TYPE_PCF_SOFT )", + if ( this.time < 0 ) { - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ + this.time = 0; + this.directionBackwards = false; - " float shadow = 0.0;", + } - " float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - " float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + } - " float dx0 = -1.0 * xPixelOffset;", - " float dy0 = -1.0 * yPixelOffset;", - " float dx1 = 1.0 * xPixelOffset;", - " float dy1 = 1.0 * yPixelOffset;", + } else { - " mat3 shadowKernel;", - " mat3 depthKernel;", + this.time = this.time % this.duration; - " depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - " depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - " depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - " depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - " depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - " depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - " depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - " depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - " depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + if ( this.time < 0 ) this.time += this.duration; - " vec3 shadowZ = vec3( shadowCoord.z );", - " shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", - " shadowKernel[0] *= vec3(0.25);", - - " shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", - " shadowKernel[1] *= vec3(0.25);", + } - " shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", - " shadowKernel[2] *= vec3(0.25);", + var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); - " vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", + if ( keyframe !== this.currentKeyframe ) { - " shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", - " shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", + this.morphTargetInfluences[ this.lastKeyframe ] = 0; + this.morphTargetInfluences[ this.currentKeyframe ] = 1; - " vec4 shadowValues;", - " shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", - " shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", - " shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", - " shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", + this.morphTargetInfluences[ keyframe ] = 0; - " shadow = dot( shadowValues, vec4( 1.0 ) );", + this.lastKeyframe = this.currentKeyframe; + this.currentKeyframe = keyframe; - " shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + } - " #else", + var mix = ( this.time % frameTime ) / frameTime; - " vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", - " float fDepth = unpackDepth( rgbaDepth );", + if ( this.directionBackwards ) { - " if ( fDepth < shadowCoord.z )", + mix = 1 - mix; - // spot with multiple shadows is darker + } - " shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", + this.morphTargetInfluences[ this.currentKeyframe ] = mix; + this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; - // spot with multiple shadows has the same color as single shadow spot +}; - //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", +THREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) { - " #endif", + var influences = this.morphTargetInfluences; - " }", + for ( var i = 0, l = influences.length; i < l; i ++ ) { + influences[ i ] = 0; - " #ifdef SHADOWMAP_DEBUG", + } - " #ifdef SHADOWMAP_CASCADE", + if ( a > -1 ) influences[ a ] = 1 - t; + if ( b > -1 ) influences[ b ] = t; - " if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", +}; - " #else", +THREE.MorphAnimMesh.prototype.clone = function ( object ) { - " if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", + if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); - " #endif", + object.duration = this.duration; + object.mirroredLoop = this.mirroredLoop; + object.time = this.time; - " #endif", + object.lastKeyframe = this.lastKeyframe; + object.currentKeyframe = this.currentKeyframe; - " }", + object.direction = this.direction; + object.directionBackwards = this.directionBackwards; - " #ifdef GAMMA_OUTPUT", + THREE.Mesh.prototype.clone.call( this, object ); - " shadowColor *= shadowColor;", + return object; - " #endif", +}; - " gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", +// File:src/objects/LOD.js - "#endif" +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - ].join("\n"), +THREE.LOD = function () { - shadowmap_pars_vertex: [ + THREE.Object3D.call( this ); - "#ifdef USE_SHADOWMAP", + this.objects = []; - " varying vec4 vShadowCoord[ MAX_SHADOWS ];", - " uniform mat4 shadowMatrix[ MAX_SHADOWS ];", +}; - "#endif" - ].join("\n"), +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); +THREE.LOD.prototype.constructor = THREE.LOD; - shadowmap_vertex: [ +THREE.LOD.prototype.addLevel = function ( object, distance ) { - "#ifdef USE_SHADOWMAP", + if ( distance === undefined ) distance = 0; - " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + distance = Math.abs( distance ); - " vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + for ( var l = 0; l < this.objects.length; l ++ ) { - " }", + if ( distance < this.objects[ l ].distance ) { - "#endif" + break; - ].join("\n"), + } - // ALPHATEST + } - alphatest_fragment: [ + this.objects.splice( l, 0, { distance: distance, object: object } ); + this.add( object ); - "#ifdef ALPHATEST", +}; - " if ( gl_FragColor.a < ALPHATEST ) discard;", +THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - "#endif" + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - ].join("\n"), + if ( distance < this.objects[ i ].distance ) { - // LINEAR SPACE + break; - linear_to_gamma_fragment: [ + } - "#ifdef GAMMA_OUTPUT", + } - " gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", + return this.objects[ i - 1 ].object; - "#endif" +}; - ].join("\n"), +THREE.LOD.prototype.raycast = ( function () { - // LOGARITHMIC DEPTH BUFFER - // http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html + var matrixPosition = new THREE.Vector3(); - // WebGL doesn't support gl_FragDepth out of the box, unless the EXT_frag_depth extension is available. On platforms - // without EXT_frag_depth, we have to fall back on linear z-buffer in the fragment shader, which means that some long - // faces close to the camera may have issues. This can be worked around by tesselating the model more finely when - // the camera is near the surface. + return function ( raycaster, intersects ) { - logdepthbuf_pars_vertex: [ + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - "#ifdef USE_LOGDEPTHBUF", + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - " #ifdef USE_LOGDEPTHBUF_EXT", + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - " varying float vFragDepth;", + }; - " #endif", +}() ); - " uniform float logDepthBufFC;", +THREE.LOD.prototype.update = function () { - "#endif", + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - ].join('\n'), + return function ( camera ) { - logdepthbuf_vertex: [ + if ( this.objects.length > 1 ) { - "#ifdef USE_LOGDEPTHBUF", + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); - " gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * logDepthBufFC;", + var distance = v1.distanceTo( v2 ); - " #ifdef USE_LOGDEPTHBUF_EXT", + this.objects[ 0 ].object.visible = true; - " vFragDepth = 1.0 + gl_Position.w;", + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - "#else", + if ( distance >= this.objects[ i ].distance ) { - " gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;", + this.objects[ i - 1 ].object.visible = false; + this.objects[ i ].object.visible = true; - " #endif", + } else { - "#endif" + break; - ].join("\n"), + } - logdepthbuf_pars_fragment: [ + } - "#ifdef USE_LOGDEPTHBUF", + for ( ; i < l; i ++ ) { - " uniform float logDepthBufFC;", + this.objects[ i ].object.visible = false; - " #ifdef USE_LOGDEPTHBUF_EXT", + } - " #extension GL_EXT_frag_depth : enable", - " varying float vFragDepth;", + } - " #endif", + }; - "#endif" +}(); - ].join('\n'), +THREE.LOD.prototype.clone = function ( object ) { - logdepthbuf_fragment: [ - "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)", + if ( object === undefined ) object = new THREE.LOD(); - " gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;", + THREE.Object3D.prototype.clone.call( this, object ); - "#endif" + for ( var i = 0, l = this.objects.length; i < l; i ++ ) { + var x = this.objects[ i ].object.clone(); + x.visible = i === 0; + object.addLevel( x, this.objects[ i ].distance ); + } - ].join("\n") + return object; }; +// File:src/objects/Sprite.js + /** - * Uniform Utilities + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ */ -THREE.UniformsUtils = { - - merge: function ( uniforms ) { +THREE.Sprite = ( function () { - var u, p, tmp, merged = {}; + var indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); + var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] ); + var uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] ); - for ( u = 0; u < uniforms.length; u ++ ) { + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - tmp = this.clone( uniforms[ u ] ); + return function ( material ) { - for ( p in tmp ) { + THREE.Object3D.call( this ); - merged[ p ] = tmp[ p ]; + this.type = 'Sprite'; - } + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - } + }; - return merged; +} )(); - }, +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Sprite.prototype.constructor = THREE.Sprite; - clone: function ( uniforms_src ) { +THREE.Sprite.prototype.raycast = ( function () { - var u, p, parameter, parameter_src, uniforms_dst = {}; + var matrixPosition = new THREE.Vector3(); - for ( u in uniforms_src ) { + return function ( raycaster, intersects ) { - uniforms_dst[ u ] = {}; + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - for ( p in uniforms_src[ u ] ) { + var distance = raycaster.ray.distanceToPoint( matrixPosition ); - parameter_src = uniforms_src[ u ][ p ]; + if ( distance > this.scale.x ) { - if ( parameter_src instanceof THREE.Color || - parameter_src instanceof THREE.Vector2 || - parameter_src instanceof THREE.Vector3 || - parameter_src instanceof THREE.Vector4 || - parameter_src instanceof THREE.Matrix4 || - parameter_src instanceof THREE.Texture ) { + return; - uniforms_dst[ u ][ p ] = parameter_src.clone(); + } - } else if ( parameter_src instanceof Array ) { + intersects.push( { - uniforms_dst[ u ][ p ] = parameter_src.slice(); + distance: distance, + point: this.position, + face: null, + object: this - } else { + } ); - uniforms_dst[ u ][ p ] = parameter_src; + }; - } +}() ); - } +THREE.Sprite.prototype.clone = function ( object ) { - } + if ( object === undefined ) object = new THREE.Sprite( this.material ); - return uniforms_dst; + THREE.Object3D.prototype.clone.call( this, object ); - } + return object; }; -/** - * Uniforms library for shared webgl shaders - */ - -THREE.UniformsLib = { - common: { +// Backwards compatibility - "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, +THREE.Particle = THREE.Sprite; - "map" : { type: "t", value: null }, - "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, +// File:src/objects/LensFlare.js - "lightMap" : { type: "t", value: null }, - "specularMap" : { type: "t", value: null }, +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - "envMap" : { type: "t", value: null }, - "flipEnvMap" : { type: "f", value: -1 }, - "useRefract" : { type: "i", value: 0 }, - "reflectivity" : { type: "f", value: 1.0 }, - "refractionRatio" : { type: "f", value: 0.98 }, - "combine" : { type: "i", value: 0 }, +THREE.LensFlare = function ( texture, size, distance, blending, color ) { - "morphTargetInfluences" : { type: "f", value: 0 } + THREE.Object3D.call( this ); - }, + this.lensFlares = []; - bump: { + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; - "bumpMap" : { type: "t", value: null }, - "bumpScale" : { type: "f", value: 1 } + if ( texture !== undefined ) { - }, + this.add( texture, size, distance, blending, color ); - normalmap: { + } - "normalMap" : { type: "t", value: null }, - "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } - }, +}; - fog : { +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); +THREE.LensFlare.prototype.constructor = THREE.LensFlare; - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - }, +/* + * Add: adds another flare + */ - lights: { +THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { - "ambientLightColor" : { type: "fv", value: [] }, + if ( size === undefined ) size = - 1; + if ( distance === undefined ) distance = 0; + if ( opacity === undefined ) opacity = 1; + if ( color === undefined ) color = new THREE.Color( 0xffffff ); + if ( blending === undefined ) blending = THREE.NormalBlending; - "directionalLightDirection" : { type: "fv", value: [] }, - "directionalLightColor" : { type: "fv", value: [] }, + distance = Math.min( distance, Math.max( 0, distance ) ); - "hemisphereLightDirection" : { type: "fv", value: [] }, - "hemisphereLightSkyColor" : { type: "fv", value: [] }, - "hemisphereLightGroundColor" : { type: "fv", value: [] }, + 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 ontop z = 1 is back + scale: 1, // scale + rotation: 1, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending // blending + } ); - "pointLightColor" : { type: "fv", value: [] }, - "pointLightPosition" : { type: "fv", value: [] }, - "pointLightDistance" : { type: "fv1", value: [] }, +}; - "spotLightColor" : { type: "fv", value: [] }, - "spotLightPosition" : { type: "fv", value: [] }, - "spotLightDirection" : { type: "fv", value: [] }, - "spotLightDistance" : { type: "fv1", value: [] }, - "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] } +/* + * 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. + */ - }, +THREE.LensFlare.prototype.updateLensFlares = function () { - particle: { + var f, fl = this.lensFlares.length; + var flare; + var vecX = - this.positionScreen.x * 2; + var vecY = - this.positionScreen.y * 2; - "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - "size" : { type: "f", value: 1.0 }, - "scale" : { type: "f", value: 1.0 }, - "map" : { type: "t", value: null }, + for ( f = 0; f < fl; f ++ ) { - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + flare = this.lensFlares[ f ]; - }, + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; - shadowmap: { + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - "shadowMap": { type: "tv", value: [] }, - "shadowMapSize": { type: "v2v", value: [] }, + } - "shadowBias" : { type: "fv1", value: [] }, - "shadowDarkness": { type: "fv1", value: [] }, +}; - "shadowMatrix" : { type: "m4v", value: [] } - } +// File:src/scenes/Scene.js -}; /** - * Webgl Shader Library for three.js - * - * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ */ +THREE.Scene = function () { -THREE.ShaderLib = { - - 'basic': { + THREE.Object3D.call( this ); - uniforms: THREE.UniformsUtils.merge( [ + this.type = 'Scene'; - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "shadowmap" ] + this.fog = null; + this.overrideMaterial = null; - ] ), + this.autoUpdate = true; // checked by the renderer - vertexShader: [ +}; - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Scene.prototype.constructor = THREE.Scene; - "void main() {", +THREE.Scene.prototype.clone = function ( object ) { - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], + if ( object === undefined ) object = new THREE.Scene(); - " #ifdef USE_ENVMAP", + THREE.Object3D.prototype.clone.call( this, object ); - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], + if ( this.fog !== null ) object.fog = this.fog.clone(); + if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); - " #endif", + object.autoUpdate = this.autoUpdate; + object.matrixAutoUpdate = this.matrixAutoUpdate; - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], + return object; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +}; - "}" +// File:src/scenes/Fog.js - ].join("\n"), +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - fragmentShader: [ +THREE.Fog = function ( color, near, far ) { - "uniform vec3 diffuse;", - "uniform float opacity;", + this.name = ''; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + this.color = new THREE.Color( color ); - "void main() {", + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; - " gl_FragColor = vec4( diffuse, opacity );", +}; - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +THREE.Fog.prototype.clone = function () { - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + return new THREE.Fog( this.color.getHex(), this.near, this.far ); - THREE.ShaderChunk[ "fog_fragment" ], +}; - "}" +// File:src/scenes/FogExp2.js - ].join("\n") +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - }, +THREE.FogExp2 = function ( color, density ) { - 'lambert': { + this.name = ''; - uniforms: THREE.UniformsUtils.merge( [ + this.color = new THREE.Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], +}; - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } +THREE.FogExp2.prototype.clone = function () { - ] ), + return new THREE.FogExp2( this.color.getHex(), this.density ); - vertexShader: [ +}; - "#define LAMBERT", +// File:src/renderers/shaders/ShaderChunk.js - "varying vec3 vLightFront;", +THREE.ShaderChunk = {}; - "#ifdef DOUBLE_SIDED", +// File:src/renderers/shaders/ShaderChunk/common.glsl - " varying vec3 vLightBack;", +THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n float distance = dot( planeNormal, point-pointOnPlane );\n return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n if ( decayExponent > 0.0 ) {\n return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n }\n return 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\n"; - "#endif", +// File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], +THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, dirVector );\n vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n #endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n float dotProduct = dot( transformedNormal, lVector );\n\n vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n #endif\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float dotProduct = dot( transformedNormal, lVector );\n vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n #endif\n\n }\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, lVector );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n #endif\n\n }\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n vLightBack += ambientLightColor;\n\n#endif\n"; - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], +// File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], +THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform vec4 offsetRepeat;\n uniform sampler2D map;\n\n#endif\n"; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_lambert_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl - "}" +THREE.ShaderChunk[ 'default_vertex'] = "#ifdef USE_SKINNING\n\n vec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n vec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; - ].join("\n"), +// File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl - fragmentShader: [ +THREE.ShaderChunk[ 'map_pars_fragment'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n uniform sampler2D map;\n\n#endif"; - "uniform float opacity;", +// File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl - "varying vec3 vLightFront;", +THREE.ShaderChunk[ 'skinnormal_vertex'] = "#ifdef USE_SKINNING\n\n mat4 skinMatrix = mat4( 0.0 );\n skinMatrix += skinWeight.x * boneMatX;\n skinMatrix += skinWeight.y * boneMatY;\n skinMatrix += skinWeight.z * boneMatZ;\n skinMatrix += skinWeight.w * boneMatW;\n skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\n #ifdef USE_MORPHNORMALS\n\n vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n #else\n\n vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n #endif\n\n#endif\n"; - "#ifdef DOUBLE_SIDED", +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl - " varying vec3 vLightBack;", +THREE.ShaderChunk[ 'logdepthbuf_pars_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n varying float vFragDepth;\n\n #endif\n\n uniform float logDepthBufFC;\n\n#endif"; - "#endif", +// File:src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], +THREE.ShaderChunk[ 'lightmap_pars_vertex'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", +THREE.ShaderChunk[ 'lights_phong_fragment'] = "#ifndef FLAT_SHADED\n\n vec3 normal = normalize( vNormal );\n\n #ifdef DOUBLE_SIDED\n\n normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n #endif\n\n#else\n\n vec3 fdx = dFdx( vViewPosition );\n vec3 fdy = dFdy( vViewPosition );\n vec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n // specular\n\n vec3 pointHalfVector = normalize( lVector + viewPosition );\n float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n // specular\n\n vec3 spotHalfVector = normalize( lVector + viewPosition );\n float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n }\n\n }\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, dirVector );\n\n #ifdef WRAP_AROUND\n\n float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n // specular\n\n vec3 dirHalfVector = normalize( dirVector + viewPosition );\n float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n /*\n // fresnel term from skin shader\n const float F0 = 0.128;\n\n float base = 1.0 - dot( viewPosition, dirHalfVector );\n float exponential = pow( base, 5.0 );\n\n float fresnel = exponential + F0 * ( 1.0 - exponential );\n */\n\n /*\n // fresnel term from fresnel shader\n const float mFresnelBias = 0.08;\n const float mFresnelScale = 0.3;\n const float mFresnelPower = 5.0;\n\n float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n */\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n // dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n totalDiffuseLight += hemiColor;\n\n // specular (sky light)\n\n vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n // specular (ground light)\n\n vec3 lVectorGround = -lVector;\n\n vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n float dotProductGround = dot( normal, lVectorGround );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n }\n\n#endif\n\n#ifdef METAL\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], +// File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl - " #ifdef DOUBLE_SIDED", +THREE.ShaderChunk[ 'fog_pars_fragment'] = "#ifdef USE_FOG\n\n uniform vec3 fogColor;\n\n #ifdef FOG_EXP2\n\n uniform float fogDensity;\n\n #else\n\n uniform float fogNear;\n uniform float fogFar;\n #endif\n\n#endif"; - //"float isFront = float( gl_FrontFacing );", - //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", +// File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl - " if ( gl_FrontFacing )", - " gl_FragColor.xyz *= vLightFront;", - " else", - " gl_FragColor.xyz *= vLightBack;", +THREE.ShaderChunk[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n vec3 morphedNormal = vec3( 0.0 );\n\n morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n morphedNormal += normal;\n\n#endif"; - " #else", +// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl - " gl_FragColor.xyz *= vLightFront;", +THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n uniform float reflectivity;\n #ifdef ENVMAP_TYPE_CUBE\n uniform samplerCube envMap;\n #else\n uniform sampler2D envMap;\n #endif\n uniform float flipEnvMap;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n uniform float refractionRatio;\n\n #else\n\n varying vec3 vReflect;\n\n #endif\n\n#endif\n"; - " #endif", +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +THREE.ShaderChunk[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], +// File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform vec2 normalScale;\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( vUv.st );\n vec2 st1 = dFdy( vUv.st );\n\n vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n vec3 N = normalize( surf_norm );\n\n vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n mapN.xy = normalScale * mapN.xy;\n mat3 tsn = mat3( S, T, N );\n return normalize( tsn * mapN );\n\n }\n\n#endif\n"; - "}" +// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl - ].join("\n") +THREE.ShaderChunk[ 'lights_phong_pars_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n"; - }, +// File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl - 'phong': { +THREE.ShaderChunk[ 'lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n uniform sampler2D lightMap;\n\n#endif"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bump" ], - THREE.UniformsLib[ "normalmap" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], +THREE.ShaderChunk[ 'shadowmap_vertex'] = "#ifdef USE_SHADOWMAP\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n }\n\n#endif"; - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, - "shininess": { type: "f", value: 30 }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } +// File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl - ] ), +THREE.ShaderChunk[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n vWorldPosition = worldPosition.xyz;\n\n#endif"; - vertexShader: [ +// File:src/renderers/shaders/ShaderChunk/map_fragment.glsl - "#define PHONG", +THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n vec4 texelColor = texture2D( map, vUv );\n\n texelColor.xyz = inputToLinear( texelColor.xyz );\n\n diffuseColor *= texelColor;\n\n#endif"; - "varying vec3 vViewPosition;", - "varying vec3 vNormal;", +// File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_phong_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], +THREE.ShaderChunk[ 'lightmap_vertex'] = "#ifdef USE_LIGHTMAP\n\n vUv2 = uv2;\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], +// File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl - " vNormal = normalize( transformedNormal );", +THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif\n"; - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], +// File:src/renderers/shaders/ShaderChunk/color_vertex.glsl - " vViewPosition = -mvPosition.xyz;", +THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n vColor.xyz = inputToLinear( color.xyz );\n\n#endif"; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_phong_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +// File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl - "}" +THREE.ShaderChunk[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n #ifdef USE_MORPHTARGETS\n\n vec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n #endif\n\n vec4 skinned = vec4( 0.0 );\n skinned += boneMatX * skinVertex * skinWeight.x;\n skinned += boneMatY * skinVertex * skinWeight.y;\n skinned += boneMatZ * skinVertex * skinWeight.z;\n skinned += boneMatW * skinVertex * skinWeight.w;\n skinned = bindMatrixInverse * skinned;\n\n#endif\n"; - ].join("\n"), +// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl - fragmentShader: [ +THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n varying vec3 vReflect;\n\n uniform float refractionRatio;\n\n#endif\n"; - "uniform vec3 diffuse;", - "uniform float opacity;", +// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl - "uniform vec3 ambient;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", +THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n outgoingLight = linearToOutput( outgoingLight );\n"; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "lights_phong_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], +// File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl - "void main() {", +THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif"; - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", +// File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], +THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n"; - THREE.ShaderChunk[ "lights_phong_fragment" ], +// File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n uniform vec4 offsetRepeat;\n\n#endif\n"; - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], +// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // Transforming Normal Vectors with the Inverse Transformation\n vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n #else\n\n vec3 reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n #else\n float flipNormal = 1.0;\n #endif\n\n #ifdef ENVMAP_TYPE_CUBE\n vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #elif defined( ENVMAP_TYPE_EQUIREC )\n vec2 sampleUV;\n sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n vec4 envColor = texture2D( envMap, sampleUV );\n\n #elif defined( ENVMAP_TYPE_SPHERE )\n vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n #endif\n\n envColor.xyz = inputToLinear( envColor.xyz );\n\n #ifdef ENVMAP_BLENDING_MULTIPLY\n\n outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_MIX )\n\n outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_ADD )\n\n outgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n #endif\n\n#endif\n"; - "}" +// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl - ].join("\n") +THREE.ShaderChunk[ 'specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n uniform sampler2D specularMap;\n\n#endif"; - }, +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl - 'particle_basic': { +THREE.ShaderChunk[ 'logdepthbuf_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n vFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n #endif\n\n#endif"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl - THREE.UniformsLib[ "particle" ], - THREE.UniformsLib[ "shadowmap" ] +THREE.ShaderChunk[ 'morphtarget_pars_vertex'] = "#ifdef USE_MORPHTARGETS\n\n #ifndef USE_MORPHNORMALS\n\n uniform float morphTargetInfluences[ 8 ];\n\n #else\n\n uniform float morphTargetInfluences[ 4 ];\n\n #endif\n\n#endif"; - ] ), +// File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl - vertexShader: [ +THREE.ShaderChunk[ 'specularmap_fragment'] = "float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n vec4 texelSpecular = texture2D( specularMap, vUv );\n specularStrength = texelSpecular.r;\n\n#else\n\n specularStrength = 1.0;\n\n#endif"; - "uniform float size;", - "uniform float scale;", +// File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], +THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n #else\n\n float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n #endif\n\n #ifdef FOG_EXP2\n\n float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n fogFactor = whiteCompliment( fogFactor );\n\n #else\n\n float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n #endif\n \n outgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n uniform sampler2D bumpMap;\n uniform float bumpScale;\n\n // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n vec2 dHdxy_fwd() {\n\n vec2 dSTdx = dFdx( vUv );\n vec2 dSTdy = dFdy( vUv );\n\n float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n return vec2( dBx, dBy );\n\n }\n\n vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n vec3 vSigmaX = dFdx( surf_pos );\n vec3 vSigmaY = dFdy( surf_pos );\n vec3 vN = surf_norm; // normalized\n\n vec3 R1 = cross( vSigmaY, vN );\n vec3 R2 = cross( vN, vSigmaX );\n\n float fDet = dot( vSigmaX, R1 );\n\n vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n return normalize( abs( fDet ) * surf_norm - vGrad );\n\n }\n\n#endif\n"; - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", +// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl - " #ifdef USE_SIZEATTENUATION", - " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", - " #else", - " gl_PointSize = size;", - " #endif", +THREE.ShaderChunk[ 'defaultnormal_vertex'] = "#ifdef USE_SKINNING\n\n vec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n vec3 objectNormal = morphedNormal;\n\n#else\n\n vec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n objectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; - " gl_Position = projectionMatrix * mvPosition;", +// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n varying vec3 vNormal;\n\n#endif\n"; - "}" +// File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl - ].join("\n"), +THREE.ShaderChunk[ 'skinbase_vertex'] = "#ifdef USE_SKINNING\n\n mat4 boneMatX = getBoneMatrix( skinIndex.x );\n mat4 boneMatY = getBoneMatrix( skinIndex.y );\n mat4 boneMatZ = getBoneMatrix( skinIndex.z );\n mat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif"; - fragmentShader: [ +// File:src/renderers/shaders/ShaderChunk/map_vertex.glsl - "uniform vec3 psColor;", - "uniform float opacity;", +THREE.ShaderChunk[ 'map_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n vUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_particle_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], +// File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl - "void main() {", +THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif"; - " gl_FragColor = vec4( psColor, opacity );", +// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n uniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif"; - "}" +// File:src/renderers/shaders/ShaderChunk/color_fragment.glsl - ].join("\n") +THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n diffuseColor.rgb *= vColor;\n\n#endif"; - }, +// File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl - 'dashed': { +THREE.ShaderChunk[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n vec3 morphed = vec3( 0.0 );\n morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n #ifndef USE_MORPHNORMALS\n\n morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n #endif\n\n morphed += position;\n\n#endif"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], +THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n vec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vReflect = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n#endif\n"; - { - "scale": { type: "f", value: 1 }, - "dashSize": { type: "f", value: 1 }, - "totalSize": { type: "f", value: 2 } - } +// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl - ] ), +THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n #ifdef SHADOWMAP_DEBUG\n\n vec3 frustumColors[3];\n frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n #endif\n\n #ifdef SHADOWMAP_CASCADE\n\n int inFrustumCount = 0;\n\n #endif\n\n float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n // if ( something && something ) breaks ATI OpenGL shader compiler\n // if ( all( something, something ) ) using this instead\n\n bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n bool inFrustum = all( inFrustumVec );\n\n // don't shadow pixels outside of light frustum\n // use just first frustum (for cascades)\n // don't shadow pixels behind far plane of light frustum\n\n #ifdef SHADOWMAP_CASCADE\n\n inFrustumCount += int( inFrustum );\n bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n #else\n\n bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n #endif\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest ) {\n\n shadowCoord.z += shadowBias[ i ];\n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\n\n for ( float y = -1.25; y <= 1.25; y += 1.25 )\n for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n\n }\n\n shadow /= 9.0;\n\n */\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.25 * xPixelOffset;\n float dy0 = -1.25 * yPixelOffset;\n float dx1 = 1.25 * xPixelOffset;\n float dy1 = 1.25 * yPixelOffset;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.0 * xPixelOffset;\n float dy0 = -1.0 * yPixelOffset;\n float dx1 = 1.0 * xPixelOffset;\n float dy1 = 1.0 * yPixelOffset;\n\n mat3 shadowKernel;\n mat3 depthKernel;\n\n depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n vec3 shadowZ = vec3( shadowCoord.z );\n shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n shadowKernel[0] *= vec3(0.25);\n\n shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n shadowKernel[1] *= vec3(0.25);\n\n shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n shadowKernel[2] *= vec3(0.25);\n\n vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n vec4 shadowValues;\n shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n shadow = dot( shadowValues, vec4( 1.0 ) );\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #else\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n\n // spot with multiple shadows is darker\n\n shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n #ifdef SHADOWMAP_CASCADE\n\n if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n #else\n\n if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n #endif\n\n #endif\n\n }\n\n // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n shadowColor = inputToLinear( shadowColor );\n\n outgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; - vertexShader: [ +// File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl - "uniform float scale;", - "attribute float lineDistance;", +THREE.ShaderChunk[ 'worldpos_vertex'] = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n #ifdef USE_SKINNING\n\n vec4 worldPosition = modelMatrix * skinned;\n\n #elif defined( USE_MORPHTARGETS )\n\n vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n #endif\n\n#endif\n"; - "varying float vLineDistance;", +// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], +THREE.ShaderChunk[ 'shadowmap_pars_fragment'] = "#ifdef USE_SHADOWMAP\n\n uniform sampler2D shadowMap[ MAX_SHADOWS ];\n uniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n uniform float shadowDarkness[ MAX_SHADOWS ];\n uniform float shadowBias[ MAX_SHADOWS ];\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n float unpackDepth( const in vec4 rgba_depth ) {\n\n const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n float depth = dot( rgba_depth, bit_shift );\n return depth;\n\n }\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'skinning_pars_vertex'] = "#ifdef USE_SKINNING\n\n uniform mat4 bindMatrix;\n uniform mat4 bindMatrixInverse;\n\n #ifdef BONE_TEXTURE\n\n uniform sampler2D boneTexture;\n uniform int boneTextureWidth;\n uniform int boneTextureHeight;\n\n mat4 getBoneMatrix( const in float i ) {\n\n float j = i * 4.0;\n float x = mod( j, float( boneTextureWidth ) );\n float y = floor( j / float( boneTextureWidth ) );\n\n float dx = 1.0 / float( boneTextureWidth );\n float dy = 1.0 / float( boneTextureHeight );\n\n y = dy * ( y + 0.5 );\n\n vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n mat4 bone = mat4( v1, v2, v3, v4 );\n\n return bone;\n\n }\n\n #else\n\n uniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n mat4 getBoneMatrix( const in float i ) {\n\n mat4 bone = boneGlobalMatrices[ int(i) ];\n return bone;\n\n }\n\n #endif\n\n#endif\n"; - " vLineDistance = scale * lineDistance;", +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n uniform float logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n #extension GL_EXT_frag_depth : enable\n varying float vFragDepth;\n\n #endif\n\n#endif"; - THREE.ShaderChunk[ "logdepthbuf_vertex" ], +// File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl - "}" +THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; - ].join("\n"), +// File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl - fragmentShader: [ +THREE.ShaderChunk[ 'alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n uniform sampler2D alphaMap;\n\n#endif\n"; - "uniform vec3 diffuse;", - "uniform float opacity;", +// File:src/renderers/shaders/UniformsUtils.js - "uniform float dashSize;", - "uniform float totalSize;", +/** + * Uniform Utilities + */ - "varying float vLineDistance;", +THREE.UniformsUtils = { - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + merge: function ( uniforms ) { - "void main() {", + var merged = {}; - " if ( mod( vLineDistance, totalSize ) > dashSize ) {", + for ( var u = 0; u < uniforms.length; u ++ ) { - " discard;", + var tmp = this.clone( uniforms[ u ] ); - " }", + for ( var p in tmp ) { - " gl_FragColor = vec4( diffuse, opacity );", + merged[ p ] = tmp[ p ]; - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], + } - "}" + } - ].join("\n") + return merged; - }, + }, - 'depth': { + clone: function ( uniforms_src ) { - uniforms: { + var uniforms_dst = {}; - "mNear": { type: "f", value: 1.0 }, - "mFar" : { type: "f", value: 2000.0 }, - "opacity" : { type: "f", value: 1.0 } + for ( var u in uniforms_src ) { - }, + uniforms_dst[ u ] = {}; - vertexShader: [ - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + for ( var p in uniforms_src[ u ] ) { - "void main() {", + var parameter_src = uniforms_src[ u ][ p ]; - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + if ( parameter_src instanceof THREE.Color || + parameter_src instanceof THREE.Vector2 || + parameter_src instanceof THREE.Vector3 || + parameter_src instanceof THREE.Vector4 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "}" + uniforms_dst[ u ][ p ] = parameter_src.clone(); - ].join("\n"), + } else if ( parameter_src instanceof Array ) { - fragmentShader: [ + uniforms_dst[ u ][ p ] = parameter_src.slice(); - "uniform float mNear;", - "uniform float mFar;", - "uniform float opacity;", - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + } else { - "void main() {", + uniforms_dst[ u ][ p ] = parameter_src; - THREE.ShaderChunk[ "logdepthbuf_fragment" ], + } - " #ifdef USE_LOGDEPTHBUF_EXT", + } - " float depth = gl_FragDepthEXT / gl_FragCoord.w;", + } - " #else", + return uniforms_dst; - " float depth = gl_FragCoord.z / gl_FragCoord.w;", + } - " #endif", +}; - " float color = 1.0 - smoothstep( mNear, mFar, depth );", - " gl_FragColor = vec4( vec3( color ), opacity );", +// File:src/renderers/shaders/UniformsLib.js - "}" +/** + * Uniforms library for shared webgl shaders + */ - ].join("\n") +THREE.UniformsLib = { - }, + common: { - 'normal': { + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, - uniforms: { + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "opacity" : { type: "f", value: 1.0 } + "lightMap" : { type: "t", value: null }, + "specularMap" : { type: "t", value: null }, + "alphaMap" : { type: "t", value: null }, - }, + "envMap" : { type: "t", value: null }, + "flipEnvMap" : { type: "f", value: - 1 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 }, - vertexShader: [ + "morphTargetInfluences" : { type: "f", value: 0 } - "varying vec3 vNormal;", + }, - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + bump: { - "void main() {", + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 } - " vNormal = normalize( normalMatrix * normal );", + }, - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], + normalmap: { - "}" + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } + }, - ].join("\n"), + fog : { - fragmentShader: [ + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - "uniform float opacity;", - "varying vec3 vNormal;", + }, - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + lights: { - "void main() {", + "ambientLightColor" : { type: "fv", value: [] }, - " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, - THREE.ShaderChunk[ "logdepthbuf_fragment" ], + "hemisphereLightDirection" : { type: "fv", value: [] }, + "hemisphereLightSkyColor" : { type: "fv", value: [] }, + "hemisphereLightGroundColor" : { type: "fv", value: [] }, - "}" + "pointLightColor" : { type: "fv", value: [] }, + "pointLightPosition" : { type: "fv", value: [] }, + "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecay" : { type: "fv1", value: [] }, - ].join("\n") + "spotLightColor" : { type: "fv", value: [] }, + "spotLightPosition" : { type: "fv", value: [] }, + "spotLightDirection" : { type: "fv", value: [] }, + "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightAngleCos" : { type: "fv1", value: [] }, + "spotLightExponent" : { type: "fv1", value: [] }, + "spotLightDecay" : { type: "fv1", value: [] } - }, + }, - /* ------------------------------------------------------------------------- - // Normal map shader - // - Blinn-Phong - // - normal + diffuse + specular + AO + displacement + reflection + shadow maps - // - point and directional lights (use with "lights: true" material option) - ------------------------------------------------------------------------- */ + particle: { - 'normalmap' : { + "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + "size" : { type: "f", value: 1.0 }, + "scale" : { type: "f", value: 1.0 }, + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - uniforms: THREE.UniformsUtils.merge( [ + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], + }, - { + shadowmap: { - "enableAO" : { type: "i", value: 0 }, - "enableDiffuse" : { type: "i", value: 0 }, - "enableSpecular" : { type: "i", value: 0 }, - "enableReflection": { type: "i", value: 0 }, - "enableDisplacement": { type: "i", value: 0 }, + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, - "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture - "tDiffuse" : { type: "t", value: null }, - "tCube" : { type: "t", value: null }, - "tNormal" : { type: "t", value: null }, - "tSpecular" : { type: "t", value: null }, - "tAO" : { type: "t", value: null }, + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, - "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + "shadowMatrix" : { type: "m4v", value: [] } - "uDisplacementBias": { type: "f", value: 0.0 }, - "uDisplacementScale": { type: "f", value: 1.0 }, + } - "diffuse": { type: "c", value: new THREE.Color( 0xffffff ) }, - "specular": { type: "c", value: new THREE.Color( 0x111111 ) }, - "ambient": { type: "c", value: new THREE.Color( 0xffffff ) }, - "shininess": { type: "f", value: 30 }, - "opacity": { type: "f", value: 1 }, +}; - "useRefract": { type: "i", value: 0 }, - "refractionRatio": { type: "f", value: 0.98 }, - "reflectivity": { type: "f", value: 0.5 }, +// File:src/renderers/shaders/ShaderLib.js - "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, - "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, +/** + * Webgl Shader Library for three.js + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } +THREE.ShaderLib = { - ] ), + 'basic': { - fragmentShader: [ + uniforms: THREE.UniformsUtils.merge( [ - "uniform vec3 ambient;", - "uniform vec3 diffuse;", - "uniform vec3 specular;", - "uniform float shininess;", - "uniform float opacity;", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] - "uniform bool enableDiffuse;", - "uniform bool enableSpecular;", - "uniform bool enableAO;", - "uniform bool enableReflection;", + ] ), - "uniform sampler2D tDiffuse;", - "uniform sampler2D tNormal;", - "uniform sampler2D tSpecular;", - "uniform sampler2D tAO;", + vertexShader: [ - "uniform samplerCube tCube;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "uniform vec2 uNormalScale;", + "void main() {", - "uniform bool useRefract;", - "uniform float refractionRatio;", - "uniform float reflectivity;", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", + " #ifdef USE_ENVMAP", - "uniform vec3 ambientLightColor;", + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - "#if MAX_DIR_LIGHTS > 0", + " #endif", - " uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - " uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "#endif", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "#if MAX_HEMI_LIGHTS > 0", + "}" - " uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - " uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + ].join("\n"), - "#endif", + fragmentShader: [ - "#if MAX_POINT_LIGHTS > 0", + "uniform vec3 diffuse;", + "uniform float opacity;", - " uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - " uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - " uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "#endif", + "void main() {", - "#if MAX_SPOT_LIGHTS > 0", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - " uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - " uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - " uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - "#endif", + " outgoingLight = diffuseColor.rgb;", // simple shader - "#ifdef WRAP_AROUND", + THREE.ShaderChunk[ "lightmap_fragment" ], // TODO: Light map on an otherwise unlit surface doesn't make sense. + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], // TODO: Shadows on an otherwise unlit surface doesn't make sense. - " uniform vec3 wrapRGB;", + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - "#endif", + THREE.ShaderChunk[ "fog_fragment" ], - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + "}" - "void main() {", - THREE.ShaderChunk[ "logdepthbuf_fragment" ], + ].join("\n") - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + }, - " vec3 specularTex = vec3( 1.0 );", + 'lambert': { - " vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", - " normalTex.xy *= uNormalScale;", - " normalTex = normalize( normalTex );", + uniforms: THREE.UniformsUtils.merge( [ - " if( enableDiffuse ) {", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - " #ifdef GAMMA_INPUT", + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } - " vec4 texelColor = texture2D( tDiffuse, vUv );", - " texelColor.xyz *= texelColor.xyz;", + ] ), - " gl_FragColor = gl_FragColor * texelColor;", + vertexShader: [ - " #else", + "#define LAMBERT", - " gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", + "varying vec3 vLightFront;", - " #endif", + "#ifdef DOUBLE_SIDED", - " }", + " varying vec3 vLightBack;", - " if( enableAO ) {", + "#endif", - " #ifdef GAMMA_INPUT", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - " vec4 aoColor = texture2D( tAO, vUv );", - " aoColor.xyz *= aoColor.xyz;", + "void main() {", - " gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - " #else", + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - " gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - " #endif", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - " }", + "}" - " if( enableSpecular )", - " specularTex = texture2D( tSpecular, vUv ).xyz;", + ].join("\n"), - " mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", - " vec3 finalNormal = tsb * normalTex;", + fragmentShader: [ - " #ifdef FLIP_SIDED", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform float opacity;", - " finalNormal = -finalNormal;", + "varying vec3 vLightFront;", - " #endif", + "#ifdef DOUBLE_SIDED", - " vec3 normal = normalize( finalNormal );", - " vec3 viewPosition = normalize( vViewPosition );", + " varying vec3 vLightBack;", - // point lights + "#endif", - " #if MAX_POINT_LIGHTS > 0", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " vec3 pointDiffuse = vec3( 0.0 );", - " vec3 pointSpecular = vec3( 0.0 );", + "void main() {", - " for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - " vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - " vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - " float pointDistance = 1.0;", - " if ( pointLightDistance[ i ] > 0.0 )", - " pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", + " #ifdef DOUBLE_SIDED", - " pointVector = normalize( pointVector );", + //"float isFront = float( gl_FrontFacing );", + //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", - // diffuse + " if ( gl_FrontFacing )", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", + " else", + " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", - " #ifdef WRAP_AROUND", + " #else", - " float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", - " float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - " vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + " #endif", - " #else", + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - " float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - " #endif", + THREE.ShaderChunk[ "fog_fragment" ], - " pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - // specular + "}" - " vec3 pointHalfVector = normalize( pointVector + viewPosition );", - " float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - " float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + ].join("\n") - // 2.0 => 2.0001 is hack to work around ANGLE bug + }, - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + 'phong': { - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", - " pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", + uniforms: THREE.UniformsUtils.merge( [ - " }", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bump" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - " #endif", + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } - // spot lights + ] ), - " #if MAX_SPOT_LIGHTS > 0", + vertexShader: [ - " vec3 spotDiffuse = vec3( 0.0 );", - " vec3 spotSpecular = vec3( 0.0 );", + "#define PHONG", - " for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + "varying vec3 vViewPosition;", - " vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - " vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", + "#ifndef FLAT_SHADED", - " float spotDistance = 1.0;", - " if ( spotLightDistance[ i ] > 0.0 )", - " spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", + " varying vec3 vNormal;", - " spotVector = normalize( spotVector );", + "#endif", - " float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_phong_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - " if ( spotEffect > spotLightAngleCos[ i ] ) {", + "void main() {", - " spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - // diffuse + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - " #ifdef WRAP_AROUND", + "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED - " float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", - " float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", + " vNormal = normalize( transformedNormal );", - " vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + "#endif", - " #else", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - " float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", + " vViewPosition = -mvPosition.xyz;", - " #endif", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - " spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;", + "}" - // specular + ].join("\n"), - " vec3 spotHalfVector = normalize( spotVector + viewPosition );", - " float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - " float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + fragmentShader: [ - // 2.0 => 2.0001 is hack to work around ANGLE bug + "#define PHONG", - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", - " spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_phong_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " }", + "void main() {", - " }", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - " #endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - // directional lights + THREE.ShaderChunk[ "lights_phong_fragment" ], - " #if MAX_DIR_LIGHTS > 0", + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - " vec3 dirDiffuse = vec3( 0.0 );", - " vec3 dirSpecular = vec3( 0.0 );", + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - " for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", + THREE.ShaderChunk[ "fog_fragment" ], - " vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - " vec3 dirVector = normalize( lDirection.xyz );", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - // diffuse + "}" - " #ifdef WRAP_AROUND", + ].join("\n") - " float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", - " float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", + }, - " vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", + 'particle_basic': { - " #else", + uniforms: THREE.UniformsUtils.merge( [ - " float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + THREE.UniformsLib[ "particle" ], + THREE.UniformsLib[ "shadowmap" ] - " #endif", + ] ), - " dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;", + vertexShader: [ - // specular + "uniform float size;", + "uniform float scale;", - " vec3 dirHalfVector = normalize( dirVector + viewPosition );", - " float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - " float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - // 2.0 => 2.0001 is hack to work around ANGLE bug + "void main() {", - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + THREE.ShaderChunk[ "color_vertex" ], - " vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", - " dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - " }", + " #ifdef USE_SIZEATTENUATION", + " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + " #else", + " gl_PointSize = size;", + " #endif", - " #endif", + " gl_Position = projectionMatrix * mvPosition;", - // hemisphere lights + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - " #if MAX_HEMI_LIGHTS > 0", + "}" - " vec3 hemiDiffuse = vec3( 0.0 );", - " vec3 hemiSpecular = vec3( 0.0 );" , + ].join("\n"), - " for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + fragmentShader: [ - " vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - " vec3 lVector = normalize( lDirection.xyz );", + "uniform vec3 psColor;", + "uniform float opacity;", - // diffuse + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_particle_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " float dotProduct = dot( normal, lVector );", - " float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + "void main() {", - " vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( psColor, opacity );", - " hemiDiffuse += diffuse * hemiColor;", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_particle_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], - // specular (sky light) + " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], - " vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", - " float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - " float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - // specular (ground light) + "}" - " vec3 lVectorGround = -lVector;", + ].join("\n") - " vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", - " float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - " float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + }, - " float dotProductGround = dot( normal, lVectorGround );", + 'dashed': { - // 2.0 => 2.0001 is hack to work around ANGLE bug + uniforms: THREE.UniformsUtils.merge( [ - " float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], - " vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", - " vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", - " hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + { + "scale" : { type: "f", value: 1 }, + "dashSize" : { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } - " }", + ] ), - " #endif", + vertexShader: [ - // all lights contribution summation + "uniform float scale;", + "attribute float lineDistance;", - " vec3 totalDiffuse = vec3( 0.0 );", - " vec3 totalSpecular = vec3( 0.0 );", + "varying float vLineDistance;", - " #if MAX_DIR_LIGHTS > 0", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - " totalDiffuse += dirDiffuse;", - " totalSpecular += dirSpecular;", + "void main() {", - " #endif", + THREE.ShaderChunk[ "color_vertex" ], - " #if MAX_HEMI_LIGHTS > 0", + " vLineDistance = scale * lineDistance;", - " totalDiffuse += hemiDiffuse;", - " totalSpecular += hemiSpecular;", + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * mvPosition;", - " #endif", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - " #if MAX_POINT_LIGHTS > 0", + "}" - " totalDiffuse += pointDiffuse;", - " totalSpecular += pointSpecular;", + ].join("\n"), - " #endif", + fragmentShader: [ - " #if MAX_SPOT_LIGHTS > 0", + "uniform vec3 diffuse;", + "uniform float opacity;", - " totalDiffuse += spotDiffuse;", - " totalSpecular += spotSpecular;", + "uniform float dashSize;", + "uniform float totalSize;", - " #endif", + "varying float vLineDistance;", - " #ifdef METAL", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );", + "void main() {", - " #else", + " if ( mod( vLineDistance, totalSize ) > dashSize ) {", - " gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + " discard;", - " #endif", + " }", - " if ( enableReflection ) {", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - " vec3 vReflect;", - " vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], - " if ( useRefract ) {", + " outgoingLight = diffuseColor.rgb;", // simple shader - " vReflect = refract( cameraToVertex, normal, refractionRatio );", + THREE.ShaderChunk[ "fog_fragment" ], - " } else {", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - " vReflect = reflect( cameraToVertex, normal );", + "}" - " }", + ].join("\n") - " vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", + }, - " #ifdef GAMMA_INPUT", + 'depth': { - " cubeColor.xyz *= cubeColor.xyz;", + uniforms: { - " #endif", + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } - " gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );", + }, - " }", + vertexShader: [ - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "}" + "void main() {", - ].join("\n"), + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - vertexShader: [ + "}" - "attribute vec4 tangent;", + ].join("\n"), - "uniform vec2 uOffset;", - "uniform vec2 uRepeat;", + fragmentShader: [ - "uniform bool enableDisplacement;", + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", - "#ifdef VERTEX_TEXTURES", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " uniform sampler2D tDisplacement;", - " uniform float uDisplacementScale;", - " uniform float uDisplacementBias;", + "void main() {", - "#endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", + " #ifdef USE_LOGDEPTHBUF_EXT", - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", + " float depth = gl_FragDepthEXT / gl_FragCoord.w;", - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + " #else", - "void main() {", + " float depth = gl_FragCoord.z / gl_FragCoord.w;", - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], + " #endif", - // normal, tangent and binormal vectors + " float color = 1.0 - smoothstep( mNear, mFar, depth );", + " gl_FragColor = vec4( vec3( color ), opacity );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - " #ifdef USE_SKINNING", + "}" - " vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + ].join("\n") - " vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", - " vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + }, - " #else", + 'normal': { - " vNormal = normalize( normalMatrix * normal );", - " vTangent = normalize( normalMatrix * tangent.xyz );", + uniforms: { - " #endif", + "opacity" : { type: "f", value: 1.0 } - " vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + }, - " vUv = uv * uRepeat + uOffset;", + vertexShader: [ - // displacement mapping + "varying vec3 vNormal;", - " vec3 displacedPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - " #ifdef VERTEX_TEXTURES", + "void main() {", - " if ( enableDisplacement ) {", + " vNormal = normalize( normalMatrix * normal );", - " vec3 dv = texture2D( tDisplacement, uv ).xyz;", - " float df = uDisplacementScale * dv.x + uDisplacementBias;", - " displacedPosition = position + normalize( normal ) * df;", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - " } else {", + "}" - " #ifdef USE_SKINNING", + ].join("\n"), - " vec4 skinVertex = vec4( position, 1.0 );", + fragmentShader: [ - " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - " skinned += boneMatY * skinVertex * skinWeight.y;", - " skinned += boneMatZ * skinVertex * skinWeight.z;", - " skinned += boneMatW * skinVertex * skinWeight.w;", + "uniform float opacity;", + "varying vec3 vNormal;", - " displacedPosition = skinned.xyz;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " #else", + "void main() {", - " displacedPosition = position;", + " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", - " #endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - " }", + "}" - " #else", + ].join("\n") - " #ifdef USE_SKINNING", + }, - " vec4 skinVertex = vec4( position, 1.0 );", + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - " vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - " skinned += boneMatY * skinVertex * skinWeight.y;", - " skinned += boneMatZ * skinVertex * skinWeight.z;", - " skinned += boneMatW * skinVertex * skinWeight.w;", + 'cube': { - " displacedPosition = skinned.xyz;", + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, - " #else", + vertexShader: [ - " displacedPosition = position;", + "varying vec3 vWorldPosition;", - " #endif", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - " #endif", + "void main() {", - // + " vWorldPosition = transformDirection( position, modelMatrix );", - " vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", - " vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * mvPosition;", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], + "}" - // + ].join("\n"), - " vWorldPosition = worldPosition.xyz;", - " vViewPosition = -mvPosition.xyz;", + fragmentShader: [ - // shadows + "uniform samplerCube tCube;", + "uniform float tFlip;", - " #ifdef USE_SHADOWMAP", + "varying vec3 vWorldPosition;", - " for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - " vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + "void main() {", - " }", + " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", - " #endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - "}" + "}" - ].join("\n") + ].join("\n") - }, + }, - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - 'cube': { + 'equirect': { - uniforms: { "tCube": { type: "t", value: null }, - "tFlip": { type: "f", value: -1 } }, + uniforms: { "tEquirect": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, - vertexShader: [ + vertexShader: [ - "varying vec3 vWorldPosition;", + "varying vec3 vWorldPosition;", - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "void main() {", + "void main() {", - " vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", - " vWorldPosition = worldPosition.xyz;", + " vWorldPosition = transformDirection( position, modelMatrix );", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "}" + "}" - ].join("\n"), + ].join("\n"), - fragmentShader: [ + fragmentShader: [ - "uniform samplerCube tCube;", - "uniform float tFlip;", + "uniform sampler2D tEquirect;", + "uniform float tFlip;", - "varying vec3 vWorldPosition;", + "varying vec3 vWorldPosition;", - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "void main() {", + "void main() {", - " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + // " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + "vec3 direction = normalize( vWorldPosition );", + "vec2 sampleUV;", + "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", + "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", + "gl_FragColor = texture2D( tEquirect, sampleUV );", - THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - "}" + "}" - ].join("\n") + ].join("\n") - }, + }, - // Depth encoding into RGBA texture - // based on SpiderGL shadow map example - // http://spidergl.org/example.php?id=6 - // originally from - // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD - // see also here: - // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + /* Depth encoding into RGBA texture + * + * based on SpiderGL shadow map example + * http://spidergl.org/example.php?id=6 + * + * originally from + * http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + * + * see also + * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + */ - 'depthRGBA': { + 'depthRGBA': { - uniforms: {}, + uniforms: {}, - vertexShader: [ + vertexShader: [ - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "void main() {", + "void main() {", - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "}" + "}" - ].join("\n"), + ].join("\n"), - fragmentShader: [ + fragmentShader: [ - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "vec4 pack_depth( const in float depth ) {", + "vec4 pack_depth( const in float depth ) {", - " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - " vec4 res = fract( depth * bit_shift );", - " res -= res.xxyz * bit_mask;", - " return res;", + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", - "}", + "}", - "void main() {", + "void main() {", - THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - " #ifdef USE_LOGDEPTHBUF_EXT", + " #ifdef USE_LOGDEPTHBUF_EXT", - " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", + " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", - " #else", + " #else", - " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", - " #endif", + " #endif", - //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", - //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", - //"gl_FragData[ 0 ] = pack_depth( z );", - //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", - "}" + "}" - ].join("\n") + ].join("\n") - } + } }; +// File:src/renderers/WebGLRenderer.js + /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ @@ -20751,17596 +17953,17301 @@ THREE.ShaderLib = { THREE.WebGLRenderer = function ( parameters ) { - console.log( 'THREE.WebGLRenderer', THREE.REVISION ); - - parameters = parameters || {}; - - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), - _context = parameters.context !== undefined ? parameters.context : null, - - _precision = parameters.precision !== undefined ? parameters.precision : 'highp', - - _buffers = {}, - - _alpha = parameters.alpha !== undefined ? parameters.alpha : false, - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, + console.log( 'THREE.WebGLRenderer', THREE.REVISION ); - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0; + parameters = parameters || {}; - // public properties + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, - this.domElement = _canvas; - this.context = null; - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; + pixelRatio = 1, - // clearing + _precision = parameters.precision !== undefined ? parameters.precision : 'highp', - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + _alpha = parameters.alpha !== undefined ? parameters.alpha : false, + _depth = parameters.depth !== undefined ? parameters.depth : true, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, - // scene graph + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = 0; - this.sortObjects = true; - this.autoUpdateObjects = true; + var lights = []; - // physically based shading + var _webglObjects = {}; + var _webglObjectsImmediate = []; - this.gammaInput = false; - this.gammaOutput = false; + var opaqueObjects = []; + var transparentObjects = []; - // shadow map + var sprites = []; + var lensFlares = []; - this.shadowMapEnabled = false; - this.shadowMapAutoUpdate = true; - this.shadowMapType = THREE.PCFShadowMap; - this.shadowMapCullFace = THREE.CullFaceFront; - this.shadowMapDebug = false; - this.shadowMapCascade = false; + // public properties - // morphs + this.domElement = _canvas; + this.context = null; - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; + // clearing - // flags + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; - this.autoScaleCubemaps = true; + // scene graph - // custom render plugins + this.sortObjects = true; - this.renderPluginsPre = []; - this.renderPluginsPost = []; + // physically based shading - // info + this.gammaFactor = 2.0; // for backwards compatibility + this.gammaInput = false; + this.gammaOutput = false; - this.info = { + // shadow map - memory: { + this.shadowMapEnabled = false; + this.shadowMapType = THREE.PCFShadowMap; + this.shadowMapCullFace = THREE.CullFaceFront; + this.shadowMapDebug = false; + this.shadowMapCascade = false; - programs: 0, - geometries: 0, - textures: 0 + // morphs - }, + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; - render: { + // flags - calls: 0, - vertices: 0, - faces: 0, - points: 0 + this.autoScaleCubemaps = true; - } + // info - }; + this.info = { - // internal properties + memory: { - var _this = this, + programs: 0, + geometries: 0, + textures: 0 - _programs = [], - - // internal state cache - - _currentProgram = null, - _currentFramebuffer = null, - _currentMaterialId = -1, - _currentGeometryGroupHash = null, - _currentCamera = null, - - _usedTextureUnits = 0, - - // GL state cache - - _oldDoubleSided = -1, - _oldFlipSided = -1, + }, - _oldBlending = -1, + render: { - _oldBlendEquation = -1, - _oldBlendSrc = -1, - _oldBlendDst = -1, + calls: 0, + vertices: 0, + faces: 0, + points: 0 - _oldDepthTest = -1, - _oldDepthWrite = -1, + } - _oldPolygonOffset = null, - _oldPolygonOffsetFactor = null, - _oldPolygonOffsetUnits = null, + }; - _oldLineWidth = null, + // internal properties - _viewportX = 0, - _viewportY = 0, - _viewportWidth = _canvas.width, - _viewportHeight = _canvas.height, - _currentWidth = 0, - _currentHeight = 0, + var _this = this, - _newAttributes = new Uint8Array( 16 ), - _enabledAttributes = new Uint8Array( 16 ), + _programs = [], - // frustum + // internal state cache - _frustum = new THREE.Frustum(), + _currentProgram = null, + _currentFramebuffer = null, + _currentMaterialId = - 1, + _currentGeometryProgram = '', + _currentCamera = null, - // camera matrices cache + _usedTextureUnits = 0, - _projScreenMatrix = new THREE.Matrix4(), - _projScreenMatrixPS = new THREE.Matrix4(), + _viewportX = 0, + _viewportY = 0, + _viewportWidth = _canvas.width, + _viewportHeight = _canvas.height, + _currentWidth = 0, + _currentHeight = 0, - _vector3 = new THREE.Vector3(), + // frustum - // light arrays cache + _frustum = new THREE.Frustum(), - _direction = new THREE.Vector3(), + // camera matrices cache - _lightsNeedUpdate = true, + _projScreenMatrix = new THREE.Matrix4(), - _lights = { + _vector3 = new THREE.Vector3(), - ambient: [ 0, 0, 0 ], - directional: { length: 0, colors: new Array(), positions: new Array() }, - point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, - spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, - hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } + // light arrays cache - }; + _direction = new THREE.Vector3(), - // initialize + _lightsNeedUpdate = true, - var _gl; + _lights = { - var _glExtensionTextureFloat; - var _glExtensionTextureFloatLinear; - var _glExtensionStandardDerivatives; - var _glExtensionTextureFilterAnisotropic; - var _glExtensionCompressedTextureS3TC; - var _glExtensionElementIndexUint; - var _glExtensionFragDepth; - + ambient: [ 0, 0, 0 ], + directional: { length: 0, colors:[], positions: [] }, + point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, + spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, + hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } - initGL(); + }; - setDefaultGLState(); + // initialize - this.context = _gl; + var _gl; - // GPU capabilities + try { - 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 attributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer + }; - var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; + _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); - var _supportsVertexTextures = ( _maxVertexTextures > 0 ); - var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; + if ( _gl === null ) { - var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; + if ( _canvas.getContext( 'webgl') !== null ) { - // + throw 'Error creating WebGL context with your selected attributes.'; - var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); - var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); - var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); + } else { - var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); - var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); - var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); + throw 'Error creating WebGL context.'; - var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); - var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); - var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); + } - var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); - var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); - var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); + } - // clamp precision to maximum available + _canvas.addEventListener( 'webglcontextlost', function ( event ) { - var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; - var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; + event.preventDefault(); - if ( _precision === "highp" && ! highpAvailable ) { + resetGLState(); + setDefaultGLState(); - if ( mediumpAvailable ) { + _webglObjects = {}; - _precision = "mediump"; - console.warn( "WebGLRenderer: highp not supported, using mediump" ); + }, false); - } else { + } catch ( error ) { - _precision = "lowp"; - console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); + THREE.error( 'THREE.WebGLRenderer: ' + error ); - } + } - } + var state = new THREE.WebGLState( _gl, paramThreeToGL ); - if ( _precision === "mediump" && ! mediumpAvailable ) { + if ( _gl.getShaderPrecisionFormat === undefined ) { - _precision = "lowp"; - console.warn( "WebGLRenderer: mediump not supported, using lowp" ); + _gl.getShaderPrecisionFormat = function () { - } + return { + 'rangeMin': 1, + 'rangeMax': 1, + 'precision': 1 + }; - // API + } - this.getContext = function () { + } - return _gl; + var extensions = new THREE.WebGLExtensions( _gl ); - }; + extensions.get( 'OES_texture_float' ); + extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); + extensions.get( 'OES_standard_derivatives' ); - this.supportsVertexTextures = function () { + if ( _logarithmicDepthBuffer ) { - return _supportsVertexTextures; + extensions.get( 'EXT_frag_depth' ); - }; + } - this.supportsFloatTextures = function () { + // - return _glExtensionTextureFloat; + var glClearColor = function ( r, g, b, a ) { - }; + if ( _premultipliedAlpha === true ) { - this.supportsStandardDerivatives = function () { + r *= a; g *= a; b *= a; - return _glExtensionStandardDerivatives; + } - }; + _gl.clearColor( r, g, b, a ); - this.supportsCompressedTextureS3TC = function () { + }; - return _glExtensionCompressedTextureS3TC; + var setDefaultGLState = function () { - }; + _gl.clearColor( 0, 0, 0, 1 ); + _gl.clearDepth( 1 ); + _gl.clearStencil( 0 ); - this.getMaxAnisotropy = function () { + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthFunc( _gl.LEQUAL ); - return _maxAnisotropy; + _gl.frontFace( _gl.CCW ); + _gl.cullFace( _gl.BACK ); + _gl.enable( _gl.CULL_FACE ); - }; + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); - this.getPrecision = function () { + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - return _precision; + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - }; + }; - this.setSize = function ( width, height, updateStyle ) { + var resetGLState = function () { - _canvas.width = width * this.devicePixelRatio; - _canvas.height = height * this.devicePixelRatio; + _currentProgram = null; + _currentCamera = null; - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + _currentGeometryProgram = ''; + _currentMaterialId = - 1; - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + _lightsNeedUpdate = true; - } + state.reset(); - this.setViewport( 0, 0, width, height ); + }; - }; + setDefaultGLState(); - this.setViewport = function ( x, y, width, height ) { + this.context = _gl; + this.state = state; - _viewportX = x * this.devicePixelRatio; - _viewportY = y * this.devicePixelRatio; + // GPU capabilities - _viewportWidth = width * this.devicePixelRatio; - _viewportHeight = height * this.devicePixelRatio; + 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 ); - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + var _supportsVertexTextures = _maxVertexTextures > 0; + var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' ); - }; + // - this.setScissor = function ( x, y, width, height ) { + var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); + var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); - _gl.scissor( - x * this.devicePixelRatio, - y * this.devicePixelRatio, - width * this.devicePixelRatio, - height * this.devicePixelRatio - ); + var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); + var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); - }; + var getCompressedTextureFormats = ( function () { - this.enableScissorTest = function ( enable ) { + var array; - enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); + return function () { - }; + if ( array !== undefined ) { - // Clearing + return array; - this.setClearColor = function ( color, alpha ) { + } - _clearColor.set( color ); - _clearAlpha = alpha !== undefined ? alpha : 1; + array = []; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { - }; + var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); - this.setClearColorHex = function ( hex, alpha ) { + for ( var i = 0; i < formats.length; i ++ ) { - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); + array.push( formats[ i ] ); - }; + } - this.getClearColor = function () { + } - return _clearColor; + return array; - }; + }; - this.getClearAlpha = function () { + } )(); - return _clearAlpha; + // clamp precision to maximum available - }; + var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; + var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; - this.clear = function ( color, depth, stencil ) { + if ( _precision === 'highp' && ! highpAvailable ) { - var bits = 0; + if ( mediumpAvailable ) { - 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; + _precision = 'mediump'; + THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); - _gl.clear( bits ); + } else { - }; + _precision = 'lowp'; + THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); - this.clearColor = function () { + } - _gl.clear( _gl.COLOR_BUFFER_BIT ); + } - }; + if ( _precision === 'mediump' && ! mediumpAvailable ) { - this.clearDepth = function () { + _precision = 'lowp'; + THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); - _gl.clear( _gl.DEPTH_BUFFER_BIT ); + } - }; + // Plugins - this.clearStencil = function () { + var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate ); - _gl.clear( _gl.STENCIL_BUFFER_BIT ); + var spritePlugin = new THREE.SpritePlugin( this, sprites ); + var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); - }; + // API - this.clearTarget = function ( renderTarget, color, depth, stencil ) { + this.getContext = function () { - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); + return _gl; - }; + }; - // Plugins + this.forceContextLoss = function () { - this.addPostPlugin = function ( plugin ) { + extensions.get( 'WEBGL_lose_context' ).loseContext(); - plugin.init( this ); - this.renderPluginsPost.push( plugin ); + }; - }; + this.supportsVertexTextures = function () { - this.addPrePlugin = function ( plugin ) { + return _supportsVertexTextures; - plugin.init( this ); - this.renderPluginsPre.push( plugin ); + }; - }; + this.supportsFloatTextures = function () { - // Rendering + return extensions.get( 'OES_texture_float' ); - this.updateShadowMap = function ( scene, camera ) { + }; - _currentProgram = null; - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; - _lightsNeedUpdate = true; - _oldDoubleSided = -1; - _oldFlipSided = -1; + this.supportsHalfFloatTextures = function () { - this.shadowMapPlugin.update( scene, camera ); + return extensions.get( 'OES_texture_half_float' ); - }; + }; - // Internal functions + this.supportsStandardDerivatives = function () { - // Buffer allocation + return extensions.get( 'OES_standard_derivatives' ); - function createParticleBuffers ( geometry ) { + }; - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); + this.supportsCompressedTextureS3TC = function () { - _this.info.memory.geometries ++; + return extensions.get( 'WEBGL_compressed_texture_s3tc' ); - }; + }; - function createLineBuffers ( geometry ) { + this.supportsCompressedTexturePVRTC = function () { - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); - geometry.__webglLineDistanceBuffer = _gl.createBuffer(); + return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - _this.info.memory.geometries ++; + }; - }; + this.supportsBlendMinMax = function () { - function createMeshBuffers ( geometryGroup ) { + return extensions.get( 'EXT_blend_minmax' ); - geometryGroup.__webglVertexBuffer = _gl.createBuffer(); - geometryGroup.__webglNormalBuffer = _gl.createBuffer(); - geometryGroup.__webglTangentBuffer = _gl.createBuffer(); - geometryGroup.__webglColorBuffer = _gl.createBuffer(); - geometryGroup.__webglUVBuffer = _gl.createBuffer(); - geometryGroup.__webglUV2Buffer = _gl.createBuffer(); + }; - geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); - geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); + this.getMaxAnisotropy = ( function () { - geometryGroup.__webglFaceBuffer = _gl.createBuffer(); - geometryGroup.__webglLineBuffer = _gl.createBuffer(); + var value; - var m, ml; + return function () { - if ( geometryGroup.numMorphTargets ) { + if ( value !== undefined ) { - geometryGroup.__webglMorphTargetsBuffers = []; + return value; - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + } - geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - } + value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; - } + return value; - if ( geometryGroup.numMorphNormals ) { + } - geometryGroup.__webglMorphNormalsBuffers = []; + } )(); - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + this.getPrecision = function () { - geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); + return _precision; - } + }; - } + this.getPixelRatio = function () { - _this.info.memory.geometries ++; + return pixelRatio; - }; + }; - // Events + this.setPixelRatio = function ( value ) { - var onGeometryDispose = function ( event ) { + pixelRatio = value; - var geometry = event.target; + }; - geometry.removeEventListener( 'dispose', onGeometryDispose ); + this.setSize = function ( width, height, updateStyle ) { - deallocateGeometry( geometry ); + _canvas.width = width * pixelRatio; + _canvas.height = height * pixelRatio; - }; + if ( updateStyle !== false ) { - var onTextureDispose = function ( event ) { + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; - var texture = event.target; + } - texture.removeEventListener( 'dispose', onTextureDispose ); + this.setViewport( 0, 0, width, height ); - deallocateTexture( texture ); + }; - _this.info.memory.textures --; + this.setViewport = function ( x, y, width, height ) { + _viewportX = x * pixelRatio; + _viewportY = y * pixelRatio; - }; + _viewportWidth = width * pixelRatio; + _viewportHeight = height * pixelRatio; - var onRenderTargetDispose = function ( event ) { + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - var renderTarget = event.target; + }; - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + this.setScissor = function ( x, y, width, height ) { - deallocateRenderTarget( renderTarget ); + _gl.scissor( + x * pixelRatio, + y * pixelRatio, + width * pixelRatio, + height * pixelRatio + ); - _this.info.memory.textures --; + }; - }; + this.enableScissorTest = function ( enable ) { - var onMaterialDispose = function ( event ) { + enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); - var material = event.target; + }; - material.removeEventListener( 'dispose', onMaterialDispose ); + // Clearing - deallocateMaterial( material ); + this.getClearColor = function () { - }; + return _clearColor; - // Buffer deallocation + }; - var deleteBuffers = function ( geometry ) { + this.setClearColor = function ( color, alpha ) { - if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); - if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); - if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); - if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); - if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); - if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); + _clearColor.set( color ); - if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); - if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); + _clearAlpha = alpha !== undefined ? alpha : 1; - if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); - if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); - // custom attributes + }; - if ( geometry.__webglCustomAttributesList !== undefined ) { + this.getClearAlpha = function () { - for ( var id in geometry.__webglCustomAttributesList ) { + return _clearAlpha; - _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); + }; - } + this.setClearAlpha = function ( alpha ) { - } + _clearAlpha = alpha; - _this.info.memory.geometries --; + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - }; + }; - var deallocateGeometry = function ( geometry ) { + this.clear = function ( color, depth, stencil ) { - geometry.__webglInit = undefined; + var bits = 0; - if ( geometry instanceof THREE.BufferGeometry ) { + 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; - var attributes = geometry.attributes; + _gl.clear( bits ); - for ( var key in attributes ) { + }; - if ( attributes[ key ].buffer !== undefined ) { + this.clearColor = function () { - _gl.deleteBuffer( attributes[ key ].buffer ); - - } + _gl.clear( _gl.COLOR_BUFFER_BIT ); - } + }; - _this.info.memory.geometries --; + this.clearDepth = function () { - } else { + _gl.clear( _gl.DEPTH_BUFFER_BIT ); - if ( geometry.geometryGroups !== undefined ) { + }; - for ( var g in geometry.geometryGroups ) { + this.clearStencil = function () { - var geometryGroup = geometry.geometryGroups[ g ]; + _gl.clear( _gl.STENCIL_BUFFER_BIT ); - if ( geometryGroup.numMorphTargets !== undefined ) { + }; - for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + this.clearTarget = function ( renderTarget, color, depth, stencil ) { - _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); - } + }; - } + // Reset - if ( geometryGroup.numMorphNormals !== undefined ) { + this.resetGLState = resetGLState; - for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + // Buffer allocation - _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); + function createParticleBuffers ( geometry ) { - } + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); - } + _this.info.memory.geometries ++; - deleteBuffers( geometryGroup ); + }; - } + function createLineBuffers ( geometry ) { - } else { + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + geometry.__webglLineDistanceBuffer = _gl.createBuffer(); - deleteBuffers( geometry ); + _this.info.memory.geometries ++; - } + }; - } + function createMeshBuffers ( geometryGroup ) { - }; + geometryGroup.__webglVertexBuffer = _gl.createBuffer(); + geometryGroup.__webglNormalBuffer = _gl.createBuffer(); + geometryGroup.__webglTangentBuffer = _gl.createBuffer(); + geometryGroup.__webglColorBuffer = _gl.createBuffer(); + geometryGroup.__webglUVBuffer = _gl.createBuffer(); + geometryGroup.__webglUV2Buffer = _gl.createBuffer(); - var deallocateTexture = function ( texture ) { + geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); + geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); - if ( texture.image && texture.image.__webglTextureCube ) { + geometryGroup.__webglFaceBuffer = _gl.createBuffer(); + geometryGroup.__webglLineBuffer = _gl.createBuffer(); - // cube texture + var numMorphTargets = geometryGroup.numMorphTargets; - _gl.deleteTexture( texture.image.__webglTextureCube ); + if ( numMorphTargets ) { - } else { + geometryGroup.__webglMorphTargetsBuffers = []; - // 2D texture + for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { - if ( ! texture.__webglInit ) return; + geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); - texture.__webglInit = false; - _gl.deleteTexture( texture.__webglTexture ); + } - } + } - }; + var numMorphNormals = geometryGroup.numMorphNormals; - var deallocateRenderTarget = function ( renderTarget ) { + if ( numMorphNormals ) { - if ( !renderTarget || ! renderTarget.__webglTexture ) return; + geometryGroup.__webglMorphNormalsBuffers = []; - _gl.deleteTexture( renderTarget.__webglTexture ); + for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); - for ( var i = 0; i < 6; i ++ ) { + } - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); + } - } + _this.info.memory.geometries ++; - } else { + }; - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); + // Events - } + var onObjectRemoved = function ( event ) { - }; + var object = event.target; - var deallocateMaterial = function ( material ) { + object.traverse( function ( child ) { - var program = material.program; + child.removeEventListener( 'remove', onObjectRemoved ); - if ( program === undefined ) return; + removeObject( child ); - material.program = undefined; + } ); - // only deallocate GL program if this was the last use of shared program - // assumed there is only single copy of any program in the _programs list - // (that's how it's constructed) + }; - var i, il, programInfo; - var deleteProgram = false; + var onGeometryDispose = function ( event ) { - for ( i = 0, il = _programs.length; i < il; i ++ ) { + var geometry = event.target; - programInfo = _programs[ i ]; + geometry.removeEventListener( 'dispose', onGeometryDispose ); - if ( programInfo.program === program ) { + deallocateGeometry( geometry ); - programInfo.usedTimes --; + }; - if ( programInfo.usedTimes === 0 ) { + var onTextureDispose = function ( event ) { - deleteProgram = true; + var texture = event.target; - } + texture.removeEventListener( 'dispose', onTextureDispose ); - break; + deallocateTexture( texture ); - } + _this.info.memory.textures --; - } - if ( deleteProgram === true ) { + }; - // avoid using array.splice, this is costlier than creating new array from scratch + var onRenderTargetDispose = function ( event ) { - var newPrograms = []; + var renderTarget = event.target; - for ( i = 0, il = _programs.length; i < il; i ++ ) { + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - programInfo = _programs[ i ]; + deallocateRenderTarget( renderTarget ); - if ( programInfo.program !== program ) { + _this.info.memory.textures --; - newPrograms.push( programInfo ); + }; - } + var onMaterialDispose = function ( event ) { - } + var material = event.target; - _programs = newPrograms; + material.removeEventListener( 'dispose', onMaterialDispose ); - _gl.deleteProgram( program ); + deallocateMaterial( material ); - _this.info.memory.programs --; + }; - } + // Buffer deallocation - }; + var deleteBuffers = function ( geometry ) { - // Buffer initialization + var buffers = [ + '__webglVertexBuffer', + '__webglNormalBuffer', + '__webglTangentBuffer', + '__webglColorBuffer', + '__webglUVBuffer', + '__webglUV2Buffer', - function initCustomAttributes ( geometry, object ) { + '__webglSkinIndicesBuffer', + '__webglSkinWeightsBuffer', - var nvertices = geometry.vertices.length; + '__webglFaceBuffer', + '__webglLineBuffer', - var material = object.material; + '__webglLineDistanceBuffer' + ]; - if ( material.attributes ) { + for ( var i = 0, l = buffers.length; i < l; i ++ ) { - if ( geometry.__webglCustomAttributesList === undefined ) { + var name = buffers[ i ]; - geometry.__webglCustomAttributesList = []; + if ( geometry[ name ] !== undefined ) { - } + _gl.deleteBuffer( geometry[ name ] ); - for ( var a in material.attributes ) { + delete geometry[ name ]; - var attribute = material.attributes[ a ]; + } - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + } - attribute.__webglInitialized = true; + // custom attributes - var size = 1; // "f" and "i" + if ( geometry.__webglCustomAttributesList !== undefined ) { - if ( attribute.type === "v2" ) size = 2; - else if ( attribute.type === "v3" ) size = 3; - else if ( attribute.type === "v4" ) size = 4; - else if ( attribute.type === "c" ) size = 3; + for ( var name in geometry.__webglCustomAttributesList ) { - attribute.size = size; + _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer ); - attribute.array = new Float32Array( nvertices * size ); + } - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; + delete geometry.__webglCustomAttributesList; - attribute.needsUpdate = true; + } - } + _this.info.memory.geometries --; - geometry.__webglCustomAttributesList.push( attribute ); + }; - } + var deallocateGeometry = function ( geometry ) { - } + delete geometry.__webglInit; - }; + if ( geometry instanceof THREE.BufferGeometry ) { - function initParticleBuffers ( geometry, object ) { + for ( var name in geometry.attributes ) { - var nvertices = geometry.vertices.length; + var attribute = geometry.attributes[ name ]; - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); + if ( attribute.buffer !== undefined ) { - geometry.__sortArray = []; + _gl.deleteBuffer( attribute.buffer ); - geometry.__webglParticleCount = nvertices; + delete attribute.buffer; - initCustomAttributes ( geometry, object ); + } - }; + } - function initLineBuffers ( geometry, object ) { + _this.info.memory.geometries --; - var nvertices = geometry.vertices.length; + } else { - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); + var geometryGroupsList = geometryGroups[ geometry.id ]; - geometry.__webglLineCount = nvertices; + if ( geometryGroupsList !== undefined ) { - initCustomAttributes ( geometry, object ); + for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) { - }; + var geometryGroup = geometryGroupsList[ i ]; - function initMeshBuffers ( geometryGroup, object ) { + if ( geometryGroup.numMorphTargets !== undefined ) { - var geometry = object.geometry, - faces3 = geometryGroup.faces3, + for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { - nvertices = faces3.length * 3, - ntris = faces3.length * 1, - nlines = faces3.length * 3, + _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); - material = getBufferMaterial( object, geometryGroup ), + } - uvType = bufferGuessUVType( material ), - normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ); + delete geometryGroup.__webglMorphTargetsBuffers; - // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); + } - geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + if ( geometryGroup.numMorphNormals !== undefined ) { - if ( normalType ) { + for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { - geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); - } + } - if ( geometry.hasTangents ) { + delete geometryGroup.__webglMorphNormalsBuffers; - geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); + } - } + deleteBuffers( geometryGroup ); - if ( vertexColorType ) { + } - geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + delete geometryGroups[ geometry.id ]; - } + } else { - if ( uvType ) { + deleteBuffers( geometry ); - if ( geometry.faceVertexUvs.length > 0 ) { + } - geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); + } - } + // TOFIX: Workaround for deleted geometry being currently bound - if ( geometry.faceVertexUvs.length > 1 ) { + _currentGeometryProgram = ''; - geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); + }; - } + var deallocateTexture = function ( texture ) { - } + if ( texture.image && texture.image.__webglTextureCube ) { - if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { + // cube texture - geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); - geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); + _gl.deleteTexture( texture.image.__webglTextureCube ); - } + delete texture.image.__webglTextureCube; - var UintArray = _glExtensionElementIndexUint !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 + } else { - geometryGroup.__typeArray = UintArray; - geometryGroup.__faceArray = new UintArray( ntris * 3 ); - geometryGroup.__lineArray = new UintArray( nlines * 2 ); + // 2D texture - var m, ml; + if ( texture.__webglInit === undefined ) return; - if ( geometryGroup.numMorphTargets ) { + _gl.deleteTexture( texture.__webglTexture ); - geometryGroup.__morphTargetsArrays = []; + delete texture.__webglTexture; + delete texture.__webglInit; - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + } - geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); + }; - } + var deallocateRenderTarget = function ( renderTarget ) { - } + if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return; - if ( geometryGroup.numMorphNormals ) { + _gl.deleteTexture( renderTarget.__webglTexture ); - geometryGroup.__morphNormalsArrays = []; + delete renderTarget.__webglTexture; - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); + for ( var i = 0; i < 6; i ++ ) { - } + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); - } + } - geometryGroup.__webglFaceCount = ntris * 3; - geometryGroup.__webglLineCount = nlines * 2; + } else { + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); - // custom attributes + } - if ( material.attributes ) { + delete renderTarget.__webglFramebuffer; + delete renderTarget.__webglRenderbuffer; - if ( geometryGroup.__webglCustomAttributesList === undefined ) { + }; - geometryGroup.__webglCustomAttributesList = []; + var deallocateMaterial = function ( material ) { - } + var program = material.program.program; - for ( var a in material.attributes ) { + if ( program === undefined ) return; - // Do a shallow copy of the attribute object so different geometryGroup chunks use different - // attribute buffers which are correctly indexed in the setMeshBuffers function + material.program = undefined; - var originalAttribute = material.attributes[ a ]; + // only deallocate GL program if this was the last use of shared program + // assumed there is only single copy of any program in the _programs list + // (that's how it's constructed) - var attribute = {}; + var i, il, programInfo; + var deleteProgram = false; - for ( var property in originalAttribute ) { + for ( i = 0, il = _programs.length; i < il; i ++ ) { - attribute[ property ] = originalAttribute[ property ]; + programInfo = _programs[ i ]; - } + if ( programInfo.program === program ) { - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + programInfo.usedTimes --; - attribute.__webglInitialized = true; + if ( programInfo.usedTimes === 0 ) { - var size = 1; // "f" and "i" + deleteProgram = true; - if( attribute.type === "v2" ) size = 2; - else if( attribute.type === "v3" ) size = 3; - else if( attribute.type === "v4" ) size = 4; - else if( attribute.type === "c" ) size = 3; + } - attribute.size = size; + break; - attribute.array = new Float32Array( nvertices * size ); + } - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; + } - originalAttribute.needsUpdate = true; - attribute.__original = originalAttribute; + if ( deleteProgram === true ) { - } + // avoid using array.splice, this is costlier than creating new array from scratch - geometryGroup.__webglCustomAttributesList.push( attribute ); + var newPrograms = []; - } + for ( i = 0, il = _programs.length; i < il; i ++ ) { - } + programInfo = _programs[ i ]; - geometryGroup.__inittedArrays = true; + if ( programInfo.program !== program ) { - }; + newPrograms.push( programInfo ); - function getBufferMaterial( object, geometryGroup ) { + } - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ geometryGroup.materialIndex ] - : object.material; + } - }; + _programs = newPrograms; - function materialNeedsSmoothNormals ( material ) { + _gl.deleteProgram( program ); - return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + _this.info.memory.programs --; - }; + } - function bufferGuessNormalType ( material ) { + }; - // only MeshBasicMaterial and MeshDepthMaterial don't need normals + // Buffer initialization - if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { + function initCustomAttributes ( object ) { - return false; + var geometry = object.geometry; + var material = object.material; - } + var nvertices = geometry.vertices.length; - if ( materialNeedsSmoothNormals( material ) ) { + if ( material.attributes ) { - return THREE.SmoothShading; + if ( geometry.__webglCustomAttributesList === undefined ) { - } else { + geometry.__webglCustomAttributesList = []; - return THREE.FlatShading; + } - } + for ( var name in material.attributes ) { - }; + var attribute = material.attributes[ name ]; - function bufferGuessVertexColorType( material ) { + if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { - if ( material.vertexColors ) { + attribute.__webglInitialized = true; - return material.vertexColors; + var size = 1; // "f" and "i" - } + if ( attribute.type === 'v2' ) size = 2; + else if ( attribute.type === 'v3' ) size = 3; + else if ( attribute.type === 'v4' ) size = 4; + else if ( attribute.type === 'c' ) size = 3; - return false; + attribute.size = size; - }; + attribute.array = new Float32Array( nvertices * size ); - function bufferGuessUVType( material ) { + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = name; - // material must use some texture to require uvs + attribute.needsUpdate = true; - if ( material.map || - material.lightMap || - material.bumpMap || - material.normalMap || - material.specularMap || - material instanceof THREE.ShaderMaterial ) { + } - return true; + geometry.__webglCustomAttributesList.push( attribute ); - } + } - return false; + } - }; + }; - // + function initParticleBuffers ( geometry, object ) { - function initDirectBuffers( geometry ) { + var nvertices = geometry.vertices.length; - for ( var name in geometry.attributes ) { + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); - var bufferType = ( name === "index" ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; + geometry.__webglParticleCount = nvertices; - var attribute = geometry.attributes[ name ]; - attribute.buffer = _gl.createBuffer(); + initCustomAttributes( object ); - _gl.bindBuffer( bufferType, attribute.buffer ); - _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW ); + }; - } + function initLineBuffers ( geometry, object ) { - } + var nvertices = geometry.vertices.length; - // Buffer setting + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); - function setParticleBuffers ( geometry, hint, object ) { + geometry.__webglLineCount = nvertices; - var v, c, vertex, offset, index, color, + initCustomAttributes( object ); - vertices = geometry.vertices, - vl = vertices.length, + }; - colors = geometry.colors, - cl = colors.length, + function initMeshBuffers ( geometryGroup, object ) { - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, + var geometry = object.geometry, + faces3 = geometryGroup.faces3, - sortArray = geometry.__sortArray, + nvertices = faces3.length * 3, + ntris = faces3.length * 1, + nlines = faces3.length * 3, - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, + material = getBufferMaterial( object, geometryGroup ); - customAttributes = geometry.__webglCustomAttributesList, - i, il, - a, ca, cal, value, - customAttribute; + geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); - if ( object.sortParticles ) { + if ( geometry.faceVertexUvs.length > 1 ) { - _projScreenMatrixPS.copy( _projScreenMatrix ); - _projScreenMatrixPS.multiply( object.matrixWorld ); + geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); - for ( v = 0; v < vl; v ++ ) { + } - vertex = vertices[ v ]; + if ( geometry.hasTangents ) { - _vector3.copy( vertex ); - _vector3.applyProjection( _projScreenMatrixPS ); + geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); - sortArray[ v ] = [ _vector3.z, v ]; + } - } + if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { - sortArray.sort( numericalSort ); + geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); + geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); - for ( v = 0; v < vl; v ++ ) { + } - vertex = vertices[ sortArray[v][1] ]; + var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 - offset = v * 3; + geometryGroup.__typeArray = UintArray; + geometryGroup.__faceArray = new UintArray( ntris * 3 ); + geometryGroup.__lineArray = new UintArray( nlines * 2 ); - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; + var numMorphTargets = geometryGroup.numMorphTargets; - } + if ( numMorphTargets ) { - for ( c = 0; c < cl; c ++ ) { + geometryGroup.__morphTargetsArrays = []; - offset = c * 3; + for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { - color = colors[ sortArray[c][1] ]; + geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; + } - } + } - if ( customAttributes ) { + var numMorphNormals = geometryGroup.numMorphNormals; - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + if ( numMorphNormals ) { - customAttribute = customAttributes[ i ]; + geometryGroup.__morphNormalsArrays = []; - if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; + for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { - offset = 0; + geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); - cal = customAttribute.value.length; + } - if ( customAttribute.size === 1 ) { + } - for ( ca = 0; ca < cal; ca ++ ) { + geometryGroup.__webglFaceCount = ntris * 3; + geometryGroup.__webglLineCount = nlines * 2; - index = sortArray[ ca ][ 1 ]; - customAttribute.array[ ca ] = customAttribute.value[ index ]; + // custom attributes - } + if ( material.attributes ) { - } else if ( customAttribute.size === 2 ) { + if ( geometryGroup.__webglCustomAttributesList === undefined ) { - for ( ca = 0; ca < cal; ca ++ ) { + geometryGroup.__webglCustomAttributesList = []; - index = sortArray[ ca ][ 1 ]; + } - value = customAttribute.value[ index ]; + for ( var name in material.attributes ) { - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; + // Do a shallow copy of the attribute object so different geometryGroup chunks use different + // attribute buffers which are correctly indexed in the setMeshBuffers function - offset += 2; + var originalAttribute = material.attributes[ name ]; - } + var attribute = {}; - } else if ( customAttribute.size === 3 ) { + for ( var property in originalAttribute ) { - if ( customAttribute.type === "c" ) { + attribute[ property ] = originalAttribute[ property ]; - for ( ca = 0; ca < cal; ca ++ ) { + } - index = sortArray[ ca ][ 1 ]; + if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { - value = customAttribute.value[ index ]; + attribute.__webglInitialized = true; - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; + var size = 1; // "f" and "i" - offset += 3; + if ( attribute.type === 'v2' ) size = 2; + else if ( attribute.type === 'v3' ) size = 3; + else if ( attribute.type === 'v4' ) size = 4; + else if ( attribute.type === 'c' ) size = 3; - } + attribute.size = size; - } else { + attribute.array = new Float32Array( nvertices * size ); - for ( ca = 0; ca < cal; ca ++ ) { + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = name; - index = sortArray[ ca ][ 1 ]; + originalAttribute.needsUpdate = true; + attribute.__original = originalAttribute; - value = customAttribute.value[ index ]; + } - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; + geometryGroup.__webglCustomAttributesList.push( attribute ); - offset += 3; + } - } + } - } + geometryGroup.__inittedArrays = true; - } else if ( customAttribute.size === 4 ) { + }; - for ( ca = 0; ca < cal; ca ++ ) { + function getBufferMaterial( object, geometryGroup ) { - index = sortArray[ ca ][ 1 ]; + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ geometryGroup.materialIndex ] + : object.material; - value = customAttribute.value[ index ]; + } - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; + function materialNeedsFaceNormals ( material ) { - offset += 4; + return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading; - } + } - } + // Buffer setting - } + function setParticleBuffers ( geometry, hint, object ) { - } + var v, c, vertex, offset, color, - } else { + vertices = geometry.vertices, + vl = vertices.length, - if ( dirtyVertices ) { + colors = geometry.colors, + cl = colors.length, - for ( v = 0; v < vl; v ++ ) { + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, - vertex = vertices[ v ]; + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, - offset = v * 3; + customAttributes = geometry.__webglCustomAttributesList, + i, il, + ca, cal, value, + customAttribute; - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; + if ( dirtyVertices ) { - } + for ( v = 0; v < vl; v ++ ) { - } + vertex = vertices[ v ]; - if ( dirtyColors ) { + offset = v * 3; - for ( c = 0; c < cl; c ++ ) { + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; - color = colors[ c ]; + } - offset = c * 3; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; + } - } + if ( dirtyColors ) { - } + for ( c = 0; c < cl; c ++ ) { - if ( customAttributes ) { + color = colors[ c ]; - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + offset = c * 3; - customAttribute = customAttributes[ i ]; + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices") ) { + } - cal = customAttribute.value.length; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - offset = 0; + } - if ( customAttribute.size === 1 ) { + if ( customAttributes ) { - for ( ca = 0; ca < cal; ca ++ ) { + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - customAttribute.array[ ca ] = customAttribute.value[ ca ]; + customAttribute = customAttributes[ i ]; - } + if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { - } else if ( customAttribute.size === 2 ) { + cal = customAttribute.value.length; - for ( ca = 0; ca < cal; ca ++ ) { + offset = 0; - value = customAttribute.value[ ca ]; + if ( customAttribute.size === 1 ) { - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; + for ( ca = 0; ca < cal; ca ++ ) { - offset += 2; + customAttribute.array[ ca ] = customAttribute.value[ ca ]; - } + } - } else if ( customAttribute.size === 3 ) { + } else if ( customAttribute.size === 2 ) { - if ( customAttribute.type === "c" ) { + for ( ca = 0; ca < cal; ca ++ ) { - for ( ca = 0; ca < cal; ca ++ ) { + value = customAttribute.value[ ca ]; - value = customAttribute.value[ ca ]; + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; + offset += 2; - offset += 3; + } - } + } else if ( customAttribute.size === 3 ) { - } else { + if ( customAttribute.type === 'c' ) { - for ( ca = 0; ca < cal; ca ++ ) { + for ( ca = 0; ca < cal; ca ++ ) { - value = customAttribute.value[ ca ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; - offset += 3; + offset += 3; - } + } - } + } else { - } else if ( customAttribute.size === 4 ) { + for ( ca = 0; ca < cal; ca ++ ) { - for ( ca = 0; ca < cal; ca ++ ) { + value = customAttribute.value[ ca ]; - value = customAttribute.value[ ca ]; + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; + offset += 3; - offset += 4; + } - } + } - } + } else if ( customAttribute.size === 4 ) { - } + for ( ca = 0; ca < cal; ca ++ ) { - } + value = customAttribute.value[ ca ]; - } + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; - } + offset += 4; - if ( dirtyVertices || object.sortParticles ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + } - } + } - if ( dirtyColors || object.sortParticles ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + customAttribute.needsUpdate = false; - } + } - if ( customAttributes ) { + } - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + } - customAttribute = customAttributes[ i ]; + function setLineBuffers ( geometry, hint ) { - if ( customAttribute.needsUpdate || object.sortParticles ) { + var v, c, d, vertex, offset, color, - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + vertices = geometry.vertices, + colors = geometry.colors, + lineDistances = geometry.lineDistances, - } + vl = vertices.length, + cl = colors.length, + dl = lineDistances.length, - } + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + lineDistanceArray = geometry.__lineDistanceArray, - } + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyLineDistances = geometry.lineDistancesNeedUpdate, - } + customAttributes = geometry.__webglCustomAttributesList, - function setLineBuffers ( geometry, hint ) { + i, il, + ca, cal, value, + customAttribute; - var v, c, d, vertex, offset, color, + if ( dirtyVertices ) { - vertices = geometry.vertices, - colors = geometry.colors, - lineDistances = geometry.lineDistances, + for ( v = 0; v < vl; v ++ ) { - vl = vertices.length, - cl = colors.length, - dl = lineDistances.length, + vertex = vertices[ v ]; - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, - lineDistanceArray = geometry.__lineDistanceArray, + offset = v * 3; - dirtyVertices = geometry.verticesNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyLineDistances = geometry.lineDistancesNeedUpdate, + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; - customAttributes = geometry.__webglCustomAttributesList, + } - i, il, - a, ca, cal, value, - customAttribute; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - if ( dirtyVertices ) { + } - for ( v = 0; v < vl; v ++ ) { + if ( dirtyColors ) { - vertex = vertices[ v ]; + for ( c = 0; c < cl; c ++ ) { - offset = v * 3; + color = colors[ c ]; - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; + offset = c * 3; - } + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + } - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - if ( dirtyColors ) { + } - for ( c = 0; c < cl; c ++ ) { + if ( dirtyLineDistances ) { - color = colors[ c ]; + for ( d = 0; d < dl; d ++ ) { - offset = c * 3; + lineDistanceArray[ d ] = lineDistances[ d ]; - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; + } - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + } - } + if ( customAttributes ) { - if ( dirtyLineDistances ) { + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - for ( d = 0; d < dl; d ++ ) { + customAttribute = customAttributes[ i ]; - lineDistanceArray[ d ] = lineDistances[ d ]; + if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { - } + offset = 0; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); + cal = customAttribute.value.length; - } + if ( customAttribute.size === 1 ) { - if ( customAttributes ) { + for ( ca = 0; ca < cal; ca ++ ) { - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + customAttribute.array[ ca ] = customAttribute.value[ ca ]; - customAttribute = customAttributes[ i ]; + } - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices" ) ) { + } else if ( customAttribute.size === 2 ) { - offset = 0; + for ( ca = 0; ca < cal; ca ++ ) { - cal = customAttribute.value.length; + value = customAttribute.value[ ca ]; - if ( customAttribute.size === 1 ) { + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; - for ( ca = 0; ca < cal; ca ++ ) { + offset += 2; - customAttribute.array[ ca ] = customAttribute.value[ ca ]; + } - } + } else if ( customAttribute.size === 3 ) { - } else if ( customAttribute.size === 2 ) { + if ( customAttribute.type === 'c' ) { - for ( ca = 0; ca < cal; ca ++ ) { + for ( ca = 0; ca < cal; ca ++ ) { - value = customAttribute.value[ ca ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; - offset += 2; + offset += 3; - } + } - } else if ( customAttribute.size === 3 ) { + } else { - if ( customAttribute.type === "c" ) { + for ( ca = 0; ca < cal; ca ++ ) { - for ( ca = 0; ca < cal; ca ++ ) { + value = customAttribute.value[ ca ]; - value = customAttribute.value[ ca ]; + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; + offset += 3; - offset += 3; + } - } + } - } else { + } else if ( customAttribute.size === 4 ) { - for ( ca = 0; ca < cal; ca ++ ) { + for ( ca = 0; ca < cal; ca ++ ) { - value = customAttribute.value[ ca ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; - offset += 3; + offset += 4; - } + } - } + } - } else if ( customAttribute.size === 4 ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - for ( ca = 0; ca < cal; ca ++ ) { + customAttribute.needsUpdate = false; - value = customAttribute.value[ ca ]; + } - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; + } - offset += 4; + } - } + } - } + function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + if ( ! geometryGroup.__inittedArrays ) { - } + return; - } + } - } + var needsFaceNormals = materialNeedsFaceNormals( material ); - } + var f, fl, fi, face, + vertexNormals, faceNormal, + vertexColors, faceColor, + vertexTangents, + uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3, + c1, c2, c3, + sw1, sw2, sw3, + si1, si2, si3, + i, il, + vn, uvi, uv2i, + vk, vkl, vka, + nka, chf, faceVertexNormals, - function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { + vertexIndex = 0, - if ( ! geometryGroup.__inittedArrays ) { + offset = 0, + offset_uv = 0, + offset_uv2 = 0, + offset_face = 0, + offset_normal = 0, + offset_tangent = 0, + offset_line = 0, + offset_color = 0, + offset_skin = 0, + offset_morphTarget = 0, + offset_custom = 0, - return; + value, - } + vertexArray = geometryGroup.__vertexArray, + uvArray = geometryGroup.__uvArray, + uv2Array = geometryGroup.__uv2Array, + normalArray = geometryGroup.__normalArray, + tangentArray = geometryGroup.__tangentArray, + colorArray = geometryGroup.__colorArray, - var normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ), - uvType = bufferGuessUVType( material ), + skinIndexArray = geometryGroup.__skinIndexArray, + skinWeightArray = geometryGroup.__skinWeightArray, - needsSmoothNormals = ( normalType === THREE.SmoothShading ); + morphTargetsArrays = geometryGroup.__morphTargetsArrays, + morphNormalsArrays = geometryGroup.__morphNormalsArrays, - var f, fl, fi, face, - vertexNormals, faceNormal, normal, - vertexColors, faceColor, - vertexTangents, - uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, - c1, c2, c3, c4, - sw1, sw2, sw3, sw4, - si1, si2, si3, si4, - sa1, sa2, sa3, sa4, - sb1, sb2, sb3, sb4, - m, ml, i, il, - vn, uvi, uv2i, - vk, vkl, vka, - nka, chf, faceVertexNormals, - a, + customAttributes = geometryGroup.__webglCustomAttributesList, + customAttribute, - vertexIndex = 0, + faceArray = geometryGroup.__faceArray, + lineArray = geometryGroup.__lineArray, - offset = 0, - offset_uv = 0, - offset_uv2 = 0, - offset_face = 0, - offset_normal = 0, - offset_tangent = 0, - offset_line = 0, - offset_color = 0, - offset_skin = 0, - offset_morphTarget = 0, - offset_custom = 0, - offset_customSrc = 0, + geometry = object.geometry, // this is shared for all chunks - value, + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyUvs = geometry.uvsNeedUpdate, + dirtyNormals = geometry.normalsNeedUpdate, + dirtyTangents = geometry.tangentsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyMorphTargets = geometry.morphTargetsNeedUpdate, - vertexArray = geometryGroup.__vertexArray, - uvArray = geometryGroup.__uvArray, - uv2Array = geometryGroup.__uv2Array, - normalArray = geometryGroup.__normalArray, - tangentArray = geometryGroup.__tangentArray, - colorArray = geometryGroup.__colorArray, + vertices = geometry.vertices, + chunk_faces3 = geometryGroup.faces3, + obj_faces = geometry.faces, - skinIndexArray = geometryGroup.__skinIndexArray, - skinWeightArray = geometryGroup.__skinWeightArray, + obj_uvs = geometry.faceVertexUvs[ 0 ], + obj_uvs2 = geometry.faceVertexUvs[ 1 ], - morphTargetsArrays = geometryGroup.__morphTargetsArrays, - morphNormalsArrays = geometryGroup.__morphNormalsArrays, + obj_skinIndices = geometry.skinIndices, + obj_skinWeights = geometry.skinWeights, - customAttributes = geometryGroup.__webglCustomAttributesList, - customAttribute, + morphTargets = geometry.morphTargets, + morphNormals = geometry.morphNormals; - faceArray = geometryGroup.__faceArray, - lineArray = geometryGroup.__lineArray, + if ( dirtyVertices ) { - geometry = object.geometry, // this is shared for all chunks + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, - dirtyUvs = geometry.uvsNeedUpdate, - dirtyNormals = geometry.normalsNeedUpdate, - dirtyTangents = geometry.tangentsNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyMorphTargets = geometry.morphTargetsNeedUpdate, + face = obj_faces[ chunk_faces3[ f ] ]; - vertices = geometry.vertices, - chunk_faces3 = geometryGroup.faces3, - obj_faces = geometry.faces, + v1 = vertices[ face.a ]; + v2 = vertices[ face.b ]; + v3 = vertices[ face.c ]; - obj_uvs = geometry.faceVertexUvs[ 0 ], - obj_uvs2 = geometry.faceVertexUvs[ 1 ], + vertexArray[ offset ] = v1.x; + vertexArray[ offset + 1 ] = v1.y; + vertexArray[ offset + 2 ] = v1.z; - obj_colors = geometry.colors, + vertexArray[ offset + 3 ] = v2.x; + vertexArray[ offset + 4 ] = v2.y; + vertexArray[ offset + 5 ] = v2.z; - obj_skinIndices = geometry.skinIndices, - obj_skinWeights = geometry.skinWeights, + vertexArray[ offset + 6 ] = v3.x; + vertexArray[ offset + 7 ] = v3.y; + vertexArray[ offset + 8 ] = v3.z; - morphTargets = geometry.morphTargets, - morphNormals = geometry.morphNormals; + offset += 9; - if ( dirtyVertices ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - face = obj_faces[ chunk_faces3[ f ] ]; + } - v1 = vertices[ face.a ]; - v2 = vertices[ face.b ]; - v3 = vertices[ face.c ]; + if ( dirtyMorphTargets ) { - vertexArray[ offset ] = v1.x; - vertexArray[ offset + 1 ] = v1.y; - vertexArray[ offset + 2 ] = v1.z; + for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { - vertexArray[ offset + 3 ] = v2.x; - vertexArray[ offset + 4 ] = v2.y; - vertexArray[ offset + 5 ] = v2.z; + offset_morphTarget = 0; - vertexArray[ offset + 6 ] = v3.x; - vertexArray[ offset + 7 ] = v3.y; - vertexArray[ offset + 8 ] = v3.z; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - offset += 9; + chf = chunk_faces3[ f ]; + face = obj_faces[ chf ]; - } + // morph positions - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + v1 = morphTargets[ vk ].vertices[ face.a ]; + v2 = morphTargets[ vk ].vertices[ face.b ]; + v3 = morphTargets[ vk ].vertices[ face.c ]; - } + vka = morphTargetsArrays[ vk ]; - if ( dirtyMorphTargets ) { + vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget + 1 ] = v1.y; + vka[ offset_morphTarget + 2 ] = v1.z; - for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { + vka[ offset_morphTarget + 3 ] = v2.x; + vka[ offset_morphTarget + 4 ] = v2.y; + vka[ offset_morphTarget + 5 ] = v2.z; - offset_morphTarget = 0; + vka[ offset_morphTarget + 6 ] = v3.x; + vka[ offset_morphTarget + 7 ] = v3.y; + vka[ offset_morphTarget + 8 ] = v3.z; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + // morph normals - chf = chunk_faces3[ f ]; - face = obj_faces[ chf ]; + if ( material.morphNormals ) { - // morph positions + if ( needsFaceNormals ) { - v1 = morphTargets[ vk ].vertices[ face.a ]; - v2 = morphTargets[ vk ].vertices[ face.b ]; - v3 = morphTargets[ vk ].vertices[ face.c ]; + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; - vka = morphTargetsArrays[ vk ]; + } else { - vka[ offset_morphTarget ] = v1.x; - vka[ offset_morphTarget + 1 ] = v1.y; - vka[ offset_morphTarget + 2 ] = v1.z; + faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; - vka[ offset_morphTarget + 3 ] = v2.x; - vka[ offset_morphTarget + 4 ] = v2.y; - vka[ offset_morphTarget + 5 ] = v2.z; + n1 = faceVertexNormals.a; + n2 = faceVertexNormals.b; + n3 = faceVertexNormals.c; - vka[ offset_morphTarget + 6 ] = v3.x; - vka[ offset_morphTarget + 7 ] = v3.y; - vka[ offset_morphTarget + 8 ] = v3.z; + } - // morph normals + nka = morphNormalsArrays[ vk ]; - if ( material.morphNormals ) { + nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget + 1 ] = n1.y; + nka[ offset_morphTarget + 2 ] = n1.z; - if ( needsSmoothNormals ) { + nka[ offset_morphTarget + 3 ] = n2.x; + nka[ offset_morphTarget + 4 ] = n2.y; + nka[ offset_morphTarget + 5 ] = n2.z; - faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; + nka[ offset_morphTarget + 6 ] = n3.x; + nka[ offset_morphTarget + 7 ] = n3.y; + nka[ offset_morphTarget + 8 ] = n3.z; - n1 = faceVertexNormals.a; - n2 = faceVertexNormals.b; - n3 = faceVertexNormals.c; + } - } else { + // - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; + offset_morphTarget += 9; - } + } - nka = morphNormalsArrays[ vk ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); - nka[ offset_morphTarget ] = n1.x; - nka[ offset_morphTarget + 1 ] = n1.y; - nka[ offset_morphTarget + 2 ] = n1.z; + if ( material.morphNormals ) { - nka[ offset_morphTarget + 3 ] = n2.x; - nka[ offset_morphTarget + 4 ] = n2.y; - nka[ offset_morphTarget + 5 ] = n2.z; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); - nka[ offset_morphTarget + 6 ] = n3.x; - nka[ offset_morphTarget + 7 ] = n3.y; - nka[ offset_morphTarget + 8 ] = n3.z; + } - } + } - // + } - offset_morphTarget += 9; + if ( obj_skinWeights.length ) { - } + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); + face = obj_faces[ chunk_faces3[ f ] ]; - if ( material.morphNormals ) { + // weights - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); + sw1 = obj_skinWeights[ face.a ]; + sw2 = obj_skinWeights[ face.b ]; + sw3 = obj_skinWeights[ face.c ]; - } + skinWeightArray[ offset_skin ] = sw1.x; + skinWeightArray[ offset_skin + 1 ] = sw1.y; + skinWeightArray[ offset_skin + 2 ] = sw1.z; + skinWeightArray[ offset_skin + 3 ] = sw1.w; - } + skinWeightArray[ offset_skin + 4 ] = sw2.x; + skinWeightArray[ offset_skin + 5 ] = sw2.y; + skinWeightArray[ offset_skin + 6 ] = sw2.z; + skinWeightArray[ offset_skin + 7 ] = sw2.w; - } + skinWeightArray[ offset_skin + 8 ] = sw3.x; + skinWeightArray[ offset_skin + 9 ] = sw3.y; + skinWeightArray[ offset_skin + 10 ] = sw3.z; + skinWeightArray[ offset_skin + 11 ] = sw3.w; - if ( obj_skinWeights.length ) { + // indices - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + si1 = obj_skinIndices[ face.a ]; + si2 = obj_skinIndices[ face.b ]; + si3 = obj_skinIndices[ face.c ]; - face = obj_faces[ chunk_faces3[ f ] ]; + skinIndexArray[ offset_skin ] = si1.x; + skinIndexArray[ offset_skin + 1 ] = si1.y; + skinIndexArray[ offset_skin + 2 ] = si1.z; + skinIndexArray[ offset_skin + 3 ] = si1.w; - // weights + skinIndexArray[ offset_skin + 4 ] = si2.x; + skinIndexArray[ offset_skin + 5 ] = si2.y; + skinIndexArray[ offset_skin + 6 ] = si2.z; + skinIndexArray[ offset_skin + 7 ] = si2.w; - sw1 = obj_skinWeights[ face.a ]; - sw2 = obj_skinWeights[ face.b ]; - sw3 = obj_skinWeights[ face.c ]; + skinIndexArray[ offset_skin + 8 ] = si3.x; + skinIndexArray[ offset_skin + 9 ] = si3.y; + skinIndexArray[ offset_skin + 10 ] = si3.z; + skinIndexArray[ offset_skin + 11 ] = si3.w; - skinWeightArray[ offset_skin ] = sw1.x; - skinWeightArray[ offset_skin + 1 ] = sw1.y; - skinWeightArray[ offset_skin + 2 ] = sw1.z; - skinWeightArray[ offset_skin + 3 ] = sw1.w; + offset_skin += 12; - skinWeightArray[ offset_skin + 4 ] = sw2.x; - skinWeightArray[ offset_skin + 5 ] = sw2.y; - skinWeightArray[ offset_skin + 6 ] = sw2.z; - skinWeightArray[ offset_skin + 7 ] = sw2.w; + } - skinWeightArray[ offset_skin + 8 ] = sw3.x; - skinWeightArray[ offset_skin + 9 ] = sw3.y; - skinWeightArray[ offset_skin + 10 ] = sw3.z; - skinWeightArray[ offset_skin + 11 ] = sw3.w; + if ( offset_skin > 0 ) { - // indices + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); - si1 = obj_skinIndices[ face.a ]; - si2 = obj_skinIndices[ face.b ]; - si3 = obj_skinIndices[ face.c ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); - skinIndexArray[ offset_skin ] = si1.x; - skinIndexArray[ offset_skin + 1 ] = si1.y; - skinIndexArray[ offset_skin + 2 ] = si1.z; - skinIndexArray[ offset_skin + 3 ] = si1.w; + } - skinIndexArray[ offset_skin + 4 ] = si2.x; - skinIndexArray[ offset_skin + 5 ] = si2.y; - skinIndexArray[ offset_skin + 6 ] = si2.z; - skinIndexArray[ offset_skin + 7 ] = si2.w; + } - skinIndexArray[ offset_skin + 8 ] = si3.x; - skinIndexArray[ offset_skin + 9 ] = si3.y; - skinIndexArray[ offset_skin + 10 ] = si3.z; - skinIndexArray[ offset_skin + 11 ] = si3.w; + if ( dirtyColors ) { - offset_skin += 12; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - } + face = obj_faces[ chunk_faces3[ f ] ]; - if ( offset_skin > 0 ) { + vertexColors = face.vertexColors; + faceColor = face.color; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); + if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); + c1 = vertexColors[ 0 ]; + c2 = vertexColors[ 1 ]; + c3 = vertexColors[ 2 ]; - } + } else { - } + c1 = faceColor; + c2 = faceColor; + c3 = faceColor; - if ( dirtyColors && vertexColorType ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + colorArray[ offset_color ] = c1.r; + colorArray[ offset_color + 1 ] = c1.g; + colorArray[ offset_color + 2 ] = c1.b; - face = obj_faces[ chunk_faces3[ f ] ]; + colorArray[ offset_color + 3 ] = c2.r; + colorArray[ offset_color + 4 ] = c2.g; + colorArray[ offset_color + 5 ] = c2.b; - vertexColors = face.vertexColors; - faceColor = face.color; + colorArray[ offset_color + 6 ] = c3.r; + colorArray[ offset_color + 7 ] = c3.g; + colorArray[ offset_color + 8 ] = c3.b; - if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { + offset_color += 9; - c1 = vertexColors[ 0 ]; - c2 = vertexColors[ 1 ]; - c3 = vertexColors[ 2 ]; + } - } else { + if ( offset_color > 0 ) { - c1 = faceColor; - c2 = faceColor; - c3 = faceColor; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - } + } - colorArray[ offset_color ] = c1.r; - colorArray[ offset_color + 1 ] = c1.g; - colorArray[ offset_color + 2 ] = c1.b; + } - colorArray[ offset_color + 3 ] = c2.r; - colorArray[ offset_color + 4 ] = c2.g; - colorArray[ offset_color + 5 ] = c2.b; + if ( dirtyTangents && geometry.hasTangents ) { - colorArray[ offset_color + 6 ] = c3.r; - colorArray[ offset_color + 7 ] = c3.g; - colorArray[ offset_color + 8 ] = c3.b; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - offset_color += 9; + face = obj_faces[ chunk_faces3[ f ] ]; - } + vertexTangents = face.vertexTangents; - if ( offset_color > 0 ) { + t1 = vertexTangents[ 0 ]; + t2 = vertexTangents[ 1 ]; + t3 = vertexTangents[ 2 ]; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + tangentArray[ offset_tangent ] = t1.x; + tangentArray[ offset_tangent + 1 ] = t1.y; + tangentArray[ offset_tangent + 2 ] = t1.z; + tangentArray[ offset_tangent + 3 ] = t1.w; - } + tangentArray[ offset_tangent + 4 ] = t2.x; + tangentArray[ offset_tangent + 5 ] = t2.y; + tangentArray[ offset_tangent + 6 ] = t2.z; + tangentArray[ offset_tangent + 7 ] = t2.w; - } + tangentArray[ offset_tangent + 8 ] = t3.x; + tangentArray[ offset_tangent + 9 ] = t3.y; + tangentArray[ offset_tangent + 10 ] = t3.z; + tangentArray[ offset_tangent + 11 ] = t3.w; - if ( dirtyTangents && geometry.hasTangents ) { + offset_tangent += 12; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - face = obj_faces[ chunk_faces3[ f ] ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); - vertexTangents = face.vertexTangents; + } - t1 = vertexTangents[ 0 ]; - t2 = vertexTangents[ 1 ]; - t3 = vertexTangents[ 2 ]; + if ( dirtyNormals ) { - tangentArray[ offset_tangent ] = t1.x; - tangentArray[ offset_tangent + 1 ] = t1.y; - tangentArray[ offset_tangent + 2 ] = t1.z; - tangentArray[ offset_tangent + 3 ] = t1.w; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - tangentArray[ offset_tangent + 4 ] = t2.x; - tangentArray[ offset_tangent + 5 ] = t2.y; - tangentArray[ offset_tangent + 6 ] = t2.z; - tangentArray[ offset_tangent + 7 ] = t2.w; + face = obj_faces[ chunk_faces3[ f ] ]; - tangentArray[ offset_tangent + 8 ] = t3.x; - tangentArray[ offset_tangent + 9 ] = t3.y; - tangentArray[ offset_tangent + 10 ] = t3.z; - tangentArray[ offset_tangent + 11 ] = t3.w; + vertexNormals = face.vertexNormals; + faceNormal = face.normal; - offset_tangent += 12; + if ( vertexNormals.length === 3 && needsFaceNormals === false ) { - } + for ( i = 0; i < 3; i ++ ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); + vn = vertexNormals[ i ]; - } + normalArray[ offset_normal ] = vn.x; + normalArray[ offset_normal + 1 ] = vn.y; + normalArray[ offset_normal + 2 ] = vn.z; - if ( dirtyNormals && normalType ) { + offset_normal += 3; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - face = obj_faces[ chunk_faces3[ f ] ]; + } else { - vertexNormals = face.vertexNormals; - faceNormal = face.normal; + for ( i = 0; i < 3; i ++ ) { - if ( vertexNormals.length === 3 && needsSmoothNormals ) { + normalArray[ offset_normal ] = faceNormal.x; + normalArray[ offset_normal + 1 ] = faceNormal.y; + normalArray[ offset_normal + 2 ] = faceNormal.z; - for ( i = 0; i < 3; i ++ ) { + offset_normal += 3; - vn = vertexNormals[ i ]; + } - normalArray[ offset_normal ] = vn.x; - normalArray[ offset_normal + 1 ] = vn.y; - normalArray[ offset_normal + 2 ] = vn.z; + } - offset_normal += 3; + } - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); - } else { + } - for ( i = 0; i < 3; i ++ ) { + if ( dirtyUvs && obj_uvs ) { - normalArray[ offset_normal ] = faceNormal.x; - normalArray[ offset_normal + 1 ] = faceNormal.y; - normalArray[ offset_normal + 2 ] = faceNormal.z; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - offset_normal += 3; + fi = chunk_faces3[ f ]; - } + uv = obj_uvs[ fi ]; - } + if ( uv === undefined ) continue; - } + for ( i = 0; i < 3; i ++ ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); + uvi = uv[ i ]; - } + uvArray[ offset_uv ] = uvi.x; + uvArray[ offset_uv + 1 ] = uvi.y; - if ( dirtyUvs && obj_uvs && uvType ) { + offset_uv += 2; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - fi = chunk_faces3[ f ]; + } - uv = obj_uvs[ fi ]; + if ( offset_uv > 0 ) { - if ( uv === undefined ) continue; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); - for ( i = 0; i < 3; i ++ ) { + } - uvi = uv[ i ]; + } - uvArray[ offset_uv ] = uvi.x; - uvArray[ offset_uv + 1 ] = uvi.y; + if ( dirtyUvs && obj_uvs2 ) { - offset_uv += 2; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - } + fi = chunk_faces3[ f ]; - } + uv2 = obj_uvs2[ fi ]; - if ( offset_uv > 0 ) { + if ( uv2 === undefined ) continue; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); + for ( i = 0; i < 3; i ++ ) { - } + uv2i = uv2[ i ]; - } + uv2Array[ offset_uv2 ] = uv2i.x; + uv2Array[ offset_uv2 + 1 ] = uv2i.y; - if ( dirtyUvs && obj_uvs2 && uvType ) { + offset_uv2 += 2; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - fi = chunk_faces3[ f ]; + } - uv2 = obj_uvs2[ fi ]; + if ( offset_uv2 > 0 ) { - if ( uv2 === undefined ) continue; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); - for ( i = 0; i < 3; i ++ ) { + } - uv2i = uv2[ i ]; + } - uv2Array[ offset_uv2 ] = uv2i.x; - uv2Array[ offset_uv2 + 1 ] = uv2i.y; + if ( dirtyElements ) { - offset_uv2 += 2; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - } + faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face + 1 ] = vertexIndex + 1; + faceArray[ offset_face + 2 ] = vertexIndex + 2; - } + offset_face += 3; - if ( offset_uv2 > 0 ) { + lineArray[ offset_line ] = vertexIndex; + lineArray[ offset_line + 1 ] = vertexIndex + 1; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); + lineArray[ offset_line + 2 ] = vertexIndex; + lineArray[ offset_line + 3 ] = vertexIndex + 2; - } + lineArray[ offset_line + 4 ] = vertexIndex + 1; + lineArray[ offset_line + 5 ] = vertexIndex + 2; - } + offset_line += 6; - if ( dirtyElements ) { + vertexIndex += 3; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - faceArray[ offset_face ] = vertexIndex; - faceArray[ offset_face + 1 ] = vertexIndex + 1; - faceArray[ offset_face + 2 ] = vertexIndex + 2; + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); - offset_face += 3; + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); - lineArray[ offset_line ] = vertexIndex; - lineArray[ offset_line + 1 ] = vertexIndex + 1; + } - lineArray[ offset_line + 2 ] = vertexIndex; - lineArray[ offset_line + 3 ] = vertexIndex + 2; + if ( customAttributes ) { - lineArray[ offset_line + 4 ] = vertexIndex + 1; - lineArray[ offset_line + 5 ] = vertexIndex + 2; + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - offset_line += 6; + customAttribute = customAttributes[ i ]; - vertexIndex += 3; + if ( ! customAttribute.__original.needsUpdate ) continue; - } + offset_custom = 0; - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); + if ( customAttribute.size === 1 ) { - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - } + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - if ( customAttributes ) { + face = obj_faces[ chunk_faces3[ f ] ]; - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; + customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; - customAttribute = customAttributes[ i ]; + offset_custom += 3; - if ( ! customAttribute.__original.needsUpdate ) continue; + } - offset_custom = 0; - offset_customSrc = 0; + } else if ( customAttribute.boundTo === 'faces' ) { - if ( customAttribute.size === 1 ) { + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + value = customAttribute.value[ chunk_faces3[ f ] ]; - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom + 1 ] = value; + customAttribute.array[ offset_custom + 2 ] = value; - face = obj_faces[ chunk_faces3[ f ] ]; + offset_custom += 3; - customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; - customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; - customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; + } - offset_custom += 3; + } - } + } else if ( customAttribute.size === 2 ) { - } else if ( customAttribute.boundTo === "faces" ) { + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - value = customAttribute.value[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = value; - customAttribute.array[ offset_custom + 1 ] = value; - customAttribute.array[ offset_custom + 2 ] = value; + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; - offset_custom += 3; + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; - } + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; - } + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; - } else if ( customAttribute.size === 2 ) { + offset_custom += 6; - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } else if ( customAttribute.boundTo === 'faces' ) { - face = obj_faces[ chunk_faces3[ f ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; + value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; + v1 = value; + v2 = value; + v3 = value; - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; - offset_custom += 6; + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; - } + offset_custom += 6; - } else if ( customAttribute.boundTo === "faces" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - value = customAttribute.value[ chunk_faces3[ f ] ]; + } else if ( customAttribute.size === 3 ) { - v1 = value; - v2 = value; - v3 = value; + var pp; - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; + if ( customAttribute.type === 'c' ) { - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; + pp = [ 'r', 'g', 'b' ]; - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; + } else { - offset_custom += 6; + pp = [ 'x', 'y', 'z' ]; - } + } - } + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - } else if ( customAttribute.size === 3 ) { + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - var pp; + face = obj_faces[ chunk_faces3[ f ] ]; - if ( customAttribute.type === "c" ) { + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; - pp = [ "r", "g", "b" ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - } else { + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - pp = [ "x", "y", "z" ]; + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - } + offset_custom += 9; - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } else if ( customAttribute.boundTo === 'faces' ) { - face = obj_faces[ chunk_faces3[ f ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; + value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + v1 = value; + v2 = value; + v3 = value; - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - offset_custom += 9; + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - } + offset_custom += 9; - } else if ( customAttribute.boundTo === "faces" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } else if ( customAttribute.boundTo === 'faceVertices' ) { - value = customAttribute.value[ chunk_faces3[ f ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - v1 = value; - v2 = value; - v3 = value; + value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - offset_custom += 9; + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - } + offset_custom += 9; - } else if ( customAttribute.boundTo === "faceVertices" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - value = customAttribute.value[ chunk_faces3[ f ] ]; + } else if ( customAttribute.size === 4 ) { - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; - offset_custom += 9; + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; - } + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; - } + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; - } else if ( customAttribute.size === 4 ) { + offset_custom += 12; - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } else if ( customAttribute.boundTo === 'faces' ) { - face = obj_faces[ chunk_faces3[ f ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; + value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; + v1 = value; + v2 = value; + v3 = value; - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; - offset_custom += 12; + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; - } + offset_custom += 12; - } else if ( customAttribute.boundTo === "faces" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } else if ( customAttribute.boundTo === 'faceVertices' ) { - value = customAttribute.value[ chunk_faces3[ f ] ]; + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - v1 = value; - v2 = value; - v3 = value; + value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; - offset_custom += 12; + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; - } + offset_custom += 12; - } else if ( customAttribute.boundTo === "faceVertices" ) { + } - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + } - value = customAttribute.value[ chunk_faces3[ f ] ]; + } - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; + } - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; + } - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; + if ( dispose ) { - offset_custom += 12; + delete geometryGroup.__inittedArrays; + delete geometryGroup.__colorArray; + delete geometryGroup.__normalArray; + delete geometryGroup.__tangentArray; + delete geometryGroup.__uvArray; + delete geometryGroup.__uv2Array; + delete geometryGroup.__faceArray; + delete geometryGroup.__vertexArray; + delete geometryGroup.__lineArray; + delete geometryGroup.__skinIndexArray; + delete geometryGroup.__skinWeightArray; - } + } - } + }; - } + // Buffer rendering - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + this.renderBufferImmediate = function ( object, program, material ) { - } + state.initAttributes(); - } + if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); + if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); + if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); + if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); - if ( dispose ) { + if ( object.hasPositions ) { - delete geometryGroup.__inittedArrays; - delete geometryGroup.__colorArray; - delete geometryGroup.__normalArray; - delete geometryGroup.__tangentArray; - delete geometryGroup.__uvArray; - delete geometryGroup.__uv2Array; - delete geometryGroup.__faceArray; - delete geometryGroup.__vertexArray; - delete geometryGroup.__lineArray; - delete geometryGroup.__skinIndexArray; - delete geometryGroup.__skinWeightArray; + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - } + state.enableAttribute( program.attributes.position ); - }; + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - function setDirectBuffers( geometry, hint ) { + } - var attributes = geometry.attributes; + if ( object.hasNormals ) { - var attributeName, attributeItem; + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - for ( attributeName in attributes ) { + if ( material instanceof THREE.MeshPhongMaterial === false && + material.shading === THREE.FlatShading ) { - attributeItem = attributes[ attributeName ]; + var nx, ny, nz, + nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, + normalArray, + i, il = object.count * 3; - if ( attributeItem.needsUpdate ) { + for ( i = 0; i < il; i += 9 ) { - if ( attributeName === 'index' ) { + normalArray = object.normalArray; - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); + nax = normalArray[ i ]; + nay = normalArray[ i + 1 ]; + naz = normalArray[ i + 2 ]; - } else { + nbx = normalArray[ i + 3 ]; + nby = normalArray[ i + 4 ]; + nbz = normalArray[ i + 5 ]; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); + ncx = normalArray[ i + 6 ]; + ncy = normalArray[ i + 7 ]; + ncz = normalArray[ i + 8 ]; - } + nx = ( nax + nbx + ncx ) / 3; + ny = ( nay + nby + ncy ) / 3; + nz = ( naz + nbz + ncz ) / 3; - attributeItem.needsUpdate = false; + normalArray[ i ] = nx; + normalArray[ i + 1 ] = ny; + normalArray[ i + 2 ] = nz; - } + normalArray[ i + 3 ] = nx; + normalArray[ i + 4 ] = ny; + normalArray[ i + 5 ] = nz; - } + normalArray[ i + 6 ] = nx; + normalArray[ i + 7 ] = ny; + normalArray[ i + 8 ] = nz; - } + } - // Buffer rendering + } - this.renderBufferImmediate = function ( object, program, material ) { + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - initAttributes(); + state.enableAttribute( program.attributes.normal ); - if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); - if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); - if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); - if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - if ( object.hasPositions ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.position ); - _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + if ( object.hasUvs && material.map ) { - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - if ( object.hasNormals ) { + state.enableAttribute( program.attributes.uv ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - if ( material.shading === THREE.FlatShading ) { + } - var nx, ny, nz, - nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, - normalArray, - i, il = object.count * 3; + if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { - for( i = 0; i < il; i += 9 ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - normalArray = object.normalArray; + state.enableAttribute( program.attributes.color ); - nax = normalArray[ i ]; - nay = normalArray[ i + 1 ]; - naz = normalArray[ i + 2 ]; + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - nbx = normalArray[ i + 3 ]; - nby = normalArray[ i + 4 ]; - nbz = normalArray[ i + 5 ]; + } - ncx = normalArray[ i + 6 ]; - ncy = normalArray[ i + 7 ]; - ncz = normalArray[ i + 8 ]; + state.disableUnusedAttributes(); - nx = ( nax + nbx + ncx ) / 3; - ny = ( nay + nby + ncy ) / 3; - nz = ( naz + nbz + ncz ) / 3; + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); - normalArray[ i ] = nx; - normalArray[ i + 1 ] = ny; - normalArray[ i + 2 ] = nz; + object.count = 0; - normalArray[ i + 3 ] = nx; - normalArray[ i + 4 ] = ny; - normalArray[ i + 5 ] = nz; + }; - normalArray[ i + 6 ] = nx; - normalArray[ i + 7 ] = ny; - normalArray[ i + 8 ] = nz; + function setupVertexAttributes( material, program, geometry, startIndex ) { - } + var geometryAttributes = geometry.attributes; - } + var programAttributes = program.attributes; + var programAttributesKeys = program.attributesKeys; - _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.normal ); - _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) { - } + var key = programAttributesKeys[ i ]; + var programAttribute = programAttributes[ key ]; - if ( object.hasUvs && material.map ) { + if ( programAttribute >= 0 ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.uv ); - _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + var geometryAttribute = geometryAttributes[ key ]; - } + if ( geometryAttribute !== undefined ) { - if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { + var size = geometryAttribute.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.color ); - _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); - } + state.enableAttribute( programAttribute ); - disableUnusedAttributes(); + _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 - _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + } else if ( material.defaultAttributeValues !== undefined ) { - object.count = 0; + if ( material.defaultAttributeValues[ key ].length === 2 ) { - }; + _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] ); - function setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) { + } else if ( material.defaultAttributeValues[ key ].length === 3 ) { - for ( var attributeName in programAttributes ) { + _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] ); - var attributePointer = programAttributes[ attributeName ]; - var attributeItem = geometryAttributes[ attributeName ]; + } - if ( attributePointer >= 0 ) { + } - if ( attributeItem ) { + } - var attributeSize = attributeItem.itemSize; + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 + state.disableUnusedAttributes(); - } else if ( material.defaultAttributeValues ) { + } - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + if ( material.visible === false ) return; - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + updateObject( object ); - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + var program = setProgram( camera, lights, fog, material, object ); - } + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit; - } + if ( geometryProgram !== _currentGeometryProgram ) { - } + _currentGeometryProgram = geometryProgram; + updateBuffers = true; - } + } - disableUnusedAttributes(); - - } + if ( updateBuffers ) { - this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { + state.initAttributes(); - if ( material.visible === false ) return; + } - var linewidth, a, attribute; - var attributeItem, attributeName, attributePointer, attributeSize; + // render mesh - var program = setProgram( camera, lights, fog, material, object ); + if ( object instanceof THREE.Mesh ) { - var programAttributes = program.attributes; - var geometryAttributes = geometry.attributes; + var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES; - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + var index = geometry.attributes.index; - if ( geometryHash !== _currentGeometryGroupHash ) { + if ( index ) { - _currentGeometryGroupHash = geometryHash; - updateBuffers = true; + // indexed triangles - } + var type, size; - if ( updateBuffers ) { + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - initAttributes(); + type = _gl.UNSIGNED_INT; + size = 4; - } + } else { - // render mesh + type = _gl.UNSIGNED_SHORT; + size = 2; - if ( object instanceof THREE.Mesh ) { + } - var index = geometryAttributes[ "index" ]; + var offsets = geometry.offsets; - if ( index ) { + if ( offsets.length === 0 ) { - // indexed triangles + if ( updateBuffers ) { - var type, size; - - if ( index.array instanceof Uint32Array ) { - - type = _gl.UNSIGNED_INT; - size = 4; - - } else { - - type = _gl.UNSIGNED_SHORT; - size = 2; - - } + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - var offsets = geometry.offsets; + } - if ( offsets.length === 0 ) { + _gl.drawElements( mode, index.array.length, type, 0 ); - if ( updateBuffers ) { + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + _this.info.render.faces += index.array.length / 3; - setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + } else { - } + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - _gl.drawElements( _gl.TRIANGLES, index.array.length, type, 0 ); + updateBuffers = true; - _this.info.render.calls ++; - _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared - _this.info.render.faces += index.array.length / 3; + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - } else { + var startIndex = offsets[ i ].index; - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change + if ( updateBuffers ) { - updateBuffers = true; + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - for ( var i = 0, il = offsets.length; i < il; i ++ ) { + } - var startIndex = offsets[ i ].index; + // render indexed triangles - if ( updateBuffers ) { + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + _this.info.render.faces += offsets[ i ].count / 3; - } + } - // render indexed triangles + } - _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, type, offsets[ i ].start * size ); + } else { - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - _this.info.render.faces += offsets[ i ].count / 3; + // non-indexed triangles - } + if ( updateBuffers ) { - } + setupVertexAttributes( material, program, geometry, 0 ); - } else { + } - // non-indexed triangles + var position = geometry.attributes[ 'position' ]; - if ( updateBuffers ) { + // render non-indexed triangles - setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + _gl.drawArrays( mode, 0, position.array.length / position.itemSize ); - } + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / position.itemSize; + _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); - var position = geometry.attributes[ "position" ]; + } - // render non-indexed triangles + } else if ( object instanceof THREE.PointCloud ) { - _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 ); + // render particles - _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / 3; - _this.info.render.faces += position.array.length / 9; + var mode = _gl.POINTS; - } + var index = geometry.attributes.index; - } else if ( object instanceof THREE.ParticleSystem ) { + if ( index ) { - // render particles + // indexed points - if ( updateBuffers ) { + var type, size; - setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - } + type = _gl.UNSIGNED_INT; + size = 4; - var position = geometryAttributes[ "position" ]; + } else { - // render particles + type = _gl.UNSIGNED_SHORT; + size = 2; - _gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); + } - _this.info.render.calls ++; - _this.info.render.points += position.array.length / 3; + var offsets = geometry.offsets; - } else if ( object instanceof THREE.Line ) { + if ( offsets.length === 0 ) { - var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + if ( updateBuffers ) { - setLineWidth( material.linewidth ); + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - var index = geometryAttributes[ "index" ]; - - if ( index ) { + } - // indexed lines + _gl.drawElements( mode, index.array.length, type, 0); - var type, size; - - if ( index.array instanceof Uint32Array ){ - - type = _gl.UNSIGNED_INT; - size = 4; - - } else { - - type = _gl.UNSIGNED_SHORT; - size = 2; - - } + _this.info.render.calls ++; + _this.info.render.points += index.array.length; - var offsets = geometry.offsets; + } else { - if ( offsets.length === 0 ) { + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - if ( updateBuffers ) { + if ( offsets.length > 1 ) updateBuffers = true; - setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - } - - _gl.drawElements( _gl.LINES, index.array.length, type, 0 ); // 2 bytes per Uint16Array + var startIndex = offsets[ i ].index; - _this.info.render.calls ++; - _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + if ( updateBuffers ) { - } else { + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change + } - if ( offsets.length > 1 ) updateBuffers = true; + // render indexed points - for ( var i = 0, il = offsets.length; i < il; i ++ ) { + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - var startIndex = offsets[ i ].index; + _this.info.render.calls ++; + _this.info.render.points += offsets[ i ].count; - if ( updateBuffers ) { + } - setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + } - } + } else { - // render indexed lines - - _gl.drawElements( _gl.LINES, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array + // non-indexed points - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + if ( updateBuffers ) { - } + setupVertexAttributes( material, program, geometry, 0 ); - } + } - } else { + var position = geometry.attributes.position; + var offsets = geometry.offsets; - // non-indexed lines + if ( offsets.length === 0 ) { - if ( updateBuffers ) { + _gl.drawArrays( mode, 0, position.array.length / 3 ); - setupVertexAttributes( material, programAttributes, geometryAttributes, 0 ); + _this.info.render.calls ++; + _this.info.render.points += position.array.length / 3; - } + } else { - var position = geometryAttributes[ "position" ]; + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - _gl.drawArrays( mode, 0, position.array.length / 3 ); + _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - _this.info.render.calls ++; - _this.info.render.points += position.array.length / 3; + _this.info.render.calls ++; + _this.info.render.points += offsets[ i ].count; - } + } - } + } - }; + } - this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { + } else if ( object instanceof THREE.Line ) { - if ( material.visible === false ) return; + var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - var linewidth, a, attribute, i, il; + state.setLineWidth( material.linewidth * pixelRatio ); - var program = setProgram( camera, lights, fog, material, object ); + var index = geometry.attributes.index; - var attributes = program.attributes; + if ( index ) { - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + // indexed lines - if ( geometryGroupHash !== _currentGeometryGroupHash ) { + var type, size; - _currentGeometryGroupHash = geometryGroupHash; - updateBuffers = true; + if ( index.array instanceof Uint32Array ) { - } + type = _gl.UNSIGNED_INT; + size = 4; - if ( updateBuffers ) { + } else { - initAttributes(); + type = _gl.UNSIGNED_SHORT; + size = 2; - } + } - // vertices + var offsets = geometry.offsets; - if ( !material.morphTargets && attributes.position >= 0 ) { + if ( offsets.length === 0 ) { - if ( updateBuffers ) { + if ( updateBuffers ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - } + } - } else { + _gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array - if ( object.morphTargetBase ) { + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared - setupMorphTargets( material, geometryGroup, object ); + } else { - } + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - } + if ( offsets.length > 1 ) updateBuffers = true; + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - if ( updateBuffers ) { + var startIndex = offsets[ i ].index; - // custom attributes + if ( updateBuffers ) { - // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - if ( geometryGroup.__webglCustomAttributesList ) { + } - for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { + // render indexed lines - attribute = geometryGroup.__webglCustomAttributesList[ i ]; + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array - if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); + } - } + } - } + } else { - } + // non-indexed lines + if ( updateBuffers ) { - // colors + setupVertexAttributes( material, program, geometry, 0 ); - if ( attributes.color >= 0 ) { + } - if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { + var position = geometry.attributes.position; + var offsets = geometry.offsets; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - enableAttribute( attributes.color ); - _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + if ( offsets.length === 0 ) { - } else if ( material.defaultAttributeValues ) { + _gl.drawArrays( mode, 0, position.array.length / 3 ); + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / 3; - _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); + } else { - } + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - } + _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - // normals + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; - if ( attributes.normal >= 0 ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - enableAttribute( attributes.normal ); - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + } - } + } - // tangents + } - if ( attributes.tangent >= 0 ) { + }; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - enableAttribute( attributes.tangent ); - _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); + this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { - } + if ( material.visible === false ) return; - // uvs + updateObject( object ); - if ( attributes.uv >= 0 ) { + var program = setProgram( camera, lights, fog, material, object ); - if ( object.geometry.faceVertexUvs[0] ) { + var attributes = program.attributes; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - enableAttribute( attributes.uv ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit; - } else if ( material.defaultAttributeValues ) { + if ( geometryProgram !== _currentGeometryProgram ) { + _currentGeometryProgram = geometryProgram; + updateBuffers = true; - _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); + } - } + if ( updateBuffers ) { - } + state.initAttributes(); - if ( attributes.uv2 >= 0 ) { + } - if ( object.geometry.faceVertexUvs[1] ) { + // vertices - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - enableAttribute( attributes.uv2 ); - _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); + if ( ! material.morphTargets && attributes.position >= 0 ) { - } else if ( material.defaultAttributeValues ) { + if ( updateBuffers ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); + state.enableAttribute( attributes.position ); - } + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - } + } - if ( material.skinning && - attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { + } else { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - enableAttribute( attributes.skinIndex ); - _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); + if ( object.morphTargetBase ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - enableAttribute( attributes.skinWeight ); - _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); + setupMorphTargets( material, geometryGroup, object ); - } + } - // line distances + } - if ( attributes.lineDistance >= 0 ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - enableAttribute( attributes.lineDistance ); - _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); + if ( updateBuffers ) { - } + // custom attributes - } + // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers - disableUnusedAttributes(); + if ( geometryGroup.__webglCustomAttributesList ) { - // render mesh + for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { - if ( object instanceof THREE.Mesh ) { + var attribute = geometryGroup.__webglCustomAttributesList[ i ]; - var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; + if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { - // wireframe - - if ( material.wireframe ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - setLineWidth( material.wireframeLinewidth ); - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); + state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - // triangles + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); - } else { + } - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 ); + } - } + } - _this.info.render.calls ++; - _this.info.render.vertices += geometryGroup.__webglFaceCount; - _this.info.render.faces += geometryGroup.__webglFaceCount / 3; - // render lines + // colors - } else if ( object instanceof THREE.Line ) { + if ( attributes.color >= 0 ) { - var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { - setLineWidth( material.linewidth ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); + state.enableAttribute( attributes.color ); - _this.info.render.calls ++; + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - // render particles + } else if ( material.defaultAttributeValues !== undefined ) { - } else if ( object instanceof THREE.ParticleSystem ) { - _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); + _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); - _this.info.render.calls ++; - _this.info.render.points += geometryGroup.__webglParticleCount; + } - } + } - }; + // normals - function initAttributes() { + if ( attributes.normal >= 0 ) { - for ( var i = 0, l = _newAttributes.length; i < l; i ++ ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - _newAttributes[ i ] = 0; + state.enableAttribute( attributes.normal ); - } + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - } + } - function enableAttribute( attribute ) { + // tangents - _newAttributes[ attribute ] = 1; + if ( attributes.tangent >= 0 ) { - if ( _enabledAttributes[ attribute ] === 0 ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - _gl.enableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = 1; + state.enableAttribute( attributes.tangent ); - } + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); - } + } - function disableUnusedAttributes() { + // uvs - for ( var i = 0, l = _enabledAttributes.length; i < l; i ++ ) { + if ( attributes.uv >= 0 ) { - if ( _enabledAttributes[ i ] !== _newAttributes[ i ] ) { + if ( object.geometry.faceVertexUvs[ 0 ] ) { - _gl.disableVertexAttribArray( i ); - _enabledAttributes[ i ] = 0; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - } + state.enableAttribute( attributes.uv ); - } + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - } + } else if ( material.defaultAttributeValues !== undefined ) { - function setupMorphTargets ( material, geometryGroup, object ) { - // set base + _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); - var attributes = material.program.attributes; + } - if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + if ( attributes.uv2 >= 0 ) { - } else if ( attributes.position >= 0 ) { + if ( object.geometry.faceVertexUvs[ 1 ] ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - } + state.enableAttribute( attributes.uv2 ); - if ( object.morphTargetForcedOrder.length ) { + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); - // set forced order + } else if ( material.defaultAttributeValues !== undefined ) { - var m = 0; - var order = object.morphTargetForcedOrder; - var influences = object.morphTargetInfluences; - while ( m < material.numSupportedMorphTargets && m < order.length ) { + _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); - if ( attributes[ "morphTarget" + m ] >= 0 ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + } - } + if ( material.skinning && + attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + state.enableAttribute( attributes.skinIndex ); - } + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); - object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - m ++; - } + state.enableAttribute( attributes.skinWeight ); - } else { + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); - // find the most influencing + } - var influence, activeInfluenceIndices = []; - var influences = object.morphTargetInfluences; - var i, il = influences.length; + // line distances - for ( i = 0; i < il; i ++ ) { + if ( attributes.lineDistance >= 0 ) { - influence = influences[ i ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - if ( influence > 0 ) { + state.enableAttribute( attributes.lineDistance ); - activeInfluenceIndices.push( [ influence, i ] ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); - } + } - } + } - if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { + state.disableUnusedAttributes(); - activeInfluenceIndices.sort( numericalSort ); - activeInfluenceIndices.length = material.numSupportedMorphTargets; + // render mesh - } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { + if ( object instanceof THREE.Mesh ) { - activeInfluenceIndices.sort( numericalSort ); + var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; - } else if ( activeInfluenceIndices.length === 0 ) { + // wireframe - activeInfluenceIndices.push( [ 0, 0 ] ); + if ( material.wireframe ) { - }; + state.setLineWidth( material.wireframeLinewidth * pixelRatio ); - var influenceIndex, m = 0; + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); - while ( m < material.numSupportedMorphTargets ) { + // triangles - if ( activeInfluenceIndices[ m ] ) { + } else { - influenceIndex = activeInfluenceIndices[ m ][ 1 ]; + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 ); - if ( attributes[ "morphTarget" + m ] >= 0 ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + _this.info.render.calls ++; + _this.info.render.vertices += geometryGroup.__webglFaceCount; + _this.info.render.faces += geometryGroup.__webglFaceCount / 3; - } + // render lines - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + } else if ( object instanceof THREE.Line ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + state.setLineWidth( material.linewidth * pixelRatio ); - } + _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); - object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; + _this.info.render.calls ++; - } else { + // render particles - /* - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + } else if ( object instanceof THREE.PointCloud ) { - if ( material.morphNormals ) { + _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + _this.info.render.calls ++; + _this.info.render.points += geometryGroup.__webglParticleCount; - } - */ + } - object.__webglMorphTargetInfluences[ m ] = 0; + }; - } + function setupMorphTargets ( material, geometryGroup, object ) { - m ++; + // set base - } + var attributes = material.program.attributes; - } + if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { - // load updated influences uniform + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - if ( material.program.uniforms.morphTargetInfluences !== null ) { + state.enableAttribute( attributes.position ); - _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - } + } else if ( attributes.position >= 0 ) { - }; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - // Sorting + state.enableAttribute( attributes.position ); - function painterSortStable ( a, b ) { + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - if ( a.z !== b.z ) { + } - return b.z - a.z; + if ( object.morphTargetForcedOrder.length ) { - } else { + // set forced order - return a.id - b.id; + var m = 0; + var order = object.morphTargetForcedOrder; + var influences = object.morphTargetInfluences; - } + var attribute; - }; + while ( m < material.numSupportedMorphTargets && m < order.length ) { - function numericalSort ( a, b ) { + attribute = attributes[ 'morphTarget' + m ]; - return b[ 0 ] - a[ 0 ]; + if ( attribute >= 0 ) { - }; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); + state.enableAttribute( attribute ); - // Rendering + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - this.render = function ( scene, camera, renderTarget, forceClear ) { + } - if ( camera instanceof THREE.Camera === false ) { + attribute = attributes[ 'morphNormal' + m ]; - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + if ( attribute >= 0 && material.morphNormals ) { - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - var i, il, + state.enableAttribute( attribute ); - webglObject, object, - renderList, + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - lights = scene.__lights, - fog = scene.fog; + } - // reset caching for this frame + object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; - _currentMaterialId = -1; - _lightsNeedUpdate = true; + m ++; - // update scene graph + } - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + } else { - // update camera matrices and frustum + // find the most influencing - if ( camera.parent === undefined ) camera.updateMatrixWorld(); + var activeInfluenceIndices = []; + var influences = object.morphTargetInfluences; + var morphTargets = object.geometry.morphTargets; - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + if ( influences.length > morphTargets.length ) { - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' ); + influences.length = morphTargets.length; - // update WebGL objects + } - if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); + for ( var i = 0, il = influences.length; i < il; i ++ ) { - // custom render plugins (pre pass) + var influence = influences[ i ]; - renderPlugins( this.renderPluginsPre, scene, camera ); + activeInfluenceIndices.push( [ influence, i ] ); - // + } - _this.info.render.calls = 0; - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - _this.info.render.points = 0; + if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { - this.setRenderTarget( renderTarget ); + activeInfluenceIndices.sort( numericalSort ); + activeInfluenceIndices.length = material.numSupportedMorphTargets; - if ( this.autoClear || forceClear ) { + } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { - this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + activeInfluenceIndices.sort( numericalSort ); - } + } else if ( activeInfluenceIndices.length === 0 ) { - // set matrices for regular objects (frustum culled) + activeInfluenceIndices.push( [ 0, 0 ] ); - renderList = scene.__webglObjects; + } - for ( i = 0, il = renderList.length; i < il; i ++ ) { + var attribute; - webglObject = renderList[ i ]; - object = webglObject.object; + for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) { - webglObject.id = i; - webglObject.render = false; + if ( activeInfluenceIndices[ m ] ) { - if ( object.visible ) { + var influenceIndex = activeInfluenceIndices[ m ][ 1 ]; - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + attribute = attributes[ 'morphTarget' + m ]; - setupMatrices( object, camera ); + if ( attribute >= 0 ) { - unrollBufferMaterial( webglObject ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - webglObject.render = true; + state.enableAttribute( attribute ); - if ( this.sortObjects === true ) { + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - if ( object.renderDepth !== null ) { + } - webglObject.z = object.renderDepth; + attribute = attributes[ 'morphNormal' + m ]; - } else { + if ( attribute >= 0 && material.morphNormals ) { - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyProjection( _projScreenMatrix ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - webglObject.z = _vector3.z; + state.enableAttribute( attribute ); - } + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - } + } - } + object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; - } + } else { - } + /* + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - if ( this.sortObjects ) { + if ( material.morphNormals ) { - renderList.sort( painterSortStable ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - } + } + */ - // set matrices for immediate objects + object.__webglMorphTargetInfluences[ m ] = 0; - renderList = scene.__webglObjectsImmediate; + } - for ( i = 0, il = renderList.length; i < il; i ++ ) { + } - webglObject = renderList[ i ]; - object = webglObject.object; + } - if ( object.visible ) { + // load updated influences uniform - setupMatrices( object, camera ); + if ( material.program.uniforms.morphTargetInfluences !== null ) { - unrollImmediateBufferMaterial( webglObject ); + _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); - } + } - } + } - if ( scene.overrideMaterial ) { + // Sorting - var material = scene.overrideMaterial; + function painterSortStable ( a, b ) { - this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - this.setDepthTest( material.depthTest ); - this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + if ( a.object.renderOrder !== b.object.renderOrder ) { - renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); + return a.object.renderOrder - b.object.renderOrder; - } else { + } else if ( a.material.id !== b.material.id ) { - var material = null; + return a.material.id - b.material.id; - // opaque pass (front-to-back order) + } else if ( a.z !== b.z ) { - this.setBlending( THREE.NoBlending ); + return a.z - b.z; - renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); + } else { - // transparent pass (back-to-front order) + return a.id - b.id; - renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); + } - } + } - // custom render plugins (post pass) + function reversePainterSortStable ( a, b ) { - renderPlugins( this.renderPluginsPost, scene, camera ); + if ( a.object.renderOrder !== b.object.renderOrder ) { + return a.object.renderOrder - b.object.renderOrder; - // Generate mipmap if we're using any kind of mipmap filtering + } if ( a.z !== b.z ) { - if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + return b.z - a.z; - updateRenderTargetMipmap( renderTarget ); + } else { - } + return a.id - b.id; - // Ensure depth buffer writing is enabled so it can be cleared on next render + } - this.setDepthTest( true ); - this.setDepthWrite( true ); + } - // _gl.finish(); + function numericalSort ( a, b ) { - }; + return b[ 0 ] - a[ 0 ]; - function renderPlugins( plugins, scene, camera ) { + } - if ( ! plugins.length ) return; + // Rendering - for ( var i = 0, il = plugins.length; i < il; i ++ ) { + this.render = function ( scene, camera, renderTarget, forceClear ) { - // reset state for plugin (to start from clean slate) + if ( camera instanceof THREE.Camera === false ) { - _currentProgram = null; - _currentCamera = null; + THREE.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; + } - _lightsNeedUpdate = true; + var fog = scene.fog; - plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); + // reset caching for this frame - // reset state after plugin (anything could have changed) + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + _currentCamera = null; + _lightsNeedUpdate = true; - _currentProgram = null; - _currentCamera = null; + // update scene graph - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - _lightsNeedUpdate = true; + // update camera matrices and frustum - } + if ( camera.parent === undefined ) camera.updateMatrixWorld(); - }; + // update Skeleton objects - function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + scene.traverse( function ( object ) { - var webglObject, object, buffer, material, start, end, delta; + if ( object instanceof THREE.SkinnedMesh ) { - if ( reverse ) { + object.skeleton.update(); - start = renderList.length - 1; - end = -1; - delta = -1; + } - } else { + } ); - start = 0; - end = renderList.length; - delta = 1; - } + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - for ( var i = start; i !== end; i += delta ) { + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - webglObject = renderList[ i ]; + lights.length = 0; + opaqueObjects.length = 0; + transparentObjects.length = 0; - if ( webglObject.render ) { + sprites.length = 0; + lensFlares.length = 0; - object = webglObject.object; - buffer = webglObject.buffer; + projectObject( scene ); - if ( overrideMaterial ) { + if ( _this.sortObjects === true ) { - material = overrideMaterial; + opaqueObjects.sort( painterSortStable ); + transparentObjects.sort( reversePainterSortStable ); - } else { + } - material = webglObject[ materialType ]; + // custom render plugins (pre pass) - if ( ! material ) continue; + shadowMapPlugin.render( scene, camera ); - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + // - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + _this.info.render.calls = 0; + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + _this.info.render.points = 0; - } + this.setRenderTarget( renderTarget ); - _this.setMaterialFaces( material ); + if ( this.autoClear || forceClear ) { - if ( buffer instanceof THREE.BufferGeometry ) { + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); - _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); + } - } else { + // set matrices for immediate objects - _this.renderBuffer( camera, lights, fog, material, buffer, object ); + for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) { - } + var webglObject = _webglObjectsImmediate[ i ]; + var object = webglObject.object; - } + if ( object.visible ) { - } + setupMatrices( object, camera ); - }; + unrollImmediateBufferMaterial( webglObject ); - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + } - var webglObject, object, material, program; + } - for ( var i = 0, il = renderList.length; i < il; i ++ ) { + if ( scene.overrideMaterial ) { - webglObject = renderList[ i ]; - object = webglObject.object; + var overrideMaterial = scene.overrideMaterial; - if ( object.visible ) { + setMaterial( overrideMaterial ); - if ( overrideMaterial ) { + renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); + renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); + renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial ); - material = overrideMaterial; + } else { - } else { + // opaque pass (front-to-back order) - material = webglObject[ materialType ]; + state.setBlending( THREE.NoBlending ); - if ( ! material ) continue; + renderObjects( opaqueObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null ); - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + // transparent pass (back-to-front order) - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + renderObjects( transparentObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null ); - } + } - _this.renderImmediateObject( camera, lights, fog, material, object ); + // custom render plugins (post pass) - } + spritePlugin.render( scene, camera ); + lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); - } + // Generate mipmap if we're using any kind of mipmap filtering - }; + if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { - this.renderImmediateObject = function ( camera, lights, fog, material, object ) { + updateRenderTargetMipmap( renderTarget ); - var program = setProgram( camera, lights, fog, material, object ); + } - _currentGeometryGroupHash = -1; + // Ensure depth buffer writing is enabled so it can be cleared on next render - _this.setMaterialFaces( material ); + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); - if ( object.immediateRenderCallback ) { + // _gl.finish(); - object.immediateRenderCallback( program, _gl, _frustum ); + }; - } else { + function projectObject( object ) { - object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); + if ( object.visible === false ) return; - } + if ( object instanceof THREE.Scene || object instanceof THREE.Group ) { - }; + // skip - function unrollImmediateBufferMaterial ( globject ) { + } else { - var object = globject.object, - material = object.material; + initObject( object ); - if ( material.transparent ) { + if ( object instanceof THREE.Light ) { - globject.transparent = material; - globject.opaque = null; + lights.push( object ); - } else { + } else if ( object instanceof THREE.Sprite ) { - globject.opaque = material; - globject.transparent = null; + sprites.push( object ); - } + } else if ( object instanceof THREE.LensFlare ) { - }; + lensFlares.push( object ); - function unrollBufferMaterial ( globject ) { + } else { - var object = globject.object; - var buffer = globject.buffer; + var webglObjects = _webglObjects[ object.id ]; - var geometry = object.geometry; - var material = object.material; + if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { - if ( material instanceof THREE.MeshFaceMaterial ) { + for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; + var webglObject = webglObjects[ i ]; - material = material.materials[ materialIndex ]; + unrollBufferMaterial( webglObject ); - if ( material.transparent ) { + webglObject.render = true; - globject.transparent = material; - globject.opaque = null; + if ( _this.sortObjects === true ) { - } else { + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); - globject.opaque = material; - globject.transparent = null; + webglObject.z = _vector3.z; - } + } - } else { + } - if ( material ) { + } - if ( material.transparent ) { + } - globject.transparent = material; - globject.opaque = null; + } - } else { + for ( var i = 0, l = object.children.length; i < l; i ++ ) { - globject.opaque = material; - globject.transparent = null; + projectObject( object.children[ i ] ); - } + } - } + } - } + function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { - }; + var material; - // Objects refresh + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - this.initWebGLObjects = function ( scene ) { + var webglObject = renderList[ i ]; - if ( !scene.__webglObjects ) { + var object = webglObject.object; + var buffer = webglObject.buffer; - scene.__webglObjects = []; - scene.__webglObjectsImmediate = []; - scene.__webglSprites = []; - scene.__webglFlares = []; + setupMatrices( object, camera ); - } + if ( overrideMaterial ) { - while ( scene.__objectsAdded.length ) { + material = overrideMaterial; - addObject( scene.__objectsAdded[ 0 ], scene ); - scene.__objectsAdded.splice( 0, 1 ); + } else { - } + material = webglObject.material; - while ( scene.__objectsRemoved.length ) { + if ( ! material ) continue; - removeObject( scene.__objectsRemoved[ 0 ], scene ); - scene.__objectsRemoved.splice( 0, 1 ); + setMaterial( material ); - } + } - // update must be called after objects adding / removal + _this.setMaterialFaces( material ); - for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { + if ( buffer instanceof THREE.BufferGeometry ) { - var object = scene.__webglObjects[ o ].object; + _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); - // TODO: Remove this hack (WebGLRenderer refactoring) + } else { - if ( object.__webglInit === undefined ) { + _this.renderBuffer( camera, lights, fog, material, buffer, object ); - if ( object.__webglActive !== undefined ) { + } - removeObject( object, scene ); + } - } + } - addObject( object, scene ); + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) { - } + var material; - updateObject( object ); + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - } + var webglObject = renderList[ i ]; + var object = webglObject.object; - }; + if ( object.visible ) { - // Objects adding + if ( overrideMaterial ) { - function addObject( object, scene ) { + material = overrideMaterial; - var g, geometry, material, geometryGroup; + } else { - if ( object.__webglInit === undefined ) { + material = webglObject[ materialType ]; - object.__webglInit = true; + if ( ! material ) continue; - object._modelViewMatrix = new THREE.Matrix4(); - object._normalMatrix = new THREE.Matrix3(); + setMaterial( material ); - geometry = object.geometry; + } - if ( geometry === undefined ) { + _this.renderImmediateObject( camera, lights, fog, material, object ); - // ImmediateRenderObject + } - } else if ( geometry.__webglInit === undefined ) { + } - geometry.__webglInit = true; - geometry.addEventListener( 'dispose', onGeometryDispose ); + } - if ( geometry instanceof THREE.BufferGeometry ) { + this.renderImmediateObject = function ( camera, lights, fog, material, object ) { - initDirectBuffers( geometry ); + var program = setProgram( camera, lights, fog, material, object ); - } else if ( object instanceof THREE.Mesh ) { + _currentGeometryProgram = ''; - material = object.material; + _this.setMaterialFaces( material ); - if ( geometry.geometryGroups === undefined ) { + if ( object.immediateRenderCallback ) { - geometry.makeGroups( material instanceof THREE.MeshFaceMaterial, _glExtensionElementIndexUint ? 4294967296 : 65535 ); + object.immediateRenderCallback( program, _gl, _frustum ); - } + } else { - // create separate VBOs per geometry chunk + object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } ); - for ( g in geometry.geometryGroups ) { + } - geometryGroup = geometry.geometryGroups[ g ]; + }; - // initialise VBO on the first access + function unrollImmediateBufferMaterial ( globject ) { - if ( ! geometryGroup.__webglVertexBuffer ) { + var object = globject.object, + material = object.material; - createMeshBuffers( geometryGroup ); - initMeshBuffers( geometryGroup, object ); + if ( material.transparent ) { - geometry.verticesNeedUpdate = true; - geometry.morphTargetsNeedUpdate = true; - geometry.elementsNeedUpdate = true; - geometry.uvsNeedUpdate = true; - geometry.normalsNeedUpdate = true; - geometry.tangentsNeedUpdate = true; - geometry.colorsNeedUpdate = true; + globject.transparent = material; + globject.opaque = null; - } + } else { - } + globject.opaque = material; + globject.transparent = null; - } else if ( object instanceof THREE.Line ) { + } - if ( ! geometry.__webglVertexBuffer ) { + } - createLineBuffers( geometry ); - initLineBuffers( geometry, object ); + function unrollBufferMaterial ( globject ) { - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - geometry.lineDistancesNeedUpdate = true; + var object = globject.object; + var buffer = globject.buffer; - } + var geometry = object.geometry; + var material = object.material; - } else if ( object instanceof THREE.ParticleSystem ) { + if ( material instanceof THREE.MeshFaceMaterial ) { - if ( ! geometry.__webglVertexBuffer ) { + var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; - createParticleBuffers( geometry ); - initParticleBuffers( geometry, object ); + material = material.materials[ materialIndex ]; - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; + globject.material = material; - } + if ( material.transparent ) { - } + transparentObjects.push( globject ); - } + } else { - } + opaqueObjects.push( globject ); - if ( object.__webglActive === undefined ) { + } - if ( object instanceof THREE.Mesh ) { + } else if ( material ) { - geometry = object.geometry; + globject.material = material; - if ( geometry instanceof THREE.BufferGeometry ) { + if ( material.transparent ) { - addBuffer( scene.__webglObjects, geometry, object ); + transparentObjects.push( globject ); - } else if ( geometry instanceof THREE.Geometry ) { + } else { - for ( g in geometry.geometryGroups ) { + opaqueObjects.push( globject ); - geometryGroup = geometry.geometryGroups[ g ]; + } - addBuffer( scene.__webglObjects, geometryGroup, object ); + } - } + } - } + function initObject( object ) { - } else if ( object instanceof THREE.Line || - object instanceof THREE.ParticleSystem ) { + if ( object.__webglInit === undefined ) { - geometry = object.geometry; - addBuffer( scene.__webglObjects, geometry, object ); + object.__webglInit = true; + object._modelViewMatrix = new THREE.Matrix4(); + object._normalMatrix = new THREE.Matrix3(); - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + object.addEventListener( 'removed', onObjectRemoved ); - addBufferImmediate( scene.__webglObjectsImmediate, object ); + } - } else if ( object instanceof THREE.Sprite ) { + var geometry = object.geometry; - scene.__webglSprites.push( object ); + if ( geometry === undefined ) { - } else if ( object instanceof THREE.LensFlare ) { + // ImmediateRenderObject - scene.__webglFlares.push( object ); + } else if ( geometry.__webglInit === undefined ) { - } + geometry.__webglInit = true; + geometry.addEventListener( 'dispose', onGeometryDispose ); - object.__webglActive = true; + if ( geometry instanceof THREE.BufferGeometry ) { - } + _this.info.memory.geometries ++; - }; + } else if ( object instanceof THREE.Mesh ) { - function addBuffer( objlist, buffer, object ) { + initGeometryGroups( object, geometry ); - objlist.push( - { - id: null, - buffer: buffer, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); + } else if ( object instanceof THREE.Line ) { - }; + if ( geometry.__webglVertexBuffer === undefined ) { - function addBufferImmediate( objlist, object ) { + createLineBuffers( geometry ); + initLineBuffers( geometry, object ); - objlist.push( - { - id: null, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.lineDistancesNeedUpdate = true; - }; + } - // Objects updates + } else if ( object instanceof THREE.PointCloud ) { - function updateObject( object ) { + if ( geometry.__webglVertexBuffer === undefined ) { - var geometry = object.geometry, - geometryGroup, customAttributesDirty, material; + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); - if ( geometry instanceof THREE.BufferGeometry ) { + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; - setDirectBuffers( geometry, _gl.DYNAMIC_DRAW ); + } - } else if ( object instanceof THREE.Mesh ) { + } - // check all geometry groups + } - for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { + if ( object.__webglActive === undefined) { - geometryGroup = geometry.geometryGroupsList[ i ]; + object.__webglActive = true; - material = getBufferMaterial( object, geometryGroup ); + if ( object instanceof THREE.Mesh ) { - if ( geometry.buffersNeedUpdate ) { + if ( geometry instanceof THREE.BufferGeometry ) { - initMeshBuffers( geometryGroup, object ); + addBuffer( _webglObjects, geometry, object ); - } + } else if ( geometry instanceof THREE.Geometry ) { - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + var geometryGroupsList = geometryGroups[ geometry.id ]; - if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || - geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || - geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { + for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) { - setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); + addBuffer( _webglObjects, geometryGroupsList[ i ], object ); - } + } - } + } - geometry.verticesNeedUpdate = false; - geometry.morphTargetsNeedUpdate = false; - geometry.elementsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.tangentsNeedUpdate = false; + } else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) { - geometry.buffersNeedUpdate = false; + addBuffer( _webglObjects, geometry, object ); - material.attributes && clearCustomAttributes( material ); + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - } else if ( object instanceof THREE.Line ) { + addBufferImmediate( _webglObjectsImmediate, object ); - material = getBufferMaterial( object, geometry ); + } - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + } - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { + } - setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); + // Geometry splitting - } + var geometryGroups = {}; + var geometryGroupCounter = 0; - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.lineDistancesNeedUpdate = false; + function makeGroups( geometry, usesFaceMaterial ) { - material.attributes && clearCustomAttributes( material ); + var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535; + var groupHash, hash_map = {}; - } else if ( object instanceof THREE.ParticleSystem ) { + var numMorphTargets = geometry.morphTargets.length; + var numMorphNormals = geometry.morphNormals.length; - material = getBufferMaterial( object, geometry ); + var group; + var groups = {}; + var groupsList = []; - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { + var face = geometry.faces[ f ]; + var materialIndex = usesFaceMaterial ? face.materialIndex : 0; - setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); + if ( ! ( materialIndex in hash_map ) ) { - } + hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 }; - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; + } - material.attributes && clearCustomAttributes( material ); + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - } + if ( ! ( groupHash in groups ) ) { - }; + group = { + id: geometryGroupCounter ++, + faces3: [], + materialIndex: materialIndex, + vertices: 0, + numMorphTargets: numMorphTargets, + numMorphNormals: numMorphNormals + }; - // Objects updates - custom attributes check + groups[ groupHash ] = group; + groupsList.push( group ); - function areCustomAttributesDirty( material ) { + } - for ( var a in material.attributes ) { + if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { - if ( material.attributes[ a ].needsUpdate ) return true; + hash_map[ materialIndex ].counter += 1; + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - } + if ( ! ( groupHash in groups ) ) { - return false; + group = { + id: geometryGroupCounter ++, + faces3: [], + materialIndex: materialIndex, + vertices: 0, + numMorphTargets: numMorphTargets, + numMorphNormals: numMorphNormals + }; - }; + groups[ groupHash ] = group; + groupsList.push( group ); - function clearCustomAttributes( material ) { + } - for ( var a in material.attributes ) { + } - material.attributes[ a ].needsUpdate = false; + groups[ groupHash ].faces3.push( f ); + groups[ groupHash ].vertices += 3; - } + } - }; + return groupsList; - // Objects removal + } - function removeObject( object, scene ) { + function initGeometryGroups( object, geometry ) { - if ( object instanceof THREE.Mesh || - object instanceof THREE.ParticleSystem || - object instanceof THREE.Line ) { + var material = object.material, addBuffers = false; - removeInstances( scene.__webglObjects, object ); + if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) { - } else if ( object instanceof THREE.Sprite ) { + delete _webglObjects[ object.id ]; - removeInstancesDirect( scene.__webglSprites, object ); + geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial ); - } else if ( object instanceof THREE.LensFlare ) { + geometry.groupsNeedUpdate = false; - removeInstancesDirect( scene.__webglFlares, object ); + } - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + var geometryGroupsList = geometryGroups[ geometry.id ]; - removeInstances( scene.__webglObjectsImmediate, object ); + // create separate VBOs per geometry chunk - } + for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - delete object.__webglActive; + var geometryGroup = geometryGroupsList[ i ]; - }; + // initialise VBO on the first access - function removeInstances( objlist, object ) { + if ( geometryGroup.__webglVertexBuffer === undefined ) { - for ( var o = objlist.length - 1; o >= 0; o -- ) { + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); - if ( objlist[ o ].object === object ) { + geometry.verticesNeedUpdate = true; + geometry.morphTargetsNeedUpdate = true; + geometry.elementsNeedUpdate = true; + geometry.uvsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + geometry.tangentsNeedUpdate = true; + geometry.colorsNeedUpdate = true; - objlist.splice( o, 1 ); + addBuffers = true; - } + } else { - } + addBuffers = false; - }; + } - function removeInstancesDirect( objlist, object ) { + if ( addBuffers || object.__webglActive === undefined ) { - for ( var o = objlist.length - 1; o >= 0; o -- ) { + addBuffer( _webglObjects, geometryGroup, object ); - if ( objlist[ o ] === object ) { + } - objlist.splice( o, 1 ); + } - } + object.__webglActive = true; - } + } - }; + function addBuffer( objlist, buffer, object ) { - // Materials + var id = object.id; + objlist[id] = objlist[id] || []; + objlist[id].push( + { + id: id, + buffer: buffer, + object: object, + material: null, + z: 0 + } + ); - this.initMaterial = function ( material, lights, fog, object ) { + }; - material.addEventListener( 'dispose', onMaterialDispose ); + function addBufferImmediate( objlist, object ) { - var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; + objlist.push( + { + id: null, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); - if ( material instanceof THREE.MeshDepthMaterial ) { + }; - shaderID = 'depth'; + // Objects updates - } else if ( material instanceof THREE.MeshNormalMaterial ) { + function updateObject( object ) { - shaderID = 'normal'; + var geometry = object.geometry; - } else if ( material instanceof THREE.MeshBasicMaterial ) { + if ( geometry instanceof THREE.BufferGeometry ) { - shaderID = 'basic'; + var attributes = geometry.attributes; + var attributesKeys = geometry.attributesKeys; - } else if ( material instanceof THREE.MeshLambertMaterial ) { + for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) { - shaderID = 'lambert'; + var key = attributesKeys[ i ]; + var attribute = attributes[ key ]; + var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; - } else if ( material instanceof THREE.MeshPhongMaterial ) { + if ( attribute.buffer === undefined ) { - shaderID = 'phong'; + attribute.buffer = _gl.createBuffer(); + _gl.bindBuffer( bufferType, attribute.buffer ); + _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW ); - } else if ( material instanceof THREE.LineBasicMaterial ) { + attribute.needsUpdate = false; - shaderID = 'basic'; + } else if ( attribute.needsUpdate === true ) { - } else if ( material instanceof THREE.LineDashedMaterial ) { + _gl.bindBuffer( bufferType, attribute.buffer ); - shaderID = 'dashed'; + if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges - } else if ( material instanceof THREE.ParticleSystemMaterial ) { + _gl.bufferSubData( bufferType, 0, attribute.array ); - shaderID = 'particle_basic'; + } else if ( attribute.updateRange.count === 0 ) { - } + console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' ); - if ( shaderID ) { + } else { - setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); + _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT, + attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) ); - } + attribute.updateRange.count = 0; // reset range - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) + } - maxLightCount = allocateLights( lights ); + attribute.needsUpdate = false; - maxShadows = allocateShadows( lights ); + } - maxBones = allocateBones( object ); + } - parameters = { + } else if ( object instanceof THREE.Mesh ) { - precision: _precision, - supportsVertexTextures: _supportsVertexTextures, + // check all geometry groups - map: !!material.map, - envMap: !!material.envMap, - lightMap: !!material.lightMap, - bumpMap: !!material.bumpMap, - normalMap: !!material.normalMap, - specularMap: !!material.specularMap, + if ( geometry.groupsNeedUpdate === true ) { - vertexColors: material.vertexColors, + initGeometryGroups( object, geometry ); - fog: fog, - useFog: material.fog, - fogExp: fog instanceof THREE.FogExp2, + } - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: _logarithmicDepthBuffer, + var geometryGroupsList = geometryGroups[ geometry.id ]; - skinning: material.skinning, - maxBones: maxBones, - useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, + for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: this.maxMorphTargets, - maxMorphNormals: this.maxMorphNormals, + var geometryGroup = geometryGroupsList[ i ]; + var material = getBufferMaterial( object, geometryGroup ); - maxDirLights: maxLightCount.directional, - maxPointLights: maxLightCount.point, - maxSpotLights: maxLightCount.spot, - maxHemiLights: maxLightCount.hemi, + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - maxShadows: maxShadows, - shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, - shadowMapType: this.shadowMapType, - shadowMapDebug: this.shadowMapDebug, - shadowMapCascade: this.shadowMapCascade, + if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { - alphaTest: material.alphaTest, - metal: material.metal, - wrapAround: material.wrapAround, - doubleSided: material.side === THREE.DoubleSide, - flipSided: material.side === THREE.BackSide + setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material ); - }; + } - // Generate code + } - var chunks = []; + geometry.verticesNeedUpdate = false; + geometry.morphTargetsNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; - if ( shaderID ) { + material.attributes && clearCustomAttributes( material ); - chunks.push( shaderID ); + } else if ( object instanceof THREE.Line ) { - } else { + var material = getBufferMaterial( object, geometry ); + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - chunks.push( material.fragmentShader ); - chunks.push( material.vertexShader ); + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { - } + setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); - for ( var d in material.defines ) { + } - chunks.push( d ); - chunks.push( material.defines[ d ] ); + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.lineDistancesNeedUpdate = false; - } + material.attributes && clearCustomAttributes( material ); - for ( var p in parameters ) { + } else if ( object instanceof THREE.PointCloud ) { - chunks.push( p ); - chunks.push( parameters[ p ] ); + var material = getBufferMaterial( object, geometry ); + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - } + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) { - var code = chunks.join(); + setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); - var program; + } - // Check if code has been already compiled + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; - for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { + material.attributes && clearCustomAttributes( material ); - var programInfo = _programs[ p ]; + } - if ( programInfo.code === code ) { + } - program = programInfo; - program.usedTimes ++; + // Objects updates - custom attributes check - break; + function areCustomAttributesDirty( material ) { - } + for ( var name in material.attributes ) { - } + if ( material.attributes[ name ].needsUpdate ) return true; - if ( program === undefined ) { + } - program = new THREE.WebGLProgram( this, code, material, parameters ); - _programs.push( program ); + return false; - _this.info.memory.programs = _programs.length; + } - } + function clearCustomAttributes( material ) { - material.program = program; + for ( var name in material.attributes ) { - var attributes = material.program.attributes; + material.attributes[ name ].needsUpdate = false; - if ( material.morphTargets ) { + } - material.numSupportedMorphTargets = 0; + } - var id, base = "morphTarget"; + // Objects removal - for ( i = 0; i < this.maxMorphTargets; i ++ ) { + function removeObject( object ) { - id = base + i; + if ( object instanceof THREE.Mesh || + object instanceof THREE.PointCloud || + object instanceof THREE.Line ) { - if ( attributes[ id ] >= 0 ) { + delete _webglObjects[ object.id ]; - material.numSupportedMorphTargets ++; + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - } + removeInstances( _webglObjectsImmediate, object ); - } + } - } + delete object.__webglInit; + delete object._modelViewMatrix; + delete object._normalMatrix; - if ( material.morphNormals ) { + delete object.__webglActive; - material.numSupportedMorphNormals = 0; + } - var id, base = "morphNormal"; + function removeInstances( objlist, object ) { - for ( i = 0; i < this.maxMorphNormals; i ++ ) { + for ( var o = objlist.length - 1; o >= 0; o -- ) { - id = base + i; + if ( objlist[ o ].object === object ) { - if ( attributes[ id ] >= 0 ) { + objlist.splice( o, 1 ); - material.numSupportedMorphNormals ++; + } - } + } - } + } - } + // Materials - material.uniformsList = []; + var shaderIDs = { + MeshDepthMaterial: 'depth', + MeshNormalMaterial: 'normal', + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + LineBasicMaterial: 'basic', + LineDashedMaterial: 'dashed', + PointCloudMaterial: 'particle_basic' + }; - for ( u in material.uniforms ) { + function initMaterial( material, lights, fog, object ) { - material.uniformsList.push( [ material.uniforms[ u ], u ] ); + material.addEventListener( 'dispose', onMaterialDispose ); - } + var shaderID = shaderIDs[ material.type ]; - }; + if ( shaderID ) { - function setMaterialShaders( material, shaders ) { + var shader = THREE.ShaderLib[ shaderID ]; - material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); - material.vertexShader = shaders.vertexShader; - material.fragmentShader = shaders.fragmentShader; + material.__webglShader = { + uniforms: THREE.UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + } - }; + } else { - function setProgram( camera, lights, fog, material, object ) { + material.__webglShader = { + uniforms: material.uniforms, + vertexShader: material.vertexShader, + fragmentShader: material.fragmentShader + } - _usedTextureUnits = 0; + } - if ( material.needsUpdate ) { + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) - if ( material.program ) deallocateMaterial( material ); + var maxLightCount = allocateLights( lights ); + var maxShadows = allocateShadows( lights ); + var maxBones = allocateBones( object ); - _this.initMaterial( material, lights, fog, object ); - material.needsUpdate = false; + var parameters = { - } + precision: _precision, + supportsVertexTextures: _supportsVertexTextures, - if ( material.morphTargets ) { + map: !! material.map, + envMap: !! material.envMap, + envMapMode: material.envMap && material.envMap.mapping, + lightMap: !! material.lightMap, + bumpMap: !! material.bumpMap, + normalMap: !! material.normalMap, + specularMap: !! material.specularMap, + alphaMap: !! material.alphaMap, - if ( ! object.__webglMorphTargetInfluences ) { + combine: material.combine, - object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); + vertexColors: material.vertexColors, - } + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, - } + flatShading: material.shading === THREE.FlatShading, - var refreshMaterial = false; + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: _logarithmicDepthBuffer, - var program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.uniforms; + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture, - if ( program.id !== _currentProgram ) { + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: _this.maxMorphTargets, + maxMorphNormals: _this.maxMorphNormals, - _gl.useProgram( program.program ); - _currentProgram = program.id; + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, - refreshMaterial = true; + maxShadows: maxShadows, + shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, + shadowMapType: _this.shadowMapType, + shadowMapDebug: _this.shadowMapDebug, + shadowMapCascade: _this.shadowMapCascade, - } + alphaTest: material.alphaTest, + metal: material.metal, + wrapAround: material.wrapAround, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide - if ( material.id !== _currentMaterialId ) { + }; - _currentMaterialId = material.id; - refreshMaterial = true; + // Generate code - } + var chunks = []; - if ( refreshMaterial || camera !== _currentCamera ) { + if ( shaderID ) { - _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + chunks.push( shaderID ); - if ( _logarithmicDepthBuffer ) { + } else { - _gl.uniform1f(p_uniforms.logDepthBufFC, 2.0 / (Math.log(camera.far + 1.0) / Math.LN2)); + chunks.push( material.fragmentShader ); + chunks.push( material.vertexShader ); - } + } + if ( material.defines !== undefined ) { - if ( camera !== _currentCamera ) _currentCamera = camera; + for ( var name in material.defines ) { - } + chunks.push( name ); + chunks.push( material.defines[ name ] ); - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen + } - if ( material.skinning ) { + } - if ( _supportsBoneTextures && object.useVertexTexture ) { + for ( var name in parameters ) { - if ( p_uniforms.boneTexture !== null ) { + chunks.push( name ); + chunks.push( parameters[ name ] ); - var textureUnit = getTextureUnit(); + } - _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); - _this.setTexture( object.boneTexture, textureUnit ); + var code = chunks.join(); - } + var program; - if ( p_uniforms.boneTextureWidth !== null ) { + // Check if code has been already compiled - _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); + for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { - } + var programInfo = _programs[ p ]; - if ( p_uniforms.boneTextureHeight !== null ) { + if ( programInfo.code === code ) { - _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); + program = programInfo; + program.usedTimes ++; - } + break; - } else { + } - if ( p_uniforms.boneGlobalMatrices !== null ) { + } - _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); + if ( program === undefined ) { - } + program = new THREE.WebGLProgram( _this, code, material, parameters ); + _programs.push( program ); - } + _this.info.memory.programs = _programs.length; - } + } - if ( refreshMaterial ) { + material.program = program; - // refresh uniforms common to several materials + var attributes = program.attributes; - if ( fog && material.fog ) { + if ( material.morphTargets ) { - refreshUniformsFog( m_uniforms, fog ); + material.numSupportedMorphTargets = 0; - } + var id, base = 'morphTarget'; - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material.lights ) { + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - if ( _lightsNeedUpdate ) { + id = base + i; - setupLights( program, lights ); - _lightsNeedUpdate = false; + if ( attributes[ id ] >= 0 ) { - } + material.numSupportedMorphTargets ++; - refreshUniformsLights( m_uniforms, _lights ); + } - } + } - if ( material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial ) { + } - refreshUniformsCommon( m_uniforms, material ); + if ( material.morphNormals ) { - } + material.numSupportedMorphNormals = 0; - // refresh single material specific uniforms + var id, base = 'morphNormal'; - if ( material instanceof THREE.LineBasicMaterial ) { + for ( i = 0; i < _this.maxMorphNormals; i ++ ) { - refreshUniformsLine( m_uniforms, material ); + id = base + i; - } else if ( material instanceof THREE.LineDashedMaterial ) { + if ( attributes[ id ] >= 0 ) { - refreshUniformsLine( m_uniforms, material ); - refreshUniformsDash( m_uniforms, material ); + material.numSupportedMorphNormals ++; - } else if ( material instanceof THREE.ParticleSystemMaterial ) { + } - refreshUniformsParticle( m_uniforms, material ); + } - } else if ( material instanceof THREE.MeshPhongMaterial ) { + } - refreshUniformsPhong( m_uniforms, material ); + material.uniformsList = []; - } else if ( material instanceof THREE.MeshLambertMaterial ) { + for ( var u in material.__webglShader.uniforms ) { - refreshUniformsLambert( m_uniforms, material ); + var location = material.program.uniforms[ u ]; - } else if ( material instanceof THREE.MeshDepthMaterial ) { + if ( location ) { + material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] ); + } - m_uniforms.mNear.value = camera.near; - m_uniforms.mFar.value = camera.far; - m_uniforms.opacity.value = material.opacity; + } - } else if ( material instanceof THREE.MeshNormalMaterial ) { + } - m_uniforms.opacity.value = material.opacity; + function setMaterial( material ) { - } + if ( material.transparent === true ) { - if ( object.receiveShadow && ! material._shadowPass ) { + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - refreshUniformsShadow( m_uniforms, lights ); + } else { - } + state.setBlending( THREE.NoBlending ); - // load common uniforms + } - loadUniformsGeneric( program, material.uniformsList ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + } - if ( material instanceof THREE.ShaderMaterial || - material instanceof THREE.MeshPhongMaterial || - material.envMap ) { + function setProgram( camera, lights, fog, material, object ) { - if ( p_uniforms.cameraPosition !== null ) { + _usedTextureUnits = 0; - _vector3.setFromMatrixPosition( camera.matrixWorld ); - _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); + if ( material.needsUpdate ) { - } + if ( material.program ) deallocateMaterial( material ); - } + initMaterial( material, lights, fog, object ); + material.needsUpdate = false; - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.ShaderMaterial || - material.skinning ) { + } - if ( p_uniforms.viewMatrix !== null ) { + if ( material.morphTargets ) { - _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); + if ( ! object.__webglMorphTargetInfluences ) { - } + object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); - } + } - } + } - loadUniformsMatrices( p_uniforms, object ); + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; - if ( p_uniforms.modelMatrix !== null ) { + var program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.__webglShader.uniforms; - _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); + if ( program.id !== _currentProgram ) { - } + _gl.useProgram( program.program ); + _currentProgram = program.id; - return program; + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - }; + } - // Uniforms (refresh uniforms objects) + if ( material.id !== _currentMaterialId ) { - function refreshUniformsCommon ( uniforms, material ) { + if ( _currentMaterialId === -1 ) refreshLights = true; + _currentMaterialId = material.id; - uniforms.opacity.value = material.opacity; + refreshMaterial = true; - if ( _this.gammaInput ) { + } - uniforms.diffuse.value.copyGammaToLinear( material.color ); + if ( refreshProgram || camera !== _currentCamera ) { - } else { + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - uniforms.diffuse.value = material.color; + if ( _logarithmicDepthBuffer ) { - } + _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - uniforms.map.value = material.map; - uniforms.lightMap.value = material.lightMap; - uniforms.specularMap.value = material.specularMap; + } - if ( material.bumpMap ) { - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + if ( camera !== _currentCamera ) _currentCamera = camera; - } + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - if ( material.normalMap ) { + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material.envMap ) { - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); + if ( p_uniforms.cameraPosition !== null ) { - } + _vector3.setFromMatrixPosition( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map + } - var uvScaleMap; + } - if ( material.map ) { + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { - uvScaleMap = material.map; + if ( p_uniforms.viewMatrix !== null ) { - } else if ( material.specularMap ) { + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); - uvScaleMap = material.specularMap; + } - } else if ( material.normalMap ) { + } - uvScaleMap = material.normalMap; + } - } else if ( material.bumpMap ) { + // 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 - uvScaleMap = material.bumpMap; + if ( material.skinning ) { - } + if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) { - if ( uvScaleMap !== undefined ) { + _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; + } - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) { - } + _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + } - if ( _this.gammaInput ) { + if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) { - //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; - uniforms.reflectivity.value = material.reflectivity; + if ( p_uniforms.boneTexture !== null ) { - } else { + var textureUnit = getTextureUnit(); - uniforms.reflectivity.value = material.reflectivity; + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.skeleton.boneTexture, textureUnit ); - } + } - uniforms.refractionRatio.value = material.refractionRatio; - uniforms.combine.value = material.combine; - uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; + if ( p_uniforms.boneTextureWidth !== null ) { - }; + _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); - function refreshUniformsLine ( uniforms, material ) { + } - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; + if ( p_uniforms.boneTextureHeight !== null ) { - }; + _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); - function refreshUniformsDash ( uniforms, material ) { + } - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; + } else if ( object.skeleton && object.skeleton.boneMatrices ) { - }; + if ( p_uniforms.boneGlobalMatrices !== null ) { - function refreshUniformsParticle ( uniforms, material ) { + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices ); - uniforms.psColor.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size; - uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. + } - uniforms.map.value = material.map; + } - }; + } - function refreshUniformsFog ( uniforms, fog ) { + if ( refreshMaterial ) { - uniforms.fogColor.value = fog.color; + // refresh uniforms common to several materials - if ( fog instanceof THREE.Fog ) { + if ( fog && material.fog ) { - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + refreshUniformsFog( m_uniforms, fog ); - } else if ( fog instanceof THREE.FogExp2 ) { + } - uniforms.fogDensity.value = fog.density; + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material.lights ) { - } + if ( _lightsNeedUpdate ) { - }; + refreshLights = true; + setupLights( lights ); + _lightsNeedUpdate = false; + } - function refreshUniformsPhong ( uniforms, material ) { + if ( refreshLights ) { + refreshUniformsLights( m_uniforms, _lights ); + markUniformsLightsNeedsUpdate( m_uniforms, true ); + } else { + markUniformsLightsNeedsUpdate( m_uniforms, false ); + } - uniforms.shininess.value = material.shininess; + } - if ( _this.gammaInput ) { + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhongMaterial ) { - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - uniforms.specular.value.copyGammaToLinear( material.specular ); + refreshUniformsCommon( m_uniforms, material ); - } else { + } - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; + // refresh single material specific uniforms - } + if ( material instanceof THREE.LineBasicMaterial ) { - if ( material.wrapAround ) { + refreshUniformsLine( m_uniforms, material ); - uniforms.wrapRGB.value.copy( material.wrapRGB ); + } else if ( material instanceof THREE.LineDashedMaterial ) { - } + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); - }; + } else if ( material instanceof THREE.PointCloudMaterial ) { - function refreshUniformsLambert ( uniforms, material ) { + refreshUniformsParticle( m_uniforms, material ); - if ( _this.gammaInput ) { + } else if ( material instanceof THREE.MeshPhongMaterial ) { - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); + refreshUniformsPhong( m_uniforms, material ); - } else { + } else if ( material instanceof THREE.MeshLambertMaterial ) { - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; + refreshUniformsLambert( m_uniforms, material ); - } + } else if ( material instanceof THREE.MeshDepthMaterial ) { - if ( material.wrapAround ) { + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; - uniforms.wrapRGB.value.copy( material.wrapRGB ); + } else if ( material instanceof THREE.MeshNormalMaterial ) { - } + m_uniforms.opacity.value = material.opacity; - }; + } - function refreshUniformsLights ( uniforms, lights ) { + if ( object.receiveShadow && ! material._shadowPass ) { - uniforms.ambientLightColor.value = lights.ambient; + refreshUniformsShadow( m_uniforms, lights ); - uniforms.directionalLightColor.value = lights.directional.colors; - uniforms.directionalLightDirection.value = lights.directional.positions; + } - uniforms.pointLightColor.value = lights.point.colors; - uniforms.pointLightPosition.value = lights.point.positions; - uniforms.pointLightDistance.value = lights.point.distances; + // load common uniforms - uniforms.spotLightColor.value = lights.spot.colors; - uniforms.spotLightPosition.value = lights.spot.positions; - uniforms.spotLightDistance.value = lights.spot.distances; - uniforms.spotLightDirection.value = lights.spot.directions; - uniforms.spotLightAngleCos.value = lights.spot.anglesCos; - uniforms.spotLightExponent.value = lights.spot.exponents; + loadUniformsGeneric( material.uniformsList ); - uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; - uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; - uniforms.hemisphereLightDirection.value = lights.hemi.positions; + } - }; + loadUniformsMatrices( p_uniforms, object ); - function refreshUniformsShadow ( uniforms, lights ) { + if ( p_uniforms.modelMatrix !== null ) { - if ( uniforms.shadowMatrix ) { + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); - var j = 0; + } - for ( var i = 0, il = lights.length; i < il; i ++ ) { + return program; - var light = lights[ i ]; + } - if ( ! light.castShadow ) continue; + // Uniforms (refresh uniforms objects) - if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { + function refreshUniformsCommon ( uniforms, material ) { - uniforms.shadowMap.value[ j ] = light.shadowMap; - uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + uniforms.opacity.value = material.opacity; - uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + uniforms.diffuse.value = material.color; - uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; - uniforms.shadowBias.value[ j ] = light.shadowBias; + uniforms.map.value = material.map; + uniforms.lightMap.value = material.lightMap; + uniforms.specularMap.value = material.specularMap; + uniforms.alphaMap.value = material.alphaMap; - j ++; + 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 ); - // Uniforms (load to GPU) + } - function loadUniformsMatrices ( uniforms, object ) { + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); + var uvScaleMap; - if ( uniforms.normalMatrix ) { + if ( material.map ) { - _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); + uvScaleMap = material.map; - } + } else if ( material.specularMap ) { - }; + uvScaleMap = material.specularMap; - function getTextureUnit() { + } else if ( material.normalMap ) { - var textureUnit = _usedTextureUnits; + uvScaleMap = material.normalMap; - if ( textureUnit >= _maxTextures ) { + } else if ( material.bumpMap ) { - console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + uvScaleMap = material.bumpMap; - } + } else if ( material.alphaMap ) { - _usedTextureUnits += 1; + uvScaleMap = material.alphaMap; - return textureUnit; + } - }; + if ( uvScaleMap !== undefined ) { - function loadUniformsGeneric ( program, uniforms ) { + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; - var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { + } - location = program.uniforms[ uniforms[ j ][ 1 ] ]; - if ( !location ) continue; + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - uniform = uniforms[ j ][ 0 ]; + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; - type = uniform.type; - value = uniform.value; + } - if ( type === "i" ) { // single integer + function refreshUniformsLine ( uniforms, material ) { - _gl.uniform1i( location, value ); + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; - } else if ( type === "f" ) { // single float + } - _gl.uniform1f( location, value ); + function refreshUniformsDash ( uniforms, material ) { - } else if ( type === "v2" ) { // single THREE.Vector2 + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; - _gl.uniform2f( location, value.x, value.y ); + } - } else if ( type === "v3" ) { // single THREE.Vector3 + function refreshUniformsParticle ( uniforms, material ) { - _gl.uniform3f( location, value.x, value.y, value.z ); + uniforms.psColor.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size; + uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. - } else if ( type === "v4" ) { // single THREE.Vector4 + uniforms.map.value = material.map; - _gl.uniform4f( location, value.x, value.y, value.z, value.w ); + if ( material.map !== null ) { - } else if ( type === "c" ) { // single THREE.Color + var offset = material.map.offset; + var repeat = material.map.repeat; - _gl.uniform3f( location, value.r, value.g, value.b ); + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) + } - _gl.uniform1iv( location, value ); + } - } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) + function refreshUniformsFog ( uniforms, fog ) { - _gl.uniform3iv( location, value ); + uniforms.fogColor.value = fog.color; - } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) + if ( fog instanceof THREE.Fog ) { - _gl.uniform1fv( location, value ); + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) + } else if ( fog instanceof THREE.FogExp2 ) { - _gl.uniform3fv( location, value ); + uniforms.fogDensity.value = fog.density; - } else if ( type === "v2v" ) { // array of THREE.Vector2 + } - if ( uniform._array === undefined ) { + } - uniform._array = new Float32Array( 2 * value.length ); + function refreshUniformsPhong ( uniforms, material ) { - } + uniforms.shininess.value = material.shininess; - for ( i = 0, il = value.length; i < il; i ++ ) { + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; - offset = i * 2; + if ( material.wrapAround ) { - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; + uniforms.wrapRGB.value.copy( material.wrapRGB ); - } + } - _gl.uniform2fv( location, uniform._array ); + } - } else if ( type === "v3v" ) { // array of THREE.Vector3 + function refreshUniformsLambert ( uniforms, material ) { - if ( uniform._array === undefined ) { + uniforms.emissive.value = material.emissive; - uniform._array = new Float32Array( 3 * value.length ); + if ( material.wrapAround ) { - } + uniforms.wrapRGB.value.copy( material.wrapRGB ); - for ( i = 0, il = value.length; i < il; i ++ ) { + } - offset = i * 3; + } - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; + function refreshUniformsLights ( uniforms, lights ) { - } + uniforms.ambientLightColor.value = lights.ambient; - _gl.uniform3fv( location, uniform._array ); + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; - } else if ( type === "v4v" ) { // array of THREE.Vector4 + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecay.value = lights.point.decays; - if ( uniform._array === undefined ) { + uniforms.spotLightColor.value = lights.spot.colors; + uniforms.spotLightPosition.value = lights.spot.positions; + uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDirection.value = lights.spot.directions; + uniforms.spotLightAngleCos.value = lights.spot.anglesCos; + uniforms.spotLightExponent.value = lights.spot.exponents; + uniforms.spotLightDecay.value = lights.spot.decays; - uniform._array = new Float32Array( 4 * value.length ); + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; - } + } - for ( i = 0, il = value.length; i < il; i ++ ) { + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - offset = i * 4; + function markUniformsLightsNeedsUpdate ( uniforms, value ) { - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - uniform._array[ offset + 3 ] = value[ i ].w; + uniforms.ambientLightColor.needsUpdate = value; - } + uniforms.directionalLightColor.needsUpdate = value; + uniforms.directionalLightDirection.needsUpdate = value; - _gl.uniform4fv( location, uniform._array ); + uniforms.pointLightColor.needsUpdate = value; + uniforms.pointLightPosition.needsUpdate = value; + uniforms.pointLightDistance.needsUpdate = value; + uniforms.pointLightDecay.needsUpdate = value; - } else if ( type === "m4") { // single THREE.Matrix4 + uniforms.spotLightColor.needsUpdate = value; + uniforms.spotLightPosition.needsUpdate = value; + uniforms.spotLightDistance.needsUpdate = value; + uniforms.spotLightDirection.needsUpdate = value; + uniforms.spotLightAngleCos.needsUpdate = value; + uniforms.spotLightExponent.needsUpdate = value; + uniforms.spotLightDecay.needsUpdate = value; - if ( uniform._array === undefined ) { + uniforms.hemisphereLightSkyColor.needsUpdate = value; + uniforms.hemisphereLightGroundColor.needsUpdate = value; + uniforms.hemisphereLightDirection.needsUpdate = value; - uniform._array = new Float32Array( 16 ); + } - } + function refreshUniformsShadow ( uniforms, lights ) { - value.flattenToArray( uniform._array ); - _gl.uniformMatrix4fv( location, false, uniform._array ); + if ( uniforms.shadowMatrix ) { - } else if ( type === "m4v" ) { // array of THREE.Matrix4 + var j = 0; - if ( uniform._array === undefined ) { + for ( var i = 0, il = lights.length; i < il; i ++ ) { - uniform._array = new Float32Array( 16 * value.length ); + var light = lights[ i ]; - } + if ( ! light.castShadow ) continue; - for ( i = 0, il = value.length; i < il; i ++ ) { + if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { - value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; - } + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; - _gl.uniformMatrix4fv( location, false, uniform._array ); + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; + uniforms.shadowBias.value[ j ] = light.shadowBias; - } else if ( type === "t" ) { // single THREE.Texture (2d or cube) + j ++; - texture = value; - textureUnit = getTextureUnit(); + } - _gl.uniform1i( location, textureUnit ); + } - if ( !texture ) continue; + } - if ( texture.image instanceof Array && texture.image.length === 6 ) { + } - setCubeTexture( texture, textureUnit ); + // Uniforms (load to GPU) - } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { + function loadUniformsMatrices ( uniforms, object ) { - setCubeTextureDynamic( texture, textureUnit ); + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); - } else { + if ( uniforms.normalMatrix ) { - _this.setTexture( texture, textureUnit ); + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); - } + } - } else if ( type === "tv" ) { // array of THREE.Texture (2d) + } - if ( uniform._array === undefined ) { + function getTextureUnit() { - uniform._array = []; + var textureUnit = _usedTextureUnits; - } + if ( textureUnit >= _maxTextures ) { - for( i = 0, il = uniform.value.length; i < il; i ++ ) { + THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); - uniform._array[ i ] = getTextureUnit(); + } - } + _usedTextureUnits += 1; - _gl.uniform1iv( location, uniform._array ); + return textureUnit; - for( i = 0, il = uniform.value.length; i < il; i ++ ) { + } - texture = uniform.value[ i ]; - textureUnit = uniform._array[ i ]; + function loadUniformsGeneric ( uniforms ) { - if ( !texture ) continue; + var texture, textureUnit, offset; - _this.setTexture( texture, textureUnit ); + for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { - } + var uniform = uniforms[ j ][ 0 ]; - } else { + // needsUpdate property is not added to all uniforms. + if ( uniform.needsUpdate === false ) continue; - console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + var type = uniform.type; + var value = uniform.value; + var location = uniforms[ j ][ 1 ]; - } + switch ( type ) { - } + case '1i': + _gl.uniform1i( location, value ); + break; - }; + case '1f': + _gl.uniform1f( location, value ); + break; - function setupMatrices ( object, camera ) { + case '2f': + _gl.uniform2f( location, value[ 0 ], value[ 1 ] ); + break; - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); + case '3f': + _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); + break; - }; + case '4f': + _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); + break; - // + case '1iv': + _gl.uniform1iv( location, value ); + break; - function setColorGamma( array, offset, color, intensitySq ) { + case '3iv': + _gl.uniform3iv( location, value ); + break; - array[ offset ] = color.r * color.r * intensitySq; - array[ offset + 1 ] = color.g * color.g * intensitySq; - array[ offset + 2 ] = color.b * color.b * intensitySq; + case '1fv': + _gl.uniform1fv( location, value ); + break; - }; + case '2fv': + _gl.uniform2fv( location, value ); + break; - function setColorLinear( array, offset, color, intensity ) { + case '3fv': + _gl.uniform3fv( location, value ); + break; - array[ offset ] = color.r * intensity; - array[ offset + 1 ] = color.g * intensity; - array[ offset + 2 ] = color.b * intensity; + case '4fv': + _gl.uniform4fv( location, value ); + break; - }; + case 'Matrix3fv': + _gl.uniformMatrix3fv( location, false, value ); + break; - function setupLights ( program, lights ) { + case 'Matrix4fv': + _gl.uniformMatrix4fv( location, false, value ); + break; - var l, ll, light, n, - r = 0, g = 0, b = 0, - color, skyColor, groundColor, - intensity, intensitySq, - position, - distance, + // - zlights = _lights, + case 'i': - dirColors = zlights.directional.colors, - dirPositions = zlights.directional.positions, + // single integer + _gl.uniform1i( location, value ); - pointColors = zlights.point.colors, - pointPositions = zlights.point.positions, - pointDistances = zlights.point.distances, + break; - spotColors = zlights.spot.colors, - spotPositions = zlights.spot.positions, - spotDistances = zlights.spot.distances, - spotDirections = zlights.spot.directions, - spotAnglesCos = zlights.spot.anglesCos, - spotExponents = zlights.spot.exponents, + case 'f': - hemiSkyColors = zlights.hemi.skyColors, - hemiGroundColors = zlights.hemi.groundColors, - hemiPositions = zlights.hemi.positions, + // single float + _gl.uniform1f( location, value ); - dirLength = 0, - pointLength = 0, - spotLength = 0, - hemiLength = 0, + break; - dirCount = 0, - pointCount = 0, - spotCount = 0, - hemiCount = 0, + case 'v2': - dirOffset = 0, - pointOffset = 0, - spotOffset = 0, - hemiOffset = 0; + // single THREE.Vector2 + _gl.uniform2f( location, value.x, value.y ); - for ( l = 0, ll = lights.length; l < ll; l ++ ) { + break; - light = lights[ l ]; + case 'v3': - if ( light.onlyShadow ) continue; + // single THREE.Vector3 + _gl.uniform3f( location, value.x, value.y, value.z ); - color = light.color; - intensity = light.intensity; - distance = light.distance; + break; - if ( light instanceof THREE.AmbientLight ) { + case 'v4': - if ( ! light.visible ) continue; + // single THREE.Vector4 + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); - if ( _this.gammaInput ) { + break; - r += color.r * color.r; - g += color.g * color.g; - b += color.b * color.b; + case 'c': - } else { + // single THREE.Color + _gl.uniform3f( location, value.r, value.g, value.b ); - r += color.r; - g += color.g; - b += color.b; + break; - } + case 'iv1': - } else if ( light instanceof THREE.DirectionalLight ) { + // flat array of integers (JS or typed array) + _gl.uniform1iv( location, value ); - dirCount += 1; + break; - if ( ! light.visible ) continue; + case 'iv': - _direction.setFromMatrixPosition( light.matrixWorld ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); + // flat array of integers with 3 x N size (JS or typed array) + _gl.uniform3iv( location, value ); - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) + break; - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + case 'fv1': - dirOffset = dirLength * 3; + // flat array of floats (JS or typed array) + _gl.uniform1fv( location, value ); - dirPositions[ dirOffset ] = _direction.x; - dirPositions[ dirOffset + 1 ] = _direction.y; - dirPositions[ dirOffset + 2 ] = _direction.z; + break; - if ( _this.gammaInput ) { + case 'fv': - setColorGamma( dirColors, dirOffset, color, intensity * intensity ); + // flat array of floats with 3 x N size (JS or typed array) + _gl.uniform3fv( location, value ); - } else { + break; - setColorLinear( dirColors, dirOffset, color, intensity ); + case 'v2v': - } + // array of THREE.Vector2 - dirLength += 1; + if ( uniform._array === undefined ) { - } else if ( light instanceof THREE.PointLight ) { + uniform._array = new Float32Array( 2 * value.length ); - pointCount += 1; + } - if ( ! light.visible ) continue; + for ( var i = 0, il = value.length; i < il; i ++ ) { - pointOffset = pointLength * 3; + offset = i * 2; - if ( _this.gammaInput ) { + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; - setColorGamma( pointColors, pointOffset, color, intensity * intensity ); + } - } else { + _gl.uniform2fv( location, uniform._array ); - setColorLinear( pointColors, pointOffset, color, intensity ); + break; - } + case 'v3v': - _vector3.setFromMatrixPosition( light.matrixWorld ); + // array of THREE.Vector3 - pointPositions[ pointOffset ] = _vector3.x; - pointPositions[ pointOffset + 1 ] = _vector3.y; - pointPositions[ pointOffset + 2 ] = _vector3.z; + if ( uniform._array === undefined ) { - pointDistances[ pointLength ] = distance; + uniform._array = new Float32Array( 3 * value.length ); - pointLength += 1; + } - } else if ( light instanceof THREE.SpotLight ) { + for ( var i = 0, il = value.length; i < il; i ++ ) { - spotCount += 1; + offset = i * 3; - if ( ! light.visible ) continue; + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; - spotOffset = spotLength * 3; + } - if ( _this.gammaInput ) { + _gl.uniform3fv( location, uniform._array ); - setColorGamma( spotColors, spotOffset, color, intensity * intensity ); + break; - } else { + case 'v4v': - setColorLinear( spotColors, spotOffset, color, intensity ); + // array of THREE.Vector4 - } + if ( uniform._array === undefined ) { - _vector3.setFromMatrixPosition( light.matrixWorld ); + uniform._array = new Float32Array( 4 * value.length ); - spotPositions[ spotOffset ] = _vector3.x; - spotPositions[ spotOffset + 1 ] = _vector3.y; - spotPositions[ spotOffset + 2 ] = _vector3.z; + } - spotDistances[ spotLength ] = distance; + for ( var i = 0, il = value.length; i < il; i ++ ) { - _direction.copy( _vector3 ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); + offset = i * 4; - spotDirections[ spotOffset ] = _direction.x; - spotDirections[ spotOffset + 1 ] = _direction.y; - spotDirections[ spotOffset + 2 ] = _direction.z; + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + uniform._array[ offset + 3 ] = value[ i ].w; - spotAnglesCos[ spotLength ] = Math.cos( light.angle ); - spotExponents[ spotLength ] = light.exponent; + } - spotLength += 1; + _gl.uniform4fv( location, uniform._array ); - } else if ( light instanceof THREE.HemisphereLight ) { + break; - hemiCount += 1; + case 'm3': - if ( ! light.visible ) continue; + // single THREE.Matrix3 + _gl.uniformMatrix3fv( location, false, value.elements ); - _direction.setFromMatrixPosition( light.matrixWorld ); - _direction.normalize(); + break; - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) + case 'm3v': - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + // array of THREE.Matrix3 - hemiOffset = hemiLength * 3; + if ( uniform._array === undefined ) { - hemiPositions[ hemiOffset ] = _direction.x; - hemiPositions[ hemiOffset + 1 ] = _direction.y; - hemiPositions[ hemiOffset + 2 ] = _direction.z; + uniform._array = new Float32Array( 9 * value.length ); - skyColor = light.color; - groundColor = light.groundColor; + } - if ( _this.gammaInput ) { + for ( var i = 0, il = value.length; i < il; i ++ ) { - intensitySq = intensity * intensity; + value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); - setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); - setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); + } - } else { + _gl.uniformMatrix3fv( location, false, uniform._array ); - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + break; - } + case 'm4': - hemiLength += 1; + // single THREE.Matrix4 + _gl.uniformMatrix4fv( location, false, value.elements ); - } + break; - } + case 'm4v': - // null eventual remains from removed lights - // (this is to avoid if in shader) + // array of THREE.Matrix4 - for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; - for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; - for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + if ( uniform._array === undefined ) { - zlights.directional.length = dirLength; - zlights.point.length = pointLength; - zlights.spot.length = spotLength; - zlights.hemi.length = hemiLength; + uniform._array = new Float32Array( 16 * value.length ); - zlights.ambient[ 0 ] = r; - zlights.ambient[ 1 ] = g; - zlights.ambient[ 2 ] = b; + } - }; + for ( var i = 0, il = value.length; i < il; i ++ ) { - // GL state setting + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); - this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + } - if ( cullFace === THREE.CullFaceNone ) { + _gl.uniformMatrix4fv( location, false, uniform._array ); - _gl.disable( _gl.CULL_FACE ); + break; - } else { + case 't': - if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { + // single THREE.Texture (2d or cube) - _gl.frontFace( _gl.CW ); + texture = value; + textureUnit = getTextureUnit(); - } else { + _gl.uniform1i( location, textureUnit ); - _gl.frontFace( _gl.CCW ); + if ( ! texture ) continue; - } + if ( texture instanceof THREE.CubeTexture || + ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ - if ( cullFace === THREE.CullFaceBack ) { + setCubeTexture( texture, textureUnit ); - _gl.cullFace( _gl.BACK ); + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - } else if ( cullFace === THREE.CullFaceFront ) { + setCubeTextureDynamic( texture, textureUnit ); - _gl.cullFace( _gl.FRONT ); + } else { - } else { + _this.setTexture( texture, textureUnit ); - _gl.cullFace( _gl.FRONT_AND_BACK ); + } - } + break; - _gl.enable( _gl.CULL_FACE ); + case 'tv': - } + // array of THREE.Texture (2d) - }; + if ( uniform._array === undefined ) { - this.setMaterialFaces = function ( material ) { + uniform._array = []; - var doubleSided = material.side === THREE.DoubleSide; - var flipSided = material.side === THREE.BackSide; + } - if ( _oldDoubleSided !== doubleSided ) { + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - if ( doubleSided ) { + uniform._array[ i ] = getTextureUnit(); - _gl.disable( _gl.CULL_FACE ); + } - } else { + _gl.uniform1iv( location, uniform._array ); - _gl.enable( _gl.CULL_FACE ); + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - } + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; - _oldDoubleSided = doubleSided; + if ( ! texture ) continue; - } + _this.setTexture( texture, textureUnit ); - if ( _oldFlipSided !== flipSided ) { + } - if ( flipSided ) { + break; - _gl.frontFace( _gl.CW ); + default: - } else { + THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); - _gl.frontFace( _gl.CCW ); + } - } + } - _oldFlipSided = flipSided; + } - } + function setupMatrices ( object, camera ) { - }; + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); - this.setDepthTest = function ( depthTest ) { + } - if ( _oldDepthTest !== depthTest ) { + function setColorLinear( array, offset, color, intensity ) { - if ( depthTest ) { + array[ offset ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; - _gl.enable( _gl.DEPTH_TEST ); + } - } else { + function setupLights ( lights ) { - _gl.disable( _gl.DEPTH_TEST ); + var l, ll, light, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, + distance, - } + zlights = _lights, - _oldDepthTest = depthTest; + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, - } + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + pointDecays = zlights.point.decays, - }; + spotColors = zlights.spot.colors, + spotPositions = zlights.spot.positions, + spotDistances = zlights.spot.distances, + spotDirections = zlights.spot.directions, + spotAnglesCos = zlights.spot.anglesCos, + spotExponents = zlights.spot.exponents, + spotDecays = zlights.spot.decays, - this.setDepthWrite = function ( depthWrite ) { + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, - if ( _oldDepthWrite !== depthWrite ) { + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, - _gl.depthMask( depthWrite ); - _oldDepthWrite = depthWrite; + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, - } + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0; - }; + for ( l = 0, ll = lights.length; l < ll; l ++ ) { - function setLineWidth ( width ) { + light = lights[ l ]; - if ( width !== _oldLineWidth ) { + if ( light.onlyShadow ) continue; - _gl.lineWidth( width ); + color = light.color; + intensity = light.intensity; + distance = light.distance; - _oldLineWidth = width; + if ( light instanceof THREE.AmbientLight ) { - } + if ( ! light.visible ) continue; - }; + r += color.r; + g += color.g; + b += color.b; - function setPolygonOffset ( polygonoffset, factor, units ) { + } else if ( light instanceof THREE.DirectionalLight ) { - if ( _oldPolygonOffset !== polygonoffset ) { + dirCount += 1; - if ( polygonoffset ) { + if ( ! light.visible ) continue; - _gl.enable( _gl.POLYGON_OFFSET_FILL ); + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); - } else { + dirOffset = dirLength * 3; - _gl.disable( _gl.POLYGON_OFFSET_FILL ); + dirPositions[ dirOffset ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; - } + setColorLinear( dirColors, dirOffset, color, intensity ); - _oldPolygonOffset = polygonoffset; + dirLength += 1; - } + } else if ( light instanceof THREE.PointLight ) { - if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { + pointCount += 1; - _gl.polygonOffset( factor, units ); + if ( ! light.visible ) continue; - _oldPolygonOffsetFactor = factor; - _oldPolygonOffsetUnits = units; + pointOffset = pointLength * 3; - } + setColorLinear( pointColors, pointOffset, color, intensity ); - }; + _vector3.setFromMatrixPosition( light.matrixWorld ); - this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { + pointPositions[ pointOffset ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; - if ( blending !== _oldBlending ) { + // distance is 0 if decay is 0, because there is no attenuation at all. + pointDistances[ pointLength ] = distance; + pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - if ( blending === THREE.NoBlending ) { + pointLength += 1; - _gl.disable( _gl.BLEND ); + } else if ( light instanceof THREE.SpotLight ) { - } else if ( blending === THREE.AdditiveBlending ) { + spotCount += 1; - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); + if ( ! light.visible ) continue; - } else if ( blending === THREE.SubtractiveBlending ) { + spotOffset = spotLength * 3; - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); + setColorLinear( spotColors, spotOffset, color, intensity ); - } else if ( blending === THREE.MultiplyBlending ) { + _direction.setFromMatrixPosition( light.matrixWorld ); - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); + spotPositions[ spotOffset ] = _direction.x; + spotPositions[ spotOffset + 1 ] = _direction.y; + spotPositions[ spotOffset + 2 ] = _direction.z; - } else if ( blending === THREE.CustomBlending ) { + spotDistances[ spotLength ] = distance; - _gl.enable( _gl.BLEND ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); - } else { + spotDirections[ spotOffset ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; - _gl.enable( _gl.BLEND ); - _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 ); + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - } + spotLength += 1; - _oldBlending = blending; + } else if ( light instanceof THREE.HemisphereLight ) { - } + hemiCount += 1; - if ( blending === THREE.CustomBlending ) { + if ( ! light.visible ) continue; - if ( blendEquation !== _oldBlendEquation ) { + _direction.setFromMatrixPosition( light.matrixWorld ); + _direction.normalize(); - _gl.blendEquation( paramThreeToGL( blendEquation ) ); + hemiOffset = hemiLength * 3; - _oldBlendEquation = blendEquation; + hemiPositions[ hemiOffset ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; - } + skyColor = light.color; + groundColor = light.groundColor; - if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); + hemiLength += 1; - _oldBlendSrc = blendSrc; - _oldBlendDst = blendDst; + } - } + } - } else { + // null eventual remains from removed lights + // (this is to avoid if in shader) - _oldBlendEquation = null; - _oldBlendSrc = null; - _oldBlendDst = null; + for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; + for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; + for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; - } + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; - }; + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; - // Textures + } - function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { + // GL state setting - if ( isImagePowerOfTwo ) { + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); + if ( cullFace === THREE.CullFaceNone ) { - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); + _gl.disable( _gl.CULL_FACE ); - } else { + } else { - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + _gl.frontFace( _gl.CW ); - } + } else { - if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { + _gl.frontFace( _gl.CCW ); - if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + } - _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); - texture.__oldAnisotropy = texture.anisotropy; + if ( cullFace === THREE.CullFaceBack ) { - } + _gl.cullFace( _gl.BACK ); - } + } else if ( cullFace === THREE.CullFaceFront ) { - }; + _gl.cullFace( _gl.FRONT ); - this.setTexture = function ( texture, slot ) { + } else { - if ( texture.needsUpdate ) { + _gl.cullFace( _gl.FRONT_AND_BACK ); - if ( ! texture.__webglInit ) { + } - texture.__webglInit = true; + _gl.enable( _gl.CULL_FACE ); - texture.addEventListener( 'dispose', onTextureDispose ); + } - texture.__webglTexture = _gl.createTexture(); + }; - _this.info.memory.textures ++; + this.setMaterialFaces = function ( material ) { - } + state.setDoubleSided( material.side === THREE.DoubleSide ); + state.setFlipSided( material.side === THREE.BackSide ); - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + }; - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + // Textures - var image = texture.image, - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { - setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); + var extension; - var mipmap, mipmaps = texture.mipmaps; + if ( isImagePowerOfTwo ) { - if ( texture instanceof THREE.DataTexture ) { + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); - // 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 + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + } else { - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { - } + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); - texture.generateMipmaps = false; + } - } else { + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { - } + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); - } else if ( texture instanceof THREE.CompressedTexture ) { + } - for( var i = 0, il = mipmaps.length; i < il; i ++ ) { + } - mipmap = mipmaps[ i ]; - if ( texture.format!==THREE.RGBAFormat ) { - _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - } else { - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } + extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - } + if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) { - } else { // regular Texture (image, video, canvas) + if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) { - // 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 + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); + texture.__currentAnisotropy = texture.anisotropy; - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + } - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + } - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + } - } + this.uploadTexture = function ( texture ) { - texture.generateMipmaps = false; + if ( texture.__webglInit === undefined ) { - } else { + texture.__webglInit = true; - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + texture.addEventListener( 'dispose', onTextureDispose ); - } + texture.__webglTexture = _gl.createTexture(); - } + _this.info.memory.textures ++; - if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + } - texture.needsUpdate = false; + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - if ( texture.onUpdate ) texture.onUpdate(); + _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 ); - } else { + texture.image = clampToMaxSize( texture.image, _maxTextureSize ); - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + var image = texture.image, + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); - } + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); - }; + var mipmap, mipmaps = texture.mipmaps; - function clampToMaxSize ( image, maxSize ) { + if ( texture instanceof THREE.DataTexture ) { - if ( image.width <= maxSize && image.height <= maxSize ) { + // 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 - return image; + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - } + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - var maxDimension = Math.max( image.width, image.height ); - var newWidth = Math.floor( image.width * maxSize / maxDimension ); - var newHeight = Math.floor( image.height * maxSize / maxDimension ); + } - var canvas = document.createElement( 'canvas' ); - canvas.width = newWidth; - canvas.height = newHeight; + texture.generateMipmaps = false; - var ctx = canvas.getContext( "2d" ); - ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); + } else { - return canvas; + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - } + } - function setCubeTexture ( texture, slot ) { + } else if ( texture instanceof THREE.CompressedTexture ) { - if ( texture.image.length === 6 ) { + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - if ( texture.needsUpdate ) { + mipmap = mipmaps[ i ]; - if ( ! texture.image.__webglTextureCube ) { + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - texture.addEventListener( 'dispose', onTextureDispose ); + if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { - texture.image.__webglTextureCube = _gl.createTexture(); + _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - _this.info.memory.textures ++; + } else { - } + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + } - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + } else { - var isCompressed = texture instanceof THREE.CompressedTexture; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - var cubeImage = []; + } - for ( var i = 0; i < 6; i ++ ) { + } - if ( _this.autoScaleCubemaps && ! isCompressed ) { + } else { // regular Texture (image, video, canvas) - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); + // 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 - } else { + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - cubeImage[ i ] = texture.image[ i ]; + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - } + } - var image = cubeImage[ 0 ], - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); + texture.generateMipmaps = false; - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); + } else { - for ( var i = 0; i < 6; i ++ ) { + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); - if( !isCompressed ) { + } - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + } - } else { - - var mipmap, mipmaps = cubeImage[ i ].mipmaps; + if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + texture.needsUpdate = false; - mipmap = mipmaps[ j ]; - if ( texture.format!==THREE.RGBAFormat ) { + if ( texture.onUpdate ) texture.onUpdate(); - _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + }; - } else { - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } + this.setTexture = function ( texture, slot ) { - } - } - } + _gl.activeTexture( _gl.TEXTURE0 + slot ); - if ( texture.generateMipmaps && isImagePowerOfTwo ) { + if ( texture.needsUpdate ) { - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _this.uploadTexture( texture ); - } + } else { - texture.needsUpdate = false; + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - if ( texture.onUpdate ) texture.onUpdate(); + } - } else { + }; - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + 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 ); - function setCubeTextureDynamic ( texture, slot ) { + var canvas = document.createElement( 'canvas' ); + canvas.width = Math.floor( image.width * scale ); + canvas.height = Math.floor( image.height * scale ); - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - }; + THREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); - // Render targets + return canvas; - function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { + } - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); + return image; - }; + } - function setupRenderBuffer ( renderbuffer, renderTarget ) { + function setCubeTexture ( texture, slot ) { - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + if ( texture.image.length === 6 ) { - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + if ( texture.needsUpdate ) { - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + if ( ! texture.image.__webglTextureCube ) { - /* For some reason this is not working. Defaulting to RGBA4. - } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + texture.addEventListener( 'dispose', onTextureDispose ); - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - */ - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + texture.image.__webglTextureCube = _gl.createTexture(); - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + _this.info.memory.textures ++; - } else { + } - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - } + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - }; + var isCompressed = texture instanceof THREE.CompressedTexture; + var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; - this.setRenderTarget = function ( renderTarget ) { + var cubeImage = []; - var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); + for ( var i = 0; i < 6; i ++ ) { - if ( renderTarget && ! renderTarget.__webglFramebuffer ) { + if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { - if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; - if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + } else { - renderTarget.__webglTexture = _gl.createTexture(); + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - _this.info.memory.textures ++; + } - // Setup texture, create render and frame buffers + } - var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), - glFormat = paramThreeToGL( renderTarget.format ), - glType = paramThreeToGL( renderTarget.type ); + var image = cubeImage[ 0 ], + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); - if ( isCube ) { + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); - renderTarget.__webglFramebuffer = []; - renderTarget.__webglRenderbuffer = []; + for ( var i = 0; i < 6; i ++ ) { - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); + if ( ! isCompressed ) { - for ( var i = 0; i < 6; i ++ ) { + if ( isDataTexture ) { - renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + } else { - setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); - setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - } + } - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + } else { - } else { + var mipmap, mipmaps = cubeImage[ i ].mipmaps; - renderTarget.__webglFramebuffer = _gl.createFramebuffer(); + for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - if ( renderTarget.shareDepthFrom ) { + mipmap = mipmaps[ j ]; - renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - } else { + if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { - renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); + _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - } + } else { - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + } - setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); + } else { - if ( renderTarget.shareDepthFrom ) { + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + } - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + } - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + } - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + } - } + if ( texture.generateMipmaps && isImagePowerOfTwo ) { - } else { + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); + } - } + texture.needsUpdate = false; - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + if ( texture.onUpdate ) texture.onUpdate(); - } + } else { - // Release everything + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - if ( isCube ) { + } - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + } - } else { + } - _gl.bindTexture( _gl.TEXTURE_2D, null ); + function setCubeTextureDynamic ( texture, slot ) { - } + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + } - } + // Render targets - var framebuffer, width, height, vx, vy; + function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { - if ( renderTarget ) { + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); - if ( isCube ) { + } - framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; + function setupRenderBuffer ( renderbuffer, renderTarget ) { - } else { + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - framebuffer = renderTarget.__webglFramebuffer; + 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 ); - width = renderTarget.width; - height = renderTarget.height; + /* For some reason this is not working. Defaulting to RGBA4. + } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - vx = 0; - vy = 0; + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + */ + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - } else { + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - framebuffer = null; + } else { - width = _viewportWidth; - height = _viewportHeight; + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); - vx = _viewportX; - vy = _viewportY; + } - } + } - if ( framebuffer !== _currentFramebuffer ) { + this.setRenderTarget = function ( renderTarget ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.viewport( vx, vy, width, height ); + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - _currentFramebuffer = framebuffer; + if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) { - } + if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; + if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; - _currentWidth = width; - _currentHeight = height; + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - }; + renderTarget.__webglTexture = _gl.createTexture(); - function updateRenderTargetMipmap ( renderTarget ) { + _this.info.memory.textures ++; - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + // Setup texture, create render and frame buffers - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), + glFormat = paramThreeToGL( renderTarget.format ), + glType = paramThreeToGL( renderTarget.type ); - } else { + if ( isCube ) { - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_2D ); - _gl.bindTexture( _gl.TEXTURE_2D, null ); + renderTarget.__webglFramebuffer = []; + renderTarget.__webglRenderbuffer = []; - } + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); - }; + for ( var i = 0; i < 6; i ++ ) { - // Fallback filters for non-power-of-2 textures + renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); - function filterFallback ( f ) { + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { + setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); - return _gl.NEAREST; + } - } + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - return _gl.LINEAR; + } else { - }; + renderTarget.__webglFramebuffer = _gl.createFramebuffer(); - // Map three.js constants to WebGL constants + if ( renderTarget.shareDepthFrom ) { - function paramThreeToGL ( p ) { + renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; - if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; - if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; - if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; + } else { - if ( p === THREE.NearestFilter ) return _gl.NEAREST; - if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; - if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; + renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); - if ( p === THREE.LinearFilter ) return _gl.LINEAR; - if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; - if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; + } - if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; - if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; - if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); - if ( p === THREE.ByteType ) return _gl.BYTE; - if ( p === THREE.ShortType ) return _gl.SHORT; - if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; - if ( p === THREE.IntType ) return _gl.INT; - if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; - if ( p === THREE.FloatType ) return _gl.FLOAT; + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - if ( p === THREE.AlphaFormat ) return _gl.ALPHA; - if ( p === THREE.RGBFormat ) return _gl.RGB; - if ( p === THREE.RGBAFormat ) return _gl.RGBA; - if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; - if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; + setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); - if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; - if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; - if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; + if ( renderTarget.shareDepthFrom ) { - if ( p === THREE.ZeroFactor ) return _gl.ZERO; - if ( p === THREE.OneFactor ) return _gl.ONE; - if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; - if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; - if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; - if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; - if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; - if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; - if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; - if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - if ( _glExtensionCompressedTextureS3TC !== undefined ) { + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - } + } - return 0; + } else { - }; + setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); - // Allocations + } - function allocateBones ( object ) { + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - if ( _supportsBoneTextures && object && object.useVertexTexture ) { + } - return 1024; + // Release everything - } else { + if ( isCube ) { - // 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) + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); - var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + } else { - var maxBones = nVertexMatrices; + _gl.bindTexture( _gl.TEXTURE_2D, null ); - if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { + } - maxBones = Math.min( object.bones.length, maxBones ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - if ( maxBones < object.bones.length ) { + } - console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + var framebuffer, width, height, vx, vy; - } + if ( renderTarget ) { - } + if ( isCube ) { - return maxBones; + framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; - } + } else { - }; + framebuffer = renderTarget.__webglFramebuffer; - function allocateLights( lights ) { + } - var dirLights = 0; - var pointLights = 0; - var spotLights = 0; - var hemiLights = 0; + width = renderTarget.width; + height = renderTarget.height; - for ( var l = 0, ll = lights.length; l < ll; l ++ ) { + vx = 0; + vy = 0; - var light = lights[ l ]; + } else { - if ( light.onlyShadow || light.visible === false ) continue; + framebuffer = null; - if ( light instanceof THREE.DirectionalLight ) dirLights ++; - if ( light instanceof THREE.PointLight ) pointLights ++; - if ( light instanceof THREE.SpotLight ) spotLights ++; - if ( light instanceof THREE.HemisphereLight ) hemiLights ++; + width = _viewportWidth; + height = _viewportHeight; - } + vx = _viewportX; + vy = _viewportY; - return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; + } - }; + if ( framebuffer !== _currentFramebuffer ) { - function allocateShadows( lights ) { + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.viewport( vx, vy, width, height ); - var maxShadows = 0; + _currentFramebuffer = framebuffer; - for ( var l = 0, ll = lights.length; l < ll; l++ ) { + } - var light = lights[ l ]; + _currentWidth = width; + _currentHeight = height; - if ( ! light.castShadow ) continue; + }; - if ( light instanceof THREE.SpotLight ) maxShadows ++; - if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; + this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { - } + if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { - return maxShadows; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - }; + } - // Initialization + if ( renderTarget.__webglFramebuffer ) { - function initGL() { + if ( renderTarget.format !== THREE.RGBAFormat ) { - try { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); + return; - 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 ); + var restore = false; - if ( _gl === null ) { + if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { - throw 'Error creating WebGL context.'; + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); - } + restore = true; - } catch ( error ) { + } - console.error( error ); + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - } + _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); - _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); - _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); - _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); + } else { - _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + } - _glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' ); - - - if ( _glExtensionTextureFloat === null ) { + if ( restore ) { - console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - } + } - if ( _glExtensionStandardDerivatives === null ) { + } - console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); + }; - } + function updateRenderTargetMipmap ( renderTarget ) { - if ( _glExtensionTextureFilterAnisotropic === null ) { + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - } + } else { - if ( _glExtensionCompressedTextureS3TC === null ) { + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_2D ); + _gl.bindTexture( _gl.TEXTURE_2D, null ); - console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); + } - } + } - if ( _glExtensionElementIndexUint === null ) { + // Fallback filters for non-power-of-2 textures - console.log( 'THREE.WebGLRenderer: elementindex as unsigned integer not supported.' ); + function filterFallback ( f ) { - } + if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { - if ( _gl.getShaderPrecisionFormat === undefined ) { + return _gl.NEAREST; - _gl.getShaderPrecisionFormat = function() { + } - return { - "rangeMin" : 1, - "rangeMax" : 1, - "precision" : 1 - }; + return _gl.LINEAR; - } - } + } - if ( _logarithmicDepthBuffer ) { + // Map three.js constants to WebGL constants - _glExtensionFragDepth = _gl.getExtension( 'EXT_frag_depth' ); + function paramThreeToGL ( p ) { - } + var extension; - }; + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; + if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; - function setDefaultGLState () { + if ( p === THREE.NearestFilter ) return _gl.NEAREST; + if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; - _gl.clearColor( 0, 0, 0, 1 ); - _gl.clearDepth( 1 ); - _gl.clearStencil( 0 ); + if ( p === THREE.LinearFilter ) return _gl.LINEAR; + if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthFunc( _gl.LEQUAL ); + if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; - _gl.frontFace( _gl.CCW ); - _gl.cullFace( _gl.BACK ); - _gl.enable( _gl.CULL_FACE ); + if ( p === THREE.ByteType ) return _gl.BYTE; + if ( p === THREE.ShortType ) return _gl.SHORT; + if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === THREE.IntType ) return _gl.INT; + if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === THREE.FloatType ) return _gl.FLOAT; - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + extension = extensions.get( 'OES_texture_half_float' ); - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + if ( extension !== null ) { - }; + if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; - // default plugins (order is important) + } - this.shadowMapPlugin = new THREE.ShadowMapPlugin(); - this.addPrePlugin( this.shadowMapPlugin ); + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; + if ( p === THREE.RGBFormat ) return _gl.RGB; + if ( p === THREE.RGBAFormat ) return _gl.RGBA; + if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; + if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; - this.addPostPlugin( new THREE.SpritePlugin() ); - this.addPostPlugin( new THREE.LensFlarePlugin() ); + if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; + if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; -}; + if ( p === THREE.ZeroFactor ) return _gl.ZERO; + if ( p === THREE.OneFactor ) return _gl.ONE; + if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; -/** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - */ + if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; + if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; -THREE.WebGLRenderTarget = function ( width, height, options ) { + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - this.width = width; - this.height = height; + if ( extension !== null ) { - options = options || {}; + if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; + } - this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; - this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; + if ( extension !== null ) { - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.Vector2( 1, 1 ); + if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; - this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; + } - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + extension = extensions.get( 'EXT_blend_minmax' ); - this.generateMipmaps = true; + if ( extension !== null ) { - this.shareDepthFrom = null; + if ( p === THREE.MinEquation ) return extension.MIN_EXT; + if ( p === THREE.MaxEquation ) return extension.MAX_EXT; -}; + } -THREE.WebGLRenderTarget.prototype = { + return 0; - constructor: THREE.WebGLRenderTarget, + } - setSize: function ( width, height ) { + // Allocations - this.width = width; - this.height = height; + function allocateBones ( object ) { - }, + if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { - clone: function () { + return 1024; - var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); + } else { - tmp.wrapS = this.wrapS; - tmp.wrapT = this.wrapT; + // 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) - tmp.magFilter = this.magFilter; - tmp.minFilter = this.minFilter; + var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - tmp.anisotropy = this.anisotropy; + var maxBones = nVertexMatrices; - tmp.offset.copy( this.offset ); - tmp.repeat.copy( this.repeat ); + if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { - tmp.format = this.format; - tmp.type = this.type; + maxBones = Math.min( object.skeleton.bones.length, maxBones ); - tmp.depthBuffer = this.depthBuffer; - tmp.stencilBuffer = this.stencilBuffer; + if ( maxBones < object.skeleton.bones.length ) { - tmp.generateMipmaps = this.generateMipmaps; + THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); - tmp.shareDepthFrom = this.shareDepthFrom; + } - return tmp; + } - }, + return maxBones; - dispose: function () { + } - this.dispatchEvent( { type: 'dispose' } ); + } - } + function allocateLights( lights ) { -}; + var dirLights = 0; + var pointLights = 0; + var spotLights = 0; + var hemiLights = 0; -THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { -/** - * @author alteredq / http://alteredqualia.com - */ + var light = lights[ l ]; -THREE.WebGLRenderTargetCube = function ( width, height, options ) { + if ( light.onlyShadow || light.visible === false ) continue; - THREE.WebGLRenderTarget.call( this, width, height, options ); + if ( light instanceof THREE.DirectionalLight ) dirLights ++; + if ( light instanceof THREE.PointLight ) pointLights ++; + if ( light instanceof THREE.SpotLight ) spotLights ++; + if ( light instanceof THREE.HemisphereLight ) hemiLights ++; - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + } -}; + return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights }; -THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); + } -THREE.WebGLProgram = ( function () { + function allocateShadows( lights ) { - var programIdCount = 0; + var maxShadows = 0; - var generateDefines = function ( defines ) { + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - var value, chunk, chunks = []; + var light = lights[ l ]; - for ( var d in defines ) { + if ( ! light.castShadow ) continue; - value = defines[ d ]; - if ( value === false ) continue; + if ( light instanceof THREE.SpotLight ) maxShadows ++; + if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; - chunk = "#define " + d + " " + value; - chunks.push( chunk ); + } - } + return maxShadows; - return chunks.join( "\n" ); + } - }; + // DEPRECATED - var cacheUniformLocations = function ( gl, program, identifiers ) { + this.initMaterial = function () { - var uniforms = {}; + THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); - for ( var i = 0, l = identifiers.length; i < l; i ++ ) { + }; - var id = identifiers[ i ]; - uniforms[ id ] = gl.getUniformLocation( program, id ); + this.addPrePlugin = function () { - } + THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - return uniforms; + }; - }; + this.addPostPlugin = function () { - var cacheAttributeLocations = function ( gl, program, identifiers ) { + THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); - var attributes = {}; + }; - for ( var i = 0, l = identifiers.length; i < l; i ++ ) { + this.updateShadowMap = function () { - var id = identifiers[ i ]; - attributes[ id ] = gl.getAttribLocation( program, id ); + THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - } + }; - return attributes; +}; - }; +// File:src/renderers/WebGLRenderTarget.js - return function ( renderer, code, material, parameters ) { +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + */ - var _this = renderer; - var _gl = _this.context; +THREE.WebGLRenderTarget = function ( width, height, options ) { - var fragmentShader = material.fragmentShader; - var vertexShader = material.vertexShader; - var uniforms = material.uniforms; - var attributes = material.attributes; - var defines = material.defines; - var index0AttributeName = material.index0AttributeName; + this.width = width; + this.height = height; - if ( index0AttributeName === undefined && parameters.morphTargets === true ) { + options = options || {}; - // programs with morphTargets displace position out of attribute 0 + this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; - index0AttributeName = 'position'; + this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; + this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; - } + this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; - var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); - if ( parameters.shadowMapType === THREE.PCFShadowMap ) { + this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; + this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { + this.generateMipmaps = true; - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; + this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; - } +}; - // console.log( "building new program " ); +THREE.WebGLRenderTarget.prototype = { - // + constructor: THREE.WebGLRenderTarget, - var customDefines = generateDefines( defines ); + setSize: function ( width, height ) { - // + this.width = width; + this.height = height; - var program = _gl.createProgram(); + }, - var prefix_vertex, prefix_fragment; + clone: function () { - if ( material instanceof THREE.RawShaderMaterial ) { + var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); - prefix_vertex = ''; - prefix_fragment = ''; + tmp.wrapS = this.wrapS; + tmp.wrapT = this.wrapT; - } else { + tmp.magFilter = this.magFilter; + tmp.minFilter = this.minFilter; - prefix_vertex = [ + tmp.anisotropy = this.anisotropy; - "precision " + parameters.precision + " float;", - "precision " + parameters.precision + " int;", + tmp.offset.copy( this.offset ); + tmp.repeat.copy( this.repeat ); - customDefines, + tmp.format = this.format; + tmp.type = this.type; - parameters.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", + tmp.depthBuffer = this.depthBuffer; + tmp.stencilBuffer = this.stencilBuffer; - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + tmp.generateMipmaps = this.generateMipmaps; - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + tmp.shareDepthFrom = this.shareDepthFrom; - "#define MAX_SHADOWS " + parameters.maxShadows, + return tmp; - "#define MAX_BONES " + parameters.maxBones, + }, - parameters.map ? "#define USE_MAP" : "", - parameters.envMap ? "#define USE_ENVMAP" : "", - parameters.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", + dispose: function () { - parameters.skinning ? "#define USE_SKINNING" : "", - parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", + this.dispatchEvent( { type: 'dispose' } ); - parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", - parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", + } - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", +}; - parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", +THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); - parameters.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", - //_this._glExtensionFragDepth ? "#define USE_LOGDEPTHBUF_EXT" : "", +// File:src/renderers/WebGLRenderTargetCube.js +/** + * @author alteredq / http://alteredqualia.com + */ - "uniform mat4 modelMatrix;", - "uniform mat4 modelViewMatrix;", - "uniform mat4 projectionMatrix;", - "uniform mat4 viewMatrix;", - "uniform mat3 normalMatrix;", - "uniform vec3 cameraPosition;", +THREE.WebGLRenderTargetCube = function ( width, height, options ) { - "attribute vec3 position;", - "attribute vec3 normal;", - "attribute vec2 uv;", - "attribute vec2 uv2;", + THREE.WebGLRenderTarget.call( this, width, height, options ); - "#ifdef USE_COLOR", + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - " attribute vec3 color;", +}; - "#endif", +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); +THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; - "#ifdef USE_MORPHTARGETS", +// File:src/renderers/webgl/WebGLExtensions.js - " attribute vec3 morphTarget0;", - " attribute vec3 morphTarget1;", - " attribute vec3 morphTarget2;", - " attribute vec3 morphTarget3;", +/** +* @author mrdoob / http://mrdoob.com/ +*/ - " #ifdef USE_MORPHNORMALS", +THREE.WebGLExtensions = function ( gl ) { - " attribute vec3 morphNormal0;", - " attribute vec3 morphNormal1;", - " attribute vec3 morphNormal2;", - " attribute vec3 morphNormal3;", + var extensions = {}; - " #else", + this.get = function ( name ) { - " attribute vec3 morphTarget4;", - " attribute vec3 morphTarget5;", - " attribute vec3 morphTarget6;", - " attribute vec3 morphTarget7;", + if ( extensions[ name ] !== undefined ) { - " #endif", + return extensions[ name ]; - "#endif", + } - "#ifdef USE_SKINNING", + var extension; - " attribute vec4 skinIndex;", - " attribute vec4 skinWeight;", + switch ( name ) { - "#endif", + 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; - ].join( '\n' ); + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; - prefix_fragment = [ + default: + extension = gl.getExtension( name ); - "precision " + parameters.precision + " float;", - "precision " + parameters.precision + " int;", + } - ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", + if ( extension === null ) { - customDefines, + THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + } - "#define MAX_SHADOWS " + parameters.maxShadows, + extensions[ name ] = extension; - parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", + return extension; - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + }; - ( 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.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", +// File:src/renderers/webgl/WebGLProgram.js - parameters.metal ? "#define METAL" : "", - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", +THREE.WebGLProgram = ( function () { - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + var programIdCount = 0; - parameters.logarithmicDepthBuffer ? "#define USE_LOGDEPTHBUF" : "", - //_this._glExtensionFragDepth ? "#define USE_LOGDEPTHBUF_EXT" : "", + var generateDefines = function ( defines ) { - "uniform mat4 viewMatrix;", - "uniform vec3 cameraPosition;", - "" + var value, chunk, chunks = []; - ].join( '\n' ); + for ( var d in defines ) { - } + value = defines[ d ]; + if ( value === false ) continue; - var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader ); - var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader ); + chunk = '#define ' + d + ' ' + value; + chunks.push( chunk ); - _gl.attachShader( program, glVertexShader ); - _gl.attachShader( program, glFragmentShader ); + } - if ( index0AttributeName !== undefined ) { + return chunks.join( '\n' ); - // Force a particular attribute to index 0. - // because potentially expensive emulation is done by browser if attribute 0 is disabled. - // And, color, for example is often automatically bound to index 0 so disabling it + }; - _gl.bindAttribLocation( program, 0, index0AttributeName ); + var cacheUniformLocations = function ( gl, program, identifiers ) { - } + var uniforms = {}; - _gl.linkProgram( program ); + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { + var id = identifiers[ i ]; + uniforms[ id ] = gl.getUniformLocation( program, id ); - console.error( 'Could not initialise shader' ); - console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); - console.error( 'gl.getError()', _gl.getError() ); + } - } + return uniforms; - if ( _gl.getProgramInfoLog( program ) !== '' ) { + }; - console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); + var cacheAttributeLocations = function ( gl, program, identifiers ) { - } + var attributes = {}; - // clean up + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - _gl.deleteShader( glVertexShader ); - _gl.deleteShader( glFragmentShader ); + var id = identifiers[ i ]; + attributes[ id ] = gl.getAttribLocation( program, id ); - // cache uniform locations + } - var identifiers = [ + return attributes; - 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', - 'morphTargetInfluences' + }; - ]; + return function ( renderer, code, material, parameters ) { - if ( parameters.useVertexTexture ) { + var _this = renderer; + var _gl = _this.context; - identifiers.push( 'boneTexture' ); - identifiers.push( 'boneTextureWidth' ); - identifiers.push( 'boneTextureHeight' ); + var defines = material.defines; + var uniforms = material.__webglShader.uniforms; + var attributes = material.attributes; - } else { + var vertexShader = material.__webglShader.vertexShader; + var fragmentShader = material.__webglShader.fragmentShader; - identifiers.push( 'boneGlobalMatrices' ); + var index0AttributeName = material.index0AttributeName; - } + if ( index0AttributeName === undefined && parameters.morphTargets === true ) { - if ( parameters.logarithmicDepthBuffer ) { + // programs with morphTargets displace position out of attribute 0 - identifiers.push('logDepthBufFC'); + index0AttributeName = 'position'; - } + } + var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - for ( var u in uniforms ) { + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { - identifiers.push( u ); + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - } + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { - this.uniforms = cacheUniformLocations( _gl, program, identifiers ); + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - // cache attributes locations + } - identifiers = [ + var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; + var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - "position", "normal", "uv", "uv2", "tangent", "color", - "skinIndex", "skinWeight", "lineDistance" + if ( parameters.envMap ) { - ]; + switch ( material.envMap.mapping ) { - for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) { + case THREE.CubeReflectionMapping: + case THREE.CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; - identifiers.push( "morphTarget" + i ); + case THREE.EquirectangularReflectionMapping: + case THREE.EquirectangularRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; + break; - } + case THREE.SphericalReflectionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; + break; - for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) { + } - identifiers.push( "morphNormal" + i ); + switch ( material.envMap.mapping ) { - } + case THREE.CubeRefractionMapping: + case THREE.EquirectangularRefractionMapping: + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; - for ( var a in attributes ) { + } - identifiers.push( a ); + switch ( material.combine ) { - } + case THREE.MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; - this.attributes = cacheAttributeLocations( _gl, program, identifiers ); + case THREE.MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; - // + case THREE.AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; - this.id = programIdCount ++; - this.code = code; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; + } - return this; + } - }; + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; -} )(); + // console.log( 'building new program ' ); -THREE.WebGLShader = ( function () { + // - var addLineNumbers = function ( string ) { + var customDefines = generateDefines( defines ); - var lines = string.split( '\n' ); + // - for ( var i = 0; i < lines.length; i ++ ) { + var program = _gl.createProgram(); - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + var prefix_vertex, prefix_fragment; - } + if ( material instanceof THREE.RawShaderMaterial ) { - return lines.join( '\n' ); + prefix_vertex = ''; + prefix_fragment = ''; - }; + } else { - return function ( gl, type, string ) { + prefix_vertex = [ - var shader = gl.createShader( type ); + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - gl.shaderSource( shader, string ); - gl.compileShader( shader ); + customDefines, - if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + _this.gammaInput ? '#define GAMMA_INPUT' : '', + _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, - } + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - if ( gl.getShaderInfoLog( shader ) !== '' ) { + '#define MAX_SHADOWS ' + parameters.maxShadows, - console.error( 'THREE.WebGLShader:', 'gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) ); - console.error( addLineNumbers( string ) ); + '#define MAX_BONES ' + parameters.maxBones, - } + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', - return shader; + parameters.flatShading ? '#define FLAT_SHADED': '', - }; + parameters.skinning ? '#define USE_SKINNING' : '', + parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', -} )(); -/** - * @author mrdoob / http://mrdoob.com/ - */ + parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', + parameters.morphNormals ? '#define USE_MORPHNORMALS' : '', + parameters.wrapAround ? '#define WRAP_AROUND' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', -THREE.RenderableVertex = function () { + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', - this.position = new THREE.Vector3(); - this.positionWorld = new THREE.Vector3(); - this.positionScreen = new THREE.Vector4(); + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - this.visible = true; + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + //_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', -}; -THREE.RenderableVertex.prototype.copy = function ( vertex ) { + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', - this.positionWorld.copy( vertex.positionWorld ); - this.positionScreen.copy( vertex.positionScreen ); + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', + 'attribute vec2 uv2;', -}; + '#ifdef USE_COLOR', -/** - * @author mrdoob / http://mrdoob.com/ - */ + ' attribute vec3 color;', -THREE.RenderableFace = function () { + '#endif', - this.id = 0; + '#ifdef USE_MORPHTARGETS', - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - this.v3 = new THREE.RenderableVertex(); + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', - this.normalModel = new THREE.Vector3(); + ' #ifdef USE_MORPHNORMALS', - this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; - this.vertexNormalsLength = 0; + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', - this.color = null; - this.material = null; - this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; + ' #else', - this.z = 0; + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', -}; + ' #endif', -/** - * @author mrdoob / http://mrdoob.com/ - */ + '#endif', -THREE.RenderableObject = function () { + '#ifdef USE_SKINNING', - this.id = 0; + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', - this.object = null; - this.z = 0; + '#endif', -}; + '' -/** - * @author mrdoob / http://mrdoob.com/ - */ + ].join( '\n' ); -THREE.RenderableSprite = function () { + prefix_fragment = [ - this.id = 0; + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - this.object = null; + ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', - this.x = 0; - this.y = 0; - this.z = 0; + customDefines, - this.rotation = 0; - this.scale = new THREE.Vector2(); + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - this.material = null; + '#define MAX_SHADOWS ' + parameters.maxShadows, -}; + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', -/** - * @author mrdoob / http://mrdoob.com/ - */ + _this.gammaInput ? '#define GAMMA_INPUT' : '', + _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, -THREE.RenderableLine = function () { + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - this.id = 0; + 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.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); + parameters.flatShading ? '#define FLAT_SHADED': '', - this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; - this.material = null; + parameters.metal ? '#define METAL' : '', + parameters.wrapAround ? '#define WRAP_AROUND' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - this.z = 0; + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', -}; + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + //_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', + '' -THREE.GeometryUtils = { + ].join( '\n' ); - // Merge two geometries or geometry and geometry from object (using object's transform) + } - merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { + var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader ); + var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader ); - var matrix, normalMatrix, - vertexOffset = geometry1.vertices.length, - uvPosition = geometry1.faceVertexUvs[ 0 ].length, - geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, - vertices1 = geometry1.vertices, - vertices2 = geometry2.vertices, - faces1 = geometry1.faces, - faces2 = geometry2.faces, - uvs1 = geometry1.faceVertexUvs[ 0 ], - uvs2 = geometry2.faceVertexUvs[ 0 ]; + _gl.attachShader( program, glVertexShader ); + _gl.attachShader( program, glFragmentShader ); - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + if ( index0AttributeName !== undefined ) { - if ( object2 instanceof THREE.Mesh ) { + // Force a particular attribute to index 0. + // because potentially expensive emulation is done by browser if attribute 0 is disabled. + // And, color, for example is often automatically bound to index 0 so disabling it - object2.matrixAutoUpdate && object2.updateMatrix(); + _gl.bindAttribLocation( program, 0, index0AttributeName ); - matrix = object2.matrix; + } - normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + _gl.linkProgram( program ); - } + var programLogInfo = _gl.getProgramInfoLog( program ); - // vertices + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo ); - var vertex = vertices2[ i ]; + } - var vertexCopy = vertex.clone(); + if ( programLogInfo !== '' ) { - if ( matrix ) vertexCopy.applyMatrix4( matrix ); + THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); - vertices1.push( vertexCopy ); + } - } + // clean up - // faces + _gl.deleteShader( glVertexShader ); + _gl.deleteShader( glFragmentShader ); - for ( i = 0, il = faces2.length; i < il; i ++ ) { + // cache uniform locations - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + var identifiers = [ - faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); + 'viewMatrix', + 'modelViewMatrix', + 'projectionMatrix', + 'normalMatrix', + 'modelMatrix', + 'cameraPosition', + 'morphTargetInfluences', + 'bindMatrix', + 'bindMatrixInverse' - if ( normalMatrix ) { + ]; - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + if ( parameters.useVertexTexture ) { - } + identifiers.push( 'boneTexture' ); + identifiers.push( 'boneTextureWidth' ); + identifiers.push( 'boneTextureHeight' ); - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + } else { - normal = faceVertexNormals[ j ].clone(); + identifiers.push( 'boneGlobalMatrices' ); - if ( normalMatrix ) { + } - normal.applyMatrix3( normalMatrix ).normalize(); + if ( parameters.logarithmicDepthBuffer ) { - } + identifiers.push('logDepthBufFC'); - faceCopy.vertexNormals.push( normal ); + } - } - faceCopy.color.copy( face.color ); + for ( var u in uniforms ) { - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + identifiers.push( u ); - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); + } - } + this.uniforms = cacheUniformLocations( _gl, program, identifiers ); - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + // cache attributes locations - faces1.push( faceCopy ); + identifiers = [ - } + 'position', + 'normal', + 'uv', + 'uv2', + 'tangent', + 'color', + 'skinIndex', + 'skinWeight', + 'lineDistance' - // uvs + ]; - for ( i = 0, il = uvs2.length; i < il; i ++ ) { + for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) { - var uv = uvs2[ i ], uvCopy = []; - - if ( uv === undefined ) { - - continue; - - } + identifiers.push( 'morphTarget' + i ); - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + } - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) { - } + identifiers.push( 'morphNormal' + i ); - uvs1.push( uvCopy ); + } - } + for ( var a in attributes ) { - }, + identifiers.push( a ); - // Get random point in triangle (via barycentric coordinates) - // (uniform distribution) - // http://www.cgafaq.info/wiki/Random_Point_In_Triangle + } - randomPointInTriangle: function () { + this.attributes = cacheAttributeLocations( _gl, program, identifiers ); + this.attributesKeys = Object.keys( this.attributes ); - var vector = new THREE.Vector3(); + // - return function ( vectorA, vectorB, vectorC ) { + this.id = programIdCount ++; + this.code = code; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; - var point = new THREE.Vector3(); + return this; - var a = THREE.Math.random16(); - var b = THREE.Math.random16(); + }; - if ( ( a + b ) > 1 ) { +} )(); - a = 1 - a; - b = 1 - b; +// File:src/renderers/webgl/WebGLShader.js - } +THREE.WebGLShader = ( function () { - var c = 1 - a - b; + var addLineNumbers = function ( string ) { - point.copy( vectorA ); - point.multiplyScalar( a ); + var lines = string.split( '\n' ); - vector.copy( vectorB ); - vector.multiplyScalar( b ); + for ( var i = 0; i < lines.length; i ++ ) { - point.add( vector ); + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - vector.copy( vectorC ); - vector.multiplyScalar( c ); + } - point.add( vector ); + return lines.join( '\n' ); - return point; + }; - }; + return function ( gl, type, string ) { - }(), + var shader = gl.createShader( type ); - // Get random point in face (triangle / quad) - // (uniform distribution) + gl.shaderSource( shader, string ); + gl.compileShader( shader ); - randomPointInFace: function ( face, geometry, useCachedAreas ) { + if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - var vA, vB, vC, vD; + THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); - vA = geometry.vertices[ face.a ]; - vB = geometry.vertices[ face.b ]; - vC = geometry.vertices[ face.c ]; + } - return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); + if ( gl.getShaderInfoLog( shader ) !== '' ) { - }, + THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); - // Get uniformly distributed random points in mesh - // - create array with cumulative sums of face areas - // - pick random number from 0 to total area - // - find corresponding place in area array by binary search - // - get random point in face + } - randomPointsInGeometry: function ( geometry, n ) { + // --enable-privileged-webgl-extension + // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - var face, i, - faces = geometry.faces, - vertices = geometry.vertices, - il = faces.length, - totalArea = 0, - cumulativeAreas = [], - vA, vB, vC, vD; + return shader; - // precompute face areas + }; - for ( i = 0; i < il; i ++ ) { +} )(); - face = faces[ i ]; +// File:src/renderers/webgl/WebGLState.js - vA = vertices[ face.a ]; - vB = vertices[ face.b ]; - vC = vertices[ face.c ]; +/** +* @author mrdoob / http://mrdoob.com/ +*/ - face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); +THREE.WebGLState = function ( gl, paramThreeToGL ) { - totalArea += face._area; + var newAttributes = new Uint8Array( 16 ); + var enabledAttributes = new Uint8Array( 16 ); - cumulativeAreas[ i ] = totalArea; + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; - } + var currentDepthTest = null; + var currentDepthWrite = null; - // binary search cumulative areas array + var currentColorWrite = null; - function binarySearchIndices( value ) { + var currentDoubleSided = null; + var currentFlipSided = null; - function binarySearch( start, end ) { + var currentLineWidth = null; - // return closest larger index - // if exact number is not found + var currentPolygonOffset = null; + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; - if ( end < start ) - return start; + this.initAttributes = function () { - var mid = start + Math.floor( ( end - start ) / 2 ); + for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { - if ( cumulativeAreas[ mid ] > value ) { + newAttributes[ i ] = 0; - return binarySearch( start, mid - 1 ); + } - } else if ( cumulativeAreas[ mid ] < value ) { + }; - return binarySearch( mid + 1, end ); + this.enableAttribute = function ( attribute ) { - } else { + newAttributes[ attribute ] = 1; - return mid; + if ( enabledAttributes[ attribute ] === 0 ) { - } + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - } + } - var result = binarySearch( 0, cumulativeAreas.length - 1 ) - return result; + }; - } + this.disableUnusedAttributes = function () { - // pick random face weighted by face area + for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { - var r, index, - result = []; + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - var stats = {}; + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; - for ( i = 0; i < n; i ++ ) { + } - r = THREE.Math.random16() * totalArea; + } - index = binarySearchIndices( r ); + }; - result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - if ( ! stats[ index ] ) { + if ( blending !== currentBlending ) { - stats[ index ] = 1; + if ( blending === THREE.NoBlending ) { - } else { + gl.disable( gl.BLEND ); - stats[ index ] += 1; + } else if ( blending === THREE.AdditiveBlending ) { - } + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - } + } else if ( blending === THREE.SubtractiveBlending ) { - return result; + // TODO: Find blendFuncSeparate() combination + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); - }, + } else if ( blending === THREE.MultiplyBlending ) { - // Get triangle area (half of parallelogram) - // http://mathworld.wolfram.com/TriangleArea.html + // TODO: Find blendFuncSeparate() combination + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - triangleArea: function () { + } else if ( blending === THREE.CustomBlending ) { - var vector1 = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); + gl.enable( gl.BLEND ); - return function ( vectorA, vectorB, vectorC ) { + } else { - vector1.subVectors( vectorB, vectorA ); - vector2.subVectors( vectorC, vectorA ); - vector1.cross( vector2 ); + gl.enable( gl.BLEND ); + 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 ); - return 0.5 * vector1.length(); + } - }; + currentBlending = blending; - }(), + } - // Center geometry so that 0,0,0 is in center of bounding box + if ( blending === THREE.CustomBlending ) { - center: function ( geometry ) { + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - geometry.computeBoundingBox(); + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - var bb = geometry.boundingBox; + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - var offset = new THREE.Vector3(); + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; - offset.addVectors( bb.min, bb.max ); - offset.multiplyScalar( -0.5 ); + } - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); - geometry.computeBoundingBox(); + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - return offset; + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - } + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; -}; + } -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + } else { -THREE.ImageUtils = { + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - crossOrigin: undefined, + } - loadTexture: function ( url, mapping, onLoad, onError ) { + }; - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; + this.setDepthTest = function ( depthTest ) { - var texture = new THREE.Texture( undefined, mapping ); + if ( currentDepthTest !== depthTest ) { - var image = loader.load( url, function () { + if ( depthTest ) { - texture.needsUpdate = true; + gl.enable( gl.DEPTH_TEST ); - if ( onLoad ) onLoad( texture ); + } else { - } ); + gl.disable( gl.DEPTH_TEST ); - texture.image = image; - texture.sourceFile = url; + } - return texture; + currentDepthTest = depthTest; - }, + } - loadCompressedTexture: function ( url, mapping, onLoad, onError ) { + }; - var texture = new THREE.CompressedTexture(); - texture.mapping = mapping; + this.setDepthWrite = function ( depthWrite ) { - var request = new XMLHttpRequest(); + if ( currentDepthWrite !== depthWrite ) { - request.onload = function () { + gl.depthMask( depthWrite ); + currentDepthWrite = depthWrite; - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + } - texture.format = dds.format; + }; - texture.mipmaps = dds.mipmaps; - texture.image.width = dds.width; - texture.image.height = dds.height; + this.setColorWrite = function ( colorWrite ) { - // gl.generateMipmap fails for compressed textures - // mipmaps must be embedded in the DDS file - // or texture filters must not use mipmapping + if ( currentColorWrite !== colorWrite ) { - texture.generateMipmaps = false; + gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); + currentColorWrite = colorWrite; - texture.needsUpdate = true; + } - if ( onLoad ) onLoad( texture ); + }; - } + this.setDoubleSided = function ( doubleSided ) { - request.onerror = onError; + if ( currentDoubleSided !== doubleSided ) { - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + if ( doubleSided ) { - return texture; + gl.disable( gl.CULL_FACE ); - }, + } else { - loadTextureCube: function ( array, mapping, onLoad, onError ) { + gl.enable( gl.CULL_FACE ); - var images = []; - images.loadCount = 0; + } - var texture = new THREE.Texture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + currentDoubleSided = doubleSided; - // no flipping needed for cube textures + } - texture.flipY = false; + }; - for ( var i = 0, il = array.length; i < il; ++ i ) { + this.setFlipSided = function ( flipSided ) { - var cubeImage = new Image(); - images[ i ] = cubeImage; + if ( currentFlipSided !== flipSided ) { - cubeImage.onload = function () { + if ( flipSided ) { - images.loadCount += 1; + gl.frontFace( gl.CW ); - if ( images.loadCount === 6 ) { + } else { - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + gl.frontFace( gl.CCW ); - } + } - }; + currentFlipSided = flipSided; - cubeImage.onerror = onError; + } - cubeImage.crossOrigin = this.crossOrigin; - cubeImage.src = array[ i ]; + }; - } + this.setLineWidth = function ( width ) { - return texture; + if ( width !== currentLineWidth ) { - }, + gl.lineWidth( width ); - loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { + currentLineWidth = width; - var images = []; - images.loadCount = 0; + } - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + }; - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + this.setPolygonOffset = function ( polygonoffset, factor, units ) { - texture.flipY = false; + if ( currentPolygonOffset !== polygonoffset ) { - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + if ( polygonoffset ) { - texture.generateMipmaps = false; + gl.enable( gl.POLYGON_OFFSET_FILL ); - var generateCubeFaceCallback = function ( rq, img ) { + } else { - return function () { + gl.disable( gl.POLYGON_OFFSET_FILL ); - var buffer = rq.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + } - img.format = dds.format; + currentPolygonOffset = polygonoffset; - img.mipmaps = dds.mipmaps; - img.width = dds.width; - img.height = dds.height; + } - images.loadCount += 1; + if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { - if ( images.loadCount === 6 ) { + gl.polygonOffset( factor, units ); - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; - } + } - } + }; - } + this.reset = function () { - // compressed cubemap textures as 6 separate DDS files + for ( var i = 0; i < enabledAttributes.length; i ++ ) { - if ( array instanceof Array ) { + enabledAttributes[ i ] = 0; - for ( var i = 0, il = array.length; i < il; ++ i ) { + } - var cubeImage = {}; - images[ i ] = cubeImage; + currentBlending = null; + currentDepthTest = null; + currentDepthWrite = null; + currentColorWrite = null; + currentDoubleSided = null; + currentFlipSided = null; - var request = new XMLHttpRequest(); + }; - request.onload = generateCubeFaceCallback( request, cubeImage ); - request.onerror = onError; +}; - var url = array[ i ]; +// File:src/renderers/webgl/plugins/LensFlarePlugin.js - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.LensFlarePlugin = function ( renderer, flares ) { - // compressed cubemap texture stored in a single DDS file + var gl = renderer.context; - } else { + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; + var hasVertexTexture; - var url = array; - var request = new XMLHttpRequest(); + var tempTexture, occlusionTexture; - request.onload = function( ) { + var init = function () { - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + var vertices = new Float32Array( [ + -1, -1, 0, 0, + 1, -1, 1, 0, + 1, 1, 1, 1, + -1, 1, 0, 1 + ] ); - if ( dds.isCubemap ) { + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - var faces = dds.mipmaps.length / dds.mipmapCount; + // buffers - for ( var f = 0; f < faces; f ++ ) { + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - images[ f ] = { mipmaps : [] }; + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; + // textures - } + tempTexture = gl.createTexture(); + occlusionTexture = gl.createTexture(); - } + gl.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 ); - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + gl.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 ); - } + hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0; - } + var shader; - request.onerror = onError; + if ( hasVertexTexture ) { - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + shader = { - } + vertexShader: [ - return texture; + "uniform lowp int renderType;", - }, + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - loadDDSTexture: function ( url, mapping, onLoad, onError ) { + "uniform sampler2D occlusionMap;", - var images = []; - images.loadCount = 0; + "attribute vec2 position;", + "attribute vec2 uv;", - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + "varying vec2 vUV;", + "varying float vVisibility;", - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + "void main() {", - texture.flipY = false; + "vUV = uv;", - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + "vec2 pos = position;", - texture.generateMipmaps = false; + "if( renderType == 2 ) {", - { - var request = new XMLHttpRequest(); + "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 ) );", - request.onload = function( ) { + "vVisibility = visibility.r / 9.0;", + "vVisibility *= 1.0 - visibility.g / 9.0;", + "vVisibility *= visibility.b / 9.0;", + "vVisibility *= 1.0 - visibility.a / 9.0;", - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - if ( dds.isCubemap ) { + "}", - var faces = dds.mipmaps.length / dds.mipmapCount; + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - for ( var f = 0; f < faces; f ++ ) { + "}" - images[ f ] = { mipmaps : [] }; + ].join( "\n" ), - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + fragmentShader: [ - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; + "uniform lowp int renderType;", - } + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", - } + "varying vec2 vUV;", + "varying float vVisibility;", + "void main() {", - } else { - texture.image.width = dds.width; - texture.image.height = dds.height; - texture.mipmaps = dds.mipmaps; - } + // pink square - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + "if( renderType == 0 ) {", - } + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", - request.onerror = onError; + // restore - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + "} else if( renderType == 1 ) {", - } + "gl_FragColor = texture2D( map, vUV );", - return texture; + // flare - }, + "} else {", - parseDDS: function ( buffer, loadMipmaps ) { + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + "}", - // Adapted from @toji's DDS utils - // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + "}" - // All values and structures referenced from: - // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + ].join( "\n" ) - var DDS_MAGIC = 0x20534444; + }; - var DDSD_CAPS = 0x1, - DDSD_HEIGHT = 0x2, - DDSD_WIDTH = 0x4, - DDSD_PITCH = 0x8, - DDSD_PIXELFORMAT = 0x1000, - DDSD_MIPMAPCOUNT = 0x20000, - DDSD_LINEARSIZE = 0x80000, - DDSD_DEPTH = 0x800000; + } else { - var DDSCAPS_COMPLEX = 0x8, - DDSCAPS_MIPMAP = 0x400000, - DDSCAPS_TEXTURE = 0x1000; + shader = { - var DDSCAPS2_CUBEMAP = 0x200, - DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, - DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, - DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, - DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, - DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, - DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, - DDSCAPS2_VOLUME = 0x200000; + vertexShader: [ - var DDPF_ALPHAPIXELS = 0x1, - DDPF_ALPHA = 0x2, - DDPF_FOURCC = 0x4, - DDPF_RGB = 0x40, - DDPF_YUV = 0x200, - DDPF_LUMINANCE = 0x20000; + "uniform lowp int renderType;", - function fourCCToInt32( value ) { + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - return value.charCodeAt(0) + - (value.charCodeAt(1) << 8) + - (value.charCodeAt(2) << 16) + - (value.charCodeAt(3) << 24); + "attribute vec2 position;", + "attribute vec2 uv;", - } + "varying vec2 vUV;", - function int32ToFourCC( value ) { + "void main() {", - return String.fromCharCode( - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); - } + "vUV = uv;", - function loadARGBMip( buffer, dataOffset, width, height ) { - var dataLength = width*height*4; - var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); - var byteArray = new Uint8Array( dataLength ); - var dst = 0; - var src = 0; - for ( var y = 0; y < height; y++ ) { - for ( var x = 0; x < width; x++ ) { - var b = srcBuffer[src]; src++; - var g = srcBuffer[src]; src++; - var r = srcBuffer[src]; src++; - var a = srcBuffer[src]; src++; - byteArray[dst] = r; dst++; //r - byteArray[dst] = g; dst++; //g - byteArray[dst] = b; dst++; //b - byteArray[dst] = a; dst++; //a - } - } - return byteArray; - } + "vec2 pos = position;", - var FOURCC_DXT1 = fourCCToInt32("DXT1"); - var FOURCC_DXT3 = fourCCToInt32("DXT3"); - var FOURCC_DXT5 = fourCCToInt32("DXT5"); + "if( renderType == 2 ) {", - var headerLengthInt = 31; // The header length in 32 bit ints + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - // Offsets into the header array + "}", - var off_magic = 0; + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - var off_size = 1; - var off_flags = 2; - var off_height = 3; - var off_width = 4; + "}" - var off_mipmapCount = 7; + ].join( "\n" ), - var off_pfFlags = 20; - var off_pfFourCC = 21; - var off_RGBBitCount = 22; - var off_RBitMask = 23; - var off_GBitMask = 24; - var off_BBitMask = 25; - var off_ABitMask = 26; + fragmentShader: [ - var off_caps = 27; - var off_caps2 = 28; - var off_caps3 = 29; - var off_caps4 = 30; + "precision mediump float;", - // Parse header + "uniform lowp int renderType;", - var header = new Int32Array( buffer, 0, headerLengthInt ); + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", - if ( header[ off_magic ] !== DDS_MAGIC ) { + "varying vec2 vUV;", - console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); - return dds; + "void main() {", - } + // pink square - if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { + "if( renderType == 0 ) {", - console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); - return dds; + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", - } + // restore - var blockBytes; + "} else if( renderType == 1 ) {", - var fourCC = header[ off_pfFourCC ]; + "gl_FragColor = texture2D( map, vUV );", - var isRGBAUncompressed = false; + // flare - switch ( fourCC ) { + "} else {", - case FOURCC_DXT1: + "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", + "visibility = ( 1.0 - visibility / 4.0 );", - blockBytes = 8; - dds.format = THREE.RGB_S3TC_DXT1_Format; - break; + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - case FOURCC_DXT3: + "}", - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT3_Format; - break; + "}" - case FOURCC_DXT5: + ].join( "\n" ) - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT5_Format; - break; + }; - default: + } - if( header[off_RGBBitCount] ==32 - && header[off_RBitMask]&0xff0000 - && header[off_GBitMask]&0xff00 - && header[off_BBitMask]&0xff - && header[off_ABitMask]&0xff000000 ) { - isRGBAUncompressed = true; - blockBytes = 64; - dds.format = THREE.RGBAFormat; - } else { - console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); - return dds; - } - } + program = createProgram( shader ); - dds.mipmapCount = 1; + attributes = { + vertex: gl.getAttribLocation ( program, "position" ), + uv: gl.getAttribLocation ( program, "uv" ) + } - if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { + 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" ) + }; - dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); + }; - } + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + */ - //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { - dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; + if ( flares.length === 0 ) return; - dds.width = header[ off_width ]; - dds.height = header[ off_height ]; + var tempPosition = new THREE.Vector3(); - var dataOffset = header[ off_size ] + 4; + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; - // Extract mipmaps buffers + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); - var width = dds.width; - var height = dds.height; + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); - var faces = dds.isCubemap ? 6 : 1; + if ( program === undefined ) { - for ( var face = 0; face < faces; face ++ ) { + init(); - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + } - if( isRGBAUncompressed ) { - var byteArray = loadARGBMip( buffer, dataOffset, width, height ); - var dataLength = byteArray.length; - } else { - var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; - var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); - } - - var mipmap = { "data": byteArray, "width": width, "height": height }; - dds.mipmaps.push( mipmap ); + gl.useProgram( program ); - dataOffset += dataLength; + gl.enableVertexAttribArray( attributes.vertex ); + gl.enableVertexAttribArray( attributes.uv ); - width = Math.max( width * 0.5, 1 ); - height = Math.max( height * 0.5, 1 ); + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/unforms - } + gl.uniform1i( uniforms.occlusionMap, 0 ); + gl.uniform1i( uniforms.map, 1 ); - width = dds.width; - height = dds.height; + 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 ); - return dds; + gl.disable( gl.CULL_FACE ); + gl.depthMask( false ); - }, + for ( var i = 0, l = flares.length; i < l; i ++ ) { - getNormalMap: function ( image, depth ) { + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); - // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + // calc object screen position - var cross = function ( a, b ) { + var flare = flares[ i ]; - return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); - } + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); - var subtract = function ( a, b ) { + // setup arrays for gl programs - return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; + screenPosition.copy( tempPosition ) - } + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; - var normalize = function ( a ) { + // screen cull - var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); - return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; + if ( hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { - } + // save current RGB to temp texture - depth = depth | 1; + gl.activeTexture( gl.TEXTURE1 ); + gl.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - var width = image.width; - var height = image.height; - var canvas = document.createElement( 'canvas' ); - canvas.width = width; - canvas.height = height; + // render pink quad - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0 ); + gl.uniform1i( uniforms.renderType, 0 ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - var data = context.getImageData( 0, 0, width, height ).data; - var imageData = context.createImageData( width, height ); - var output = imageData.data; + gl.disable( gl.BLEND ); + gl.enable( gl.DEPTH_TEST ); - for ( var x = 0; x < width; x ++ ) { + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - for ( var y = 0; y < height; y ++ ) { - var ly = y - 1 < 0 ? 0 : y - 1; - var uy = y + 1 > height - 1 ? height - 1 : y + 1; - var lx = x - 1 < 0 ? 0 : x - 1; - var ux = x + 1 > width - 1 ? width - 1 : x + 1; + // copy result to occlusionMap - var points = []; - var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; - points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + gl.activeTexture( gl.TEXTURE0 ); + gl.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - var normals = []; - var num_points = points.length; - for ( var i = 0; i < num_points; i ++ ) { + // restore graphics - var v1 = points[ i ]; - var v2 = points[ ( i + 1 ) % num_points ]; - v1 = subtract( v1, origin ); - v2 = subtract( v2, origin ); - normals.push( normalize( cross( v1, v2 ) ) ); + gl.uniform1i( uniforms.renderType, 1 ); + gl.disable( gl.DEPTH_TEST ); - } + gl.activeTexture( gl.TEXTURE1 ); + gl.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - var normal = [ 0, 0, 0 ]; - for ( var i = 0; i < normals.length; i ++ ) { + // update object positions - normal[ 0 ] += normals[ i ][ 0 ]; - normal[ 1 ] += normals[ i ][ 1 ]; - normal[ 2 ] += normals[ i ][ 2 ]; + flare.positionScreen.copy( screenPosition ) - } + if ( flare.customUpdateCallback ) { - normal[ 0 ] /= normals.length; - normal[ 1 ] /= normals.length; - normal[ 2 ] /= normals.length; + flare.customUpdateCallback( flare ); - var idx = ( y * width + x ) * 4; + } else { - output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; - output[ idx + 3 ] = 255; + flare.updateLensFlares(); - } + } - } + // render flares - context.putImageData( imageData, 0, 0 ); + gl.uniform1i( uniforms.renderType, 2 ); + gl.enable( gl.BLEND ); - return canvas; + for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - }, + var sprite = flare.lensFlares[ j ]; - generateDataTexture: function ( width, height, color ) { + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - var size = width * height; - var data = new Uint8Array( 3 * size ); + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; - var r = Math.floor( color.r * 255 ); - var g = Math.floor( color.g * 255 ); - var b = Math.floor( color.b * 255 ); + size = sprite.size * sprite.scale / viewportHeight; - for ( var i = 0; i < size; i ++ ) { + scale.x = size * invAspect; + scale.y = size; - data[ i * 3 ] = r; - data[ i * 3 + 1 ] = g; - data[ i * 3 + 2 ] = b; + 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 ); - var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); - texture.needsUpdate = true; + renderer.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + renderer.setTexture( sprite.texture, 1 ); - return texture; + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - } + } -}; + } -/** - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.SceneUtils = { + } - createMultiMaterialObject: function ( geometry, materials ) { + // restore gl - var group = new THREE.Object3D(); + gl.enable( gl.CULL_FACE ); + gl.enable( gl.DEPTH_TEST ); + gl.depthMask( true ); - for ( var i = 0, l = materials.length; i < l; i ++ ) { + renderer.resetGLState(); - group.add( new THREE.Mesh( geometry, materials[ i ] ) ); + }; - } + function createProgram ( shader ) { - return group; + var program = gl.createProgram(); - }, + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - detach : function ( child, parent, scene ) { + var prefix = "precision " + renderer.getPrecision() + " float;\n"; - child.applyMatrix( parent.matrixWorld ); - parent.remove( child ); - scene.add( child ); + gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - }, + gl.compileShader( fragmentShader ); + gl.compileShader( vertexShader ); - attach: function ( child, scene, parent ) { + gl.attachShader( program, fragmentShader ); + gl.attachShader( program, vertexShader ); - var matrixWorldInverse = new THREE.Matrix4(); - matrixWorldInverse.getInverse( parent.matrixWorld ); - child.applyMatrix( matrixWorldInverse ); + gl.linkProgram( program ); - scene.remove( child ); - parent.add( child ); + return program; - } + } }; +// File:src/renderers/webgl/plugins/ShadowMapPlugin.js + /** - * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ - * - * For Text operations in three.js (See TextGeometry) - * - * It uses techniques used in: - * - * typeface.js and canvastext - * For converting fonts and rendering with javascript - * http://typeface.neocracy.org - * - * Triangulation ported from AS3 - * Simple Polygon Triangulation - * http://actionsnippet.com/?p=1462 - * - * A Method to triangulate shapes with holes - * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ - * */ -THREE.FontUtils = { +THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) { - faces : {}, + var _gl = _renderer.context; - // Just for now. face[weight][style] + var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, - face : "helvetiker", - weight: "normal", - style : "normal", - size : 150, - divisions : 10, + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), - getFace : function() { - console.log('THREE: ',this.faces) - return this.faces[ this.face ][ this.weight ][ this.style ]; + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), - }, + _matrixPosition = new THREE.Vector3(), - loadFace : function( data ) { + _renderList = []; - var family = data.familyName.toLowerCase(); + // init - var ThreeFont = this; + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); - ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; + _depthMaterial = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader + } ); - ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; - ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + _depthMaterialMorph = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + morphTargets: true + } ); - var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + _depthMaterialSkin = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + skinning: true + } ); - return data; + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + morphTargets: true, + skinning: true + } ); - }, + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; - drawText : function( text ) { + this.render = function ( scene, camera ) { - var characterPts = [], allPts = []; + if ( _renderer.shadowMapEnabled === false ) return; - // RenderText + var i, il, j, jl, n, - var i, p, - face = this.getFace(), - scale = this.size / face.resolution, - offset = 0, - chars = String( text ).split( '' ), - length = chars.length; + shadowMap, shadowMatrix, shadowCamera, + buffer, material, + webglObject, object, light, - var fontPaths = []; + lights = [], + k = 0, - for ( i = 0; i < length; i ++ ) { + fog = null; - var path = new THREE.Path(); + // set GL state for depth map - var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); - offset += ret.offset; + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); - fontPaths.push( ret.path ); + _gl.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); - } + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - // get the width + _gl.cullFace( _gl.FRONT ); - var width = offset / 2; - // - // for ( p = 0; p < allPts.length; p++ ) { - // - // allPts[ p ].x -= width; - // - // } + } else { - //var extract = this.extractPoints( allPts, characterPts ); - //extract.contour = allPts; + _gl.cullFace( _gl.BACK ); - //extract.paths = fontPaths; - //extract.offset = width; + } - return { paths : fontPaths, offset : width }; + _renderer.state.setDepthTest( true ); - }, + // preprocess lights + // - skip lights that are not casting shadows + // - create virtual lights for cascaded shadow maps + for ( i = 0, il = _lights.length; i < il; i ++ ) { + light = _lights[ i ]; + if ( ! light.castShadow ) continue; - extractGlyphPoints : function( c, face, scale, offset, path ) { + if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { - var pts = []; + for ( n = 0; n < light.shadowCascadeCount; n ++ ) { - var i, i2, divisions, - outline, action, length, - scaleX, scaleY, - x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, - laste, - glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; + var virtualLight; - if ( !glyph ) return; + if ( ! light.shadowCascadeArray[ n ] ) { - if ( glyph.o ) { + virtualLight = createVirtualLight( light, n ); + virtualLight.originalCamera = camera; - outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - length = outline.length; + var gyro = new THREE.Gyroscope(); + gyro.position.copy( light.shadowCascadeOffset ); - scaleX = scale; - scaleY = scale; + gyro.add( virtualLight ); + gyro.add( virtualLight.target ); - for ( i = 0; i < length; ) { + camera.add( gyro ); - action = outline[ i ++ ]; + light.shadowCascadeArray[ n ] = virtualLight; - //console.log( action ); + //console.log( "Created virtualLight", virtualLight ); - switch( action ) { + } else { - case 'm': + virtualLight = light.shadowCascadeArray[ n ]; - // Move To + } - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; + updateVirtualLight( light, n ); - path.moveTo( x, y ); - break; + lights[ k ] = virtualLight; + k ++; - case 'l': + } - // Line To + } else { - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; - path.lineTo(x,y); - break; + lights[ k ] = light; + k ++; - case 'q': + } - // QuadraticCurveTo + } - cpx = outline[ i++ ] * scaleX + offset; - cpy = outline[ i++ ] * scaleY; - cpx1 = outline[ i++ ] * scaleX + offset; - cpy1 = outline[ i++ ] * scaleY; + // render depth map - path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + for ( i = 0, il = lights.length; i < il; i ++ ) { - laste = pts[ pts.length - 1 ]; + light = lights[ i ]; - if ( laste ) { + if ( ! light.shadowMap ) { - cpx0 = laste.x; - cpy0 = laste.y; + var shadowFilter = THREE.LinearFilter; - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { - var t = i2 / divisions; - var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - } + shadowFilter = THREE.NearestFilter; - } + } - break; + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; - case 'b': + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); - // Cubic Bezier Curve + light.shadowMatrix = new THREE.Matrix4(); - cpx = outline[ i++ ] * scaleX + offset; - cpy = outline[ i++ ] * scaleY; - cpx1 = outline[ i++ ] * scaleX + offset; - cpy1 = outline[ i++ ] * -scaleY; - cpx2 = outline[ i++ ] * scaleX + offset; - cpy2 = outline[ i++ ] * -scaleY; + } - path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); + if ( ! light.shadowCamera ) { - laste = pts[ pts.length - 1 ]; + if ( light instanceof THREE.SpotLight ) { - if ( laste ) { + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); - cpx0 = laste.x; - cpy0 = laste.y; + } else if ( light instanceof THREE.DirectionalLight ) { - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); - var t = i2 / divisions; - var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + } else { - } + THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); + continue; - } + } - break; + scene.add( light.shadowCamera ); - } + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - } - } + } + if ( light.shadowCameraVisible && ! light.cameraHelper ) { + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + scene.add( light.cameraHelper ); - return { offset: glyph.ha*scale, path:path}; - } + } -}; + if ( light.isVirtual && virtualLight.originalCamera == camera ) { + updateShadowCamera( camera, light ); -THREE.FontUtils.generateShapes = function( text, parameters ) { + } - // Parameters + shadowMap = light.shadowMap; + shadowMatrix = light.shadowMatrix; + shadowCamera = light.shadowCamera; - parameters = parameters || {}; + // - var size = parameters.size !== undefined ? parameters.size : 100; - var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; + shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); + _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _matrixPosition ); + shadowCamera.updateMatrixWorld(); - var font = parameters.font !== undefined ? parameters.font : "helvetiker"; - var weight = parameters.weight !== undefined ? parameters.weight : "normal"; - var style = parameters.style !== undefined ? parameters.style : "normal"; + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); - THREE.FontUtils.size = size; - THREE.FontUtils.divisions = curveSegments; + // - THREE.FontUtils.face = font; - THREE.FontUtils.weight = weight; - THREE.FontUtils.style = style; + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); - // Get a Font data json object + // compute shadow matrix - var data = THREE.FontUtils.drawText( text ); + 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 + ); - var paths = data.paths; - var shapes = []; + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + // update camera matrices and frustum - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - } + // render shadow map - return shapes; + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); -}; + // set object matrices & frustum culling + _renderList.length = 0; -/** - * 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 - * - */ + projectObject( scene, scene, shadowCamera ); -( function( namespace ) { + // render regular objects - var EPSILON = 0.0000000001; + var objectMaterial, useMorphing, useSkinning; - // takes in an contour array and returns + for ( j = 0, jl = _renderList.length; j < jl; j ++ ) { - var process = function( contour, indices ) { + webglObject = _renderList[ j ]; - var n = contour.length; + object = webglObject.object; + buffer = webglObject.buffer; - if ( n < 3 ) return null; + // culling is overriden globally for all objects + // while rendering depth map - var result = [], - verts = [], - vertIndices = []; + // need to deal with MeshFaceMaterial somehow + // in that case just use the first of material.materials for now + // (proper solution would require to break objects by materials + // similarly to regular rendering and then set corresponding + // depth materials per each chunk instead of just once per object) - /* we want a counter-clockwise polygon in verts */ + objectMaterial = getObjectMaterial( object ); - var u, v, w; + useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; - if ( area( contour ) > 0.0 ) { + if ( object.customDepthMaterial ) { - for ( v = 0; v < n; v++ ) verts[ v ] = v; + material = object.customDepthMaterial; - } else { + } else if ( useSkinning ) { - for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; - } + } else if ( useMorphing ) { - var nv = n; + material = _depthMaterialMorph; - /* remove nv - 2 vertices, creating 1 triangle every time */ + } else { - var count = 2 * nv; /* error detection */ + material = _depthMaterial; - for( v = nv - 1; nv > 2; ) { + } - /* if we loop, it is probably a non-simple polygon */ + _renderer.setMaterialFaces( objectMaterial ); - if ( ( count-- ) <= 0 ) { + if ( buffer instanceof THREE.BufferGeometry ) { - //** Triangulate: ERROR - probable bad polygon! + _renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object ); - //throw ( "Warning, unable to triangulate polygon!" ); - //return null; - // Sometimes warning is fine, especially polygons are triangulated in reverse. - console.log( "Warning, unable to triangulate polygon!" ); + } else { - if ( indices ) return vertIndices; - return result; + _renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object ); - } + } - /* 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 */ + // set matrices and render immediate objects - if ( snip( contour, u, v, w, nv, verts ) ) { + for ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) { - var a, b, c, s, t; + webglObject = _webglObjectsImmediate[ j ]; + object = webglObject.object; - /* true names of the vertices */ + if ( object.visible && object.castShadow ) { - a = verts[ u ]; - b = verts[ v ]; - c = verts[ w ]; + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - /* output Triangle */ + _renderer.renderImmediateObject( shadowCamera, _lights, fog, _depthMaterial, object ); - result.push( [ contour[ a ], - contour[ b ], - contour[ c ] ] ); + } + } - vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); + } - /* remove v from the remaining polygon */ + // restore GL state - for( s = v, t = v + 1; t < nv; s++, t++ ) { + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); - verts[ s ] = verts[ t ]; + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); - } + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - nv--; + _gl.cullFace( _gl.BACK ); - /* reset error detection counter */ + } - count = 2 * nv; + _renderer.resetGLState(); - } + }; - } + function projectObject( scene, object, shadowCamera ) { - if ( indices ) return vertIndices; - return result; + if ( object.visible ) { - }; + var webglObjects = _webglObjects[ object.id ]; - // calculate area of the contour polygon + if ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) { - var area = function ( contour ) { + for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - var n = contour.length; - var a = 0.0; + var webglObject = webglObjects[ i ]; - for( var p = n - 1, q = 0; q < n; p = q++ ) { + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + _renderList.push( webglObject ); - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + } - } + } - return a * 0.5; + for ( var i = 0, l = object.children.length; i < l; i ++ ) { - }; + projectObject( scene, object.children[ i ], shadowCamera ); - var snip = function ( 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; + function createVirtualLight( light, cascade ) { - cx = contour[ verts[ w ] ].x; - cy = contour[ verts[ w ] ].y; + var virtualLight = new THREE.DirectionalLight(); - if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; + virtualLight.isVirtual = true; - var aX, aY, bX, bY, cX, cY; - var apx, apy, bpx, bpy, cpx, cpy; - var cCROSSap, bCROSScp, aCROSSbp; + virtualLight.onlyShadow = true; + virtualLight.castShadow = true; - aX = cx - bx; aY = cy - by; - bX = ax - cx; bY = ay - cy; - cX = bx - ax; cY = by - ay; + virtualLight.shadowCameraNear = light.shadowCameraNear; + virtualLight.shadowCameraFar = light.shadowCameraFar; - for ( p = 0; p < n; p++ ) { + virtualLight.shadowCameraLeft = light.shadowCameraLeft; + virtualLight.shadowCameraRight = light.shadowCameraRight; + virtualLight.shadowCameraBottom = light.shadowCameraBottom; + virtualLight.shadowCameraTop = light.shadowCameraTop; - px = contour[ verts[ p ] ].x - py = contour[ verts[ p ] ].y + virtualLight.shadowCameraVisible = light.shadowCameraVisible; - if ( ( (px === ax) && (py === ay) ) || - ( (px === bx) && (py === by) ) || - ( (px === cx) && (py === cy) ) ) continue; + virtualLight.shadowDarkness = light.shadowDarkness; - apx = px - ax; apy = py - ay; - bpx = px - bx; bpy = py - by; - cpx = px - cx; cpy = py - cy; + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; + virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; - // see if p is inside triangle abc + virtualLight.pointsWorld = []; + virtualLight.pointsFrustum = []; - aCROSSbp = aX*bpy - aY*bpx; - cCROSSap = cX*apy - cY*apx; - bCROSScp = bX*cpy - bY*cpx; + var pointsWorld = virtualLight.pointsWorld, + pointsFrustum = virtualLight.pointsFrustum; - if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; + for ( var i = 0; i < 8; i ++ ) { - } + pointsWorld[ i ] = new THREE.Vector3(); + pointsFrustum[ i ] = new THREE.Vector3(); - return true; + } - }; + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + pointsFrustum[ 0 ].set( - 1, - 1, nearZ ); + pointsFrustum[ 1 ].set( 1, - 1, nearZ ); + pointsFrustum[ 2 ].set( - 1, 1, nearZ ); + pointsFrustum[ 3 ].set( 1, 1, nearZ ); - namespace.Triangulate = process; - namespace.Triangulate.area = area; + pointsFrustum[ 4 ].set( - 1, - 1, farZ ); + pointsFrustum[ 5 ].set( 1, - 1, farZ ); + pointsFrustum[ 6 ].set( - 1, 1, farZ ); + pointsFrustum[ 7 ].set( 1, 1, farZ ); - return namespace; + return virtualLight; -})(THREE.FontUtils); + } -// To use the typeface.js face files, hook up the API -self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; -THREE.typeface_js = self._typeface_js; + // Synchronize virtual light with the original light -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of Curve methods - * .getPoint(t), getTangent(t) - * .getPointAt(u), getTagentAt(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.SplineCurve3 - * THREE.ClosedSplineCurve3 - * - * A series of curves can be represented as a THREE.CurvePath - * - **/ + function updateVirtualLight( light, cascade ) { -/************************************************************** - * Abstract Curve base class - **************************************************************/ + var virtualLight = light.shadowCascadeArray[ cascade ]; -THREE.Curve = function () { + virtualLight.position.copy( light.position ); + virtualLight.target.position.copy( light.target.position ); + virtualLight.lookAt( virtualLight.target ); -}; + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + virtualLight.shadowDarkness = light.shadowDarkness; -// Virtual base class method to overwrite and implement in subclasses -// - t [0 .. 1] + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; -THREE.Curve.prototype.getPoint = function ( t ) { + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; - console.log( "Warning, getPoint() not implemented!" ); - return null; + var pointsFrustum = virtualLight.pointsFrustum; -}; + pointsFrustum[ 0 ].z = nearZ; + pointsFrustum[ 1 ].z = nearZ; + pointsFrustum[ 2 ].z = nearZ; + pointsFrustum[ 3 ].z = nearZ; -// Get point at relative position in curve according to arc length -// - u [0 .. 1] + pointsFrustum[ 4 ].z = farZ; + pointsFrustum[ 5 ].z = farZ; + pointsFrustum[ 6 ].z = farZ; + pointsFrustum[ 7 ].z = farZ; -THREE.Curve.prototype.getPointAt = function ( u ) { + } - var t = this.getUtoTmapping( u ); - return this.getPoint( t ); + // Fit shadow camera's ortho frustum to camera frustum -}; + function updateShadowCamera( camera, light ) { -// Get sequence of points using getPoint( t ) + var shadowCamera = light.shadowCamera, + pointsFrustum = light.pointsFrustum, + pointsWorld = light.pointsWorld; -THREE.Curve.prototype.getPoints = function ( divisions ) { + _min.set( Infinity, Infinity, Infinity ); + _max.set( - Infinity, - Infinity, - Infinity ); - if ( !divisions ) divisions = 5; + for ( var i = 0; i < 8; i ++ ) { - var d, pts = []; + var p = pointsWorld[ i ]; - for ( d = 0; d <= divisions; d ++ ) { + p.copy( pointsFrustum[ i ] ); + p.unproject( camera ); - pts.push( this.getPoint( d / divisions ) ); + p.applyMatrix4( shadowCamera.matrixWorldInverse ); - } + if ( p.x < _min.x ) _min.x = p.x; + if ( p.x > _max.x ) _max.x = p.x; - return pts; + if ( p.y < _min.y ) _min.y = p.y; + if ( p.y > _max.y ) _max.y = p.y; -}; + if ( p.z < _min.z ) _min.z = p.z; + if ( p.z > _max.z ) _max.z = p.z; -// Get sequence of points using getPointAt( u ) + } -THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { + shadowCamera.left = _min.x; + shadowCamera.right = _max.x; + shadowCamera.top = _max.y; + shadowCamera.bottom = _min.y; - if ( !divisions ) divisions = 5; + // can't really fit near/far + //shadowCamera.near = _min.z; + //shadowCamera.far = _max.z; - var d, pts = []; + shadowCamera.updateProjectionMatrix(); - for ( d = 0; d <= divisions; d ++ ) { + } - pts.push( this.getPointAt( d / divisions ) ); + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use for shadow maps - } + function getObjectMaterial( object ) { - return pts; + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; }; -// Get total curve arc length +// File:src/renderers/webgl/plugins/SpritePlugin.js -THREE.Curve.prototype.getLength = function () { +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; +THREE.SpritePlugin = function ( renderer, sprites ) { -}; + var gl = renderer.context; -// Get list of cumulative segment lengths + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; -THREE.Curve.prototype.getLengths = function ( divisions ) { + var texture; - if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + // decompose matrixWorld - if ( this.cacheArcLengths - && ( this.cacheArcLengths.length == divisions + 1 ) - && !this.needsUpdate) { + var spritePosition = new THREE.Vector3(); + var spriteRotation = new THREE.Quaternion(); + var spriteScale = new THREE.Vector3(); - //console.log( "cached", this.cacheArcLengths ); - return this.cacheArcLengths; + var init = function () { - } + 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 + ] ); - this.needsUpdate = false; + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - cache.push( 0 ); + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - for ( p = 1; p <= divisions; p ++ ) { + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - current = this.getPoint ( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + program = createProgram(); - } + attributes = { + position: gl.getAttribLocation ( program, 'position' ), + uv: gl.getAttribLocation ( program, 'uv' ) + }; - this.cacheArcLengths = cache; + uniforms = { + uvOffset: gl.getUniformLocation( program, 'uvOffset' ), + uvScale: gl.getUniformLocation( program, 'uvScale' ), - return cache; // { sums: cache, sum:sum }; Sum is in the last element. + 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' ), -THREE.Curve.prototype.updateArcLengths = function() { - this.needsUpdate = true; - this.getLengths(); -}; + 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' ), -// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance + alphaTest: gl.getUniformLocation( program, 'alphaTest' ) + }; -THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { + var canvas = document.createElement( 'canvas' ); + canvas.width = 8; + canvas.height = 8; - var arcLengths = this.getLengths(); + var context = canvas.getContext( '2d' ); + context.fillStyle = 'white'; + context.fillRect( 0, 0, 8, 8 ); - var i = 0, il = arcLengths.length; + texture = new THREE.Texture( canvas ); + texture.needsUpdate = true; - var targetArcLength; // The targeted u distance value to get + }; - if ( distance ) { + this.render = function ( scene, camera ) { - targetArcLength = distance; + if ( sprites.length === 0 ) return; - } else { + // setup gl - targetArcLength = u * arcLengths[ il - 1 ]; + if ( program === undefined ) { - } + init(); - //var time = Date.now(); + } - // binary search for the index with largest value smaller than target u distance + gl.useProgram( program ); - var low = 0, high = il - 1, comparison; + gl.enableVertexAttribArray( attributes.position ); + gl.enableVertexAttribArray( attributes.uv ); - while ( low <= high ) { + gl.disable( gl.CULL_FACE ); + gl.enable( gl.BLEND ); - 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 + 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 ); - comparison = arcLengths[ i ] - targetArcLength; + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - if ( comparison < 0 ) { + gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - low = i + 1; - continue; + gl.activeTexture( gl.TEXTURE0 ); + gl.uniform1i( uniforms.map, 0 ); - } else if ( comparison > 0 ) { + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; - high = i - 1; - continue; + if ( fog ) { - } else { + gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); - high = i; - break; + if ( fog instanceof THREE.Fog ) { - // DONE + gl.uniform1f( uniforms.fogNear, fog.near ); + gl.uniform1f( uniforms.fogFar, fog.far ); - } + gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; - } + } else if ( fog instanceof THREE.FogExp2 ) { - i = high; + gl.uniform1f( uniforms.fogDensity, fog.density ); - //console.log('b' , i, low, high, Date.now()- time); + gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; - if ( arcLengths[ i ] == targetArcLength ) { + } - var t = i / ( il - 1 ); - return t; + } else { - } + gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; - // we could get finer grain at lengths, or use simple interpolatation between two points + } - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; - var segmentLength = lengthAfter - lengthBefore; + // update positions and sort - // determine where we are between the 'before' and 'after' points + for ( var i = 0, l = sprites.length; i < l; i ++ ) { - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + var sprite = sprites[ i ]; - // add that fractional amount to t + sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; - var t = ( i + segmentFraction ) / ( il -1 ); + } - return t; + sprites.sort( painterSortStable ); -}; + // render all sprites -// 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 + var scale = []; -THREE.Curve.prototype.getTangent = function( t ) { + for ( var i = 0, l = sprites.length; i < l; i ++ ) { - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + var sprite = sprites[ i ]; + var material = sprite.material; - // Capping in case of danger + gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + scale[ 0 ] = spriteScale.x; + scale[ 1 ] = spriteScale.y; - var vec = pt2.clone().sub(pt1); - return vec.normalize(); + var fogType = 0; -}; + if ( scene.fog && material.fog ) { + fogType = sceneFogType; -THREE.Curve.prototype.getTangentAt = function ( u ) { + } - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); + 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 { -/************************************************************** - * Utils - **************************************************************/ + gl.uniform2f( uniforms.uvOffset, 0, 0 ); + gl.uniform2f( uniforms.uvScale, 1, 1 ); -THREE.Curve.Utils = { + } - tangentQuadraticBezier: function ( t, p0, p1, p2 ) { + gl.uniform1f( uniforms.opacity, material.opacity ); + gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); - return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + gl.uniform1f( uniforms.rotation, material.rotation ); + gl.uniform2fv( uniforms.scale, scale ); - }, + renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + renderer.state.setDepthTest( material.depthTest ); + renderer.state.setDepthWrite( material.depthWrite ); - // Puay Bing, thanks for helping with this derivative! + if ( material.map && material.map.image && material.map.image.width ) { - tangentCubicBezier: function (t, p0, p1, p2, p3 ) { + renderer.setTexture( material.map, 0 ); - return -3 * p0 * (1 - t) * (1 - t) + - 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + - 6 * t * p2 * (1-t) - 3 * t * t * p2 + - 3 * t * t * p3; - }, + } else { + renderer.setTexture( texture, 0 ); - tangentSpline: function ( t, p0, p1, p2, p3 ) { + } - // To check if my formulas are correct + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 - var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t - var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 - var h11 = 3 * t * t - 2 * t; // t3 − t2 + } - return h00 + h10 + h01 + h11; + // restore gl - }, + gl.enable( gl.CULL_FACE ); - // Catmull-Rom + renderer.resetGLState(); - interpolate: function( p0, p1, p2, p3, t ) { + }; - 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 createProgram () { - } + var program = gl.createProgram(); -}; + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + gl.shaderSource( vertexShader, [ -// TODO: Transformation for Curves? + 'precision ' + renderer.getPrecision() + ' float;', -/************************************************************** - * 3D Curves - **************************************************************/ + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform float rotation;', + 'uniform vec2 scale;', + 'uniform vec2 uvOffset;', + 'uniform vec2 uvScale;', -// A Factory method for creating new curve subclasses + 'attribute vec2 position;', + 'attribute vec2 uv;', -THREE.Curve.create = function ( constructor, getPointFunc ) { + 'varying vec2 vUV;', - constructor.prototype = Object.create( THREE.Curve.prototype ); - constructor.prototype.getPoint = getPointFunc; + 'void main() {', - return constructor; + 'vUV = uvOffset + uv * uvScale;', -}; + 'vec2 alignedPosition = position * scale;', -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ + 'vec2 rotatedPosition;', + 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', + 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ + 'vec4 finalPosition;', -THREE.CurvePath = function () { + 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', + 'finalPosition.xy += rotatedPosition;', + 'finalPosition = projectionMatrix * finalPosition;', - this.curves = []; - this.bends = []; - - this.autoClose = false; // Automatically closes the path -}; + 'gl_Position = finalPosition;', -THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); + '}' -THREE.CurvePath.prototype.add = function ( curve ) { + ].join( '\n' ) ); - this.curves.push( curve ); + gl.shaderSource( fragmentShader, [ -}; + 'precision ' + renderer.getPrecision() + ' float;', -THREE.CurvePath.prototype.checkConnection = function() { - // TODO - // If the ending of curve is not connected to the starting - // or the next curve, then, this is not a real path -}; + 'uniform vec3 color;', + 'uniform sampler2D map;', + 'uniform float opacity;', -THREE.CurvePath.prototype.closePath = function() { - // TODO Test - // and verify for vector3 (needs to implement equals) - // 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 THREE.LineCurve(endPoint, startPoint) ); - } - -}; + 'uniform int fogType;', + 'uniform vec3 fogColor;', + 'uniform float fogDensity;', + 'uniform float fogNear;', + 'uniform float fogFar;', + 'uniform float alphaTest;', -// To get accurate point with reference to -// entire path distance at time t, -// following has to be done: + 'varying vec2 vUV;', -// 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') + 'void main() {', -THREE.CurvePath.prototype.getPoint = function( t ) { + 'vec4 texture = texture2D( map, vUV );', - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0, diff, curve; + 'if ( texture.a < alphaTest ) discard;', - // To think about boundaries points. + 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', - while ( i < curveLengths.length ) { + 'if ( fogType > 0 ) {', - if ( curveLengths[ i ] >= d ) { + 'float depth = gl_FragCoord.z / gl_FragCoord.w;', + 'float fogFactor = 0.0;', - diff = curveLengths[ i ] - d; - curve = this.curves[ i ]; + 'if ( fogType == 1 ) {', - var u = 1 - diff / curve.getLength(); + 'fogFactor = smoothstep( fogNear, fogFar, depth );', - return curve.getPointAt( u ); + '} else {', - break; - } + 'const float LOG2 = 1.442695;', + 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', + 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', - i ++; + '}', - } + 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', - return null; + '}', - // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; - else if ( p.x < minX ) minX = p.x; + crossOrigin: undefined, - if ( p.y > maxY ) maxY = p.y; - else if ( p.y < minY ) minY = p.y; + loadTexture: function ( url, mapping, onLoad, onError ) { - if ( v3 ) { + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; - if ( p.z > maxZ ) maxZ = p.z; - else if ( p.z < minZ ) minZ = p.z; + var texture = new THREE.Texture( undefined, mapping ); - } + loader.load( url, function ( image ) { - sum.add( p ); + texture.image = image; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); - var ret = { + }, undefined, function ( event ) { - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY + if ( onError ) onError( event ); - }; + } ); - if ( v3 ) { + texture.sourceFile = url; - ret.maxZ = maxZ; - ret.minZ = minZ; + return texture; - } + }, - return ret; + loadTextureCube: function ( array, mapping, onLoad, onError ) { -}; + var images = []; -/************************************************************** - * Create Geometries Helpers - **************************************************************/ + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; -/// Generate geometry from path points (for Line or ParticleSystem objects) + var texture = new THREE.CubeTexture( images, mapping ); -THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + // no flipping needed for cube textures - var pts = this.getPoints( divisions, true ); - return this.createGeometry( pts ); + texture.flipY = false; -}; + var loaded = 0; -// Generate geometry from equidistance sampling along the path + var loadTexture = function ( i ) { -THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { + loader.load( array[ i ], function ( image ) { - var pts = this.getSpacedPoints( divisions, true ); - return this.createGeometry( pts ); + texture.images[ i ] = image; -}; + loaded += 1; -THREE.CurvePath.prototype.createGeometry = function( points ) { + if ( loaded === 6 ) { - var geometry = new THREE.Geometry(); + texture.needsUpdate = true; - for ( var i = 0; i < points.length; i ++ ) { + if ( onLoad ) onLoad( texture ); - geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); + } - } + }, undefined, onError ); - return geometry; + } -}; + for ( var i = 0, il = array.length; i < il; ++ i ) { + loadTexture( i ); -/************************************************************** - * Bend / Wrap Helper Methods - **************************************************************/ + } -// Wrap path / Bend modifiers? + return texture; -THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + }, - this.bends.push( bendpath ); + loadCompressedTexture: function () { -}; + THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) -THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { + }, - var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints - var i, il; + loadCompressedTextureCube: function () { - if ( !bends ) { + THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) - bends = this.bends; + }, - } + getNormalMap: function ( image, depth ) { - for ( i = 0, il = bends.length; i < il; i ++ ) { + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + var cross = function ( a, b ) { - } + return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; - return oldPts; + } -}; + var subtract = function ( a, b ) { -THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; - var oldPts = this.getSpacedPoints( segments ); + } - var i, il; + var normalize = function ( a ) { - if ( !bends ) { + var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); + return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; - bends = this.bends; + } - } + depth = depth | 1; - for ( i = 0, il = bends.length; i < il; i ++ ) { + var width = image.width; + var height = image.height; - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - } + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0 ); - return oldPts; + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; -}; + for ( var x = 0; x < width; x ++ ) { -// This returns getPoints() bend/wrapped around the contour of a path. -// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html + for ( var y = 0; y < height; y ++ ) { -THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { + var ly = y - 1 < 0 ? 0 : y - 1; + var uy = y + 1 > height - 1 ? height - 1 : y + 1; + var lx = x - 1 < 0 ? 0 : x - 1; + var ux = x + 1 > width - 1 ? width - 1 : x + 1; + + var points = []; + var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; + points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + + var normals = []; + var num_points = points.length; - var bounds = this.getBoundingBox(); + for ( var i = 0; i < num_points; i ++ ) { - var i, il, p, oldX, oldY, xNorm; + var v1 = points[ i ]; + var v2 = points[ ( i + 1 ) % num_points ]; + v1 = subtract( v1, origin ); + v2 = subtract( v2, origin ); + normals.push( normalize( cross( v1, v2 ) ) ); - for ( i = 0, il = oldPts.length; i < il; i ++ ) { + } - p = oldPts[ i ]; + var normal = [ 0, 0, 0 ]; - oldX = p.x; - oldY = p.y; + for ( var i = 0; i < normals.length; i ++ ) { - xNorm = oldX / bounds.maxX; + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; - // If using actual distance, for length > path, requires line extrusions - //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance + } - xNorm = path.getUtoTmapping( xNorm, oldX ); + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; - // check for out of bounds? + var idx = ( y * width + x ) * 4; - var pathPt = path.getPoint( xNorm ); - var normal = path.getTangent( xNorm ); - normal.set( -normal.y, normal.x ).multiplyScalar( oldY ); + output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; + output[ idx + 3 ] = 255; - p.x = pathPt.x + normal.x; - p.y = pathPt.y + normal.y; + } - } + } - return oldPts; + context.putImageData( imageData, 0, 0 ); -}; + return canvas; + }, -/** - * @author alteredq / http://alteredqualia.com/ - */ + generateDataTexture: function ( width, height, color ) { + + var size = width * height; + var data = new Uint8Array( 3 * size ); -THREE.Gyroscope = function () { + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); - THREE.Object3D.call( this ); + for ( var i = 0; i < size; i ++ ) { -}; + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; -THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); + } -THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; - this.matrixAutoUpdate && this.updateMatrix(); + return texture; - // update matrixWorld + } - if ( this.matrixWorldNeedsUpdate || force ) { +}; + +// File:src/extras/SceneUtils.js - if ( this.parent ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); +THREE.SceneUtils = { - this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); - this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); + createMultiMaterialObject: function ( geometry, materials ) { - this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); + var group = new THREE.Object3D(); + for ( var i = 0, l = materials.length; i < l; i ++ ) { - } else { + group.add( new THREE.Mesh( geometry, materials[ i ] ) ); - this.matrixWorld.copy( this.matrix ); + } - } + return group; + }, - this.matrixWorldNeedsUpdate = false; + detach: function ( child, parent, scene ) { - force = true; + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); - } + }, - // update children + attach: function ( child, scene, parent ) { - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + var matrixWorldInverse = new THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); - this.children[ i ].updateMatrixWorld( force ); + scene.remove( child ); + parent.add( child ); - } + } }; -THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); -THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); -THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); -THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); - +// File:src/extras/FontUtils.js /** * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. + * @author alteredq / http://alteredqualia.com/ * - **/ + * For Text operations in three.js (See TextGeometry) + * + * It uses techniques used in: + * + * typeface.js and canvastext + * For converting fonts and rendering with javascript + * http://typeface.neocracy.org + * + * Triangulation ported from AS3 + * Simple Polygon Triangulation + * http://actionsnippet.com/?p=1462 + * + * A Method to triangulate shapes with holes + * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ + * + */ -THREE.Path = function ( points ) { +THREE.FontUtils = { - THREE.CurvePath.call(this); + faces: {}, - this.actions = []; + // Just for now. face[weight][style] - if ( points ) { + face: 'helvetiker', + weight: 'normal', + style: 'normal', + size: 150, + divisions: 10, - this.fromPoints( points ); + getFace: function () { - } + try { -}; + return this.faces[ this.face ][ this.weight ][ this.style ]; -THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); + } catch (e) { -THREE.PathActions = { + throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." - MOVE_TO: 'moveTo', - LINE_TO: 'lineTo', - QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve - BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve - CSPLINE_THRU: 'splineThru', // Catmull-rom spline - ARC: 'arc', // Circle - ELLIPSE: 'ellipse' -}; + }; -// TODO Clean up PATH API + }, -// Create path using straight lines to connect all points -// - vectors: array of Vector2 + loadFace: function ( data ) { -THREE.Path.prototype.fromPoints = function ( vectors ) { + var family = data.familyName.toLowerCase(); - this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + var ThreeFont = this; - for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; - this.lineTo( vectors[ v ].x, vectors[ v ].y ); + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - }; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; -}; + return data; -// startPath() endPath()? + }, -THREE.Path.prototype.moveTo = function ( x, y ) { + drawText: function ( text ) { - var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); + // RenderText -}; + var i, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; -THREE.Path.prototype.lineTo = function ( x, y ) { + var fontPaths = []; - var args = Array.prototype.slice.call( arguments ); + for ( i = 0; i < length; i ++ ) { - var lastargs = this.actions[ this.actions.length - 1 ].args; + var path = new THREE.Path(); - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; - var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); - this.curves.push( curve ); + fontPaths.push( ret.path ); - this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); + } -}; + // get the width -THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } - var args = Array.prototype.slice.call( arguments ); + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; - var lastargs = this.actions[ this.actions.length - 1 ].args; + //extract.paths = fontPaths; + //extract.offset = width; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + return { paths: fontPaths, offset: width }; - var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCPx, aCPy ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); + }, - this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); -}; -THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY ) { - var args = Array.prototype.slice.call( arguments ); + extractGlyphPoints: function ( c, face, scale, offset, path ) { - var lastargs = this.actions[ this.actions.length - 1 ].args; + var pts = []; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + var i, i2, divisions, + outline, action, length, + scaleX, scaleY, + x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, + laste, + glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; - var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCP1x, aCP1y ), - new THREE.Vector2( aCP2x, aCP2y ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); + if ( ! glyph ) return; - this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + if ( glyph.o ) { -}; + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; -THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { + scaleX = scale; + scaleY = scale; - var args = Array.prototype.slice.call( arguments ); - var lastargs = this.actions[ this.actions.length - 1 ].args; + for ( i = 0; i < length; ) { - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; -//--- - var npts = [ new THREE.Vector2( x0, y0 ) ]; - Array.prototype.push.apply( npts, pts ); + action = outline[ i ++ ]; - var curve = new THREE.SplineCurve( npts ); - this.curves.push( curve ); + //console.log( action ); - this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + switch ( action ) { -}; + case 'm': -// FUTURE: Change the API or follow canvas API? + // Move To -THREE.Path.prototype.arc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + path.moveTo( x, y ); + break; - this.absarc(aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + case 'l': - }; + // Line To - THREE.Path.prototype.absarc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); - }; + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; + path.lineTo( x, y ); + break; -THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { + case 'q': - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + // QuadraticCurveTo - this.absellipse(aX + x0, aY + y0, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); + cpx = outline[ i ++ ] * scaleX + offset; + cpy = outline[ i ++ ] * scaleY; + cpx1 = outline[ i ++ ] * scaleX + offset; + cpy1 = outline[ i ++ ] * scaleY; - }; + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); + laste = pts[ pts.length - 1 ]; -THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { + if ( laste ) { - var args = Array.prototype.slice.call( arguments ); - var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - this.curves.push( curve ); + cpx0 = laste.x; + cpy0 = laste.y; - var lastPoint = curve.getPoint(1); - args.push(lastPoint.x); - args.push(lastPoint.y); + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); + var t = i2 / divisions; + THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } - }; + } -THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { + break; - if ( ! divisions ) divisions = 40; + case 'b': - var points = []; + // Cubic Bezier Curve - for ( var i = 0; i < divisions; i ++ ) { + cpx = outline[ i ++ ] * scaleX + offset; + cpy = outline[ i ++ ] * scaleY; + cpx1 = outline[ i ++ ] * scaleX + offset; + cpy1 = outline[ i ++ ] * scaleY; + cpx2 = outline[ i ++ ] * scaleX + offset; + cpy2 = outline[ i ++ ] * scaleY; - points.push( this.getPoint( i / divisions ) ); + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - //if( !this.getPoint( i / divisions ) ) throw "DIE"; + laste = pts[ pts.length - 1 ]; - } + if ( laste ) { - // if ( closedPath ) { - // - // points.push( points[ 0 ] ); - // - // } + cpx0 = laste.x; + cpy0 = laste.y; - return points; + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { -}; + var t = i2 / divisions; + THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); -/* Return an array of vectors based on contour of the path */ + } -THREE.Path.prototype.getPoints = function( divisions, closedPath ) { + } - if (this.useSpacedPoints) { - console.log('tata'); - return this.getSpacedPoints( divisions, closedPath ); - } + break; - divisions = divisions || 12; + } - var points = []; + } + } - var i, il, item, action, args; - var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, - laste, j, - t, tx, ty; - for ( i = 0, il = this.actions.length; i < il; i ++ ) { - item = this.actions[ i ]; + return { offset: glyph.ha * scale, path:path }; + } - action = item.action; - args = item.args; +}; - switch( action ) { - case THREE.PathActions.MOVE_TO: +THREE.FontUtils.generateShapes = function ( text, parameters ) { - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + // Parameters - break; + parameters = parameters || {}; - case THREE.PathActions.LINE_TO: + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; + var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; + var style = parameters.style !== undefined ? parameters.style : 'normal'; - break; + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; - case THREE.PathActions.QUADRATIC_CURVE_TO: + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; - cpx = args[ 2 ]; - cpy = args[ 3 ]; + // Get a Font data json object - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; + var data = THREE.FontUtils.drawText( text ); - if ( points.length > 0 ) { + var paths = data.paths; + var shapes = []; - laste = points[ points.length - 1 ]; + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - cpx0 = laste.x; - cpy0 = laste.y; + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - } else { + } - laste = this.actions[ i - 1 ].args; + return shapes; - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; +}; - } - for ( j = 1; j <= divisions; j ++ ) { +/** + * 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 + * + */ - t = j / divisions; - tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); +( function ( namespace ) { - points.push( new THREE.Vector2( tx, ty ) ); + var EPSILON = 0.0000000001; - } + // takes in an contour array and returns - break; + var process = function ( contour, indices ) { - case THREE.PathActions.BEZIER_CURVE_TO: + var n = contour.length; - cpx = args[ 4 ]; - cpy = args[ 5 ]; + if ( n < 3 ) return null; - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; + var result = [], + verts = [], + vertIndices = []; - cpx2 = args[ 2 ]; - cpy2 = args[ 3 ]; + /* we want a counter-clockwise polygon in verts */ - if ( points.length > 0 ) { + var u, v, w; - laste = points[ points.length - 1 ]; + if ( area( contour ) > 0.0 ) { - cpx0 = laste.x; - cpy0 = laste.y; + for ( v = 0; v < n; v ++ ) verts[ v ] = v; - } else { + } else { - laste = this.actions[ i - 1 ].args; + for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; + } - } + var nv = n; + /* remove nv - 2 vertices, creating 1 triangle every time */ - for ( j = 1; j <= divisions; j ++ ) { + var count = 2 * nv; /* error detection */ - t = j / divisions; + for ( v = nv - 1; nv > 2; ) { - tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + /* if we loop, it is probably a non-simple polygon */ - points.push( new THREE.Vector2( tx, ty ) ); + if ( ( count -- ) <= 0 ) { - } + //** Triangulate: ERROR - probable bad polygon! - break; + //throw ( "Warning, unable to triangulate polygon!" ); + //return null; + // Sometimes warning is fine, especially polygons are triangulated in reverse. + THREE.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); - case THREE.PathActions.CSPLINE_THRU: + if ( indices ) return vertIndices; + return result; - laste = this.actions[ i - 1 ].args; + } - var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); - var spts = [ last ]; + /* three consecutive vertices in current polygon, */ - var n = divisions * args[ 0 ].length; + 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 */ - spts = spts.concat( args[ 0 ] ); + if ( snip( contour, u, v, w, nv, verts ) ) { - var spline = new THREE.SplineCurve( spts ); + var a, b, c, s, t; - for ( j = 1; j <= n; j ++ ) { + /* true names of the vertices */ - points.push( spline.getPointAt( j / n ) ) ; + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; - } + /* output Triangle */ - break; + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); - case THREE.PathActions.ARC: - var aX = args[ 0 ], aY = args[ 1 ], - aRadius = args[ 2 ], - aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], - aClockwise = !!args[ 5 ]; + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + /* remove v from the remaining polygon */ - for ( j = 1; j <= tdivisions; j ++ ) { + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { - t = j / tdivisions; + verts[ s ] = verts[ t ]; - if ( ! aClockwise ) { + } - t = 1 - t; + nv --; - } + /* reset error detection counter */ - angle = aStartAngle + t * deltaAngle; + count = 2 * nv; - tx = aX + aRadius * Math.cos( angle ); - ty = aY + aRadius * Math.sin( angle ); + } - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + } - points.push( new THREE.Vector2( tx, ty ) ); + if ( indices ) return vertIndices; + return result; - } + }; - //console.log(points); + // calculate area of the contour polygon - break; - - case THREE.PathActions.ELLIPSE: + var area = function ( contour ) { - var aX = args[ 0 ], aY = args[ 1 ], - xRadius = args[ 2 ], - yRadius = args[ 3 ], - aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], - aClockwise = !!args[ 6 ]; + var n = contour.length; + var a = 0.0; + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - for ( j = 1; j <= tdivisions; j ++ ) { + } - t = j / tdivisions; + return a * 0.5; - if ( ! aClockwise ) { + }; - t = 1 - t; + var snip = function ( contour, u, v, w, n, verts ) { - } + var p; + var ax, ay, bx, by; + var cx, cy, px, py; - angle = aStartAngle + t * deltaAngle; + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; - tx = aX + xRadius * Math.cos( angle ); - ty = aY + yRadius * Math.sin( angle ); + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; - points.push( new THREE.Vector2( tx, ty ) ); + if ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false; - } + var aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; - //console.log(points); + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; - break; + for ( p = 0; p < n; p ++ ) { - } // end switch + 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 - // Normalize to remove the closing point by default. - var lastPoint = points[ points.length - 1]; - var EPSILON = 0.0000000001; - if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && - Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) - points.splice( points.length - 1, 1); - if ( closedPath ) { + aCROSSbp = aX * bpy - aY * bpx; + cCROSSap = cX * apy - cY * apx; + bCROSScp = bX * cpy - bY * cpx; - points.push( points[ 0 ] ); + if ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false; - } + } - return points; + return true; -}; + }; -// Breaks path into shapes -THREE.Path.prototype.toShapes = function( isCCW ) { + namespace.Triangulate = process; + namespace.Triangulate.area = area; - function isPointInsidePolygon( inPt, inPolygon ) { - var EPSILON = 0.0000000001; + return namespace; - var polyLen = inPolygon.length; +} )( THREE.FontUtils ); - // 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 ]; +// To use the typeface.js face files, hook up the API +self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; +THREE.typeface_js = self._typeface_js; - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; +// File:src/extras/audio/Audio.js - if ( Math.abs(edgeDy) > 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; +/** + * @author mrdoob / http://mrdoob.com/ + */ - 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 colinear - if ( inPt.y != edgeLowPt.y ) continue; // parallel - // egde 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; - } - } +THREE.Audio = function ( listener ) { - return inside; - } + THREE.Object3D.call( this ); - var i, il, item, action, args; + this.type = 'Audio'; - var subPaths = [], lastPath = new THREE.Path(); + this.context = listener.context; + this.source = this.context.createBufferSource(); + this.source.onended = this.onEnded.bind(this); - for ( i = 0, il = this.actions.length; i < il; i ++ ) { + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - item = this.actions[ i ]; + this.panner = this.context.createPanner(); + this.panner.connect( this.gain ); - args = item.args; - action = item.action; + this.autoplay = false; - if ( action == THREE.PathActions.MOVE_TO ) { + this.startTime = 0; + this.isPlaying = false; - if ( lastPath.actions.length != 0 ) { +}; - subPaths.push( lastPath ); - lastPath = new THREE.Path(); +THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Audio.prototype.constructor = THREE.Audio; - } +THREE.Audio.prototype.load = function ( file ) { - } + var scope = this; - lastPath[ action ].apply( lastPath, args ); + var request = new XMLHttpRequest(); + request.open( 'GET', file, true ); + request.responseType = 'arraybuffer'; + request.onload = function ( e ) { - } + scope.context.decodeAudioData( this.response, function ( buffer ) { - if ( lastPath.actions.length != 0 ) { + scope.source.buffer = buffer; - subPaths.push( lastPath ); + if( scope.autoplay ) scope.play(); - } + } ); - // console.log(subPaths); + }; + request.send(); - if ( subPaths.length == 0 ) return []; + return this; - var solid, tmpPath, tmpShape, shapes = []; +}; - if ( subPaths.length == 1) { +THREE.Audio.prototype.play = function () { - tmpPath = subPaths[0]; - tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; + if ( this.isPlaying === true ) { - } + THREE.warn( 'THREE.Audio: Audio is already playing.' ); + return; - var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? !holesFirst : holesFirst; + } - // console.log("Holes first", holesFirst); - - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; + var source = this.context.createBufferSource(); - newShapes[mainIdx] = undefined; - newShapeHoles[mainIdx] = []; + source.buffer = this.source.buffer; + source.loop = this.source.loop; + source.onended = this.source.onended; + source.connect( this.panner ); + source.start( 0, this.startTime ); - for ( i = 0, il = subPaths.length; i < il; i ++ ) { + this.isPlaying = true; - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = THREE.Shape.Utils.isClockWise( tmpPoints ); - solid = isCCW ? !solid : solid; + this.source = source; - if ( solid ) { +}; - if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx++; +THREE.Audio.prototype.pause = function () { - newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; - newShapes[mainIdx].s.actions = tmpPath.actions; - newShapes[mainIdx].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx++; - newShapeHoles[mainIdx] = []; + this.source.stop(); + this.startTime = this.context.currentTime; - //console.log('cw', i); +}; - } else { +THREE.Audio.prototype.stop = function () { - newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); + this.source.stop(); + this.startTime = 0; - //console.log('ccw', i); +}; - } +THREE.Audio.prototype.onEnded = function() { - } + this.isPlaying = false; - if ( newShapes.length > 1 ) { - var ambigious = 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 sh = newShapes[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 { - ambigious = true; - } - } - } - if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } - } - } - // console.log("ambigious: ", ambigious); - if ( toChange.length > 0 ) { - // console.log("to change: ", toChange); - if (! ambigious) newShapeHoles = betterShapeHoles; - } - } +THREE.Audio.prototype.setLoop = function ( value ) { - var tmpHoles, j, jl; - for ( i = 0, il = newShapes.length; i < il; i ++ ) { - tmpShape = newShapes[i].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[i]; - for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - tmpShape.holes.push( tmpHoles[j].h ); - } - } - - //console.log("shape", shapes); - - return shapes; + this.source.loop = value; }; -/** - * @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. - -THREE.Shape = function () { +THREE.Audio.prototype.setRefDistance = function ( value ) { - THREE.Path.apply( this, arguments ); - this.holes = []; + this.panner.refDistance = value; }; -THREE.Shape.prototype = Object.create( THREE.Path.prototype ); +THREE.Audio.prototype.setRolloffFactor = function ( value ) { -// Convenience method to return ExtrudeGeometry + this.panner.rolloffFactor = value; -THREE.Shape.prototype.extrude = function ( options ) { +}; - var extruded = new THREE.ExtrudeGeometry( this, options ); - return extruded; +THREE.Audio.prototype.setVolume = function ( value ) { + + this.gain.gain.value = value; }; -// Convenience method to return ShapeGeometry +THREE.Audio.prototype.updateMatrixWorld = ( function () { -THREE.Shape.prototype.makeGeometry = function ( options ) { + var position = new THREE.Vector3(); - var geometry = new THREE.ShapeGeometry( this, options ); - return geometry; + return function ( force ) { -}; + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); -// Get points of holes + position.setFromMatrixPosition( this.matrixWorld ); -THREE.Shape.prototype.getPointsHoles = function ( divisions ) { + this.panner.setPosition( position.x, position.y, position.z ); - var i, il = this.holes.length, holesPts = []; + }; - for ( i = 0; i < il; i ++ ) { +} )(); - holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); +// File:src/extras/audio/AudioListener.js - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - return holesPts; +THREE.AudioListener = function () { -}; + THREE.Object3D.call( this ); -// Get points of holes (spaced by regular distance) + this.type = 'AudioListener'; -THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { + this.context = new ( window.AudioContext || window.webkitAudioContext )(); - var i, il = this.holes.length, holesPts = []; +}; - for ( i = 0; i < il; i ++ ) { +THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype ); +THREE.AudioListener.prototype.constructor = THREE.AudioListener; - holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); +THREE.AudioListener.prototype.updateMatrixWorld = ( function () { - } + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3(); - return holesPts; + var orientation = new THREE.Vector3(); -}; + return function ( force ) { + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); -// Get points of shape and holes (keypoints based on segments parameter) + var listener = this.context.listener; + var up = this.up; -THREE.Shape.prototype.extractAllPoints = function ( divisions ) { + this.matrixWorld.decompose( position, quaternion, scale ); - return { + orientation.set( 0, 0, -1 ).applyQuaternion( quaternion ); - shape: this.getTransformedPoints( divisions ), - holes: this.getPointsHoles( divisions ) + listener.setPosition( position.x, position.y, position.z ); + listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); - }; + }; -}; +} )(); -THREE.Shape.prototype.extractPoints = function ( divisions ) { +// File:src/extras/core/Curve.js + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTagentAt(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.SplineCurve3 + * THREE.ClosedSplineCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ - if (this.useSpacedPoints) { - return this.extractAllSpacedPoints(divisions); - } +/************************************************************** + * Abstract Curve base class + **************************************************************/ - return this.extractAllPoints(divisions); +THREE.Curve = function () { }; -// -// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { -// -// return { -// -// shape: this.transform( bend, divisions ), -// holes: this.getPointsHoles( divisions, bend ) -// -// }; -// -// }; +// Virtual base class method to overwrite and implement in subclasses +// - t [0 .. 1] -// Get points of shape and holes (spaced by regular distance) +THREE.Curve.prototype.getPoint = function ( t ) { -THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + THREE.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); + return null; + +}; - return { +// Get point at relative position in curve according to arc length +// - u [0 .. 1] - shape: this.getTransformedSpacedPoints( divisions ), - holes: this.getSpacedPointsHoles( divisions ) +THREE.Curve.prototype.getPointAt = function ( u ) { - }; + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); }; -/************************************************************** - * Utils - **************************************************************/ +// Get sequence of points using getPoint( t ) -THREE.Shape.Utils = { +THREE.Curve.prototype.getPoints = function ( divisions ) { - triangulateShape: function ( contour, holes ) { - - function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { - // inOtherPt needs to be colinear 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 EPSILON = 0.0000000001; - - 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) > 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 colinear - if ( ( perpSeg1 != 0 ) || - ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; - - // they are collinear or degenerate - var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? - var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist 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 - - var EPSILON = 0.0000000001; - - // 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) > 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; - } + if ( ! divisions ) divisions = 5; - var holeIndex, shapeIndex, - shapePt, holePt, - holeIdx, cutKey, failedCuts = [], - tmpShape1, tmpShape2, - tmpHole1, tmpHole2; + var d, pts = []; - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + for ( d = 0; d <= divisions; d ++ ) { - indepHoles.push( h ); + pts.push( this.getPoint( d / divisions ) ); - } + } - 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; - } + return pts; - // search for shape-vertex and hole-vertex, - // which can be connected without intersections - for ( shapeIndex = 0; shapeIndex < shape.length; shapeIndex++ ) { +}; + +// Get sequence of points using getPointAt( u ) - shapePt = shape[ shapeIndex ]; - holeIndex = -1; +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { - // search for hole which can be reached without intersections - for ( var h = 0; h < indepHoles.length; h ++ ) { - holeIdx = indepHoles[h]; + if ( ! divisions ) divisions = 5; - // prevent multiple checks - cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; - if ( failedCuts[cutKey] !== undefined ) continue; + var d, pts = []; - 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; + for ( d = 0; d <= divisions; d ++ ) { - holeIndex = h2; - indepHoles.splice(h,1); + pts.push( this.getPointAt( d / divisions ) ); - 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 ); + return pts; - // Debug only, to show the selected cuts - // glob_CutLines.push( [ shapePt, holePt ] ); +}; - break; - } - if ( holeIndex >= 0 ) break; // hole-vertex found +// Get total curve arc length - failedCuts[cutKey] = true; // remember failure - } - if ( holeIndex >= 0 ) break; // hole-vertex found - } - } +THREE.Curve.prototype.getLength = function () { - return shape; /* shape with no holes */ - } + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; +}; - var i, il, f, face, - key, index, - allPointsMap = {}; +// Get list of cumulative segment lengths - // 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. +THREE.Curve.prototype.getLengths = function ( divisions ) { - var allpoints = contour.concat(); + if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length == divisions + 1 ) + && ! this.needsUpdate) { - Array.prototype.push.apply( allpoints, holes[h] ); + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; - } + } - //console.log( "allpoints",allpoints, allpoints.length ); + this.needsUpdate = false; - // prepare all points map + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - for ( i = 0, il = allpoints.length; i < il; i ++ ) { + cache.push( 0 ); - key = allpoints[ i ].x + ":" + allpoints[ i ].y; + for ( p = 1; p <= divisions; p ++ ) { - if ( allPointsMap[ key ] !== undefined ) { + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - console.log( "Duplicate point", key ); + } - } + this.cacheArcLengths = cache; - allPointsMap[ key ] = i; + return cache; // { sums: cache, sum:sum }; Sum is in the last element. - } +}; - // remove holes by cutting paths to holes and adding them to the shape - var shapeWithoutHoles = removeHoles( contour, holes ); - var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape - //console.log( "triangles",triangles, triangles.length ); +THREE.Curve.prototype.updateArcLengths = function() { + this.needsUpdate = true; + this.getLengths(); +}; - // check all face vertices against all points map +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance - for ( i = 0, il = triangles.length; i < il; i ++ ) { +THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { - face = triangles[ i ]; + var arcLengths = this.getLengths(); - for ( f = 0; f < 3; f ++ ) { + var i = 0, il = arcLengths.length; - key = face[ f ].x + ":" + face[ f ].y; + var targetArcLength; // The targeted u distance value to get - index = allPointsMap[ key ]; + if ( distance ) { - if ( index !== undefined ) { + targetArcLength = distance; - face[ f ] = index; + } else { - } + targetArcLength = u * arcLengths[ il - 1 ]; - } + } - } + //var time = Date.now(); - return triangles.concat(); + // binary search for the index with largest value smaller than target u distance - }, + var low = 0, high = il - 1, comparison; - isClockWise: function ( pts ) { + while ( low <= high ) { - return THREE.FontUtils.Triangulate.area( pts ) < 0; + 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; - // Bezier Curves formulas obtained from - // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + if ( comparison < 0 ) { - // Quad Bezier Functions + low = i + 1; - b2p0: function ( t, p ) { + } else if ( comparison > 0 ) { - var k = 1 - t; - return k * k * p; + high = i - 1; - }, + } else { - b2p1: function ( t, p ) { + high = i; + break; - return 2 * ( 1 - t ) * t * p; + // DONE - }, + } - b2p2: function ( t, p ) { + } - return t * t * p; + i = high; - }, + //console.log('b' , i, low, high, Date.now()- time); - b2: function ( t, p0, p1, p2 ) { + if ( arcLengths[ i ] == targetArcLength ) { - return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); + var t = i / ( il - 1 ); + return t; - }, + } - // Cubic Bezier Functions + // we could get finer grain at lengths, or use simple interpolatation between two points - b3p0: function ( t, p ) { + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - var k = 1 - t; - return k * k * k * p; + var segmentLength = lengthAfter - lengthBefore; - }, + // determine where we are between the 'before' and 'after' points - b3p1: function ( t, p ) { + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - var k = 1 - t; - return 3 * k * k * t * p; + // add that fractional amount to t - }, + var t = ( i + segmentFraction ) / ( il - 1 ); - b3p2: function ( t, p ) { + return t; - var k = 1 - t; - return 3 * k * t * t * p; +}; - }, +// 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 - b3p3: function ( t, p ) { +THREE.Curve.prototype.getTangent = function( t ) { - return t * t * t * p; + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - }, + // Capping in case of danger - b3: function ( t, p0, p1, p2, p3 ) { + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - } + var vec = pt2.clone().sub(pt1); + return vec.normalize(); }; -/************************************************************** - * Line - **************************************************************/ - -THREE.LineCurve = function ( v1, v2 ) { +THREE.Curve.prototype.getTangentAt = function ( u ) { - this.v1 = v1; - this.v2 = v2; + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); }; -THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.LineCurve.prototype.getPoint = function ( t ) { - 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 +/************************************************************** + * Utils + **************************************************************/ -THREE.LineCurve.prototype.getPointAt = function ( u ) { +THREE.Curve.Utils = { - return this.getPoint( u ); + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { -}; + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); -THREE.LineCurve.prototype.getTangent = function( t ) { + }, - var tangent = this.v2.clone().sub(this.v1); + // Puay Bing, thanks for helping with this derivative! - return tangent.normalize(); + tangentCubicBezier: function (t, p0, p1, p2, p3 ) { -}; -/************************************************************** - * Quadratic Bezier curve - **************************************************************/ + return - 3 * p0 * (1 - t) * (1 - t) + + 3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) + + 6 * t * p2 * (1 - t) - 3 * t * t * p2 + + 3 * t * t * p3; + }, -THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { + tangentSpline: function ( t, p0, p1, p2, p3 ) { - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + // To check if my formulas are correct -}; + var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 + var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t + var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2 + var h11 = 3 * t * t - 2 * t; // t3 − t2 -THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + return h00 + h10 + h01 + h11; + }, -THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { + // Catmull-Rom - var tx, ty; + interpolate: function( p0, p1, p2, p3, t ) { - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + 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; - return new THREE.Vector2( tx, ty ); + } }; -THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { +// TODO: Transformation for Curves? - var tx, ty; +/************************************************************** + * 3D Curves + **************************************************************/ - tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); +// A Factory method for creating new curve subclasses - // returns unit vector +THREE.Curve.create = function ( constructor, getPointFunc ) { - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.constructor = constructor; + constructor.prototype.getPoint = getPointFunc; - return tangent; + return constructor; }; + +// File:src/extras/core/CurvePath.js + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ + /************************************************************** - * Cubic Bezier curve + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve **************************************************************/ -THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; +THREE.CurvePath = function () { + this.curves = []; + this.bends = []; + + this.autoClose = false; // Automatically closes the path }; -THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); +THREE.CurvePath.prototype.constructor = THREE.CurvePath; - var tx, ty; +THREE.CurvePath.prototype.add = function ( curve ) { - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + this.curves.push( curve ); - return new THREE.Vector2( tx, ty ); +}; +THREE.CurvePath.prototype.checkConnection = function() { + // TODO + // If the ending of curve is not connected to the starting + // or the next curve, then, this is not a real path }; -THREE.CubicBezierCurve.prototype.getTangent = function( t ) { +THREE.CurvePath.prototype.closePath = function() { + // TODO Test + // and verify for vector3 (needs to implement equals) + // 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 THREE.LineCurve(endPoint, startPoint) ); + } + +}; - var tx, ty; +// To get accurate point with reference to +// entire path distance at time t, +// following has to be done: - tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); +// 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') - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); +THREE.CurvePath.prototype.getPoint = function( t ) { - return tangent; + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; -}; -/************************************************************** - * Spline curve - **************************************************************/ + // To think about boundaries points. -THREE.SplineCurve = function ( points /* array of Vector2 */ ) { + while ( i < curveLengths.length ) { - this.points = (points == undefined) ? [] : points; + if ( curveLengths[ i ] >= d ) { -}; + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; -THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); + var u = 1 - diff / curve.getLength(); -THREE.SplineCurve.prototype.getPoint = function ( t ) { + return curve.getPointAt( u ); - var v = new THREE.Vector2(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; + } - intPoint = Math.floor( point ); - weight = point - intPoint; + i ++; - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; + } - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + return null; - return v; + // loop where sum != 0, sum > d , sum+1 Math.PI * 2 ) deltaAngle -= Math.PI * 2; + // We use cache values if curves and cache array are same length - if ( this.aClockwise === true ) { + if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) { - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + return this.cacheLengths; - } else { + }; - angle = this.aStartAngle + t * deltaAngle; + // Get length of subsurve + // Push sums into cached array - } + var lengths = [], sums = 0; + var i, il = this.curves.length; - var tx = this.aX + this.xRadius * Math.cos( angle ); - var ty = this.aY + this.yRadius * Math.sin( angle ); + for ( i = 0; i < il; i ++ ) { - return new THREE.Vector2( tx, ty ); + sums += this.curves[ i ].getLength(); + lengths.push( sums ); -}; + } -/************************************************************** - * Arc curve - **************************************************************/ + this.cacheLengths = lengths; -THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + return lengths; - THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; -THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); -/************************************************************** - * Line3D - **************************************************************/ -THREE.LineCurve3 = THREE.Curve.create( - function ( v1, v2 ) { +// Returns min and max coordinates - this.v1 = v1; - this.v2 = v2; +THREE.CurvePath.prototype.getBoundingBox = function () { - }, + var points = this.getPoints(); - function ( t ) { + var maxX, maxY, maxZ; + var minX, minY, minZ; - var r = new THREE.Vector3(); + maxX = maxY = Number.NEGATIVE_INFINITY; + minX = minY = Number.POSITIVE_INFINITY; + var p, i, il, sum; - r.subVectors( this.v2, this.v1 ); // diff - r.multiplyScalar( t ); - r.add( this.v1 ); + var v3 = points[0] instanceof THREE.Vector3; - return r; + sum = v3 ? new THREE.Vector3() : new THREE.Vector2(); - } + for ( i = 0, il = points.length; i < il; i ++ ) { -); + p = points[ i ]; -/************************************************************** - * Quadratic Bezier 3D curve - **************************************************************/ + if ( p.x > maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; -THREE.QuadraticBezierCurve3 = THREE.Curve.create( + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; - function ( v0, v1, v2 ) { + if ( v3 ) { - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; - }, + } - function ( t ) { + sum.add( p ); - var tx, ty, tz; + } - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); + var ret = { - return new THREE.Vector3( tx, ty, tz ); + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY - } + }; -); -/************************************************************** - * Cubic Bezier 3D curve - **************************************************************/ + if ( v3 ) { -THREE.CubicBezierCurve3 = THREE.Curve.create( + ret.maxZ = maxZ; + ret.minZ = minZ; - function ( v0, v1, v2, v3 ) { + } - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + return ret; - }, +}; - function ( t ) { +/************************************************************** + * Create Geometries Helpers + **************************************************************/ - var tx, ty, tz; +/// Generate geometry from path points (for Line or Points objects) - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { - return new THREE.Vector3( tx, ty, tz ); + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); - } +}; -); -/************************************************************** - * Spline 3D curve - **************************************************************/ +// Generate geometry from equidistance sampling along the path +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { -THREE.SplineCurve3 = THREE.Curve.create( + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); - function ( points /* array of Vector3 */) { +}; - this.points = (points == undefined) ? [] : points; +THREE.CurvePath.prototype.createGeometry = function( points ) { - }, + var geometry = new THREE.Geometry(); - function ( t ) { + for ( var i = 0; i < points.length; i ++ ) { - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); - intPoint = Math.floor( point ); - weight = point - intPoint; + } - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + return geometry; - var pt0 = points[ c[0] ], - pt1 = points[ c[1] ], - pt2 = points[ c[2] ], - pt3 = points[ c[3] ]; +}; - v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); - v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); - v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); - return v; +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ - } +// Wrap path / Bend modifiers? -); +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + this.bends.push( bendpath ); -// THREE.SplineCurve3.prototype.getTangent = function(t) { -// var v = new THREE.Vector3(); -// var c = []; -// var points = this.points, point, intPoint, weight; -// point = ( points.length - 1 ) * t; +}; -// intPoint = Math.floor( point ); -// weight = point - intPoint; +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { -// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; -// c[ 1 ] = intPoint; -// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; -// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; -// var pt0 = points[ c[0] ], -// pt1 = points[ c[1] ], -// pt2 = points[ c[2] ], -// pt3 = points[ c[3] ]; + if ( ! bends ) { -// // t = weight; -// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); -// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); -// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); + bends = this.bends; -// return v; + } -// } -/************************************************************** - * Closed Spline 3D curve - **************************************************************/ + for ( i = 0, il = bends.length; i < il; i ++ ) { + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); -THREE.ClosedSplineCurve3 = THREE.Curve.create( + } - function ( points /* array of Vector3 */) { + return oldPts; - this.points = (points == undefined) ? [] : points; +}; - }, +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { - function ( t ) { + var oldPts = this.getSpacedPoints( segments ); - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 0 ) * t; - // This needs to be from 0-length +1 + var i, il; - intPoint = Math.floor( point ); - weight = point - intPoint; + if ( ! bends ) { - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - c[ 0 ] = ( intPoint - 1 ) % points.length; - c[ 1 ] = ( intPoint ) % points.length; - c[ 2 ] = ( intPoint + 1 ) % points.length; - c[ 3 ] = ( intPoint + 2 ) % points.length; + bends = this.bends; - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); - v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); + } - return v; + for ( i = 0, il = bends.length; i < il; i ++ ) { - } + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); -); -/** - * @author mikael emtinger / http://gomo.se/ - */ + } -THREE.AnimationHandler = ( function () { + return oldPts; - var playing = []; - var library = {}; - var that = {}; +}; + +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html - that.update = function ( deltaTimeMS ) { +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { - for ( var i = 0; i < playing.length; i ++ ) { + var bounds = this.getBoundingBox(); - playing[ i ].update( deltaTimeMS ); + var i, il, p, oldX, oldY, xNorm; - } + for ( i = 0, il = oldPts.length; i < il; i ++ ) { - }; + p = oldPts[ i ]; - that.addToUpdate = function ( animation ) { + oldX = p.x; + oldY = p.y; - if ( playing.indexOf( animation ) === -1 ) { + xNorm = oldX / bounds.maxX; - playing.push( animation ); + // If using actual distance, for length > path, requires line extrusions + //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance - } + xNorm = path.getUtoTmapping( xNorm, oldX ); - }; + // check for out of bounds? - that.removeFromUpdate = function ( animation ) { + var pathPt = path.getPoint( xNorm ); + var normal = path.getTangent( xNorm ); + normal.set( - normal.y, normal.x ).multiplyScalar( oldY ); - var index = playing.indexOf( animation ); + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; - if ( index !== -1 ) { + } - playing.splice( index, 1 ); + return oldPts; - } +}; - }; - that.add = function ( data ) { +// File:src/extras/core/Gyroscope.js - if ( library[ data.name ] !== undefined ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); +THREE.Gyroscope = function () { - } + THREE.Object3D.call( this ); - library[ data.name ] = data; - initData( data ); +}; - }; +THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Gyroscope.prototype.constructor = THREE.Gyroscope; - that.remove = function ( name ) { +THREE.Gyroscope.prototype.updateMatrixWorld = ( function () { - if ( library[ name ] === undefined ) { + var translationObject = new THREE.Vector3(); + var quaternionObject = new THREE.Quaternion(); + var scaleObject = new THREE.Vector3(); - console.log( "THREE.AnimationHandler.add: Warning! " + name + " doesn't exists in library. Doing nothing." ); + var translationWorld = new THREE.Vector3(); + var quaternionWorld = new THREE.Quaternion(); + var scaleWorld = new THREE.Vector3(); - } - - library[ name ] = undefined; + return function ( force ) { - }; + this.matrixAutoUpdate && this.updateMatrix(); - that.get = function ( name ) { + // update matrixWorld - if ( typeof name === "string" ) { + if ( this.matrixWorldNeedsUpdate || force ) { - if ( library[ name ] ) { + if ( this.parent ) { - return library[ name ]; + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - } else { + this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld ); + this.matrix.decompose( translationObject, quaternionObject, scaleObject ); - return null; + this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld ); - } - } else { + } else { - // todo: add simple tween library + this.matrixWorld.copy( this.matrix ); - } + } - }; - that.parse = function ( root ) { + this.matrixWorldNeedsUpdate = false; - // setup hierarchy + force = true; - var hierarchy = []; + } - if ( root instanceof THREE.SkinnedMesh ) { + // update children - for ( var b = 0; b < root.bones.length; b++ ) { + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - hierarchy.push( root.bones[ b ] ); + this.children[ i ].updateMatrixWorld( force ); - } + } - } else { + }; + +}() ); - parseRecurseHierarchy( root, hierarchy ); +// File:src/extras/core/Path.js - } +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ - return hierarchy; +THREE.Path = function ( points ) { - }; + THREE.CurvePath.call(this); - var parseRecurseHierarchy = function ( root, hierarchy ) { + this.actions = []; - hierarchy.push( root ); + if ( points ) { - for ( var c = 0; c < root.children.length; c++ ) - parseRecurseHierarchy( root.children[ c ], hierarchy ); + this.fromPoints( points ); - } + } - var initData = function ( data ) { +}; - if ( data.initialized === true ) - return; +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); +THREE.Path.prototype.constructor = THREE.Path; +THREE.PathActions = { - // loop through all keys + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve + BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve + CSPLINE_THRU: 'splineThru', // Catmull-rom spline + ARC: 'arc', // Circle + ELLIPSE: 'ellipse' +}; - for ( var h = 0; h < data.hierarchy.length; h ++ ) { +// TODO Clean up PATH API - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { +// Create path using straight lines to connect all points +// - vectors: array of Vector2 - // remove minus times +THREE.Path.prototype.fromPoints = function ( vectors ) { - if ( data.hierarchy[ h ].keys[ k ].time < 0 ) { + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - data.hierarchy[ h ].keys[ k ].time = 0; + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { - } + this.lineTo( vectors[ v ].x, vectors[ v ].y ); - // create quaternions + }; - if ( data.hierarchy[ h ].keys[ k ].rot !== undefined && - !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { +}; - var quat = data.hierarchy[ h ].keys[ k ].rot; - data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat ); +// startPath() endPath()? - } +THREE.Path.prototype.moveTo = function ( x, y ) { - } + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); - // prepare morph target keys +}; - if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { +THREE.Path.prototype.lineTo = function ( x, y ) { - // get all used + var args = Array.prototype.slice.call( arguments ); - var usedMorphTargets = {}; + var lastargs = this.actions[ this.actions.length - 1 ].args; - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); + this.curves.push( curve ); - var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; - usedMorphTargets[ morphTargetName ] = -1; + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); - } +}; - } +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { - data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; - // set all used on all frames + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); - var influences = {}; + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); - for ( var morphTargetName in usedMorphTargets ) { +}; - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { - if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { + var args = Array.prototype.slice.call( arguments ); - influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; - break; + var lastargs = this.actions[ this.actions.length - 1 ].args; - } + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - } + var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCP1x, aCP1y ), + new THREE.Vector2( aCP2x, aCP2y ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); - if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); - influences[ morphTargetName ] = 0; +}; - } +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { - } + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; - data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; +//--- + var npts = [ new THREE.Vector2( x0, y0 ) ]; + Array.prototype.push.apply( npts, pts ); - } + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); - } + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); +}; - // remove all keys that are on the same time +// FUTURE: Change the API or follow canvas API? - for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { - if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - data.hierarchy[ h ].keys.splice( k, 1 ); - k --; + this.absarc(aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - } + }; - } + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); + }; +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { - // set index + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + this.absellipse(aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); - data.hierarchy[ h ].keys[ k ].index = k; + }; - } - } +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { - data.initialized = true; + var args = Array.prototype.slice.call( arguments ); + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + this.curves.push( curve ); - }; + var lastPoint = curve.getPoint(1); + args.push(lastPoint.x); + args.push(lastPoint.y); + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); - // interpolation types + }; - that.LINEAR = 0; - that.CATMULLROM = 1; - that.CATMULLROM_FORWARD = 2; +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { - return that; + if ( ! divisions ) divisions = 40; -}() ); + var points = []; -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( var i = 0; i < divisions; i ++ ) { -THREE.Animation = function ( root, name ) { + points.push( this.getPoint( i / divisions ) ); - this.root = root; - this.data = THREE.AnimationHandler.get( name ); - this.hierarchy = THREE.AnimationHandler.parse( root ); + //if( !this.getPoint( i / divisions ) ) throw "DIE"; - this.currentTime = 0; - this.timeScale = 1; + } - this.isPlaying = false; - this.isPaused = true; - this.loop = true; + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } - this.interpolationType = THREE.AnimationHandler.LINEAR; + return points; }; -THREE.Animation.prototype.play = function ( startTime ) { - - this.currentTime = startTime !== undefined ? startTime : 0; +/* Return an array of vectors based on contour of the path */ - if ( this.isPlaying === false ) { +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { - this.isPlaying = true; + if (this.useSpacedPoints) { + console.log('tata'); + return this.getSpacedPoints( divisions, closedPath ); + } - this.reset(); - this.update( 0 ); + divisions = divisions || 12; - } + var points = []; - this.isPaused = false; + var i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; - THREE.AnimationHandler.addToUpdate( this ); + for ( i = 0, il = this.actions.length; i < il; i ++ ) { -}; + item = this.actions[ i ]; + action = item.action; + args = item.args; -THREE.Animation.prototype.pause = function() { + switch ( action ) { - if ( this.isPaused === true ) { + case THREE.PathActions.MOVE_TO: - THREE.AnimationHandler.addToUpdate( this ); + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - } else { + break; - THREE.AnimationHandler.removeFromUpdate( this ); + case THREE.PathActions.LINE_TO: - } + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - this.isPaused = !this.isPaused; + break; -}; + case THREE.PathActions.QUADRATIC_CURVE_TO: + cpx = args[ 2 ]; + cpy = args[ 3 ]; -THREE.Animation.prototype.stop = function() { + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; - this.isPlaying = false; - this.isPaused = false; - THREE.AnimationHandler.removeFromUpdate( this ); + if ( points.length > 0 ) { -}; + laste = points[ points.length - 1 ]; -THREE.Animation.prototype.reset = function () { + cpx0 = laste.x; + cpy0 = laste.y; - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + } else { - var object = this.hierarchy[ h ]; + laste = this.actions[ i - 1 ].args; - object.matrixAutoUpdate = true; + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - if ( object.animationCache === undefined ) { + } - object.animationCache = {}; - object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + for ( j = 1; j <= divisions; j ++ ) { - } + t = j / divisions; - var prevKey = object.animationCache.prevKey; - var nextKey = object.animationCache.nextKey; + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; + points.push( new THREE.Vector2( tx, ty ) ); - nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); - nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); - nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); + } - } + break; -}; + case THREE.PathActions.BEZIER_CURVE_TO: + cpx = args[ 4 ]; + cpy = args[ 5 ]; -THREE.Animation.prototype.update = (function(){ + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; - var points = []; - var target = new THREE.Vector3(); - - // Catmull-Rom spline + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; - var interpolateCatmullRom = function ( points, scale ) { + if ( points.length > 0 ) { - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; - - point = ( points.length - 1 ) * scale; - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - - pa = points[ c[ 0 ] ]; - pb = points[ c[ 1 ] ]; - pc = points[ c[ 2 ] ]; - pd = points[ c[ 3 ] ]; - - w2 = weight * weight; - w3 = weight * w2; - - v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); - v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); - v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); - - return v3; - - }; - - var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { - - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - }; - - return function ( delta ) { - if ( this.isPlaying === false ) return; - - this.currentTime += delta * this.timeScale; - - // - - var vector; - var types = [ "pos", "rot", "scl" ]; - - var duration = this.data.length; - - if ( this.loop === true && this.currentTime > duration ) { - - this.currentTime %= duration; - this.reset(); - - } else if ( this.loop === false && this.currentTime > duration ) { - - this.stop(); - return; - - } - - this.currentTime = Math.min( this.currentTime, duration ); - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - var animationCache = object.animationCache; - - // loop through pos/rot/scl - - for ( var t = 0; t < 3; t ++ ) { - - // get keys - - var type = types[ t ]; - var prevKey = animationCache.prevKey[ type ]; - var nextKey = animationCache.nextKey[ type ]; - - if ( nextKey.time <= this.currentTime ) { - - prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - nextKey = this.getNextKeyWith( type, h, 1 ); - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - - } - - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; - - } - - object.matrixAutoUpdate = true; - object.matrixWorldNeedsUpdate = true; - - var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - - var prevXYZ = prevKey[ type ]; - var nextXYZ = nextKey[ type ]; - - if ( scale < 0 ) scale = 0; - if ( scale > 1 ) scale = 1; - - // interpolate - - if ( type === "pos" ) { - - vector = object.position; - - if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; - points[ 1 ] = prevXYZ; - points[ 2 ] = nextXYZ; - points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; - - scale = scale * 0.33 + 0.33; - - var currentPoint = interpolateCatmullRom( points, scale ); - - vector.x = currentPoint[ 0 ]; - vector.y = currentPoint[ 1 ]; - vector.z = currentPoint[ 2 ]; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - - target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); - target.sub( vector ); - target.y = 0; - target.normalize(); - - var angle = Math.atan2( target.x, target.z ); - object.rotation.set( 0, angle, 0 ); - - } - - } - - } else if ( type === "rot" ) { - - THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); - - } else if ( type === "scl" ) { - - vector = object.scale; - - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - } - - } - - } - - }; - -})(); - - - - - -// Get next key with + laste = points[ points.length - 1 ]; -THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + cpx0 = laste.x; + cpy0 = laste.y; - var keys = this.data.hierarchy[ h ].keys; + } else { - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + laste = this.actions[ i - 1 ].args; - key = key < keys.length - 1 ? key : keys.length - 1; + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - } else { + } - key = key % keys.length; - } + for ( j = 1; j <= divisions; j ++ ) { - for ( ; key < keys.length; key++ ) { + t = j / divisions; - if ( keys[ key ][ type ] !== undefined ) { + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - return keys[ key ]; + points.push( new THREE.Vector2( tx, ty ) ); - } + } - } + break; - return this.data.hierarchy[ h ].keys[ 0 ]; + case THREE.PathActions.CSPLINE_THRU: -}; + laste = this.actions[ i - 1 ].args; -// Get previous key with + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; -THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + var n = divisions * args[ 0 ].length; - var keys = this.data.hierarchy[ h ].keys; + spts = spts.concat( args[ 0 ] ); - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + var spline = new THREE.SplineCurve( spts ); - key = key > 0 ? key : 0; + for ( j = 1; j <= n; j ++ ) { - } else { + points.push( spline.getPointAt( j / n ) ) ; - key = key >= 0 ? key : key + keys.length; + } - } + break; + case THREE.PathActions.ARC: - for ( ; key >= 0; key -- ) { + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !! args[ 5 ]; - if ( keys[ key ][ type ] !== undefined ) { + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; - return keys[ key ]; + for ( j = 1; j <= tdivisions; j ++ ) { - } + t = j / tdivisions; - } + if ( ! aClockwise ) { - return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; + t = 1 - t; -}; + } -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author khang duong - * @author erik kitson - */ + angle = aStartAngle + t * deltaAngle; -THREE.KeyFrameAnimation = function ( root, data ) { + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); - this.root = root; - this.data = THREE.AnimationHandler.get( data ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - this.currentTime = 0; - this.timeScale = 0.001; - this.isPlaying = false; - this.isPaused = true; - this.loop = true; + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - // initialize to first keyframes + points.push( new THREE.Vector2( tx, ty ) ); - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + } - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - obj = this.hierarchy[h]; + //console.log(points); - if ( keys.length && sids ) { + break; + + case THREE.PathActions.ELLIPSE: - for ( var s = 0; s < sids.length; s++ ) { + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !! args[ 6 ]; - var sid = sids[ s ], - next = this.getNextKeyWith( sid, h, 0 ); - if ( next ) { + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; - next.apply( sid ); + for ( j = 1; j <= tdivisions; j ++ ) { - } + t = j / tdivisions; - } + if ( ! aClockwise ) { - obj.matrixAutoUpdate = false; - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; + t = 1 - t; - } + } - } + angle = aStartAngle + t * deltaAngle; -}; + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); -// Play + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); -THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { + points.push( new THREE.Vector2( tx, ty ) ); - this.currentTime = startTime !== undefined ? startTime : 0; + } - if ( this.isPlaying === false ) { + //console.log(points); - this.isPlaying = true; + break; - // reset key cache + } // end switch - var h, hl = this.hierarchy.length, - object, - node; + } - for ( h = 0; h < hl; h++ ) { - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; - if ( node.animationCache === undefined ) { + // Normalize to remove the closing point by default. + var lastPoint = points[ points.length - 1]; + var EPSILON = 0.0000000001; + if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && + Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) + points.splice( points.length - 1, 1); + if ( closedPath ) { - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + points.push( points[ 0 ] ); - } + } - var keys = this.data.hierarchy[h].keys; + return points; - if (keys.length) { +}; - node.animationCache.prevKey = keys[ 0 ]; - node.animationCache.nextKey = keys[ 1 ]; +// +// Breaks path into shapes +// +// Assumptions (if parameter isCCW==true the opposite holds): +// - solid shapes are defined clockwise (CW) +// - holes are defined counterclockwise (CCW) +// +// If parameter noHoles==true: +// - all subPaths are regarded as solid shapes +// - definition order CW/CCW has no relevance +// - this.startTime = Math.min( keys[0].time, this.startTime ); - this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); +THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { - } + function extractSubpaths( inActions ) { - } + var i, il, item, action, args; - this.update( 0 ); + var subPaths = [], lastPath = new THREE.Path(); - } + for ( i = 0, il = inActions.length; i < il; i ++ ) { - this.isPaused = false; + item = inActions[ i ]; - THREE.AnimationHandler.addToUpdate( this ); + args = item.args; + action = item.action; -}; + if ( action == THREE.PathActions.MOVE_TO ) { + if ( lastPath.actions.length != 0 ) { + subPaths.push( lastPath ); + lastPath = new THREE.Path(); -// Pause + } -THREE.KeyFrameAnimation.prototype.pause = function() { + } - if( this.isPaused ) { + lastPath[ action ].apply( lastPath, args ); - THREE.AnimationHandler.addToUpdate( this ); + } - } else { + if ( lastPath.actions.length != 0 ) { - THREE.AnimationHandler.removeFromUpdate( this ); + subPaths.push( lastPath ); - } + } - this.isPaused = !this.isPaused; + // console.log(subPaths); -}; + return subPaths; + } + function toShapesNoHoles( inSubpaths ) { -// Stop + var shapes = []; -THREE.KeyFrameAnimation.prototype.stop = function() { + for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) { - this.isPlaying = false; - this.isPaused = false; + var tmpPath = inSubpaths[ i ]; - THREE.AnimationHandler.removeFromUpdate( this ); + var tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; - // reset JIT matrix and remove cache + shapes.push( tmpShape ); + } - for ( var h = 0; h < this.data.hierarchy.length; h++ ) { - - var obj = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; + //console.log("shape", shapes); - if ( node.animationCache !== undefined ) { + return shapes; + }; - var original = node.animationCache.originalMatrix; + function isPointInsidePolygon( inPt, inPolygon ) { + var EPSILON = 0.0000000001; - if( obj instanceof THREE.Bone ) { + var polyLen = inPolygon.length; - original.copy( obj.skinMatrix ); - obj.skinMatrix = original; + // 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 ]; - } else { + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; - original.copy( obj.matrix ); - obj.matrix = original; + if ( Math.abs(edgeDy) > 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 colinear + if ( inPt.y != edgeLowPt.y ) continue; // parallel + // egde 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; + } - delete node.animationCache; - } + var subPaths = extractSubpaths( this.actions ); + if ( subPaths.length == 0 ) return []; - } + if ( noHoles === true ) return toShapesNoHoles( subPaths ); -}; + var solid, tmpPath, tmpShape, shapes = []; -// Update + if ( subPaths.length == 1) { -THREE.KeyFrameAnimation.prototype.update = function ( delta ) { + tmpPath = subPaths[0]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - if ( this.isPlaying === false ) return; + } - this.currentTime += delta * this.timeScale; + var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - // + // console.log("Holes first", holesFirst); + + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; - var duration = this.data.length; + newShapes[mainIdx] = undefined; + newShapeHoles[mainIdx] = []; - if ( this.loop === true && this.currentTime > duration ) { + var i, il; - this.currentTime %= duration; + for ( i = 0, il = subPaths.length; i < il; i ++ ) { - } + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = THREE.Shape.Utils.isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; - this.currentTime = Math.min( this.currentTime, duration ); + if ( solid ) { - for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx ++; - var object = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; + newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; + newShapes[mainIdx].s.actions = tmpPath.actions; + newShapes[mainIdx].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx ++; + newShapeHoles[mainIdx] = []; - var keys = node.keys, - animationCache = node.animationCache; + //console.log('cw', i); + } else { - if ( keys.length ) { + newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); - var prevKey = animationCache.prevKey; - var nextKey = animationCache.nextKey; + //console.log('ccw', i); - if ( nextKey.time <= this.currentTime ) { + } - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + } - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[0] ) return toShapesNoHoles( subPaths ); - } - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; + if ( newShapes.length > 1 ) { + var ambigious = 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 { + ambigious = true; + } + } + } + if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } + } + } + // console.log("ambigious: ", ambigious); + if ( toChange.length > 0 ) { + // console.log("to change: ", toChange); + if (! ambigious) newShapeHoles = betterShapeHoles; + } + } + + var tmpHoles, j, jl; + for ( i = 0, il = newShapes.length; i < il; i ++ ) { + tmpShape = newShapes[i].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[i]; + for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + tmpShape.holes.push( tmpHoles[j].h ); + } + } - if ( nextKey.time >= this.currentTime ) { + //console.log("shape", shapes); - prevKey.interpolate( nextKey, this.currentTime ); + return shapes; - } else { +}; - prevKey.interpolate( nextKey, nextKey.time ); +// File:src/extras/core/Shape.js - } +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ - this.data.hierarchy[ h ].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; +// 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. - } +THREE.Shape = function () { - } + THREE.Path.apply( this, arguments ); + this.holes = []; }; -// Get next key with - -THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); +THREE.Shape.prototype.constructor = THREE.Shape; - var keys = this.data.hierarchy[ h ].keys; - key = key % keys.length; +// Convenience method to return ExtrudeGeometry - for ( ; key < keys.length; key++ ) { +THREE.Shape.prototype.extrude = function ( options ) { - if ( keys[ key ].hasTarget( sid ) ) { + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; - return keys[ key ]; +}; - } +// Convenience method to return ShapeGeometry - } +THREE.Shape.prototype.makeGeometry = function ( options ) { - return keys[ 0 ]; + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; }; -// Get previous key with +// Get points of holes + +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { -THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + var i, il = this.holes.length, holesPts = []; - var keys = this.data.hierarchy[ h ].keys; - key = key >= 0 ? key : key + keys.length; + for ( i = 0; i < il; i ++ ) { - for ( ; key >= 0; key-- ) { + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); - if ( keys[ key ].hasTarget( sid ) ) { + } - return keys[ key ]; + return holesPts; - } +}; - } +// Get points of holes (spaced by regular distance) - return keys[ keys.length - 1 ]; +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { -}; + var i, il = this.holes.length, holesPts = []; -/** - * @author mrdoob / http://mrdoob.com - */ + for ( i = 0; i < il; i ++ ) { -THREE.MorphAnimation = function ( mesh ) { + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); - this.mesh = mesh; - this.frames = mesh.morphTargetInfluences.length; - this.currentTime = 0; - this.duration = 1000; - this.loop = true; + } - this.isPlaying = false; + return holesPts; }; -THREE.MorphAnimation.prototype = { - play: function () { +// Get points of shape and holes (keypoints based on segments parameter) + +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { + + return { - this.isPlaying = true; + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) - }, + }; - pause: function () { +}; - this.isPlaying = false; - }, +THREE.Shape.prototype.extractPoints = function ( divisions ) { - update: ( function () { + if (this.useSpacedPoints) { + return this.extractAllSpacedPoints(divisions); + } - var lastFrame = 0; - var currentFrame = 0; + return this.extractAllPoints(divisions); - return function ( delta ) { +}; - if ( this.isPlaying === false ) return; +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; - this.currentTime += delta; +// Get points of shape and holes (spaced by regular distance) - if ( this.loop === true && this.currentTime > this.duration ) { +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { - this.currentTime %= this.duration; + return { - } + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) - this.currentTime = Math.min( this.currentTime, this.duration ); + }; - var interpolation = this.duration / this.frames; - var frame = Math.floor( this.currentTime / interpolation ); +}; - if ( frame != currentFrame ) { +/************************************************************** + * Utils + **************************************************************/ - this.mesh.morphTargetInfluences[ lastFrame ] = 0; - this.mesh.morphTargetInfluences[ currentFrame ] = 1; - this.mesh.morphTargetInfluences[ frame ] = 0; +THREE.Shape.Utils = { - lastFrame = currentFrame; - currentFrame = frame; + triangulateShape: function ( contour, holes ) { - } + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { + // inOtherPt needs to be colinear 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 ) ); + } + } + } - this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; - this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; + function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { + var EPSILON = 0.0000000001; - } + 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; -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ + if ( Math.abs(limit) > EPSILON ) { // not parallel -THREE.CubeCamera = function ( near, far, cubeResolution ) { + 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 []; + } - THREE.Object3D.call( this ); + // 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 colinear + if ( ( perpSeg1 != 0 ) || + ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; + + // they are collinear or degenerate + var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? + var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist 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 ]; + } - var fov = 90, aspect = 1; + // 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 ]; + } + } + } - var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPX.up.set( 0, -1, 0 ); - cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); + function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { + // The order of legs is important - var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, -1, 0 ); - cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); - this.add( cameraNX ); + var EPSILON = 0.0000000001; - var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); + // 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; - var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, -1 ); - cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); - this.add( cameraNY ); + // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. + var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; + var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, -1, 0 ); - cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); + if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg. - var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, -1, 0 ); - cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); - this.add( cameraNZ ); + var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; + // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); + 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 ); + } + } - this.updateCubeMap = function ( renderer, scene ) { - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.generateMipmaps; + function removeHoles( contour, holes ) { - renderTarget.generateMipmaps = false; + var shape = contour.concat(); // work on this shape + var hole; - renderTarget.activeCubeFace = 0; - renderer.render( scene, cameraPX, renderTarget ); + function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { + // Check if hole point lies within angle around shape point + var lastShapeIdx = shape.length - 1; - renderTarget.activeCubeFace = 1; - renderer.render( scene, cameraNX, renderTarget ); + var prevShapeIdx = inShapeIdx - 1; + if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; - renderTarget.activeCubeFace = 2; - renderer.render( scene, cameraPY, renderTarget ); + var nextShapeIdx = inShapeIdx + 1; + if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; - renderTarget.activeCubeFace = 3; - renderer.render( scene, cameraNY, renderTarget ); + 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; + } - renderTarget.activeCubeFace = 4; - renderer.render( scene, cameraPZ, renderTarget ); + // Check if shape point lies within angle around hole point + var lastHoleIdx = hole.length - 1; - renderTarget.generateMipmaps = generateMipmaps; + var prevHoleIdx = inHoleIdx - 1; + if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); + 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; + } -THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); + 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; + } -/** - * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog - * - * A general perpose camera, for setting FOV, Lens Focal Length, - * and switching between perspective and orthographic views easily. - * Use this only if you do not wish to manage - * both a Orthographic and Perspective Camera - * - */ + 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; -THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - THREE.Camera.call( this ); + indepHoles.push( h ); - this.fov = fov; + } - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; + 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; + } - // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects + // search for shape-vertex and hole-vertex, + // which can be connected without intersections + for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { - this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); - this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); + shapePt = shape[ shapeIndex ]; + holeIndex = - 1; - this.zoom = 1; + // search for hole which can be reached without intersections + for ( var h = 0; h < indepHoles.length; h ++ ) { + holeIdx = indepHoles[h]; - this.toPerspective(); + // prevent multiple checks + cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; + if ( failedCuts[cutKey] !== undefined ) continue; - var aspect = width/height; + 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); -THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); -THREE.CombinedCamera.prototype.toPerspective = function () { + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); - // Switches to the Perspective Camera + minShapeIndex = shapeIndex; - this.near = this.cameraP.near; - this.far = this.cameraP.far; + // Debug only, to show the selected cuts + // glob_CutLines.push( [ shapePt, holePt ] ); - this.cameraP.fov = this.fov / this.zoom ; + break; + } + if ( holeIndex >= 0 ) break; // hole-vertex found - this.cameraP.updateProjectionMatrix(); + failedCuts[cutKey] = true; // remember failure + } + if ( holeIndex >= 0 ) break; // hole-vertex found + } + } - this.projectionMatrix = this.cameraP.projectionMatrix; + return shape; /* shape with no holes */ + } - this.inPerspectiveMode = true; - this.inOrthographicMode = false; -}; + var i, il, f, face, + key, index, + allPointsMap = {}; -THREE.CombinedCamera.prototype.toOrthographic = function () { + // 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. - // Switches to the Orthographic camera estimating viewport from Perspective + var allpoints = contour.concat(); - var fov = this.fov; - var aspect = this.cameraP.aspect; - var near = this.cameraP.near; - var far = this.cameraP.far; + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - // The size that we set is the mid plane of the viewing frustum + Array.prototype.push.apply( allpoints, holes[h] ); - var hyperfocus = ( near + far ) / 2; + } - var halfHeight = Math.tan( fov / 2 ) * hyperfocus; - var planeHeight = 2 * halfHeight; - var planeWidth = planeHeight * aspect; - var halfWidth = planeWidth / 2; + //console.log( "allpoints",allpoints, allpoints.length ); - halfHeight /= this.zoom; - halfWidth /= this.zoom; + // prepare all points map - this.cameraO.left = -halfWidth; - this.cameraO.right = halfWidth; - this.cameraO.top = halfHeight; - this.cameraO.bottom = -halfHeight; + for ( i = 0, il = allpoints.length; i < il; i ++ ) { - // this.cameraO.left = -farHalfWidth; - // this.cameraO.right = farHalfWidth; - // this.cameraO.top = farHalfHeight; - // this.cameraO.bottom = -farHalfHeight; + key = allpoints[ i ].x + ":" + allpoints[ i ].y; - // this.cameraO.left = this.left / this.zoom; - // this.cameraO.right = this.right / this.zoom; - // this.cameraO.top = this.top / this.zoom; - // this.cameraO.bottom = this.bottom / this.zoom; + if ( allPointsMap[ key ] !== undefined ) { - this.cameraO.updateProjectionMatrix(); + THREE.warn( "THREE.Shape: Duplicate point", key ); - this.near = this.cameraO.near; - this.far = this.cameraO.far; - this.projectionMatrix = this.cameraO.projectionMatrix; + } - this.inPerspectiveMode = false; - this.inOrthographicMode = true; + allPointsMap[ key ] = i; -}; + } + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); -THREE.CombinedCamera.prototype.setSize = function( width, height ) { + var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape + //console.log( "triangles",triangles, triangles.length ); - this.cameraP.aspect = width / height; - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; + // check all face vertices against all points map -}; + for ( i = 0, il = triangles.length; i < il; i ++ ) { + face = triangles[ i ]; -THREE.CombinedCamera.prototype.setFov = function( fov ) { + for ( f = 0; f < 3; f ++ ) { - this.fov = fov; + key = face[ f ].x + ":" + face[ f ].y; - if ( this.inPerspectiveMode ) { + index = allPointsMap[ key ]; - this.toPerspective(); + if ( index !== undefined ) { - } else { + face[ f ] = index; - this.toOrthographic(); + } - } + } -}; + } -// For mantaining similar API with PerspectiveCamera + return triangles.concat(); -THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { + }, - if ( this.inPerspectiveMode ) { + isClockWise: function ( pts ) { - this.toPerspective(); + return THREE.FontUtils.Triangulate.area( pts ) < 0; - } else { + }, - this.toPerspective(); - this.toOrthographic(); + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve - } + // Quad Bezier Functions -}; + b2p0: function ( t, p ) { -/* -* Uses Focal Length (in mm) to estimate and set FOV -* 35mm (fullframe) camera is used if frame size is not specified; -* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html -*/ -THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { + var k = 1 - t; + return k * k * p; - if ( frameHeight === undefined ) frameHeight = 24; + }, - var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + b2p1: function ( t, p ) { - this.setFov( fov ); + return 2 * ( 1 - t ) * t * p; - return fov; -}; + }, + b2p2: function ( t, p ) { -THREE.CombinedCamera.prototype.setZoom = function( zoom ) { + return t * t * p; - this.zoom = zoom; + }, - if ( this.inPerspectiveMode ) { + b2: function ( t, p0, p1, p2 ) { - this.toPerspective(); + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); - } else { + }, - this.toOrthographic(); + // Cubic Bezier Functions - } + b3p0: function ( t, p ) { -}; + var k = 1 - t; + return k * k * k * p; -THREE.CombinedCamera.prototype.toFrontView = function() { + }, - this.rotation.x = 0; - this.rotation.y = 0; - this.rotation.z = 0; + b3p1: function ( t, p ) { - // should we be modifing the matrix instead? + var k = 1 - t; + return 3 * k * k * t * p; - this.rotationAutoUpdate = false; + }, -}; + b3p2: function ( t, p ) { -THREE.CombinedCamera.prototype.toBackView = function() { + var k = 1 - t; + return 3 * k * t * t * p; - this.rotation.x = 0; - this.rotation.y = Math.PI; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + }, -}; + b3p3: function ( t, p ) { -THREE.CombinedCamera.prototype.toLeftView = function() { + return t * t * t * p; - this.rotation.x = 0; - this.rotation.y = - Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + }, -}; + b3: function ( t, p0, p1, p2, p3 ) { -THREE.CombinedCamera.prototype.toRightView = function() { + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); - this.rotation.x = 0; - this.rotation.y = Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + } }; -THREE.CombinedCamera.prototype.toTopView = function() { - this.rotation.x = - Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; +// File:src/extras/curves/LineCurve.js -}; +/************************************************************** + * Line + **************************************************************/ -THREE.CombinedCamera.prototype.toBottomView = function() { +THREE.LineCurve = function ( v1, v2 ) { - this.rotation.x = Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + this.v1 = v1; + this.v2 = v2; }; -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as - */ +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.LineCurve.prototype.constructor = THREE.LineCurve; -THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { +THREE.LineCurve.prototype.getPoint = function ( t ) { - THREE.Geometry.call( this ); + var point = this.v2.clone().sub(this.v1); + point.multiplyScalar( t ).add( this.v1 ); - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; + return point; - this.widthSegments = widthSegments || 1; - this.heightSegments = heightSegments || 1; - this.depthSegments = depthSegments || 1; +}; - var scope = this; +// Line curve is linear, so we can overwrite default getPointAt - var width_half = width / 2; - var height_half = height / 2; - var depth_half = depth / 2; +THREE.LineCurve.prototype.getPointAt = function ( u ) { - buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px - buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx - buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py - buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny - buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz - buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz + return this.getPoint( u ); - function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { +}; - var w, ix, iy, - gridX = scope.widthSegments, - gridY = scope.heightSegments, - width_half = width / 2, - height_half = height / 2, - offset = scope.vertices.length; +THREE.LineCurve.prototype.getTangent = function( t ) { - if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + var tangent = this.v2.clone().sub(this.v1); - w = 'z'; + return tangent.normalize(); - } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { +}; - w = 'y'; - gridY = scope.depthSegments; +// File:src/extras/curves/QuadraticBezierCurve.js - } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ - w = 'x'; - gridX = scope.depthSegments; - } +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { - var gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY, - normal = new THREE.Vector3(); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - normal[ w ] = depth > 0 ? 1 : - 1; +}; - for ( iy = 0; iy < gridY1; iy ++ ) { +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; - for ( ix = 0; ix < gridX1; ix ++ ) { - var vector = new THREE.Vector3(); - vector[ u ] = ( ix * segment_width - width_half ) * udir; - vector[ v ] = ( iy * segment_height - height_half ) * vdir; - vector[ w ] = depth; +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { - scope.vertices.push( vector ); + var vector = new THREE.Vector2(); - } + vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - } + return vector; - 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; +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { - var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); + var vector = new THREE.Vector2(); - var face = new THREE.Face3( a + offset, b + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; + vector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + // returns unit vector - face = new THREE.Face3( b + offset, c + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; + return vector.normalize(); - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); +}; - } +// File:src/extras/curves/CubicBezierCurve.js - } +/************************************************************** + * Cubic Bezier curve + **************************************************************/ - } +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - this.mergeVertices(); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; }; -THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author hughes - * @author mrdoob / http://mrdoob.com/ - */ +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; -THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + var tx, ty; - radius = radius || 50; - segments = segments !== undefined ? Math.max( 3, segments ) : 8; + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + return new THREE.Vector2( tx, ty ); - // +}; - var elements = segments + 2; +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { - var indices = new Uint16Array( segments * 3 ); - var vertices = new Float32Array( elements * 3 ); - var normals = new Float32Array( elements * 3 ); - var uvs = new Float32Array( elements * 2 ); + var tx, ty; - // center + tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - normals[ 2 ] = 1; + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); - uvs[ 0 ] = 0.5; - uvs[ 1 ] = 0.5; + return tangent; - var offset = 0, offset2 = 2, offset3 = 3; +}; - for ( var i = 0; i <= segments; i ++ ) { +// File:src/extras/curves/SplineCurve.js - var segment = thetaStart + i / segments * thetaLength; +/************************************************************** + * Spline curve + **************************************************************/ - var x = radius * Math.cos( segment ); - var y = radius * Math.sin( segment ); +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - vertices[ offset3 ] = x; - vertices[ offset3 + 1 ] = y; + this.points = ( points == undefined ) ? [] : points; - normals[ offset3 + 2 ] = 1; +}; - uvs[ offset2 ] = ( x / radius + 1 ) / 2; - uvs[ offset2 + 1 ] = ( y / radius + 1 ) / 2; +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; - offset2 += 2; - offset3 += 3; +THREE.SplineCurve.prototype.getPoint = function ( t ) { - // + var points = this.points; + var point = ( points.length - 1 ) * t; - indices[ offset ] = 0; - indices[ offset + 1 ] = i + 1; - indices[ offset + 2 ] = i + 2; + var intPoint = Math.floor( point ); + var weight = point - intPoint; - offset += 3; + 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 ] - } + var vector = new THREE.Vector2(); - THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs ); + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + return vector; }; -THREE.CircleGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype ); - -// DEPRECATED - -THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - console.warn( 'DEPRECATED: THREE.CubeGeometry is deprecated. Use THREE.BoxGeometry instead.' ); - return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); - }; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { +// File:src/extras/curves/EllipseCurve.js - THREE.Geometry.call( this ); - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded - }; - - radiusTop = radiusTop !== undefined ? radiusTop : 20; - radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; - height = height !== undefined ? height : 100; - - radialSegments = radialSegments || 8; - heightSegments = heightSegments || 1; - - openEnded = openEnded !== undefined ? openEnded : false; - - var heightHalf = height / 2; +/************************************************************** + * Ellipse curve + **************************************************************/ - var x, y, vertices = [], uvs = []; +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { - for ( y = 0; y <= heightSegments; y ++ ) { + this.aX = aX; + this.aY = aY; - var verticesRow = []; - var uvsRow = []; + this.xRadius = xRadius; + this.yRadius = yRadius; - var v = y / heightSegments; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; - for ( x = 0; x <= radialSegments; x ++ ) { + this.aClockwise = aClockwise; - var u = x / radialSegments; +}; - var vertex = new THREE.Vector3(); - vertex.x = radius * Math.sin( u * Math.PI * 2 ); - vertex.y = - v * height + heightHalf; - vertex.z = radius * Math.cos( u * Math.PI * 2 ); +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; - this.vertices.push( vertex ); +THREE.EllipseCurve.prototype.getPoint = function ( t ) { - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + var deltaAngle = this.aEndAngle - this.aStartAngle; - } + if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; + if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; - vertices.push( verticesRow ); - uvs.push( uvsRow ); + var angle; - } + if ( this.aClockwise === true ) { - var tanTheta = ( radiusBottom - radiusTop ) / height; - var na, nb; + angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); - for ( x = 0; x < radialSegments; x ++ ) { + } else { - if ( radiusTop !== 0 ) { + angle = this.aStartAngle + t * deltaAngle; - na = this.vertices[ vertices[ 0 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); + } + + var vector = new THREE.Vector2(); - } else { + vector.x = this.aX + this.xRadius * Math.cos( angle ); + vector.y = this.aY + this.yRadius * Math.sin( angle ); - na = this.vertices[ vertices[ 1 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); + return vector; - } +}; - na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); - nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); +// File:src/extras/curves/ArcCurve.js - for ( y = 0; y < heightSegments; y ++ ) { +/************************************************************** + * Arc curve + **************************************************************/ - var v1 = vertices[ y ][ x ]; - var v2 = vertices[ y + 1 ][ x ]; - var v3 = vertices[ y + 1 ][ x + 1 ]; - var v4 = vertices[ y ][ x + 1 ]; +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - var n1 = na.clone(); - var n2 = na.clone(); - var n3 = nb.clone(); - var n4 = nb.clone(); + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +}; - var uv1 = uvs[ y ][ x ].clone(); - var uv2 = uvs[ y + 1 ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); - var uv4 = uvs[ y ][ x + 1 ].clone(); +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); +// File:src/extras/curves/LineCurve3.js - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); +/************************************************************** + * Line3D + **************************************************************/ - } +THREE.LineCurve3 = THREE.Curve.create( - } + function ( v1, v2 ) { - // top cap + this.v1 = v1; + this.v2 = v2; - if ( openEnded === false && radiusTop > 0 ) { + }, - this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); + function ( t ) { - for ( x = 0; x < radialSegments; x ++ ) { + var vector = new THREE.Vector3(); - var v1 = vertices[ 0 ][ x ]; - var v2 = vertices[ 0 ][ x + 1 ]; - var v3 = this.vertices.length - 1; + vector.subVectors( this.v2, this.v1 ); // diff + vector.multiplyScalar( t ); + vector.add( this.v1 ); - var n1 = new THREE.Vector3( 0, 1, 0 ); - var n2 = new THREE.Vector3( 0, 1, 0 ); - var n3 = new THREE.Vector3( 0, 1, 0 ); + return vector; - var uv1 = uvs[ 0 ][ x ].clone(); - var uv2 = uvs[ 0 ][ x + 1 ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 0 ); + } - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); +); - } +// File:src/extras/curves/QuadraticBezierCurve3.js - } +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ - // bottom cap +THREE.QuadraticBezierCurve3 = THREE.Curve.create( - if ( openEnded === false && radiusBottom > 0 ) { + function ( v0, v1, v2 ) { - this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - for ( x = 0; x < radialSegments; x ++ ) { + }, - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = this.vertices.length - 1; + function ( t ) { - var n1 = new THREE.Vector3( 0, - 1, 0 ); - var n2 = new THREE.Vector3( 0, - 1, 0 ); - var n3 = new THREE.Vector3( 0, - 1, 0 ); + var vector = new THREE.Vector3(); - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 1 ); + vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + vector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + return vector; - } + } - } +); - this.computeFaceNormals(); +// File:src/extras/curves/CubicBezierCurve3.js -} +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ -THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CubicBezierCurve3 = THREE.Curve.create( -/** - * @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 segements 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: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) - * frames: // containing arrays of tangents, normals, binormals - * - * material: // material index for front and back faces - * extrudeMaterial: // material index for extrusion and beveled faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ + function ( v0, v1, v2, v3 ) { -THREE.ExtrudeGeometry = function ( shapes, options ) { + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - if ( typeof( shapes ) === "undefined" ) { - shapes = []; - return; - } + }, - THREE.Geometry.call( this ); + function ( t ) { - shapes = shapes instanceof Array ? shapes : [ shapes ]; + var vector = new THREE.Vector3(); - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + vector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + vector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + vector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); - this.addShapeList( shapes, options ); + return vector; - 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(); +// File:src/extras/curves/SplineCurve3.js - //console.log( "took", ( Date.now() - startTime ) ); +/************************************************************** + * Spline 3D curve + **************************************************************/ -}; -THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.SplineCurve3 = THREE.Curve.create( -THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { - var sl = shapes.length; + function ( points /* array of Vector3 */) { - for ( var s = 0; s < sl; s ++ ) { - var shape = shapes[ s ]; - this.addShape( shape, options ); - } -}; + this.points = ( points == undefined ) ? [] : points; -THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + }, - var amount = options.amount !== undefined ? options.amount : 100; + function ( t ) { - 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 points = this.points; + var point = ( points.length - 1 ) * t; - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + var intPoint = Math.floor( point ); + var weight = point - intPoint; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + 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 ]; - var steps = options.steps !== undefined ? options.steps : 1; + var vector = new THREE.Vector3(); - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); + vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - var material = options.material; - var extrudeMaterial = options.extrudeMaterial; + return vector; - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + } - var shapebb = this.shapebb; - //shapebb = shape.getBoundingBox(); +); +// File:src/extras/curves/ClosedSplineCurve3.js +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ - var splineTube, binormal, normal, position2; - if ( extrudePath ) { - extrudePts = extrudePath.getSpacedPoints( steps ); +THREE.ClosedSplineCurve3 = THREE.Curve.create( - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + function ( points /* array of Vector3 */) { - // SETUP TNB variables + this.points = ( points == undefined ) ? [] : points; - // Reuse TNB from TubeGeomtry for now. - // TODO1 - have a .isClosed in spline? + }, - splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + function ( t ) { - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + var points = this.points; + var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 - binormal = new THREE.Vector3(); - normal = new THREE.Vector3(); - position2 = new THREE.Vector3(); + var intPoint = Math.floor( point ); + var weight = point - intPoint; - } + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - // Safeguards if bevels are not enabled + var point0 = points[ ( intPoint - 1 ) % points.length ]; + var point1 = points[ ( intPoint ) % points.length ]; + var point2 = points[ ( intPoint + 1 ) % points.length ]; + var point3 = points[ ( intPoint + 2 ) % points.length ]; - if ( ! bevelEnabled ) { + var vector = new THREE.Vector3(); - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); + vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - } + return vector; - // Variables initalization + } - var ahole, h, hl; // looping of holes - var scope = this; - var bevelPoints = []; +); - var shapesOffset = this.vertices.length; +// File:src/extras/animation/AnimationHandler.js - var shapePoints = shape.extractPoints( curveSegments ); +/** + * @author mikael emtinger / http://gomo.se/ + */ - var vertices = shapePoints.shape; - var holes = shapePoints.holes; +THREE.AnimationHandler = { - var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; + LINEAR: 0, + CATMULLROM: 1, + CATMULLROM_FORWARD: 2, - if ( reverse ) { + // - vertices = vertices.reverse(); + add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, + get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, + remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, - // 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 ++ ) { + animations: [], - ahole = holes[ h ]; + init: function ( data ) { - if ( THREE.Shape.Utils.isClockWise( ahole ) ) { + if ( data.initialized === true ) return data; - holes[ h ] = ahole.reverse(); + // loop through all keys - } + for ( var h = 0; h < data.hierarchy.length; h ++ ) { - } + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + // remove minus times - } + if ( data.hierarchy[ h ].keys[ k ].time < 0 ) { + data.hierarchy[ h ].keys[ k ].time = 0; - var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); + } - /* Vertices */ + // create quaternions - var contour = vertices; // vertices has all points but contour has only points of circumference + if ( data.hierarchy[ h ].keys[ k ].rot !== undefined && + ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + var quat = data.hierarchy[ h ].keys[ k ].rot; + data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat ); - ahole = holes[ h ]; + } - vertices = vertices.concat( ahole ); + } - } + // prepare morph target keys + if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { - function scalePt2 ( pt, vec, size ) { + // get all used - if ( !vec ) console.log( "die" ); + var usedMorphTargets = {}; - return vec.clone().multiplyScalar( size ).add( pt ); + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - } + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length, - cont, clen = contour.length; + var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; + usedMorphTargets[ morphTargetName ] = - 1; + } - // Find directions for point movement + } - var RAD_TO_DEGREES = 180 / Math.PI; + data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; - function getBevelVec( inPt, inPrev, inNext ) { + // set all used on all frames - var EPSILON = 0.0000000001; - var sign = THREE.Math.sign; - - // computes for inPt the corresponding point inPt' on a new contour - // shiftet 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 + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html + var influences = {}; - 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 colinear edges - var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear - - // 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 THREE.Vector2( v_trans_x, v_trans_y ); - } else { - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - } - - } else { // handle special case of colinear edges + for ( var morphTargetName in usedMorphTargets ) { - var direction_eq = false; // assumes: opposite - if ( v_prev_x > EPSILON ) { - if ( v_next_x > EPSILON ) { direction_eq = true; } - } else { - if ( v_prev_x < -EPSILON ) { - if ( v_next_x < -EPSILON ) { direction_eq = true; } - } else { - if ( sign(v_prev_y) == sign(v_next_y) ) { direction_eq = true; } - } - } + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - 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 ); - } + if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { - } + influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; + break; - return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + } - } + } + if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { - var contourMovements = []; + influences[ morphTargetName ] = 0; - 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) + data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; - var pt_i = contour[ i ]; - var pt_j = contour[ j ]; - var pt_k = contour[ k ]; + } - contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + } - } - var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + // remove all keys that are on the same time - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { - ahole = holes[ h ]; + if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { - oneHoleMovements = []; + data.hierarchy[ h ].keys.splice( k, 1 ); + k --; - 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 ] ); - } + // set index - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - } + data.hierarchy[ h ].keys[ k ].index = k; + } - // Loop bevelSegments, 1 for the front, 1 for the back + } - for ( b = 0; b < bevelSegments; b ++ ) { - //for ( b = bevelSegments; b > 0; b -- ) { + data.initialized = true; - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); + return data; - //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved - //bs = bevelSize * t ; // linear + }, - // contract shape + parse: function ( root ) { - for ( i = 0, il = contour.length; i < il; i ++ ) { + var parseRecurseHierarchy = function ( root, hierarchy ) { - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + hierarchy.push( root ); - v( vert.x, vert.y, - z ); + for ( var c = 0; c < root.children.length; c ++ ) + parseRecurseHierarchy( root.children[ c ], hierarchy ); - } + }; - // expand holes + // setup hierarchy - for ( h = 0, hl = holes.length; h < hl; h++ ) { + var hierarchy = []; - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + if ( root instanceof THREE.SkinnedMesh ) { - for ( i = 0, il = ahole.length; i < il; i++ ) { + for ( var b = 0; b < root.skeleton.bones.length; b ++ ) { - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + hierarchy.push( root.skeleton.bones[ b ] ); - v( vert.x, vert.y, -z ); + } - } + } else { - } + parseRecurseHierarchy( root, hierarchy ); - } + } - bs = bevelSize; + return hierarchy; - // Back facing vertices + }, - for ( i = 0; i < vlen; i ++ ) { + play: function ( animation ) { - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + if ( this.animations.indexOf( animation ) === - 1 ) { - if ( !extrudeByPath ) { + this.animations.push( animation ); - v( vert.x, vert.y, 0 ); + } - } else { + }, - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + stop: function ( animation ) { - normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); - binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); + var index = this.animations.indexOf( animation ); - position2.copy( extrudePts[0] ).add(normal).add(binormal); + if ( index !== - 1 ) { - v( position2.x, position2.y, position2.z ); + this.animations.splice( index, 1 ); - } + } - } + }, - // Add stepped vertices... - // Including front facing vertices + update: function ( deltaTimeMS ) { - var s; + for ( var i = 0; i < this.animations.length; i ++ ) { - for ( s = 1; s <= steps; s ++ ) { + this.animations[ i ].resetBlendWeights( ); - for ( i = 0; i < vlen; i ++ ) { + } - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + for ( var i = 0; i < this.animations.length; i ++ ) { - if ( !extrudeByPath ) { + this.animations[ i ].update( deltaTimeMS ); - 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 ); +// File:src/extras/animation/Animation.js - position2.copy( extrudePts[s] ).add( normal ).add( binormal ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - v( position2.x, position2.y, position2.z ); +THREE.Animation = function ( root, data ) { - } + this.root = root; + this.data = THREE.AnimationHandler.init( data ); + this.hierarchy = THREE.AnimationHandler.parse( root ); - } + this.currentTime = 0; + this.timeScale = 1; - } + this.isPlaying = false; + this.loop = true; + this.weight = 0; + this.interpolationType = THREE.AnimationHandler.LINEAR; - // Add bevel segments planes +}; - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { +THREE.Animation.prototype = { - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); - //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); - bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; + constructor: THREE.Animation, - // contract shape + keyTypes: [ "pos", "rot", "scl" ], - for ( i = 0, il = contour.length; i < il; i ++ ) { + play: function ( startTime, weight ) { - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); + this.currentTime = startTime !== undefined ? startTime : 0; + this.weight = weight !== undefined ? weight : 1; - } + this.isPlaying = true; - // expand holes + this.reset(); - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + THREE.AnimationHandler.play( this ); - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + }, - for ( i = 0, il = ahole.length; i < il; i ++ ) { + stop: function() { - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + this.isPlaying = false; - if ( !extrudeByPath ) { + THREE.AnimationHandler.stop( this ); - v( vert.x, vert.y, amount + z ); + }, - } else { + reset: function () { - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - } + var object = this.hierarchy[ h ]; - } + if ( object.animationCache === undefined ) { - } + object.animationCache = { + animations: {}, + blending: { + positionWeight: 0.0, + quaternionWeight: 0.0, + scaleWeight: 0.0 + } + }; + } - } + var name = this.data.name; + var animations = object.animationCache.animations; + var animationCache = animations[ name ]; - /* Faces */ + if ( animationCache === undefined ) { - // Top and bottom faces + animationCache = { + prevKey: { pos: 0, rot: 0, scl: 0 }, + nextKey: { pos: 0, rot: 0, scl: 0 }, + originalMatrix: object.matrix + }; - buildLidFaces(); + animations[ name ] = animationCache; - // Sides faces + } - buildSideFaces(); + // Get keys to match our current time + for ( var t = 0; t < 3; t ++ ) { - ///// Internal functions + var type = this.keyTypes[ t ]; - function buildLidFaces() { + var prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + var nextKey = this.getNextKeyWith( type, h, 1 ); - if ( bevelEnabled ) { + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - var layer = 0 ; // steps + 1 - var offset = vlen * layer; + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - // Bottom faces + } - for ( i = 0; i < flen; i ++ ) { + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; - face = faces[ i ]; - f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); + } - } + } - layer = steps + bevelSegments * 2; - offset = vlen * layer; + }, - // Top faces + resetBlendWeights: function () { - for ( i = 0; i < flen; i ++ ) { + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache; - } + if ( animationCache !== undefined ) { - } else { + var blending = animationCache.blending; - // Bottom faces + blending.positionWeight = 0.0; + blending.quaternionWeight = 0.0; + blending.scaleWeight = 0.0; - for ( i = 0; i < flen; i++ ) { + } - face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); + } - } + }, - // Top faces + update: ( function() { - for ( i = 0; i < flen; i ++ ) { + var points = []; + var target = new THREE.Vector3(); + var newVector = new THREE.Vector3(); + var newQuat = new THREE.Quaternion(); - face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); + // Catmull-Rom spline - } - } + var interpolateCatmullRom = function ( points, scale ) { - } + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; - // Create faces for the z-sides of the shape + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; - function buildSideFaces() { + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - var layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; + pa = points[ c[ 0 ] ]; + pb = points[ c[ 1 ] ]; + pc = points[ c[ 2 ] ]; + pd = points[ c[ 3 ] ]; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + w2 = weight * weight; + w3 = weight * w2; - ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); + v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); + v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); + v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); - //, true - layeroffset += ahole.length; + return v3; - } + }; - } + var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { - function sidewalls( contour, layeroffset ) { + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; - var j, k; - i = contour.length; + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - while ( --i >= 0 ) { + }; - j = i; - k = i - 1; - if ( k < 0 ) k = contour.length - 1; + return function ( delta ) { - //console.log('b', i,j, i-1, k,vertices.length); + if ( this.isPlaying === false ) return; - var s = 0, sl = steps + bevelSegments * 2; + this.currentTime += delta * this.timeScale; - for ( s = 0; s < sl; s ++ ) { + if ( this.weight === 0 ) + return; - 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; + var duration = this.data.length; - f4( a, b, c, d, contour, s, sl, j, k ); + if ( this.currentTime > duration || this.currentTime < 0 ) { - } - } + if ( this.loop ) { - } + this.currentTime %= duration; + if ( this.currentTime < 0 ) + this.currentTime += duration; - function v( x, y, z ) { + this.reset(); - scope.vertices.push( new THREE.Vector3( x, y, z ) ); + } else { - } + this.stop(); - function f3( a, b, c, isBottom ) { + } - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; + } - // normal, color, material - scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache.animations[this.data.name]; + var blending = object.animationCache.blending; - scope.faceVertexUvs[ 0 ].push( uvs ); + // loop through pos/rot/scl - } + for ( var t = 0; t < 3; t ++ ) { - function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + // get keys - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - d += shapesOffset; + var type = this.keyTypes[ t ]; + var prevKey = animationCache.prevKey[ type ]; + var nextKey = animationCache.nextKey[ type ]; - scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); - scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); + if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) || + ( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) { - var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, - stepIndex, stepsLength, contourIndex1, contourIndex2 ); + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - } + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); -}; + } -THREE.ExtrudeGeometry.WorldUVGenerator = { + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; - generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, + } - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, + var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y; + var prevXYZ = prevKey[ type ]; + var nextXYZ = nextKey[ type ]; - return [ - new THREE.Vector2( ax, ay ), - new THREE.Vector2( bx, by ), - new THREE.Vector2( cx, cy ) - ]; + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; - }, + // interpolate - generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + if ( type === "pos" ) { - return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - }, + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, - indexA, indexB, indexC, indexD, stepIndex, stepsLength, - contourIndex1, contourIndex2 ) { + // blend + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + object.position.lerp( newVector, proportionalWeight ); + blending.positionWeight += this.weight; - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, - az = geometry.vertices[ indexA ].z, + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, - bz = geometry.vertices[ indexB ].z, + points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; + points[ 1 ] = prevXYZ; + points[ 2 ] = nextXYZ; + points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y, - cz = geometry.vertices[ indexC ].z, + scale = scale * 0.33 + 0.33; - dx = geometry.vertices[ indexD ].x, - dy = geometry.vertices[ indexD ].y, - dz = geometry.vertices[ indexD ].z; + var currentPoint = interpolateCatmullRom( points, scale ); + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + blending.positionWeight += this.weight; - if ( Math.abs( ay - by ) < 0.01 ) { - return [ - new THREE.Vector2( ax, 1 - az ), - new THREE.Vector2( bx, 1 - bz ), - new THREE.Vector2( cx, 1 - cz ), - new THREE.Vector2( dx, 1 - dz ) - ]; - } else { - return [ - new THREE.Vector2( ay, 1 - az ), - new THREE.Vector2( by, 1 - bz ), - new THREE.Vector2( cy, 1 - cz ), - new THREE.Vector2( dy, 1 - dz ) - ]; - } - } -}; + // blend -THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); + var vector = object.position; -/** - * @author jonobr1 / http://jonobr1.com - * - * Creates a one-sided polygonal geometry from a path shape. Similar to - * ExtrudeGeometry. - * - * parameters = { - * - * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. - * - * material: // material index for front and back faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ + vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight; + vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight; + vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight; -THREE.ShapeGeometry = function ( shapes, options ) { + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - THREE.Geometry.call( this ); + var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - if ( shapes instanceof Array === false ) shapes = [ shapes ]; + target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + target.sub( vector ); + target.y = 0; + target.normalize(); - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + var angle = Math.atan2( target.x, target.z ); + object.rotation.set( 0, angle, 0 ); - this.addShapeList( shapes, options ); + } - this.computeFaceNormals(); + } -}; + } else if ( type === "rot" ) { -THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale ); -/** - * Add an array of shapes to THREE.ShapeGeometry. - */ -THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { + // Avoid paying the cost of an additional slerp if we don't have to + if ( blending.quaternionWeight === 0 ) { - for ( var i = 0, l = shapes.length; i < l; i++ ) { + object.quaternion.copy(newQuat); + blending.quaternionWeight = this.weight; - this.addShape( shapes[ i ], options ); + } else { - } + var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); + THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight ); + blending.quaternionWeight += this.weight; - return this; + } -}; + } else if ( type === "scl" ) { -/** - * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. - */ -THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - if ( options === undefined ) options = {}; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); + object.scale.lerp( newVector, proportionalWeight ); + blending.scaleWeight += this.weight; - var material = options.material; - var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; + } - var shapebb = this.shapebb; + } - // + } - var i, l, hole, s; + return true; - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints( curveSegments ); + }; - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + } )(), - var reverse = !THREE.Shape.Utils.isClockWise( vertices ); + getNextKeyWith: function ( type, h, key ) { - if ( reverse ) { + var keys = this.data.hierarchy[ h ].keys; - vertices = vertices.reverse(); + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - // Maybe we should also check if holes are in the opposite direction, just to be safe... + key = key < keys.length - 1 ? key : keys.length - 1; - for ( i = 0, l = holes.length; i < l; i++ ) { + } else { - hole = holes[ i ]; + key = key % keys.length; - if ( THREE.Shape.Utils.isClockWise( hole ) ) { + } - holes[ i ] = hole.reverse(); + for ( ; key < keys.length; key ++ ) { - } + if ( keys[ key ][ type ] !== undefined ) { - } + return keys[ key ]; - reverse = false; + } - } + } - var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); + return this.data.hierarchy[ h ].keys[ 0 ]; - // Vertices + }, - var contour = vertices; + getPrevKeyWith: function ( type, h, key ) { - for ( i = 0, l = holes.length; i < l; i++ ) { + var keys = this.data.hierarchy[ h ].keys; - hole = holes[ i ]; - vertices = vertices.concat( hole ); + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - } + key = key > 0 ? key : 0; - // + } else { - var vert, vlen = vertices.length; - var face, flen = faces.length; - var cont, clen = contour.length; + key = key >= 0 ? key : key + keys.length; - for ( i = 0; i < vlen; i++ ) { + } - vert = vertices[ i ]; - this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); + for ( ; key >= 0; key -- ) { - } + if ( keys[ key ][ type ] !== undefined ) { - for ( i = 0; i < flen; i++ ) { + return keys[ key ]; - face = faces[ i ]; + } - var a = face[ 0 ] + shapesOffset; - var b = face[ 1 ] + shapesOffset; - var c = face[ 2 ] + shapesOffset; + } - this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; - } + } }; +// File:src/extras/animation/KeyFrameAnimation.js + /** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://exocortex.com + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author khang duong + * @author erik kitson */ -// 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 2*PI) range of the lathed section -// 2*pi is a closed lathe, less than 2PI is a portion. -THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { +THREE.KeyFrameAnimation = function ( data ) { - THREE.Geometry.call( this ); + this.root = data.node; + this.data = THREE.AnimationHandler.init( data ); + this.hierarchy = THREE.AnimationHandler.parse( this.root ); + this.currentTime = 0; + this.timeScale = 0.001; + this.isPlaying = false; + this.isPaused = true; + this.loop = true; - segments = segments || 12; - phiStart = phiStart || 0; - phiLength = phiLength || 2 * Math.PI; + // initialize to first keyframes - var inversePointLength = 1.0 / ( points.length - 1 ); - var inverseSegments = 1.0 / segments; + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - for ( var i = 0, il = segments; i <= il; i ++ ) { + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + obj = this.hierarchy[h]; - var phi = phiStart + i * inverseSegments * phiLength; + if ( keys.length && sids ) { - var c = Math.cos( phi ), - s = Math.sin( phi ); + for ( var s = 0; s < sids.length; s ++ ) { - for ( var j = 0, jl = points.length; j < jl; j ++ ) { + var sid = sids[ s ], + next = this.getNextKeyWith( sid, h, 0 ); - var pt = points[ j ]; + if ( next ) { - var vertex = new THREE.Vector3(); + next.apply( sid ); - vertex.x = c * pt.x - s * pt.y; - vertex.y = s * pt.x + c * pt.y; - vertex.z = pt.z; + } - this.vertices.push( vertex ); + } - } + obj.matrixAutoUpdate = false; + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; - } + } - var np = points.length; + } - for ( var i = 0, il = segments; i < il; i ++ ) { +}; - for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { +THREE.KeyFrameAnimation.prototype = { - var base = j + np * i; - var a = base; - var b = base + np; - var c = base + 1 + np; - var d = base + 1; + constructor: THREE.KeyFrameAnimation, - var u0 = i * inverseSegments; - var v0 = j * inversePointLength; - var u1 = u0 + inverseSegments; - var v1 = v0 + inversePointLength; + play: function ( startTime ) { - this.faces.push( new THREE.Face3( a, b, d ) ); + this.currentTime = startTime !== undefined ? startTime : 0; - this.faceVertexUvs[ 0 ].push( [ + if ( this.isPlaying === false ) { - new THREE.Vector2( u0, v0 ), - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u0, v1 ) + this.isPlaying = true; - ] ); + // reset key cache - this.faces.push( new THREE.Face3( b, c, d ) ); + var h, hl = this.hierarchy.length, + object, + node; - this.faceVertexUvs[ 0 ].push( [ + for ( h = 0; h < hl; h ++ ) { - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u0, v1 ) + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; - ] ); + if ( node.animationCache === undefined ) { + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object.matrix; - } + } - } + var keys = this.data.hierarchy[h].keys; - this.mergeVertices(); - this.computeFaceNormals(); - this.computeVertexNormals(); + if (keys.length) { -}; + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; -THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); + this.startTime = Math.min( keys[0].time, this.startTime ); + this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ + } -THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { + } - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; + this.update( 0 ); - var width_half = width / 2; - var height_half = height / 2; + } - var gridX = widthSegments || 1; - var gridY = heightSegments || 1; + this.isPaused = false; - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; + THREE.AnimationHandler.play( this ); - var segment_width = width / gridX; - var segment_height = height / gridY; + }, - var vertices = new Float32Array( gridX1 * gridY1 * 3 ); - var normals = new Float32Array( gridX1 * gridY1 * 3 ); - var uvs = new Float32Array( gridX1 * gridY1 * 2 ); + stop: function () { - var offset = 0; - var offset2 = 0; + this.isPlaying = false; + this.isPaused = false; - for ( var iy = 0; iy < gridY1; iy ++ ) { + THREE.AnimationHandler.stop( this ); - var y = iy * segment_height - height_half; + // reset JIT matrix and remove cache - for ( var ix = 0; ix < gridX1; ix ++ ) { + for ( var h = 0; h < this.data.hierarchy.length; h ++ ) { - var x = ix * segment_width - width_half; + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; - vertices[ offset ] = x; - vertices[ offset + 1 ] = - y; + if ( node.animationCache !== undefined ) { - normals[ offset + 2 ] = 1; + var original = node.animationCache.originalMatrix; - uvs[ offset2 ] = ix / gridX; - uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); + original.copy( obj.matrix ); + obj.matrix = original; - offset += 3; - offset2 += 2; + delete node.animationCache; - } + } - } + } - offset = 0; + }, - var indices = new ( vertices.length > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); + update: function ( delta ) { - for ( var iy = 0; iy < gridY; iy ++ ) { + if ( this.isPlaying === false ) return; - for ( var ix = 0; ix < gridX; ix ++ ) { + this.currentTime += delta * this.timeScale; - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; + // - indices[ offset ] = a; - indices[ offset + 1 ] = b; - indices[ offset + 2 ] = d; + var duration = this.data.length; - indices[ offset + 3 ] = b; - indices[ offset + 4 ] = c; - indices[ offset + 5 ] = d; + if ( this.loop === true && this.currentTime > duration ) { - offset += 6; + this.currentTime %= duration; - } + } - } + this.currentTime = Math.min( this.currentTime, duration ); - THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs ); + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { -}; + var object = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; -THREE.PlaneGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype ); + var keys = node.keys, + animationCache = node.animationCache; -/** - * @author Kaleb Murphy - */ -THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + if ( keys.length ) { + + var prevKey = animationCache.prevKey; + var nextKey = animationCache.nextKey; - THREE.Geometry.call( this ); + if ( nextKey.time <= this.currentTime ) { - innerRadius = innerRadius || 0; - outerRadius = outerRadius || 50; + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8; + } - var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; - for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring + } + + if ( nextKey.time >= this.currentTime ) { - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + prevKey.interpolate( nextKey, this.currentTime ); - var vertex = new THREE.Vector3(); - var segment = thetaStart + o / thetaSegments * thetaLength; + } else { - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + prevKey.interpolate( nextKey, nextKey.time ); - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); - } + } - radius += radiusStep; + this.data.hierarchy[ h ].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; - } + } - var n = new THREE.Vector3( 0, 0, 1 ); + } - for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring + }, - var thetaSegment = i * thetaSegments; + getNextKeyWith: function ( sid, h, key ) { - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; - var segment = o + thetaSegment; + for ( ; key < keys.length; key ++ ) { - var v1 = segment + i; - var v2 = segment + thetaSegments + i; - var v3 = segment + thetaSegments + 1 + i; + if ( keys[ key ].hasTarget( sid ) ) { - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + return keys[ key ]; - v1 = segment + i; - v2 = segment + thetaSegments + 1 + i; - v3 = segment + 1 + i; + } - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + } - } - } + return keys[ 0 ]; - this.computeFaceNormals(); + }, - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + getPrevKeyWith: function ( sid, h, key ) { -}; + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; -THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); + for ( ; key >= 0; key -- ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + if ( keys[ key ].hasTarget( sid ) ) { -THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + return keys[ key ]; - THREE.Geometry.call( this ); + } - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } - radius = radius || 50; + return keys[ keys.length - 1 ]; - 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; +// File:src/extras/animation/MorphAnimation.js - var x, y, vertices = [], uvs = []; +/** + * @author mrdoob / http://mrdoob.com + * @author willy-vvu / http://willy-vvu.github.io + */ - for ( y = 0; y <= heightSegments; y ++ ) { +THREE.MorphAnimation = function ( mesh ) { - var verticesRow = []; - var uvsRow = []; + this.mesh = mesh; + this.frames = mesh.morphTargetInfluences.length; + this.currentTime = 0; + this.duration = 1000; + this.loop = true; + this.lastFrame = 0; + this.currentFrame = 0; - for ( x = 0; x <= widthSegments; x ++ ) { + this.isPlaying = false; - var u = x / widthSegments; - var v = y / heightSegments; +}; - var vertex = new THREE.Vector3(); - 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 ); +THREE.MorphAnimation.prototype = { - this.vertices.push( vertex ); + constructor: THREE.MorphAnimation, - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + play: function () { - } + this.isPlaying = true; - vertices.push( verticesRow ); - uvs.push( uvsRow ); + }, - } + pause: function () { - for ( y = 0; y < heightSegments; y ++ ) { + this.isPlaying = false; - for ( x = 0; x < widthSegments; x ++ ) { + }, - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = vertices[ y + 1 ][ x ]; - var v4 = vertices[ y + 1 ][ x + 1 ]; + update: function ( delta ) { - var n1 = this.vertices[ v1 ].clone().normalize(); - var n2 = this.vertices[ v2 ].clone().normalize(); - var n3 = this.vertices[ v3 ].clone().normalize(); - var n4 = this.vertices[ v4 ].clone().normalize(); + if ( this.isPlaying === false ) return; - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x ].clone(); - var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); + this.currentTime += delta; - if ( Math.abs( this.vertices[ v1 ].y ) === radius ) { + if ( this.loop === true && this.currentTime > this.duration ) { - uv1.x = ( uv1.x + uv2.x ) / 2; - this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); + this.currentTime %= this.duration; - } else if ( Math.abs( this.vertices[ v3 ].y ) === radius ) { + } - uv3.x = ( uv3.x + uv4.x ) / 2; - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + this.currentTime = Math.min( this.currentTime, this.duration ); - } else { + var interpolation = this.duration / this.frames; + var frame = Math.floor( this.currentTime / interpolation ); - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + var influences = this.mesh.morphTargetInfluences; - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + if ( frame != this.currentFrame ) { - } + influences[ this.lastFrame ] = 0; + influences[ this.currentFrame ] = 1; + influences[ frame ] = 0; - } + this.lastFrame = this.currentFrame; + this.currentFrame = frame; - } + } - this.computeFaceNormals(); + influences[ frame ] = ( this.currentTime % interpolation ) / interpolation; + influences[ this.lastFrame ] = 1 - influences[ frame ]; - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + } }; -THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); +// File:src/extras/geometries/BoxGeometry.js /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For creating 3D text geometry in three.js - * - * Text = 3D Text - * - * parameters = { - * size: , // size of the text - * height: , // thickness to extrude text - * curveSegments: , // number of points on the curves - * - * font: , // font name - * weight: , // font weight (normal, bold) - * style: , // font style (normal, italics) - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into text bevel goes - * bevelSize: , // how far from text outline is bevel - * } - * + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as */ -/* Usage Examples - - // TextGeometry wrapper - - var text3d = new TextGeometry( text, options ); - - // Complete manner +THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - var textShapes = THREE.FontUtils.generateShapes( text, options ); - var text3d = new ExtrudeGeometry( textShapes, options ); + THREE.Geometry.call( this ); -*/ + this.type = 'BoxGeometry'; + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; -THREE.TextGeometry = function ( text, parameters ) { + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; - parameters = parameters || {}; + var scope = this; - var textShapes = THREE.FontUtils.generateShapes( text, parameters ); + var width_half = width / 2; + var height_half = height / 2; + var depth_half = depth / 2; - // translate parameters to ExtrudeGeometry API + buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx + buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py + buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny + buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz + buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz - parameters.amount = parameters.height !== undefined ? parameters.height : 50; + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { - // defaults + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { - THREE.ExtrudeGeometry.call( this, textShapes, parameters ); + w = 'z'; -}; + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { -THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); + w = 'y'; + gridY = scope.depthSegments; -/** - * @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 - */ + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { -THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { + w = 'x'; + gridX = scope.depthSegments; - THREE.Geometry.call( this ); + } - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 8; - tubularSegments = tubularSegments || 6; - arc = arc || Math.PI * 2; + normal[ w ] = depth > 0 ? 1 : - 1; - var center = new THREE.Vector3(), uvs = [], normals = []; + for ( iy = 0; iy < gridY1; iy ++ ) { - for ( var j = 0; j <= radialSegments; j ++ ) { + for ( ix = 0; ix < gridX1; ix ++ ) { - for ( var i = 0; i <= tubularSegments; i ++ ) { + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; + scope.vertices.push( vector ); - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); + } - var vertex = new THREE.Vector3(); - 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 ); + } - this.vertices.push( vertex ); + for ( iy = 0; iy < gridY; iy ++ ) { - uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); - normals.push( vertex.clone().sub( center ).normalize() ); + 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; - } + var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); + var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); + var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); + var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); - for ( var j = 1; j <= radialSegments; j ++ ) { + var face = new THREE.Face3( a + offset, b + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; - for ( var i = 1; i <= tubularSegments; i ++ ) { + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - 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; + face = new THREE.Face3( b + offset, c + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; - var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); + } - } + } - } + } - this.computeFaceNormals(); + this.mergeVertices(); }; -THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; + +// File:src/extras/geometries/CircleGeometry.js /** - * @author oosmoxiecode - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 + * @author hughes */ -THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { - - THREE.Geometry.call( this ); +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - p: p, - q: q, - heightScale: heightScale - }; + THREE.Geometry.call( this ); - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 64; - tubularSegments = tubularSegments || 8; - p = p || 2; - q = q || 3; - heightScale = heightScale || 1; - - var grid = new Array( radialSegments ); - var tang = new THREE.Vector3(); - var n = new THREE.Vector3(); - var bitan = new THREE.Vector3(); + this.type = 'CircleGeometry'; - for ( var i = 0; i < radialSegments; ++ i ) { + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - grid[ i ] = new Array( tubularSegments ); - var u = i / radialSegments * 2 * p * Math.PI; - var p1 = getPos( u, q, p, radius, heightScale ); - var p2 = getPos( u + 0.01, q, p, radius, heightScale ); - tang.subVectors( p2, p1 ); - n.addVectors( p2, p1 ); + radius = radius || 50; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - bitan.crossVectors( tang, n ); - n.crossVectors( bitan, tang ); - bitan.normalize(); - n.normalize(); + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - for ( var j = 0; j < tubularSegments; ++ j ) { + var i, uvs = [], + center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); - var v = j / tubularSegments * 2 * Math.PI; - var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - var cy = tube * Math.sin( v ); + this.vertices.push(center); + uvs.push( centerUV ); - var pos = new THREE.Vector3(); - pos.x = p1.x + cx * n.x + cy * bitan.x; - pos.y = p1.y + cx * n.y + cy * bitan.y; - pos.z = p1.z + cx * n.z + cy * bitan.z; + for ( i = 0; i <= segments; i ++ ) { - grid[ i ][ j ] = this.vertices.push( pos ) - 1; + var vertex = new THREE.Vector3(); + var segment = thetaStart + i / segments * thetaLength; - } + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - } + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); - for ( var i = 0; i < radialSegments; ++ i ) { + } - for ( var j = 0; j < tubularSegments; ++ j ) { + var n = new THREE.Vector3( 0, 0, 1 ); - var ip = ( i + 1 ) % radialSegments; - var jp = ( j + 1 ) % tubularSegments; + for ( i = 1; i <= segments; i ++ ) { - var a = grid[ i ][ j ]; - var b = grid[ ip ][ j ]; - var c = grid[ ip ][ jp ]; - var d = grid[ i ][ jp ]; + this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); - var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); - var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); - var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); - var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); + } - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + this.computeFaceNormals(); - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - } - } +}; - this.computeFaceNormals(); - this.computeVertexNormals(); +THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; - function getPos( u, in_q, in_p, radius, heightScale ) { +// File:src/extras/geometries/CubeGeometry.js - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = in_q / in_p * u; - var cs = Math.cos( quOverP ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - var tx = radius * ( 2 + cs ) * 0.5 * cu; - var ty = radius * ( 2 + cs ) * su * 0.5; - var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; - return new THREE.Vector3( tx, ty, tz ); +THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - } + THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); + return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); -}; + }; -THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); +// File:src/extras/geometries/CylinderGeometry.js /** - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * - * Modified from the TorusKnotGeometry by @oosmoxiecode - * - * Creates a tube which extrudes along a 3d spline - * - * Uses parallel transport frames as described in - * http://www.cs.indiana.edu/pub/techreports/TR425.pdf + * @author mrdoob / http://mrdoob.com/ */ -THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed ) { - - THREE.Geometry.call( this ); +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - this.parameters = { - path: path, - segments: segments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + THREE.Geometry.call( this ); - segments = segments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; + this.type = 'CylinderGeometry'; - var grid = []; + 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; - tangent, - normal, - binormal, + radialSegments = radialSegments || 8; + heightSegments = heightSegments || 1; - numpoints = segments + 1, + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; - x, y, z, - tx, ty, tz, - u, v, + var heightHalf = height / 2; - cx, cy, - pos, pos2 = new THREE.Vector3(), - i, j, - ip, jp, - a, b, c, d, - uva, uvb, uvc, uvd; + var x, y, vertices = [], uvs = []; - var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), - tangents = frames.tangents, - normals = frames.normals, - binormals = frames.binormals; + for ( y = 0; y <= heightSegments; y ++ ) { - // proxy internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; + var verticesRow = []; + var uvsRow = []; - function vert( x, y, z ) { + var v = y / heightSegments; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + for ( x = 0; x <= radialSegments; x ++ ) { - } + var u = x / radialSegments; - // consruct the grid + var vertex = new THREE.Vector3(); + vertex.x = radius * Math.sin( u * thetaLength + thetaStart ); + vertex.y = - v * height + heightHalf; + vertex.z = radius * Math.cos( u * thetaLength + thetaStart ); - for ( i = 0; i < numpoints; i++ ) { + this.vertices.push( vertex ); - grid[ i ] = []; + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - u = i / ( numpoints - 1 ); - - pos = path.getPointAt( u ); + } - tangent = tangents[ i ]; - normal = normals[ i ]; - binormal = binormals[ i ]; + vertices.push( verticesRow ); + uvs.push( uvsRow ); - for ( j = 0; j < radialSegments; j++ ) { + } - v = j / radialSegments * 2 * Math.PI; + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; - cx = -radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - cy = radius * Math.sin( v ); + for ( x = 0; x < radialSegments; x ++ ) { - pos2.copy( pos ); - pos2.x += cx * normal.x + cy * binormal.x; - pos2.y += cx * normal.y + cy * binormal.y; - pos2.z += cx * normal.z + cy * binormal.z; + if ( radiusTop !== 0 ) { - grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - } - } + } else { + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); - // construct the mesh + } - for ( i = 0; i < segments; i++ ) { + na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); + nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); - for ( j = 0; j < radialSegments; j++ ) { + for ( y = 0; y < heightSegments; y ++ ) { - ip = ( closed ) ? (i + 1) % segments : i + 1; - jp = (j + 1) % radialSegments; + var v1 = vertices[ y ][ x ]; + var v2 = vertices[ y + 1 ][ x ]; + var v3 = vertices[ y + 1 ][ x + 1 ]; + var v4 = vertices[ y ][ x + 1 ]; - a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** - b = grid[ ip ][ j ]; - c = grid[ ip ][ jp ]; - d = grid[ i ][ jp ]; + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); - uva = new THREE.Vector2( i / segments, j / radialSegments ); - uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); - uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); - uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); + var uv1 = uvs[ y ][ x ].clone(); + var uv2 = uvs[ y + 1 ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); + var uv4 = uvs[ y ][ x + 1 ].clone(); - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - } - } + } - this.computeFaceNormals(); - this.computeVertexNormals(); + } -}; + // top cap -THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + if ( openEnded === false && radiusTop > 0 ) { + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); -// For computing of Frenet frames, exposing the tangents, normals and binormals the spline -THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { + for ( x = 0; x < radialSegments; x ++ ) { - var tangent = new THREE.Vector3(), - normal = new THREE.Vector3(), - binormal = new THREE.Vector3(), + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; - tangents = [], - normals = [], - binormals = [], + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); - vec = new THREE.Vector3(), - mat = new THREE.Matrix4(), + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 0 ); - numpoints = segments + 1, - theta, - epsilon = 0.0001, - smallest, + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - tx, ty, tz, - i, u, v; + } + } - // expose internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; + // bottom cap - // compute the tangent vectors for each segment on the path + if ( openEnded === false && radiusBottom > 0 ) { - for ( i = 0; i < numpoints; i++ ) { + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); - u = i / ( numpoints - 1 ); + for ( x = 0; x < radialSegments; x ++ ) { - tangents[ i ] = path.getTangentAt( u ); - tangents[ i ].normalize(); + var v1 = vertices[ heightSegments ][ x + 1 ]; + var v2 = vertices[ heightSegments ][ x ]; + var v3 = this.vertices.length - 1; - } + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); - initialNormal3(); + var uv1 = uvs[ heightSegments ][ x + 1 ].clone(); + var uv2 = uvs[ heightSegments ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 1 ); - function initialNormal1(lastBinormal) { - // fixed start binormal. Has dangers of 0 vectors - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); - normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - } + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - function initialNormal2() { + } - // This uses the Frenet-Serret formula for deriving binormal - var t2 = path.getTangentAt( epsilon ); + } - normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); - binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + this.computeFaceNormals(); - normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); +}; - } +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry; - function initialNormal3() { - // select an initial normal vector perpenicular to the first tangent vector, - // and in the direction of the smallest tangent xyz component +// File:src/extras/geometries/ExtrudeGeometry.js - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - smallest = Number.MAX_VALUE; - tx = Math.abs( tangents[ 0 ].x ); - ty = Math.abs( tangents[ 0 ].y ); - tz = Math.abs( tangents[ 0 ].z ); +/** + * @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 segements 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: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) + * frames: // containing arrays of tangents, normals, binormals + * + * material: // material index for front and back faces + * extrudeMaterial: // material index for extrusion and beveled faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ - if ( tx <= smallest ) { - smallest = tx; - normal.set( 1, 0, 0 ); - } +THREE.ExtrudeGeometry = function ( shapes, options ) { - if ( ty <= smallest ) { - smallest = ty; - normal.set( 0, 1, 0 ); - } + if ( typeof( shapes ) === "undefined" ) { + shapes = []; + return; + } - if ( tz <= smallest ) { - normal.set( 0, 0, 1 ); - } + THREE.Geometry.call( this ); - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + this.type = 'ExtrudeGeometry'; - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - } + shapes = shapes instanceof Array ? shapes : [ shapes ]; + this.addShapeList( shapes, options ); - // compute the slowly-varying normal and binormal vectors for each segment on the path + this.computeFaceNormals(); - for ( i = 1; i < numpoints; i++ ) { + // can't really use automatic vertex normals + // as then front and back sides get smoothed too + // should do separate smoothing just for sides - normals[ i ] = normals[ i-1 ].clone(); + //this.computeVertexNormals(); - binormals[ i ] = binormals[ i-1 ].clone(); + //console.log( "took", ( Date.now() - startTime ) ); - vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); +}; - if ( vec.length() > epsilon ) { +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; - vec.normalize(); +THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + var sl = shapes.length; - theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors + for ( var s = 0; s < sl; s ++ ) { + var shape = shapes[ s ]; + this.addShape( shape, options ); + } +}; - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); +THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { - } + var amount = options.amount !== undefined ? options.amount : 100; - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + 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; - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + var steps = options.steps !== undefined ? options.steps : 1; - if ( closed ) { + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); - theta /= ( numpoints - 1 ); + var material = options.material; + var extrudeMaterial = options.extrudeMaterial; - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; - theta = -theta; + var splineTube, binormal, normal, position2; + if ( extrudePath ) { - } + extrudePts = extrudePath.getSpacedPoints( steps ); - for ( i = 1; i < numpoints; i++ ) { + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + // SETUP TNB variables - } + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? - } -}; + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley -*/ + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); -THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); - THREE.Geometry.call( this ); + } - radius = radius || 1; - detail = detail || 0; + // Safeguards if bevels are not enabled - var that = this; + if ( ! bevelEnabled ) { - for ( var i = 0, l = vertices.length; i < l; i += 3 ) { + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; - prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); + } - } + // Variables initalization - var midpoints = [], p = this.vertices; + var ahole, h, hl; // looping of holes + var scope = this; - var faces = []; + var shapesOffset = this.vertices.length; - for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { + var shapePoints = shape.extractPoints( curveSegments ); - var v1 = p[ indices[ i ] ]; - var v2 = p[ indices[ i + 1 ] ]; - var v3 = p[ indices[ i + 2 ] ]; + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ) ; - } + if ( reverse ) { - var centroid = new THREE.Vector3(); + vertices = vertices.reverse(); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + // Maybe we should also check if holes are in the opposite direction, just to be safe ... - subdivide( faces[ i ], detail ); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - } + ahole = holes[ h ]; + if ( THREE.Shape.Utils.isClockWise( ahole ) ) { - // Handle case when face straddles the seam + holes[ h ] = ahole.reverse(); - for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { + } - var uvs = this.faceVertexUvs[ 0 ][ i ]; + } - var x0 = uvs[ 0 ].x; - var x1 = uvs[ 1 ].x; - var x2 = uvs[ 2 ].x; + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + + } + + + var faces = THREE.Shape.Utils.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 ) THREE.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 ) { + + var EPSILON = 0.0000000001; + + // computes for inPt the corresponding point inPt' on a new contour + // shiftet 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 colinear edges + var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear + + // 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 THREE.Vector2( v_trans_x, v_trans_y ); + } else { + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + } + + } else { // handle special case of colinear edges + + var direction_eq = false; // assumes: opposite + if ( v_prev_x > EPSILON ) { + if ( v_next_x > EPSILON ) { direction_eq = true; } + } else { + if ( v_prev_x < - EPSILON ) { + if ( v_next_x < - 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 ); + } - var max = Math.max( x0, Math.max( x1, x2 ) ); - var min = Math.min( x0, Math.min( x1, x2 ) ); + } - if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary + return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - if ( x0 < 0.2 ) uvs[ 0 ].x += 1; - if ( x1 < 0.2 ) uvs[ 1 ].x += 1; - if ( x2 < 0.2 ) uvs[ 2 ].x += 1; + } - } - } + var contourMovements = []; + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - // Apply radius + if ( j === il ) j = 0; + if ( k === il ) k = 0; - for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - this.vertices[ i ].multiplyScalar( radius ); + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - } + } + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); - // Merge vertices + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - this.mergeVertices(); + ahole = holes[ h ]; - this.computeFaceNormals(); + oneHoleMovements = []; - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + 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; - // Project vector onto sphere's surface + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - function prepare( vector ) { + } - var vertex = vector.normalize().clone(); - vertex.index = that.vertices.push( vertex ) - 1; + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); - // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + } - var u = azimuth( vector ) / 2 / Math.PI + 0.5; - var v = inclination( vector ) / Math.PI + 0.5; - vertex.uv = new THREE.Vector2( u, 1 - v ); - return vertex; + // Loop bevelSegments, 1 for the front, 1 for the back - } + for ( b = 0; b < bevelSegments; b ++ ) { + //for ( b = bevelSegments; b > 0; b -- ) { + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); - // Approximate a curved face with recursively sub-divided triangles. + //z = bevelThickness * t; + bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ) ; // curved + //bs = bevelSize * t ; // linear - function make( v1, v2, v3 ) { + // contract shape - var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - that.faces.push( face ); + for ( i = 0, il = contour.length; i < il; i ++ ) { - centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - var azi = azimuth( centroid ); + v( vert.x, vert.y, - z ); - that.faceVertexUvs[ 0 ].push( [ - correctUV( v1.uv, v1, azi ), - correctUV( v2.uv, v2, azi ), - correctUV( v3.uv, v3, azi ) - ] ); + } - } + // expand holes + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - // Analytically subdivide a face to the required detail level. + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - function subdivide( face, detail ) { + for ( i = 0, il = ahole.length; i < il; i ++ ) { - var cols = Math.pow(2, detail); - var cells = Math.pow(4, detail); - var a = prepare( that.vertices[ face.a ] ); - var b = prepare( that.vertices[ face.b ] ); - var c = prepare( that.vertices[ face.c ] ); - var v = []; + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - // Construct all of the vertices for this subdivision. + v( vert.x, vert.y, - z ); - for ( var i = 0 ; i <= cols; i ++ ) { + } - v[ i ] = []; + } - var aj = prepare( a.clone().lerp( c, i / cols ) ); - var bj = prepare( b.clone().lerp( c, i / cols ) ); - var rows = cols - i; + } - for ( var j = 0; j <= rows; j ++) { + bs = bevelSize; - if ( j == 0 && i == cols ) { + // Back facing vertices - v[ i ][ j ] = aj; + for ( i = 0; i < vlen; i ++ ) { - } else { + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); + if ( ! extrudeByPath ) { - } + v( vert.x, vert.y, 0 ); - } + } else { - } + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - // Construct all of the faces. + normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); + binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); - for ( var i = 0; i < cols ; i ++ ) { + position2.copy( extrudePts[0] ).add(normal).add(binormal); - for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { + v( position2.x, position2.y, position2.z ); - var k = Math.floor( j / 2 ); + } - if ( j % 2 == 0 ) { + } - make( - v[ i ][ k + 1], - v[ i + 1 ][ k ], - v[ i ][ k ] - ); + // Add stepped vertices... + // Including front facing vertices - } else { + var s; - make( - v[ i ][ k + 1 ], - v[ i + 1][ k + 1], - v[ i + 1 ][ k ] - ); + 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 { - // Angle around the Y axis, counter-clockwise when looking from above. + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - function azimuth( vector ) { + normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); - return Math.atan2( vector.z, -vector.x ); + position2.copy( extrudePts[s] ).add( normal ).add( binormal ); - } + v( position2.x, position2.y, position2.z ); + } - // Angle above the XZ plane. + } - function inclination( vector ) { + } - return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - } + // Add bevel segments planes + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { - // Texture fixing helper. Spheres have some odd behaviours. + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); + bs = bevelSize * Math.sin ( t * Math.PI / 2 ) ; - function correctUV( uv, vector, azimuth ) { + // contract shape - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); - return uv.clone(); + 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 -THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { -/** - * @author timothypratley / https://github.com/timothypratley - */ + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; -THREE.IcosahedronGeometry = function ( radius, detail ) { + for ( i = 0, il = ahole.length; i < il; i ++ ) { - this.parameters = { - radius: radius, - detail: detail - }; + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - var t = ( 1 + Math.sqrt( 5 ) ) / 2; + if ( ! extrudeByPath ) { - 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 - ]; + v( vert.x, vert.y, amount + z ); - 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 - ]; + } else { - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); -}; + } -THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + } -/** - * @author timothypratley / https://github.com/timothypratley - */ + } -THREE.OctahedronGeometry = function ( radius, detail ) { + } - this.parameters = { - radius: radius, - detail: detail - }; + /* Faces */ - var vertices = [ - 1, 0, 0, -1, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 1, 0, 0,-1 - ]; + // Top and bottom faces - 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 - ]; + buildLidFaces(); - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); -}; + // Sides faces -THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + buildSideFaces(); -/** - * @author timothypratley / https://github.com/timothypratley - */ -THREE.TetrahedronGeometry = function ( radius, detail ) { + ///// Internal functions - var vertices = [ - 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1 - ]; + function buildLidFaces() { - var indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; + if ( bevelEnabled ) { - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); + var layer = 0 ; // steps + 1 + var offset = vlen * layer; -}; + // Bottom faces -THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + for ( i = 0; i < flen; i ++ ) { -/** - * @author zz85 / https://github.com/zz85 - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - * - * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); - * - */ + face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); -THREE.ParametricGeometry = function ( func, slices, stacks ) { + } - THREE.Geometry.call( this ); + layer = steps + bevelSegments * 2; + offset = vlen * layer; - var verts = this.vertices; - var faces = this.faces; - var uvs = this.faceVertexUvs[ 0 ]; + // Top faces - var i, il, j, p; - var u, v; + for ( i = 0; i < flen; i ++ ) { - var stackCount = stacks + 1; - var sliceCount = slices + 1; + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - for ( i = 0; i <= stacks; i ++ ) { + } - v = i / stacks; + } else { - for ( j = 0; j <= slices; j ++ ) { + // Bottom faces - u = j / slices; + for ( i = 0; i < flen; i ++ ) { - p = func( u, v ); - verts.push( p ); + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - } - } + } - var a, b, c, d; - var uva, uvb, uvc, uvd; + // Top faces - for ( i = 0; i < stacks; i ++ ) { + for ( i = 0; i < flen; i ++ ) { - for ( j = 0; j < slices; j ++ ) { + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - a = i * sliceCount + j; - b = i * sliceCount + j + 1; - c = (i + 1) * sliceCount + j + 1; - d = (i + 1) * sliceCount + j; + } + } - uva = new THREE.Vector2( j / slices, i / stacks ); - uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); - uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); - uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); + } - faces.push( new THREE.Face3( a, b, d ) ); - uvs.push( [ uva, uvb, uvd ] ); + // Create faces for the z-sides of the shape - faces.push( new THREE.Face3( b, c, d ) ); - uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); + function buildSideFaces() { - } + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - // console.log(this); + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); - // magic bullet - // var diff = this.mergeVertices(); - // console.log('removed ', diff, ' vertices by merging'); + //, true + layeroffset += ahole.length; - this.computeFaceNormals(); - this.computeVertexNormals(); + } -}; + } -THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); + function sidewalls( contour, layeroffset ) { -/** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ + var j, k; + i = contour.length; -THREE.AxisHelper = function ( size ) { + while ( -- i >= 0 ) { - size = size || 1; + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; - var geometry = new THREE.Geometry(); + //console.log('b', i,j, i-1, k,vertices.length); - geometry.vertices.push( - new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) - ); + var s = 0, sl = steps + bevelSegments * 2; - geometry.colors.push( - new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), - new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), - new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) - ); + for ( s = 0; s < sl; s ++ ) { - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); - THREE.Line.call( this, geometry, material, THREE.LinePieces ); + 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 ); -THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); + } + } -/** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 - * @author bhouston / http://exocortex.com - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * hex - color in hex value - * headLength - Number - * headWidth - Number - */ + } -THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) { - // dir is assumed to be normalized + function v( x, y, z ) { - THREE.Object3D.call( this ); + scope.vertices.push( new THREE.Vector3( x, y, z ) ); - if ( hex === undefined ) hex = 0xffff00; - if ( length === undefined ) length = 1; - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; + } - this.position = origin; + function f3( a, b, c ) { - var lineGeometry = new THREE.Geometry(); - lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); - lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; - this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); + // normal, color, material + scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); - coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); + var uvs = uvgen.generateTopUV( scope, a, b, c ); - this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); + scope.faceVertexUvs[ 0 ].push( uvs ); - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); + } -}; + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { -THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; -THREE.ArrowHelper.prototype.setDirection = function () { + scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); + scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); - var axis = new THREE.Vector3(); - var radians; + var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); - return function ( dir ) { + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); - // dir is assumed to be normalized + } - if ( dir.y > 0.99999 ) { +}; - this.quaternion.set( 0, 0, 0, 1 ); +THREE.ExtrudeGeometry.WorldUVGenerator = { - } else if ( dir.y < - 0.99999 ) { + generateTopUV: function ( geometry, indexA, indexB, indexC ) { + + var vertices = geometry.vertices; + + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; + + return [ + new THREE.Vector2( a.x, a.y ), + new THREE.Vector2( b.x, b.y ), + new THREE.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 THREE.Vector2( a.x, 1 - a.z ), + new THREE.Vector2( b.x, 1 - b.z ), + new THREE.Vector2( c.x, 1 - c.z ), + new THREE.Vector2( d.x, 1 - d.z ) + ]; + } else { + return [ + new THREE.Vector2( a.y, 1 - a.z ), + new THREE.Vector2( b.y, 1 - b.z ), + new THREE.Vector2( c.y, 1 - c.z ), + new THREE.Vector2( d.y, 1 - d.z ) + ]; + } + } +}; - this.quaternion.set( 1, 0, 0, 0 ); +// File:src/extras/geometries/ShapeGeometry.js - } else { +/** + * @author jonobr1 / http://jonobr1.com + * + * Creates a one-sided polygonal geometry from a path shape. Similar to + * ExtrudeGeometry. + * + * parameters = { + * + * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. + * + * material: // material index for front and back faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ - axis.set( dir.z, 0, - dir.x ).normalize(); +THREE.ShapeGeometry = function ( shapes, options ) { - radians = Math.acos( dir.y ); + THREE.Geometry.call( this ); - this.quaternion.setFromAxisAngle( axis, radians ); + this.type = 'ShapeGeometry'; - } + if ( shapes instanceof Array === false ) shapes = [ shapes ]; - }; + this.addShapeList( shapes, options ); -}(); + this.computeFaceNormals(); -THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { +}; - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry; - this.line.scale.set( 1, length, 1 ); - this.line.updateMatrix(); +/** + * Add an array of shapes to THREE.ShapeGeometry. + */ +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); + for ( var i = 0, l = shapes.length; i < l; i ++ ) { -}; + this.addShape( shapes[ i ], options ); -THREE.ArrowHelper.prototype.setColor = function ( hex ) { + } - this.line.material.color.setHex( hex ); - this.cone.material.color.setHex( hex ); + return this; }; /** - * @author mrdoob / http://mrdoob.com/ + * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. */ +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { -THREE.BoxHelper = function ( object ) { - - // 5____4 - // 1/___0/| - // | 6__|_7 - // 2/___3/ - - var vertices = [ - new THREE.Vector3( 1, 1, 1 ), - new THREE.Vector3( - 1, 1, 1 ), - new THREE.Vector3( - 1, - 1, 1 ), - new THREE.Vector3( 1, - 1, 1 ), - - new THREE.Vector3( 1, 1, - 1 ), - new THREE.Vector3( - 1, 1, - 1 ), - new THREE.Vector3( - 1, - 1, - 1 ), - new THREE.Vector3( 1, - 1, - 1 ) - ]; + if ( options === undefined ) options = {}; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - this.vertices = vertices; + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; - // TODO: Wouldn't be nice if Line had .segments? + // - var geometry = new THREE.Geometry(); - geometry.vertices.push( - vertices[ 0 ], vertices[ 1 ], - vertices[ 1 ], vertices[ 2 ], - vertices[ 2 ], vertices[ 3 ], - vertices[ 3 ], vertices[ 0 ], + var i, l, hole; - vertices[ 4 ], vertices[ 5 ], - vertices[ 5 ], vertices[ 6 ], - vertices[ 6 ], vertices[ 7 ], - vertices[ 7 ], vertices[ 4 ], + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); - vertices[ 0 ], vertices[ 4 ], - vertices[ 1 ], vertices[ 5 ], - vertices[ 2 ], vertices[ 6 ], - vertices[ 3 ], vertices[ 7 ] - ); + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ); - if ( object !== undefined ) { + if ( reverse ) { - this.update( object ); + vertices = vertices.reverse(); - } + // Maybe we should also check if holes are in the opposite direction, just to be safe... -}; + for ( i = 0, l = holes.length; i < l; i ++ ) { -THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); + hole = holes[ i ]; -THREE.BoxHelper.prototype.update = function ( object ) { + if ( THREE.Shape.Utils.isClockWise( hole ) ) { - var geometry = object.geometry; + holes[ i ] = hole.reverse(); - if ( geometry.boundingBox === null ) { + } - geometry.computeBoundingBox(); + } - } + reverse = false; - var min = geometry.boundingBox.min; - var max = geometry.boundingBox.max; - var vertices = this.vertices; + } - vertices[ 0 ].set( max.x, max.y, max.z ); - vertices[ 1 ].set( min.x, max.y, max.z ); - vertices[ 2 ].set( min.x, min.y, max.z ); - vertices[ 3 ].set( max.x, min.y, max.z ); - vertices[ 4 ].set( max.x, max.y, min.z ); - vertices[ 5 ].set( min.x, max.y, min.z ); - vertices[ 6 ].set( min.x, min.y, min.z ); - vertices[ 7 ].set( max.x, min.y, min.z ); + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); - this.geometry.computeBoundingSphere(); - this.geometry.verticesNeedUpdate = true; + // Vertices - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; + var contour = vertices; -}; + for ( i = 0, l = holes.length; i < l; i ++ ) { -/** - * @author WestLangley / http://github.com/WestLangley - */ + hole = holes[ i ]; + vertices = vertices.concat( hole ); -// a helper to show the world-axis-aligned bounding box for an object + } -THREE.BoundingBoxHelper = function ( object, hex ) { + // - var color = ( hex !== undefined ) ? hex : 0x888888; + var vert, vlen = vertices.length; + var face, flen = faces.length; - this.object = object; + for ( i = 0; i < vlen; i ++ ) { - this.box = new THREE.Box3(); + vert = vertices[ i ]; - THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); -}; + } -THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); + for ( i = 0; i < flen; i ++ ) { -THREE.BoundingBoxHelper.prototype.update = function () { + face = faces[ i ]; - this.box.setFromObject( this.object ); + var a = face[ 0 ] + shapesOffset; + var b = face[ 1 ] + shapesOffset; + var c = face[ 2 ] + shapesOffset; - this.box.size( this.scale ); + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) ); - this.box.center( this.position ); + } }; +// File:src/extras/geometries/LatheGeometry.js + /** - * @author alteredq / http://alteredqualia.com/ - * - * - 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 + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://exocortex.com */ -THREE.CameraHelper = function ( camera ) { +// 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 2*PI) range of the lathed section +// 2*pi is a closed lathe, less than 2PI is a portion. - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); +THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { - var pointMap = {}; + THREE.Geometry.call( this ); - // colors + this.type = 'LatheGeometry'; - var hexFrustum = 0xffaa00; - var hexCone = 0xff0000; - var hexUp = 0x00aaff; - var hexTarget = 0xffffff; - var hexCross = 0x333333; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - // near + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; - addLine( "n1", "n2", hexFrustum ); - addLine( "n2", "n4", hexFrustum ); - addLine( "n4", "n3", hexFrustum ); - addLine( "n3", "n1", hexFrustum ); + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; - // far + for ( var i = 0, il = segments; i <= il; i ++ ) { - addLine( "f1", "f2", hexFrustum ); - addLine( "f2", "f4", hexFrustum ); - addLine( "f4", "f3", hexFrustum ); - addLine( "f3", "f1", hexFrustum ); + var phi = phiStart + i * inverseSegments * phiLength; - // sides + var c = Math.cos( phi ), + s = Math.sin( phi ); - addLine( "n1", "f1", hexFrustum ); - addLine( "n2", "f2", hexFrustum ); - addLine( "n3", "f3", hexFrustum ); - addLine( "n4", "f4", hexFrustum ); + for ( var j = 0, jl = points.length; j < jl; j ++ ) { - // cone + var pt = points[ j ]; - addLine( "p", "n1", hexCone ); - addLine( "p", "n2", hexCone ); - addLine( "p", "n3", hexCone ); - addLine( "p", "n4", hexCone ); + var vertex = new THREE.Vector3(); - // up + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; - addLine( "u1", "u2", hexUp ); - addLine( "u2", "u3", hexUp ); - addLine( "u3", "u1", hexUp ); + this.vertices.push( vertex ); - // target + } - addLine( "c", "t", hexTarget ); - addLine( "p", "c", hexCross ); + } - // cross + var np = points.length; - addLine( "cn1", "cn2", hexCross ); - addLine( "cn3", "cn4", hexCross ); + for ( var i = 0, il = segments; i < il; i ++ ) { - addLine( "cf1", "cf2", hexCross ); - addLine( "cf3", "cf4", hexCross ); + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { - function addLine( a, b, hex ) { + var base = j + np * i; + var a = base; + var b = base + np; + var c = base + 1 + np; + var d = base + 1; - addPoint( a, hex ); - addPoint( b, hex ); + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; - } + this.faces.push( new THREE.Face3( a, b, d ) ); - function addPoint( id, hex ) { + this.faceVertexUvs[ 0 ].push( [ - geometry.vertices.push( new THREE.Vector3() ); - geometry.colors.push( new THREE.Color( hex ) ); + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u0, v1 ) - if ( pointMap[ id ] === undefined ) { + ] ); - pointMap[ id ] = []; + this.faces.push( new THREE.Face3( b, c, d ) ); - } + this.faceVertexUvs[ 0 ].push( [ - pointMap[ id ].push( geometry.vertices.length - 1 ); + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) - } + ] ); - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - this.camera = camera; - this.matrixWorld = camera.matrixWorld; - this.matrixAutoUpdate = false; + } - this.pointMap = pointMap; + } - this.update(); + this.mergeVertices(); + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry; -THREE.CameraHelper.prototype.update = function () { +// File:src/extras/geometries/PlaneGeometry.js - var vector = new THREE.Vector3(); - var camera = new THREE.Camera(); - var projector = new THREE.Projector(); +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ - return function () { +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { - var scope = this; + console.info( 'THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.' ); - var w = 1, h = 1; + THREE.Geometry.call( this ); - // we need just camera projection matrix - // world matrix must be identity + this.type = 'PlaneGeometry'; - camera.projectionMatrix.copy( this.camera.projectionMatrix ); + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - // center / target + this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - setPoint( "c", 0, 0, -1 ); - setPoint( "t", 0, 0, 1 ); +}; - // near +THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; - setPoint( "n1", -w, -h, -1 ); - setPoint( "n2", w, -h, -1 ); - setPoint( "n3", -w, h, -1 ); - setPoint( "n4", w, h, -1 ); +// File:src/extras/geometries/PlaneBufferGeometry.js - // far +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ - setPoint( "f1", -w, -h, 1 ); - setPoint( "f2", w, -h, 1 ); - setPoint( "f3", -w, h, 1 ); - setPoint( "f4", w, h, 1 ); +THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) { - // up + THREE.BufferGeometry.call( this ); - setPoint( "u1", w * 0.7, h * 1.1, -1 ); - setPoint( "u2", -w * 0.7, h * 1.1, -1 ); - setPoint( "u3", 0, h * 2, -1 ); + this.type = 'PlaneBufferGeometry'; - // cross + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - setPoint( "cf1", -w, 0, 1 ); - setPoint( "cf2", w, 0, 1 ); - setPoint( "cf3", 0, -h, 1 ); - setPoint( "cf4", 0, h, 1 ); + var width_half = width / 2; + var height_half = height / 2; - setPoint( "cn1", -w, 0, -1 ); - setPoint( "cn2", w, 0, -1 ); - setPoint( "cn3", 0, -h, -1 ); - setPoint( "cn4", 0, h, -1 ); + var gridX = widthSegments || 1; + var gridY = heightSegments || 1; - function setPoint( point, x, y, z ) { + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; - vector.set( x, y, z ); - projector.unprojectVector( vector, camera ); + var segment_width = width / gridX; + var segment_height = height / gridY; - var points = scope.pointMap[ point ]; + var vertices = new Float32Array( gridX1 * gridY1 * 3 ); + var normals = new Float32Array( gridX1 * gridY1 * 3 ); + var uvs = new Float32Array( gridX1 * gridY1 * 2 ); - if ( points !== undefined ) { + var offset = 0; + var offset2 = 0; - for ( var i = 0, il = points.length; i < il; i ++ ) { + for ( var iy = 0; iy < gridY1; iy ++ ) { - scope.geometry.vertices[ points[ i ] ].copy( vector ); + var y = iy * segment_height - height_half; - } + for ( var ix = 0; ix < gridX1; ix ++ ) { - } + var x = ix * segment_width - width_half; - } + vertices[ offset ] = x; + vertices[ offset + 1 ] = - y; - this.geometry.verticesNeedUpdate = true; + normals[ offset + 2 ] = 1; - }; + uvs[ offset2 ] = ix / gridX; + uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); -}(); + offset += 3; + offset2 += 2; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + } -THREE.DirectionalLightHelper = function ( light, size ) { + } - THREE.Object3D.call( this ); + offset = 0; - this.light = light; - this.light.updateMatrixWorld(); + var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + for ( var iy = 0; iy < gridY; iy ++ ) { - size = size || 1; + for ( var ix = 0; ix < gridX; ix ++ ) { - var geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3( - size, size, 0 ), - new THREE.Vector3( size, size, 0 ), - new THREE.Vector3( size, - size, 0 ), - new THREE.Vector3( - size, - size, 0 ), - new THREE.Vector3( - size, size, 0 ) - ); + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; - var material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + indices[ offset ] = a; + indices[ offset + 1 ] = b; + indices[ offset + 2 ] = d; - this.lightPlane = new THREE.Line( geometry, material ); - this.add( this.lightPlane ); + indices[ offset + 3 ] = b; + indices[ offset + 4 ] = c; + indices[ offset + 5 ] = d; - geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3(), - new THREE.Vector3() - ); + offset += 6; - material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + } - this.targetLine = new THREE.Line( geometry, material ); - this.add( this.targetLine ); + } - this.update(); + this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); + this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); }; -THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; -THREE.DirectionalLightHelper.prototype.dispose = function () { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); -}; +// File:src/extras/geometries/RingGeometry.js -THREE.DirectionalLightHelper.prototype.update = function () { +/** + * @author Kaleb Murphy + */ - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var v3 = new THREE.Vector3(); +THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - return function () { + THREE.Geometry.call( this ); - v1.setFromMatrixPosition( this.light.matrixWorld ); - v2.setFromMatrixPosition( this.light.target.matrixWorld ); - v3.subVectors( v2, v1 ); + this.type = 'RingGeometry'; - this.lightPlane.lookAt( v3 ); - this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.targetLine.geometry.vertices[ 1 ].copy( v3 ); - this.targetLine.geometry.verticesNeedUpdate = true; - this.targetLine.material.color.copy( this.lightPlane.material.color ); + innerRadius = innerRadius || 0; + 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 ) : 8; + var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); -/** - * @author WestLangley / http://github.com/WestLangley - */ + for ( i = 0; i < phiSegments + 1; i ++ ) { // concentric circles inside ring -THREE.EdgesHelper = function ( object, hex ) { + for ( o = 0; o < thetaSegments + 1; o ++ ) { // number of segments per circle - var color = ( hex !== undefined ) ? hex : 0xffffff; + var vertex = new THREE.Vector3(); + var segment = thetaStart + o / thetaSegments * thetaLength; + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); + } - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); + radius += radiusStep; - var geometry2 = object.geometry.clone(); + } - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); + var n = new THREE.Vector3( 0, 0, 1 ); - var vertices = geometry2.vertices; - var faces = geometry2.faces; - var numEdges = 0; + for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring - for ( var i = 0, l = faces.length; i < l; i ++ ) { + var thetaSegment = i * (thetaSegments + 1); - var face = faces[ i ]; + for ( o = 0; o < thetaSegments ; o ++ ) { // number of segments per circle - for ( var j = 0; j < 3; j ++ ) { + var segment = o + thetaSegment; - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); + var v1 = segment; + var v2 = segment + thetaSegments + 1; + var v3 = segment + thetaSegments + 2; - var key = edge.toString(); + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - if ( hash[ key ] === undefined ) { + v1 = segment; + v2 = segment + thetaSegments + 2; + v3 = segment + 1; - hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; - numEdges ++; + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - } else { + } + } - hash[ key ].face2 = i; + this.computeFaceNormals(); - } + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - } +}; - } +THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; - geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); - var coords = geometry.attributes.position.array; +// File:src/extras/geometries/SphereGeometry.js - var index = 0; +/** + * @author mrdoob / http://mrdoob.com/ + */ - for ( var key in hash ) { +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - var h = hash[ key ]; + THREE.Geometry.call( this ); - if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK + this.type = 'SphereGeometry'; - var vertex = vertices[ h.vert1 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - vertex = vertices[ h.vert2 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; + 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; - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; + var x, y, vertices = [], uvs = []; -}; + for ( y = 0; y <= heightSegments; y ++ ) { -THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); + var verticesRow = []; + var uvsRow = []; -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ + for ( x = 0; x <= widthSegments; x ++ ) { -THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { + var u = x / widthSegments; + var v = y / heightSegments; - this.object = object; + var vertex = new THREE.Vector3(); + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - this.size = ( size !== undefined ) ? size : 1; + this.vertices.push( vertex ); - var color = ( hex !== undefined ) ? hex : 0xffff00; + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - var width = ( linewidth !== undefined ) ? linewidth : 1; + } - var geometry = new THREE.Geometry(); + vertices.push( verticesRow ); + uvs.push( uvsRow ); - var faces = this.object.geometry.faces; + } - for ( var i = 0, l = faces.length; i < l; i ++ ) { + for ( y = 0; y < heightSegments; y ++ ) { - geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); + for ( x = 0; x < widthSegments; x ++ ) { - } + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = vertices[ y + 1 ][ x ]; + var v4 = vertices[ y + 1 ][ x + 1 ]; - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + var n1 = this.vertices[ v1 ].clone().normalize(); + var n2 = this.vertices[ v2 ].clone().normalize(); + var n3 = this.vertices[ v3 ].clone().normalize(); + var n4 = this.vertices[ v4 ].clone().normalize(); - this.matrixAutoUpdate = false; + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x ].clone(); + var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); - this.normalMatrix = new THREE.Matrix3(); + if ( Math.abs( this.vertices[ v1 ].y ) === radius ) { - this.update(); + uv1.x = ( uv1.x + uv2.x ) / 2; + this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); -}; + } else if ( Math.abs( this.vertices[ v3 ].y ) === radius ) { -THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + uv3.x = ( uv3.x + uv4.x ) / 2; + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); -THREE.FaceNormalsHelper.prototype.update = function () { + } else { + + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - var vertices = this.geometry.vertices; + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - var object = this.object; - var objectVertices = object.geometry.vertices; - var objectFaces = object.geometry.faces; - var objectWorldMatrix = object.matrixWorld; + } - object.updateMatrixWorld( true ); + } - this.normalMatrix.getNormalMatrix( objectWorldMatrix ); + } - for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) { + this.computeFaceNormals(); - var face = objectFaces[ i ]; + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - vertices[ i2 ].copy( objectVertices[ face.a ] ) - .add( objectVertices[ face.b ] ) - .add( objectVertices[ face.c ] ) - .divideScalar( 3 ) - .applyMatrix4( objectWorldMatrix ); +}; - vertices[ i2 + 1 ].copy( face.normal ) - .applyMatrix3( this.normalMatrix ) - .normalize() - .multiplyScalar( this.size ) - .add( vertices[ i2 ] ); +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; - } +// File:src/extras/geometries/TextGeometry.js - this.geometry.verticesNeedUpdate = true; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For creating 3D text geometry in three.js + * + * Text = 3D Text + * + * parameters = { + * size: , // size of the text + * height: , // thickness to extrude text + * curveSegments: , // number of points on the curves + * + * font: , // font name + * weight: , // font weight (normal, bold) + * style: , // font style (normal, italics) + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into text bevel goes + * bevelSize: , // how far from text outline is bevel + * } + * + */ - return this; +/* Usage Examples -}; + // TextGeometry wrapper + var text3d = new TextGeometry( text, options ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + // Complete manner -THREE.GridHelper = function ( size, step ) { + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); +*/ - this.color1 = new THREE.Color( 0x444444 ); - this.color2 = new THREE.Color( 0x888888 ); - for ( var i = - size; i <= size; i += step ) { +THREE.TextGeometry = function ( text, parameters ) { - geometry.vertices.push( - new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), - new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) - ); + parameters = parameters || {}; - var color = i === 0 ? this.color1 : this.color2; + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - geometry.colors.push( color, color, color, color ); + // translate parameters to ExtrudeGeometry API - } + parameters.amount = parameters.height !== undefined ? parameters.height : 50; - THREE.Line.call( this, geometry, material, THREE.LinePieces ); + // defaults -}; + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; -THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); -THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { + this.type = 'TextGeometry'; - this.color1.set( colorCenterLine ); - this.color2.set( colorGrid ); +}; - this.geometry.colorsNeedUpdate = true; +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); +THREE.TextGeometry.prototype.constructor = THREE.TextGeometry; -} +// File:src/extras/geometries/TorusGeometry.js /** - * @author alteredq / http://alteredqualia.com/ + * @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 */ -THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { - THREE.Object3D.call( this ); + THREE.Geometry.call( this ); - this.light = light; - this.light.updateMatrixWorld(); + this.type = 'TorusGeometry'; - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - this.colors = [ new THREE.Color(), new THREE.Color() ]; + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 8; + tubularSegments = tubularSegments || 6; + arc = arc || Math.PI * 2; - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + var center = new THREE.Vector3(), uvs = [], normals = []; - for ( var i = 0, il = 8; i < il; i ++ ) { + for ( var j = 0; j <= radialSegments; j ++ ) { - geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; + for ( var i = 0; i <= tubularSegments; i ++ ) { - } + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; - var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); - this.lightSphere = new THREE.Mesh( geometry, material ); - this.add( this.lightSphere ); + var vertex = new THREE.Vector3(); + 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 ); - this.update(); + this.vertices.push( vertex ); -}; + uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); -THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + } -THREE.HemisphereLightHelper.prototype.dispose = function () { - this.lightSphere.geometry.dispose(); - this.lightSphere.material.dispose(); -}; + } -THREE.HemisphereLightHelper.prototype.update = function () { + for ( var j = 1; j <= radialSegments; j ++ ) { - var vector = new THREE.Vector3(); + for ( var i = 1; i <= tubularSegments; i ++ ) { - return function () { + 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; - this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); - this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - this.lightSphere.geometry.colorsNeedUpdate = true; + face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); - } + } -}(); + } + + this.computeFaceNormals(); + +}; + +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; +// File:src/extras/geometries/TorusKnotGeometry.js /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ + * @author oosmoxiecode + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 */ -THREE.PointLightHelper = function ( light, sphereSize ) { +THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { + + THREE.Geometry.call( this ); + + this.type = 'TorusKnotGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + p: p, + q: q, + heightScale: heightScale + }; + + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 64; + tubularSegments = tubularSegments || 8; + p = p || 2; + q = q || 3; + heightScale = heightScale || 1; + + var grid = new Array( radialSegments ); + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); + + for ( var i = 0; i < radialSegments; ++ i ) { + + grid[ i ] = new Array( tubularSegments ); + var u = i / radialSegments * 2 * p * Math.PI; + var p1 = getPos( u, q, p, radius, heightScale ); + var p2 = getPos( u + 0.01, q, p, radius, heightScale ); + tang.subVectors( p2, p1 ); + n.addVectors( p2, p1 ); + + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); + + for ( var j = 0; j < tubularSegments; ++ j ) { + + var v = j / tubularSegments * 2 * Math.PI; + var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + var cy = tube * Math.sin( v ); + + var pos = new THREE.Vector3(); + pos.x = p1.x + cx * n.x + cy * bitan.x; + pos.y = p1.y + cx * n.y + cy * bitan.y; + pos.z = p1.z + cx * n.z + cy * bitan.z; + + grid[ i ][ j ] = this.vertices.push( pos ) - 1; - this.light = light; - this.light.updateMatrixWorld(); + } - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + } - THREE.Mesh.call( this, geometry, material ); + for ( var i = 0; i < radialSegments; ++ i ) { - this.matrixWorld = this.light.matrixWorld; - this.matrixAutoUpdate = false; + for ( var j = 0; j < tubularSegments; ++ j ) { - /* - var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + var ip = ( i + 1 ) % radialSegments; + var jp = ( j + 1 ) % tubularSegments; - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + var a = grid[ i ][ j ]; + var b = grid[ ip ][ j ]; + var c = grid[ ip ][ jp ]; + var d = grid[ i ][ jp ]; - var d = light.distance; + var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); + var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); + var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); + var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); - if ( d === 0.0 ) { + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - this.lightDistance.visible = false; + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - } else { + } + } - this.lightDistance.scale.set( d, d, d ); + this.computeFaceNormals(); + this.computeVertexNormals(); - } + function getPos( u, in_q, in_p, radius, heightScale ) { - this.add( this.lightDistance ); - */ + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); -}; + var tx = radius * ( 2 + cs ) * 0.5 * cu; + var ty = radius * ( 2 + cs ) * su * 0.5; + var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; -THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); + return new THREE.Vector3( tx, ty, tz ); -THREE.PointLightHelper.prototype.dispose = function () { - - this.geometry.dispose(); - this.material.dispose(); -}; + } -THREE.PointLightHelper.prototype.update = function () { +}; - this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); +THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; - /* - var d = this.light.distance; +// File:src/extras/geometries/TubeGeometry.js - if ( d === 0.0 ) { +/** + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * @author jonobr1 / https://github.com/jonobr1 + * + * Modified from the TorusKnotGeometry by @oosmoxiecode + * + * Creates a tube which extrudes along a 3d spline + * + * Uses parallel transport frames as described in + * http://www.cs.indiana.edu/pub/techreports/TR425.pdf + */ - this.lightDistance.visible = false; +THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, taper ) { - } else { + THREE.Geometry.call( this ); - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + this.type = 'TubeGeometry'; - } - */ + this.parameters = { + path: path, + segments: segments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; -}; + segments = segments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; + taper = taper || THREE.TubeGeometry.NoTaper; + var grid = []; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ + var scope = this, -THREE.SpotLightHelper = function ( light ) { + tangent, + normal, + binormal, - THREE.Object3D.call( this ); + numpoints = segments + 1, - this.light = light; - this.light.updateMatrixWorld(); + u, v, r, - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + cx, cy, + pos, pos2 = new THREE.Vector3(), + i, j, + ip, jp, + a, b, c, d, + uva, uvb, uvc, uvd; - var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); + var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), + tangents = frames.tangents, + normals = frames.normals, + binormals = frames.binormals; - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - - this.cone = new THREE.Mesh( geometry, material ); - this.add( this.cone ); + function vert( x, y, z ) { - this.update(); + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; -}; + } -THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + // consruct the grid -THREE.SpotLightHelper.prototype.dispose = function () { - this.cone.geometry.dispose(); - this.cone.material.dispose(); -}; + for ( i = 0; i < numpoints; i ++ ) { -THREE.SpotLightHelper.prototype.update = function () { + grid[ i ] = []; - var vector = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); + u = i / ( numpoints - 1 ); - return function () { + pos = path.getPointAt( u ); - var coneLength = this.light.distance ? this.light.distance : 10000; - var coneWidth = coneLength * Math.tan( this.light.angle ); + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; - this.cone.scale.set( coneWidth, coneWidth, coneLength ); + r = radius * taper( u ); - vector.setFromMatrixPosition( this.light.matrixWorld ); - vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + for ( j = 0; j < radialSegments; j ++ ) { - this.cone.lookAt( vector2.sub( vector ) ); + v = j / radialSegments * 2 * Math.PI; - this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = r * Math.sin( v ); - }; + pos2.copy( pos ); + pos2.x += cx * normal.x + cy * binormal.x; + pos2.y += cx * normal.y + cy * binormal.y; + pos2.z += cx * normal.z + cy * binormal.z; -}(); + grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ + } + } -THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - this.object = object; + // construct the mesh - this.size = ( size !== undefined ) ? size : 1; + for ( i = 0; i < segments; i ++ ) { - var color = ( hex !== undefined ) ? hex : 0xff0000; + for ( j = 0; j < radialSegments; j ++ ) { - var width = ( linewidth !== undefined ) ? linewidth : 1; + ip = ( closed ) ? (i + 1) % segments : i + 1; + jp = (j + 1) % radialSegments; - var geometry = new THREE.Geometry(); + a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = grid[ ip ][ j ]; + c = grid[ ip ][ jp ]; + d = grid[ i ][ jp ]; - var vertices = object.geometry.vertices; + uva = new THREE.Vector2( i / segments, j / radialSegments ); + uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); + uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); + uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); - var faces = object.geometry.faces; + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - var face = faces[ i ]; + } + } - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + this.computeFaceNormals(); + this.computeVertexNormals(); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); +}; - } +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; - } +THREE.TubeGeometry.NoTaper = function ( u ) { - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + return 1; - this.matrixAutoUpdate = false; +}; - this.normalMatrix = new THREE.Matrix3(); +THREE.TubeGeometry.SinusoidalTaper = function ( u ) { - this.update(); + return Math.sin( Math.PI * u ); }; -THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); +// For computing of Frenet frames, exposing the tangents, normals and binormals the spline +THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { -THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { + var normal = new THREE.Vector3(), - var v1 = new THREE.Vector3(); + tangents = [], + normals = [], + binormals = [], - return function( object ) { + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), - var keys = [ 'a', 'b', 'c', 'd' ]; + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, - this.object.updateMatrixWorld( true ); + tx, ty, tz, + i, u; - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - var vertices = this.geometry.vertices; + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - var verts = this.object.geometry.vertices; + // compute the tangent vectors for each segment on the path - var faces = this.object.geometry.faces; + for ( i = 0; i < numpoints; i ++ ) { - var worldMatrix = this.object.matrixWorld; + u = i / ( numpoints - 1 ); - var idx = 0; + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + } - var face = faces[ i ]; + initialNormal3(); - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + /* + function initialNormal1(lastBinormal) { + // fixed start binormal. Has dangers of 0 vectors + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); + normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + } - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; + function initialNormal2() { - var normal = face.vertexNormals[ j ]; + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); + binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); - v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - v1.add( vertices[ idx ] ); - idx = idx + 1; + } + */ - vertices[ idx ].copy( v1 ); - idx = idx + 1; + function initialNormal3() { + // select an initial normal vector perpenicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component - } + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + smallest = Number.MAX_VALUE; + tx = Math.abs( tangents[ 0 ].x ); + ty = Math.abs( tangents[ 0 ].y ); + tz = Math.abs( tangents[ 0 ].z ); - } + if ( tx <= smallest ) { + smallest = tx; + normal.set( 1, 0, 0 ); + } - this.geometry.verticesNeedUpdate = true; + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); + } - return this; + if ( tz <= smallest ) { + normal.set( 0, 0, 1 ); + } - } + vec.crossVectors( tangents[ 0 ], normal ).normalize(); -}()); + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + } -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ -THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { + // compute the slowly-varying normal and binormal vectors for each segment on the path - this.object = object; + for ( i = 1; i < numpoints; i ++ ) { - this.size = ( size !== undefined ) ? size : 1; + normals[ i ] = normals[ i - 1 ].clone(); - var color = ( hex !== undefined ) ? hex : 0x0000ff; + binormals[ i ] = binormals[ i - 1 ].clone(); - var width = ( linewidth !== undefined ) ? linewidth : 1; + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - var geometry = new THREE.Geometry(); + if ( vec.length() > epsilon ) { - var vertices = object.geometry.vertices; + vec.normalize(); - var faces = object.geometry.faces; + theta = Math.acos( THREE.Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - for ( var i = 0, l = faces.length; i < l; i ++ ) { + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - var face = faces[ i ]; + } - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); + } - } - } + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + if ( closed ) { - this.matrixAutoUpdate = false; + theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) ); + theta /= ( numpoints - 1 ); - this.update(); + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { -}; + theta = - theta; -THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); + } -THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { + for ( i = 1; i < numpoints; i ++ ) { - var v1 = new THREE.Vector3(); + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - return function( object ) { + } - var keys = [ 'a', 'b', 'c', 'd' ]; + } +}; - this.object.updateMatrixWorld( true ); +// File:src/extras/geometries/PolyhedronGeometry.js - var vertices = this.geometry.vertices; +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + * @author WestLangley / http://github.com/WestLangley +*/ - var verts = this.object.geometry.vertices; +THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { - var faces = this.object.geometry.faces; + THREE.Geometry.call( this ); - var worldMatrix = this.object.matrixWorld; + this.type = 'PolyhedronGeometry'; - var idx = 0; + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + radius = radius || 1; + detail = detail || 0; - var face = faces[ i ]; + var that = this; - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + for ( var i = 0, l = vertices.length; i < l; i += 3 ) { - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; + prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - var tangent = face.vertexTangents[ j ]; + } - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + var p = this.vertices; - v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); + var faces = []; - v1.add( vertices[ idx ] ); - idx = idx + 1; + for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { - vertices[ idx ].copy( v1 ); - idx = idx + 1; + var v1 = p[ indices[ i ] ]; + var v2 = p[ indices[ i + 1 ] ]; + var v3 = p[ indices[ i + 2 ] ]; - } + faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - } + } - this.geometry.verticesNeedUpdate = true; + var centroid = new THREE.Vector3(); - return this; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - } + subdivide( faces[ i ], detail ); -}()); + } -/** - * @author mrdoob / http://mrdoob.com/ - */ -THREE.WireframeHelper = function ( object, hex ) { + // Handle case when face straddles the seam - var color = ( hex !== undefined ) ? hex : 0xffffff; + for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; + var uvs = this.faceVertexUvs[ 0 ][ i ]; - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); + var x0 = uvs[ 0 ].x; + var x1 = uvs[ 1 ].x; + var x2 = uvs[ 2 ].x; - if ( object.geometry instanceof THREE.Geometry ) { + var max = Math.max( x0, Math.max( x1, x2 ) ); + var min = Math.min( x0, Math.min( x1, x2 ) ); - var vertices = object.geometry.vertices; - var faces = object.geometry.faces; - var numEdges = 0; + if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary - // allocate maximal size - var edges = new Uint32Array( 6 * faces.length ); + if ( x0 < 0.2 ) uvs[ 0 ].x += 1; + if ( x1 < 0.2 ) uvs[ 1 ].x += 1; + if ( x2 < 0.2 ) uvs[ 2 ].x += 1; - 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 ); + // Apply radius - var key = edge.toString(); + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { - if ( hash[ key ] === undefined ) { + this.vertices[ i ].multiplyScalar( radius ); - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; + } - } - } + // Merge vertices - } + this.mergeVertices(); - geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + this.computeFaceNormals(); - var coords = geometry.attributes.position.array; + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - for ( var i = 0, l = numEdges; i < l; i ++ ) { - for ( var j = 0; j < 2; j ++ ) { + // Project vector onto sphere's surface - var vertex = vertices[ edges [ 2 * i + j] ]; + function prepare( vector ) { - var index = 6 * i + 3 * j; - coords[ index + 0 ] = vertex.x; - coords[ index + 1 ] = vertex.y; - coords[ index + 2 ] = vertex.z; + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; - } + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. - } + var u = azimuth( vector ) / 2 / Math.PI + 0.5; + var v = inclination( vector ) / Math.PI + 0.5; + vertex.uv = new THREE.Vector2( u, 1 - v ); - } else if ( object.geometry instanceof THREE.BufferGeometry && object.geometry.attributes.index !== undefined ) { // indexed BufferGeometry + return vertex; - var vertices = object.geometry.attributes.position.array; - var indices = object.geometry.attributes.index.array; - var offsets = object.geometry.offsets; - var numEdges = 0; + } - // allocate maximal size - var edges = new Uint32Array( 2 * indices.length ); - for ( var o = 0, ol = offsets.length; o < ol; ++ o ) { + // Approximate a curved face with recursively sub-divided triangles. - var start = offsets[ o ].start; - var count = offsets[ o ].count; - var index = offsets[ o ].index; + function make( v1, v2, v3 ) { - for ( var i = start, il = start + count; i < il; i += 3 ) { + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + that.faces.push( face ); - for ( var j = 0; j < 3; j ++ ) { + centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - edge[ 0 ] = index + indices[ i + j ]; - edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; - edge.sort( sortFunction ); + var azi = azimuth( centroid ); - var key = edge.toString(); + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); - if ( hash[ key ] === undefined ) { + } - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; - } + // Analytically subdivide a face to the required detail level. - } + function subdivide( face, detail ) { - } + var cols = Math.pow(2, detail); + var a = prepare( that.vertices[ face.a ] ); + var b = prepare( that.vertices[ face.b ] ); + var c = prepare( that.vertices[ face.c ] ); + var v = []; - } + // Construct all of the vertices for this subdivision. - geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + for ( var i = 0 ; i <= cols; i ++ ) { - var coords = geometry.attributes.position.array; + v[ i ] = []; - for ( var i = 0, l = numEdges; i < l; i ++ ) { + var aj = prepare( a.clone().lerp( c, i / cols ) ); + var bj = prepare( b.clone().lerp( c, i / cols ) ); + var rows = cols - i; - for ( var j = 0; j < 2; j ++ ) { + for ( var j = 0; j <= rows; j ++) { - var index = 6 * i + 3 * j; - var index2 = 3 * edges[ 2 * i + j]; - coords[ index + 0 ] = vertices[ index2 ]; - coords[ index + 1 ] = vertices[ index2 + 1 ]; - coords[ index + 2 ] = vertices[ index2 + 2 ]; + if ( j == 0 && i == cols ) { - } + v[ i ][ j ] = aj; - } + } else { - } else if ( object.geometry instanceof THREE.BufferGeometry ) { // non-indexed BufferGeometry + v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); - var vertices = object.geometry.attributes.position.array; - var numEdges = vertices.length / 3; - var numTris = numEdges / 3; + } - geometry.addAttribute( 'position', new THREE.Float32Attribute( numEdges * 2, 3 ) ); + } - var coords = geometry.attributes.position.array; + } - for ( var i = 0, l = numTris; i < l; i ++ ) { + // Construct all of the faces. - for ( var j = 0; j < 3; j ++ ) { + for ( var i = 0; i < cols ; i ++ ) { - var index = 18 * i + 6 * j; + for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { - var index1 = 9 * i + 3 * j; - coords[ index + 0 ] = vertices[ index1 ]; - coords[ index + 1 ] = vertices[ index1 + 1 ]; - coords[ index + 2 ] = vertices[ index1 + 2 ]; + var k = Math.floor( j / 2 ); - var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); - coords[ index + 3 ] = vertices[ index2 ]; - coords[ index + 4 ] = vertices[ index2 + 1 ]; - coords[ index + 5 ] = vertices[ index2 + 2 ]; + if ( j % 2 == 0 ) { - } + make( + v[ i ][ k + 1], + v[ i + 1 ][ k ], + v[ i ][ k ] + ); - } + } else { - } + make( + v[ i ][ k + 1 ], + v[ i + 1][ k + 1], + v[ i + 1 ][ k ] + ); - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + } - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; + } -}; + } -THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); + } -/** - * @author alteredq / http://alteredqualia.com/ - */ -THREE.ImmediateRenderObject = function () { + // Angle around the Y axis, counter-clockwise when looking from above. - THREE.Object3D.call( this ); + function azimuth( vector ) { - this.render = function ( renderCallback ) { }; + return Math.atan2( vector.z, - vector.x ); -}; + } -THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + // Angle above the XZ plane. -THREE.LensFlare = function ( texture, size, distance, blending, color ) { + function inclination( vector ) { + + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - THREE.Object3D.call( this ); + } - this.lensFlares = []; - this.positionScreen = new THREE.Vector3(); - this.customUpdateCallback = undefined; + // Texture fixing helper. Spheres have some odd behaviours. - if( texture !== undefined ) { + function correctUV( uv, vector, azimuth ) { - this.add( texture, size, distance, blending, color ); + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); + return uv.clone(); + + } - } }; -THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); +THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry; +// File:src/extras/geometries/DodecahedronGeometry.js -/* - * Add: adds another flare +/** + * @author Abe Pazos / https://hamoid.com */ -THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { +THREE.DodecahedronGeometry = function ( radius, detail ) { + + this.parameters = { + radius: radius, + detail: detail + }; + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; + + var vertices = [ - if( size === undefined ) size = -1; - if( distance === undefined ) distance = 0; - if( opacity === undefined ) opacity = 1; - if( color === undefined ) color = new THREE.Color( 0xffffff ); - if( blending === undefined ) blending = THREE.NormalBlending; + // (±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, - distance = Math.min( distance, Math.max( 0, distance ) ); + // (0, ±1/φ, ±φ) + 0, -r, -t, 0, -r, t, + 0, r, -t, 0, r, t, - 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 ontop z = 1 is back - scale: 1, // scale - rotation: 1, // rotation - opacity: opacity, // opacity - color: color, // color - blending: blending } ); // blending + // (±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 + ]; + + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); }; +THREE.DodecahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry; -/* - * 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. - */ +// File:src/extras/geometries/IcosahedronGeometry.js -THREE.LensFlare.prototype.updateLensFlares = function () { +/** + * @author timothypratley / https://github.com/timothypratley + */ - var f, fl = this.lensFlares.length; - var flare; - var vecX = -this.positionScreen.x * 2; - var vecY = -this.positionScreen.y * 2; +THREE.IcosahedronGeometry = function ( radius, detail ) { - for( f = 0; f < fl; f ++ ) { + var t = ( 1 + Math.sqrt( 5 ) ) / 2; - flare = this.lensFlares[ f ]; + 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 + ]; - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; + 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 + ]; - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - } + this.type = 'IcosahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail + }; }; +THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry; +// File:src/extras/geometries/OctahedronGeometry.js +/** + * @author timothypratley / https://github.com/timothypratley + */ +THREE.OctahedronGeometry = function ( radius, detail ) { + this.parameters = { + radius: radius, + detail: 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 + ]; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); + this.type = 'OctahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail + }; +}; +THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry; +// File:src/extras/geometries/TetrahedronGeometry.js /** - * @author alteredq / http://alteredqualia.com/ + * @author timothypratley / https://github.com/timothypratley */ -THREE.MorphBlendMesh = function( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); +THREE.TetrahedronGeometry = function ( radius, detail ) { - this.animationsMap = {}; - this.animationsList = []; + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; - // prepare default animation - // (all frames played together in 1 second) + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; - var numFrames = this.geometry.morphTargets.length; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - var name = "__default"; + this.type = 'TetrahedronGeometry'; - var startFrame = 0; - var endFrame = numFrames - 1; + this.parameters = { + radius: radius, + detail: detail + }; - var fps = numFrames / 1; +}; - this.createAnimation( name, startFrame, endFrame, fps ); - this.setAnimationWeight( name, 1 ); +THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; -}; +// File:src/extras/geometries/ParametricGeometry.js -THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); +/** + * @author zz85 / https://github.com/zz85 + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + * + * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); + * + */ -THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { +THREE.ParametricGeometry = function ( func, slices, stacks ) { - var animation = { + THREE.Geometry.call( this ); - startFrame: start, - endFrame: end, + this.type = 'ParametricGeometry'; - length: end - start + 1, + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; - fps: fps, - duration: ( end - start ) / fps, + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; - lastFrame: 0, - currentFrame: 0, + var i, j, p; + var u, v; - active: false, + var sliceCount = slices + 1; - time: 0, - direction: 1, - weight: 1, + for ( i = 0; i <= stacks; i ++ ) { - directionBackwards: false, - mirroredLoop: false + v = i / stacks; - }; + for ( j = 0; j <= slices; j ++ ) { - this.animationsMap[ name ] = animation; - this.animationsList.push( animation ); + u = j / slices; -}; + p = func( u, v ); + verts.push( p ); -THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { + } + } - var pattern = /([a-z]+)(\d+)/; + var a, b, c, d; + var uva, uvb, uvc, uvd; - var firstAnimation, frameRanges = {}; + for ( i = 0; i < stacks; i ++ ) { - var geometry = this.geometry; + for ( j = 0; j < slices; j ++ ) { - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = (i + 1) * sliceCount + j + 1; + d = (i + 1) * sliceCount + j; - var morph = geometry.morphTargets[ i ]; - var chunks = morph.name.match( pattern ); + uva = new THREE.Vector2( j / slices, i / stacks ); + uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); + uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); + uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); - if ( chunks && chunks.length > 1 ) { + faces.push( new THREE.Face3( a, b, d ) ); + uvs.push( [ uva, uvb, uvd ] ); - var name = chunks[ 1 ]; - var num = chunks[ 2 ]; + faces.push( new THREE.Face3( b, c, d ) ); + uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); - 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; + // console.log(this); - if ( ! firstAnimation ) firstAnimation = name; + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); - } + this.computeFaceNormals(); + this.computeVertexNormals(); - } +}; - for ( var name in frameRanges ) { +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; - var range = frameRanges[ name ]; - this.createAnimation( name, range.start, range.end, fps ); +// File:src/extras/helpers/AxisHelper.js - } +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ - this.firstAnimation = firstAnimation; +THREE.AxisHelper = function ( size ) { -}; + size = size || 1; -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { + var vertices = new Float32Array( [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ] ); - var animation = this.animationsMap[ name ]; + var colors = new Float32Array( [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ] ); - if ( animation ) { + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - animation.direction = 1; - animation.directionBackwards = false; + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - } + THREE.Line.call( this, geometry, material, THREE.LinePieces ); }; -THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - - var animation = this.animationsMap[ name ]; +THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; - if ( animation ) { +// File:src/extras/helpers/ArrowHelper.js - animation.direction = -1; - animation.directionBackwards = true; +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://github.com/zz85 + * @author bhouston / http://exocortex.com + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * color - color in hex value + * headLength - Number + * headWidth - Number + */ - } +THREE.ArrowHelper = ( function () { -}; + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); -THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); - var animation = this.animationsMap[ name ]; + return function ( dir, origin, length, color, headLength, headWidth ) { - if ( animation ) { + // dir is assumed to be normalized - animation.fps = fps; - animation.duration = ( animation.end - animation.start ) / animation.fps; + THREE.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; -}; + this.position.copy( origin ); -THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); - var animation = this.animationsMap[ name ]; + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); - if ( animation ) { + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); - animation.duration = duration; - animation.fps = ( animation.end - animation.start ) / animation.duration; + } - } +}() ); -}; +THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.ArrowHelper.prototype.constructor = THREE.ArrowHelper; -THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { +THREE.ArrowHelper.prototype.setDirection = ( function () { - var animation = this.animationsMap[ name ]; + var axis = new THREE.Vector3(); + var radians; - if ( animation ) { + return function ( dir ) { - animation.weight = weight; + // dir is assumed to be normalized - } + if ( dir.y > 0.99999 ) { -}; + this.quaternion.set( 0, 0, 0, 1 ); -THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { + } else if ( dir.y < - 0.99999 ) { - var animation = this.animationsMap[ name ]; + this.quaternion.set( 1, 0, 0, 0 ); - if ( animation ) { + } else { - animation.time = time; + axis.set( dir.z, 0, - dir.x ).normalize(); - } + radians = Math.acos( dir.y ); -}; + this.quaternion.setFromAxisAngle( axis, radians ); -THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + } - var time = 0; + }; - var animation = this.animationsMap[ name ]; +}() ); - if ( animation ) { +THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { - time = animation.time; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; - } + this.line.scale.set( 1, length - headLength, 1 ); + this.line.updateMatrix(); - return time; + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); }; -THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { +THREE.ArrowHelper.prototype.setColor = function ( color ) { - var duration = -1; + this.line.material.color.set( color ); + this.cone.material.color.set( color ); - var animation = this.animationsMap[ name ]; +}; + +// File:src/extras/helpers/BoxHelper.js + +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( animation ) { +THREE.BoxHelper = function ( object ) { - duration = animation.duration; + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 72 ), 3 ) ); - } + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); - return duration; + if ( object !== undefined ) { -}; + this.update( object ); -THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { + } - var animation = this.animationsMap[ name ]; +}; - if ( animation ) { +THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.BoxHelper.prototype.constructor = THREE.BoxHelper; - animation.time = 0; - animation.active = true; +THREE.BoxHelper.prototype.update = function ( object ) { - } else { + var geometry = object.geometry; - console.warn( "animation[" + name + "] undefined" ); + if ( geometry.boundingBox === null ) { - } + geometry.computeBoundingBox(); -}; + } -THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { + var min = geometry.boundingBox.min; + var max = geometry.boundingBox.max; - var animation = this.animationsMap[ name ]; + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ - if ( animation ) { + 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 + */ - animation.active = false; + var vertices = this.geometry.attributes.position.array; - } + vertices[ 0 ] = max.x; vertices[ 1 ] = max.y; vertices[ 2 ] = max.z; + vertices[ 3 ] = min.x; vertices[ 4 ] = max.y; vertices[ 5 ] = max.z; -}; + vertices[ 6 ] = min.x; vertices[ 7 ] = max.y; vertices[ 8 ] = max.z; + vertices[ 9 ] = min.x; vertices[ 10 ] = min.y; vertices[ 11 ] = max.z; -THREE.MorphBlendMesh.prototype.update = function ( delta ) { + vertices[ 12 ] = min.x; vertices[ 13 ] = min.y; vertices[ 14 ] = max.z; + vertices[ 15 ] = max.x; vertices[ 16 ] = min.y; vertices[ 17 ] = max.z; - for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { + vertices[ 18 ] = max.x; vertices[ 19 ] = min.y; vertices[ 20 ] = max.z; + vertices[ 21 ] = max.x; vertices[ 22 ] = max.y; vertices[ 23 ] = max.z; - var animation = this.animationsList[ i ]; + // - if ( ! animation.active ) continue; + vertices[ 24 ] = max.x; vertices[ 25 ] = max.y; vertices[ 26 ] = min.z; + vertices[ 27 ] = min.x; vertices[ 28 ] = max.y; vertices[ 29 ] = min.z; - var frameTime = animation.duration / animation.length; + vertices[ 30 ] = min.x; vertices[ 31 ] = max.y; vertices[ 32 ] = min.z; + vertices[ 33 ] = min.x; vertices[ 34 ] = min.y; vertices[ 35 ] = min.z; - animation.time += animation.direction * delta; + vertices[ 36 ] = min.x; vertices[ 37 ] = min.y; vertices[ 38 ] = min.z; + vertices[ 39 ] = max.x; vertices[ 40 ] = min.y; vertices[ 41 ] = min.z; - if ( animation.mirroredLoop ) { + vertices[ 42 ] = max.x; vertices[ 43 ] = min.y; vertices[ 44 ] = min.z; + vertices[ 45 ] = max.x; vertices[ 46 ] = max.y; vertices[ 47 ] = min.z; - if ( animation.time > animation.duration || animation.time < 0 ) { + // - animation.direction *= -1; + vertices[ 48 ] = max.x; vertices[ 49 ] = max.y; vertices[ 50 ] = max.z; + vertices[ 51 ] = max.x; vertices[ 52 ] = max.y; vertices[ 53 ] = min.z; - if ( animation.time > animation.duration ) { + vertices[ 54 ] = min.x; vertices[ 55 ] = max.y; vertices[ 56 ] = max.z; + vertices[ 57 ] = min.x; vertices[ 58 ] = max.y; vertices[ 59 ] = min.z; - animation.time = animation.duration; - animation.directionBackwards = true; + vertices[ 60 ] = min.x; vertices[ 61 ] = min.y; vertices[ 62 ] = max.z; + vertices[ 63 ] = min.x; vertices[ 64 ] = min.y; vertices[ 65 ] = min.z; - } + vertices[ 66 ] = max.x; vertices[ 67 ] = min.y; vertices[ 68 ] = max.z; + vertices[ 69 ] = max.x; vertices[ 70 ] = min.y; vertices[ 71 ] = min.z; - if ( animation.time < 0 ) { + this.geometry.attributes.position.needsUpdate = true; - animation.time = 0; - animation.directionBackwards = false; + this.geometry.computeBoundingSphere(); - } + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - } +}; - } else { +// File:src/extras/helpers/BoundingBoxHelper.js - animation.time = animation.time % animation.duration; +/** + * @author WestLangley / http://github.com/WestLangley + */ - if ( animation.time < 0 ) animation.time += animation.duration; +// a helper to show the world-axis-aligned bounding box for an object - } +THREE.BoundingBoxHelper = function ( object, hex ) { - var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); - var weight = animation.weight; + var color = ( hex !== undefined ) ? hex : 0x888888; - if ( keyframe !== animation.currentFrame ) { + this.object = object; - this.morphTargetInfluences[ animation.lastFrame ] = 0; - this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; + this.box = new THREE.Box3(); - this.morphTargetInfluences[ keyframe ] = 0; + THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); - animation.lastFrame = animation.currentFrame; - animation.currentFrame = keyframe; +}; - } +THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); +THREE.BoundingBoxHelper.prototype.constructor = THREE.BoundingBoxHelper; - var mix = ( animation.time % frameTime ) / frameTime; +THREE.BoundingBoxHelper.prototype.update = function () { - if ( animation.directionBackwards ) mix = 1 - mix; + this.box.setFromObject( this.object ); - this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; - this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + this.box.size( this.scale ); - } + this.box.center( this.position ); }; +// File:src/extras/helpers/CameraHelper.js + /** - * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ + * + * - 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 */ -THREE.LensFlarePlugin = function () { - - var _gl, _renderer, _precision, _lensFlare = {}; +THREE.CameraHelper = function ( camera ) { - this.init = function ( renderer ) { + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); - _gl = renderer.context; - _renderer = renderer; + var pointMap = {}; - _precision = renderer.getPrecision(); + // colors - _lensFlare.vertices = new Float32Array( 8 + 8 ); - _lensFlare.faces = new Uint16Array( 6 ); + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; - var i = 0; - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. + // near - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + // far - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); - i = 0; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; + // sides - // buffers + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); - _lensFlare.vertexBuffer = _gl.createBuffer(); - _lensFlare.elementBuffer = _gl.createBuffer(); + // cone - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); + // up - // textures + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); - _lensFlare.tempTexture = _gl.createTexture(); - _lensFlare.occlusionTexture = _gl.createTexture(); + // target - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.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 ); + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.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 ); + // cross - if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); - _lensFlare.hasVertexTexture = false; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); - } else { + function addLine( a, b, hex ) { - _lensFlare.hasVertexTexture = true; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); + addPoint( a, hex ); + addPoint( b, hex ); - } + } - _lensFlare.attributes = {}; - _lensFlare.uniforms = {}; + function addPoint( id, hex ) { - _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); - _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( hex ) ); - _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); - _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); - _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); - _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); - _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); - _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); - _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); - _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); + if ( pointMap[ id ] === undefined ) { - }; + pointMap[ id ] = []; + } - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - * Then _lensFlare.update_lensFlares() is called to re-position and - * update transparency of flares. Then they are rendered. - * - */ + pointMap[ id ].push( geometry.vertices.length - 1 ); - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + } - var flares = scene.__webglFlares, - nFlares = flares.length; + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - if ( ! nFlares ) return; + this.camera = camera; + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - var tempPosition = new THREE.Vector3(); + this.pointMap = pointMap; - var invAspect = viewportHeight / viewportWidth, - halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; + this.update(); - var size = 16 / viewportHeight, - scale = new THREE.Vector2( size * invAspect, size ); +}; - var screenPosition = new THREE.Vector3( 1, 1, 0 ), - screenPositionPixels = new THREE.Vector2( 1, 1 ); +THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.CameraHelper.prototype.constructor = THREE.CameraHelper; - var uniforms = _lensFlare.uniforms, - attributes = _lensFlare.attributes; +THREE.CameraHelper.prototype.update = function () { - // set _lensFlare program and reset blending + var geometry, pointMap; + + var vector = new THREE.Vector3(); + var camera = new THREE.Camera(); - _gl.useProgram( _lensFlare.program ); + var setPoint = function ( point, x, y, z ) { - _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); - _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); + vector.set( x, y, z ).unproject( camera ); - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/unforms + var points = pointMap[ point ]; - _gl.uniform1i( uniforms.occlusionMap, 0 ); - _gl.uniform1i( uniforms.map, 1 ); + if ( points !== undefined ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + for ( var i = 0, il = points.length; i < il; i ++ ) { - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + geometry.vertices[ points[ i ] ].copy( vector ); - _gl.disable( _gl.CULL_FACE ); - _gl.depthMask( false ); + } - var i, j, jl, flare, sprite; + } - for ( i = 0; i < nFlares; i ++ ) { + }; - size = 16 / viewportHeight; - scale.set( size * invAspect, size ); + return function () { - // calc object screen position + geometry = this.geometry; + pointMap = this.pointMap; - flare = flares[ i ]; + var w = 1, h = 1; - tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + // we need just camera projection matrix + // world matrix must be identity - tempPosition.applyMatrix4( camera.matrixWorldInverse ); - tempPosition.applyProjection( camera.projectionMatrix ); + camera.projectionMatrix.copy( this.camera.projectionMatrix ); - // setup arrays for gl programs + // center / target - screenPosition.copy( tempPosition ) + setPoint( "c", 0, 0, - 1 ); + setPoint( "t", 0, 0, 1 ); - screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; - screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + // near - // screen cull + setPoint( "n1", - w, - h, - 1 ); + setPoint( "n2", w, - h, - 1 ); + setPoint( "n3", - w, h, - 1 ); + setPoint( "n4", w, h, - 1 ); - if ( _lensFlare.hasVertexTexture || ( - screenPositionPixels.x > 0 && - screenPositionPixels.x < viewportWidth && - screenPositionPixels.y > 0 && - screenPositionPixels.y < viewportHeight ) ) { + // far - // save current RGB to temp texture + setPoint( "f1", - w, - h, 1 ); + setPoint( "f2", w, - h, 1 ); + setPoint( "f3", - w, h, 1 ); + setPoint( "f4", w, h, 1 ); - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + // 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 ); - // render pink quad + // cross - _gl.uniform1i( uniforms.renderType, 0 ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + setPoint( "cf1", - w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, - h, 1 ); + setPoint( "cf4", 0, h, 1 ); - _gl.disable( _gl.BLEND ); - _gl.enable( _gl.DEPTH_TEST ); + setPoint( "cn1", - w, 0, - 1 ); + setPoint( "cn2", w, 0, - 1 ); + setPoint( "cn3", 0, - h, - 1 ); + setPoint( "cn4", 0, h, - 1 ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + geometry.verticesNeedUpdate = true; + }; - // copy result to occlusionMap +}(); - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); +// File:src/extras/helpers/DirectionalLightHelper.js +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ - // restore graphics +THREE.DirectionalLightHelper = function ( light, size ) { - _gl.uniform1i( uniforms.renderType, 1 ); - _gl.disable( _gl.DEPTH_TEST ); + THREE.Object3D.call( this ); - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + this.light = light; + this.light.updateMatrixWorld(); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - // update object positions + size = size || 1; - flare.positionScreen.copy( screenPosition ) + var geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3( - size, size, 0 ), + new THREE.Vector3( size, size, 0 ), + new THREE.Vector3( size, - size, 0 ), + new THREE.Vector3( - size, - size, 0 ), + new THREE.Vector3( - size, size, 0 ) + ); - if ( flare.customUpdateCallback ) { + var material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - flare.customUpdateCallback( flare ); + this.lightPlane = new THREE.Line( geometry, material ); + this.add( this.lightPlane ); - } else { + geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3(), + new THREE.Vector3() + ); - flare.updateLensFlares(); + material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - } + this.targetLine = new THREE.Line( geometry, material ); + this.add( this.targetLine ); - // render flares + this.update(); - _gl.uniform1i( uniforms.renderType, 2 ); - _gl.enable( _gl.BLEND ); +}; - for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { +THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.DirectionalLightHelper.prototype.constructor = THREE.DirectionalLightHelper; - sprite = flare.lensFlares[ j ]; +THREE.DirectionalLightHelper.prototype.dispose = function () { - if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); +}; - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; +THREE.DirectionalLightHelper.prototype.update = function () { - size = sprite.size * sprite.scale / viewportHeight; + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var v3 = new THREE.Vector3(); - scale.x = size * invAspect; - scale.y = size; + return function () { - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform1f( uniforms.rotation, sprite.rotation ); + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); - _gl.uniform1f( uniforms.opacity, sprite.opacity ); - _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); + this.lightPlane.lookAt( v3 ); + this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - _renderer.setTexture( sprite.texture, 1 ); + this.targetLine.geometry.vertices[ 1 ].copy( v3 ); + this.targetLine.geometry.verticesNeedUpdate = true; + this.targetLine.material.color.copy( this.lightPlane.material.color ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + }; - } +}(); - } +// File:src/extras/helpers/EdgesHelper.js - } +/** + * @author WestLangley / http://github.com/WestLangley + * @param object THREE.Mesh whose geometry will be used + * @param hex line color + * @param thresholdAngle the minimim angle (in degrees), + * between the face normals of adjacent faces, + * that is required to render an edge. A value of 10 means + * an edge is only rendered if the angle is at least 10 degrees. + */ - } +THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { - // restore gl + var color = ( hex !== undefined ) ? hex : 0xffffff; + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - _gl.enable( _gl.CULL_FACE ); - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthMask( true ); + var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); - }; + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; - function createProgram ( shader, precision ) { + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); - var program = _gl.createProgram(); + var geometry2; - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + if ( object.geometry instanceof THREE.BufferGeometry ) { - var prefix = "precision " + precision + " float;\n"; + geometry2 = new THREE.Geometry(); + geometry2.fromBufferGeometry( object.geometry ); - _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + } else { - _gl.compileShader( fragmentShader ); - _gl.compileShader( vertexShader ); + geometry2 = object.geometry.clone(); - _gl.attachShader( program, fragmentShader ); - _gl.attachShader( program, vertexShader ); + } - _gl.linkProgram( program ); + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); - return program; + var vertices = geometry2.vertices; + var faces = geometry2.faces; + var numEdges = 0; - }; + for ( var i = 0, l = faces.length; i < l; i ++ ) { -}; + var face = faces[ i ]; -/** - * @author alteredq / http://alteredqualia.com/ - */ + for ( var j = 0; j < 3; j ++ ) { -THREE.ShadowMapPlugin = function () { + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + var key = edge.toString(); - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(), + if ( hash[ key ] === undefined ) { - _min = new THREE.Vector3(), - _max = new THREE.Vector3(), + hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; + numEdges ++; - _matrixPosition = new THREE.Vector3(); + } else { - this.init = function ( renderer ) { + hash[ key ].face2 = i; - _gl = renderer.context; - _renderer = renderer; + } - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + } - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + } - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; + var coords = new Float32Array( numEdges * 2 * 3 ); - }; + var index = 0; - this.render = function ( scene, camera ) { + for ( var key in hash ) { - if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; + var h = hash[ key ]; - this.update( scene, camera ); + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { - }; + var vertex = vertices[ h.vert1 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; - this.update = function ( scene, camera ) { + vertex = vertices[ h.vert2 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; - var i, il, j, jl, n, + } - shadowMap, shadowMatrix, shadowCamera, - program, buffer, material, - webglObject, object, light, - renderList, + } - lights = [], - k = 0, + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - fog = null; + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - // set GL state for depth map + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); +}; - _gl.enable( _gl.CULL_FACE ); - _gl.frontFace( _gl.CCW ); +THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { +// File:src/extras/helpers/FaceNormalsHelper.js - _gl.cullFace( _gl.FRONT ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - } else { +THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { - _gl.cullFace( _gl.BACK ); + this.object = object; - } + this.size = ( size !== undefined ) ? size : 1; - _renderer.setDepthTest( true ); + var color = ( hex !== undefined ) ? hex : 0xffff00; - // preprocess lights - // - skip lights that are not casting shadows - // - create virtual lights for cascaded shadow maps + var width = ( linewidth !== undefined ) ? linewidth : 1; - for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { + var geometry = new THREE.Geometry(); - light = scene.__lights[ i ]; + var faces = this.object.geometry.faces; - if ( ! light.castShadow ) continue; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { + geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - for ( n = 0; n < light.shadowCascadeCount; n ++ ) { + } - var virtualLight; + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - if ( ! light.shadowCascadeArray[ n ] ) { + this.matrixAutoUpdate = false; - virtualLight = createVirtualLight( light, n ); - virtualLight.originalCamera = camera; + this.normalMatrix = new THREE.Matrix3(); - var gyro = new THREE.Gyroscope(); - gyro.position.copy( light.shadowCascadeOffset ); + this.update(); - gyro.add( virtualLight ); - gyro.add( virtualLight.target ); +}; - camera.add( gyro ); +THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper; - light.shadowCascadeArray[ n ] = virtualLight; +THREE.FaceNormalsHelper.prototype.update = function () { - console.log( "Created virtualLight", virtualLight ); + var vertices = this.geometry.vertices; - } else { + var object = this.object; + var objectVertices = object.geometry.vertices; + var objectFaces = object.geometry.faces; + var objectWorldMatrix = object.matrixWorld; - virtualLight = light.shadowCascadeArray[ n ]; + object.updateMatrixWorld( true ); - } + this.normalMatrix.getNormalMatrix( objectWorldMatrix ); - updateVirtualLight( light, n ); + for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) { - lights[ k ] = virtualLight; - k ++; + var face = objectFaces[ i ]; - } + vertices[ i2 ].copy( objectVertices[ face.a ] ) + .add( objectVertices[ face.b ] ) + .add( objectVertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( objectWorldMatrix ); - } else { + vertices[ i2 + 1 ].copy( face.normal ) + .applyMatrix3( this.normalMatrix ) + .normalize() + .multiplyScalar( this.size ) + .add( vertices[ i2 ] ); - lights[ k ] = light; - k ++; + } - } + this.geometry.verticesNeedUpdate = true; - } + return this; - // render depth map +}; - for ( i = 0, il = lights.length; i < il; i ++ ) { - light = lights[ i ]; +// File:src/extras/helpers/GridHelper.js - if ( ! light.shadowMap ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - var shadowFilter = THREE.LinearFilter; +THREE.GridHelper = function ( size, step ) { - if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - shadowFilter = THREE.NearestFilter; + this.color1 = new THREE.Color( 0x444444 ); + this.color2 = new THREE.Color( 0x888888 ); - } + for ( var i = - size; i <= size; i += step ) { - var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; + geometry.vertices.push( + new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), + new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) + ); - light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); - light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + var color = i === 0 ? this.color1 : this.color2; - light.shadowMatrix = new THREE.Matrix4(); + geometry.colors.push( color, color, color, color ); - } + } - if ( ! light.shadowCamera ) { + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - if ( light instanceof THREE.SpotLight ) { +}; - light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); +THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.GridHelper.prototype.constructor = THREE.GridHelper; - } else if ( light instanceof THREE.DirectionalLight ) { +THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { - light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); + this.color1.set( colorCenterLine ); + this.color2.set( colorGrid ); - } else { + this.geometry.colorsNeedUpdate = true; - console.error( "Unsupported light type for shadow" ); - continue; +} - } +// File:src/extras/helpers/HemisphereLightHelper.js - scene.add( light.shadowCamera ); +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); +THREE.HemisphereLightHelper = function ( light, sphereSize ) { - } + THREE.Object3D.call( this ); - if ( light.shadowCameraVisible && ! light.cameraHelper ) { + this.light = light; + this.light.updateMatrixWorld(); - light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); - light.shadowCamera.add( light.cameraHelper ); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - } + this.colors = [ new THREE.Color(), new THREE.Color() ]; - if ( light.isVirtual && virtualLight.originalCamera == camera ) { + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - updateShadowCamera( camera, light ); + for ( var i = 0, il = 8; i < il; i ++ ) { - } + geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; - shadowMap = light.shadowMap; - shadowMatrix = light.shadowMatrix; - shadowCamera = light.shadowCamera; + } - shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); - _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _matrixPosition ); - shadowCamera.updateMatrixWorld(); + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); - shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + this.lightSphere = new THREE.Mesh( geometry, material ); + this.add( this.lightSphere ); - if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; - if ( light.shadowCameraVisible ) light.cameraHelper.update(); + this.update(); - // 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 ); +THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.HemisphereLightHelper.prototype.constructor = THREE.HemisphereLightHelper; - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); +THREE.HemisphereLightHelper.prototype.dispose = function () { + this.lightSphere.geometry.dispose(); + this.lightSphere.material.dispose(); +}; - // update camera matrices and frustum +THREE.HemisphereLightHelper.prototype.update = function () { - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + var vector = new THREE.Vector3(); - // render shadow map + return function () { - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); + this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); - // set object matrices & frustum culling + this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + this.lightSphere.geometry.colorsNeedUpdate = true; - renderList = scene.__webglObjects; + } - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { +}(); - webglObject = renderList[ j ]; - object = webglObject.object; +// File:src/extras/helpers/PointLightHelper.js - webglObject.render = false; +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - if ( object.visible && object.castShadow ) { +THREE.PointLightHelper = function ( light, sphereSize ) { - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + this.light = light; + this.light.updateMatrixWorld(); - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - webglObject.render = true; + THREE.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 ); - // render regular objects + var d = light.distance; - var objectMaterial, useMorphing, useSkinning; + if ( d === 0.0 ) { - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + this.lightDistance.visible = false; - webglObject = renderList[ j ]; + } else { - if ( webglObject.render ) { + this.lightDistance.scale.set( d, d, d ); - object = webglObject.object; - buffer = webglObject.buffer; + } - // culling is overriden globally for all objects - // while rendering depth map + this.add( this.lightDistance ); + */ - // need to deal with MeshFaceMaterial somehow - // in that case just use the first of material.materials for now - // (proper solution would require to break objects by materials - // similarly to regular rendering and then set corresponding - // depth materials per each chunk instead of just once per object) +}; - objectMaterial = getObjectMaterial( object ); +THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); +THREE.PointLightHelper.prototype.constructor = THREE.PointLightHelper; - useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; +THREE.PointLightHelper.prototype.dispose = function () { - if ( object.customDepthMaterial ) { + this.geometry.dispose(); + this.material.dispose(); +}; - material = object.customDepthMaterial; +THREE.PointLightHelper.prototype.update = function () { - } else if ( useSkinning ) { + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + /* + var d = this.light.distance; - } else if ( useMorphing ) { + if ( d === 0.0 ) { - material = _depthMaterialMorph; + this.lightDistance.visible = false; - } else { + } else { - material = _depthMaterial; + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); - } + } + */ - if ( buffer instanceof THREE.BufferGeometry ) { +}; - _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); +// File:src/extras/helpers/SkeletonHelper.js - } else { +/** + * @author Sean Griffin / http://twitter.com/sgrif + * @author Michael Guerrero / http://realitymeltdown.com + * @author mrdoob / http://mrdoob.com/ + * @author ikerr / http://verold.com + */ - _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); +THREE.SkeletonHelper = function ( object ) { - } + this.bones = this.getBoneList( object ); - } + var geometry = new THREE.Geometry(); - } + for ( var i = 0; i < this.bones.length; i ++ ) { - // set matrices and render immediate objects + var bone = this.bones[ i ]; - renderList = scene.__webglObjectsImmediate; + if ( bone.parent instanceof THREE.Bone ) { - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( 0, 0, 1 ) ); + geometry.colors.push( new THREE.Color( 0, 1, 0 ) ); - webglObject = renderList[ j ]; - object = webglObject.object; + } - if ( object.visible && object.castShadow ) { + } - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } ); - _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - } + this.root = object; - } + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - } + this.update(); - // restore GL state +}; - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); +THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper; - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { +THREE.SkeletonHelper.prototype.getBoneList = function( object ) { - _gl.cullFace( _gl.BACK ); + var boneList = []; - } + if ( object instanceof THREE.Bone ) { - }; + boneList.push( object ); - function createVirtualLight( light, cascade ) { + } - var virtualLight = new THREE.DirectionalLight(); + for ( var i = 0; i < object.children.length; i ++ ) { - virtualLight.isVirtual = true; + boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); - virtualLight.onlyShadow = true; - virtualLight.castShadow = true; + } - virtualLight.shadowCameraNear = light.shadowCameraNear; - virtualLight.shadowCameraFar = light.shadowCameraFar; + return boneList; - virtualLight.shadowCameraLeft = light.shadowCameraLeft; - virtualLight.shadowCameraRight = light.shadowCameraRight; - virtualLight.shadowCameraBottom = light.shadowCameraBottom; - virtualLight.shadowCameraTop = light.shadowCameraTop; +}; - virtualLight.shadowCameraVisible = light.shadowCameraVisible; +THREE.SkeletonHelper.prototype.update = function () { - virtualLight.shadowDarkness = light.shadowDarkness; + var geometry = this.geometry; - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; - virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; + var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld ); - virtualLight.pointsWorld = []; - virtualLight.pointsFrustum = []; + var boneMatrix = new THREE.Matrix4(); - var pointsWorld = virtualLight.pointsWorld, - pointsFrustum = virtualLight.pointsFrustum; + var j = 0; - for ( var i = 0; i < 8; i ++ ) { + for ( var i = 0; i < this.bones.length; i ++ ) { - pointsWorld[ i ] = new THREE.Vector3(); - pointsFrustum[ i ] = new THREE.Vector3(); + var bone = this.bones[ i ]; - } + if ( bone.parent instanceof THREE.Bone ) { - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; + boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); + geometry.vertices[ j ].setFromMatrixPosition( boneMatrix ); - pointsFrustum[ 0 ].set( -1, -1, nearZ ); - pointsFrustum[ 1 ].set( 1, -1, nearZ ); - pointsFrustum[ 2 ].set( -1, 1, nearZ ); - pointsFrustum[ 3 ].set( 1, 1, nearZ ); + boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); + geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix ); - pointsFrustum[ 4 ].set( -1, -1, farZ ); - pointsFrustum[ 5 ].set( 1, -1, farZ ); - pointsFrustum[ 6 ].set( -1, 1, farZ ); - pointsFrustum[ 7 ].set( 1, 1, farZ ); + j += 2; - return virtualLight; + } - } + } - // Synchronize virtual light with the original light + geometry.verticesNeedUpdate = true; - function updateVirtualLight( light, cascade ) { + geometry.computeBoundingSphere(); - var virtualLight = light.shadowCascadeArray[ cascade ]; +}; - virtualLight.position.copy( light.position ); - virtualLight.target.position.copy( light.target.position ); - virtualLight.lookAt( virtualLight.target ); +// File:src/extras/helpers/SpotLightHelper.js - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - virtualLight.shadowDarkness = light.shadowDarkness; +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; +THREE.SpotLightHelper = function ( light ) { - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; + THREE.Object3D.call( this ); - var pointsFrustum = virtualLight.pointsFrustum; + this.light = light; + this.light.updateMatrixWorld(); - pointsFrustum[ 0 ].z = nearZ; - pointsFrustum[ 1 ].z = nearZ; - pointsFrustum[ 2 ].z = nearZ; - pointsFrustum[ 3 ].z = nearZ; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - pointsFrustum[ 4 ].z = farZ; - pointsFrustum[ 5 ].z = farZ; - pointsFrustum[ 6 ].z = farZ; - pointsFrustum[ 7 ].z = farZ; + var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); - } + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - // Fit shadow camera's ortho frustum to camera frustum + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - function updateShadowCamera( camera, light ) { + this.cone = new THREE.Mesh( geometry, material ); + this.add( this.cone ); - var shadowCamera = light.shadowCamera, - pointsFrustum = light.pointsFrustum, - pointsWorld = light.pointsWorld; + this.update(); - _min.set( Infinity, Infinity, Infinity ); - _max.set( -Infinity, -Infinity, -Infinity ); +}; - for ( var i = 0; i < 8; i ++ ) { +THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.SpotLightHelper.prototype.constructor = THREE.SpotLightHelper; - var p = pointsWorld[ i ]; +THREE.SpotLightHelper.prototype.dispose = function () { + this.cone.geometry.dispose(); + this.cone.material.dispose(); +}; - p.copy( pointsFrustum[ i ] ); - THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); +THREE.SpotLightHelper.prototype.update = function () { - p.applyMatrix4( shadowCamera.matrixWorldInverse ); + var vector = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); - if ( p.x < _min.x ) _min.x = p.x; - if ( p.x > _max.x ) _max.x = p.x; + return function () { - if ( p.y < _min.y ) _min.y = p.y; - if ( p.y > _max.y ) _max.y = p.y; + var coneLength = this.light.distance ? this.light.distance : 10000; + var coneWidth = coneLength * Math.tan( this.light.angle ); - if ( p.z < _min.z ) _min.z = p.z; - if ( p.z > _max.z ) _max.z = p.z; + this.cone.scale.set( coneWidth, coneWidth, coneLength ); - } + vector.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); - shadowCamera.left = _min.x; - shadowCamera.right = _max.x; - shadowCamera.top = _max.y; - shadowCamera.bottom = _min.y; + this.cone.lookAt( vector2.sub( vector ) ); - // can't really fit near/far - //shadowCamera.near = _min.z; - //shadowCamera.far = _max.z; + this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - shadowCamera.updateProjectionMatrix(); + }; - } +}(); - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use for shadow maps +// File:src/extras/helpers/VertexNormalsHelper.js - function getObjectMaterial( object ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; +THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - }; + this.object = object; -}; + this.size = ( size !== undefined ) ? size : 1; -THREE.ShadowMapPlugin.__projector = new THREE.Projector(); + var color = ( hex !== undefined ) ? hex : 0xff0000; -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + var width = ( linewidth !== undefined ) ? linewidth : 1; -THREE.SpritePlugin = function () { + var geometry = new THREE.Geometry(); - var _gl, _renderer, _texture; + var faces = object.geometry.faces; - var vertices, faces, vertexBuffer, elementBuffer; - var program, attributes, uniforms; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - this.init = function ( renderer ) { + var face = faces[ i ]; - _gl = renderer.context; - _renderer = renderer; + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - 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 - ] ); + geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - 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 ); + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faces, _gl.STATIC_DRAW ); + this.matrixAutoUpdate = false; - program = createProgram(); + this.normalMatrix = new THREE.Matrix3(); - attributes = { - position: _gl.getAttribLocation ( program, 'position' ), - uv: _gl.getAttribLocation ( program, 'uv' ) - }; + this.update(); - uniforms = { - uvOffset: _gl.getUniformLocation( program, 'uvOffset' ), - uvScale: _gl.getUniformLocation( program, 'uvScale' ), +}; - rotation: _gl.getUniformLocation( program, 'rotation' ), - scale: _gl.getUniformLocation( program, 'scale' ), +THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper; - color: _gl.getUniformLocation( program, 'color' ), - map: _gl.getUniformLocation( program, 'map' ), - opacity: _gl.getUniformLocation( program, 'opacity' ), +THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { - modelViewMatrix: _gl.getUniformLocation( program, 'modelViewMatrix' ), - projectionMatrix: _gl.getUniformLocation( program, 'projectionMatrix' ), + var v1 = new THREE.Vector3(); - 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' ), + return function( object ) { - alphaTest: _gl.getUniformLocation( program, 'alphaTest' ) - }; + var keys = [ 'a', 'b', 'c', 'd' ]; - var canvas = document.createElement( 'canvas' ); - canvas.width = 8; - canvas.height = 8; + this.object.updateMatrixWorld( true ); - var context = canvas.getContext( '2d' ); - context.fillStyle = '#ffffff'; - context.fillRect( 0, 0, canvas.width, canvas.height ); + this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - _texture = new THREE.Texture( canvas ); - _texture.needsUpdate = true; + var vertices = this.geometry.vertices; - }; + var verts = this.object.geometry.vertices; - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + var faces = this.object.geometry.faces; - var sprites = scene.__webglSprites, - nSprites = sprites.length; + var worldMatrix = this.object.matrixWorld; - if ( ! nSprites ) return; + var idx = 0; - // setup gl + for ( var i = 0, l = faces.length; i < l; i ++ ) { - _gl.useProgram( program ); + var face = faces[ i ]; - _gl.enableVertexAttribArray( attributes.position ); - _gl.enableVertexAttribArray( attributes.uv ); + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - _gl.disable( _gl.CULL_FACE ); - _gl.enable( _gl.BLEND ); + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; - _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 ); + var normal = face.vertexNormals[ j ]; - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.uniform1i( uniforms.map, 0 ); + v1.add( vertices[ idx ] ); + idx = idx + 1; - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; + vertices[ idx ].copy( v1 ); + idx = idx + 1; - if ( fog ) { + } - _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); + } - if ( fog instanceof THREE.Fog ) { + this.geometry.verticesNeedUpdate = true; - _gl.uniform1f( uniforms.fogNear, fog.near ); - _gl.uniform1f( uniforms.fogFar, fog.far ); + return this; - _gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; + } - } else if ( fog instanceof THREE.FogExp2 ) { +}()); - _gl.uniform1f( uniforms.fogDensity, fog.density ); +// File:src/extras/helpers/VertexTangentsHelper.js - _gl.uniform1i( uniforms.fogType, 2 ); - oldFogType = 2; - sceneFogType = 2; +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - } +THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { - } else { + this.object = object; - _gl.uniform1i( uniforms.fogType, 0 ); - oldFogType = 0; - sceneFogType = 0; + this.size = ( size !== undefined ) ? size : 1; - } + var color = ( hex !== undefined ) ? hex : 0x0000ff; + var width = ( linewidth !== undefined ) ? linewidth : 1; - // update positions and sort + var geometry = new THREE.Geometry(); - var i, sprite, material, fogType, scale = []; + var faces = object.geometry.faces; - for( i = 0; i < nSprites; i ++ ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - sprite = sprites[ i ]; - material = sprite.material; + var face = faces[ i ]; - if ( sprite.visible === false ) continue; + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); - sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); - } + } - sprites.sort( painterSortStable ); + } - // render all sprites + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - for( i = 0; i < nSprites; i ++ ) { + this.matrixAutoUpdate = false; - sprite = sprites[ i ]; + this.update(); - if ( sprite.visible === false ) continue; +}; - material = sprite.material; +THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.VertexTangentsHelper.prototype.constructor = THREE.VertexTangentsHelper; - _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); +THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { - scale[ 0 ] = sprite.scale.x; - scale[ 1 ] = sprite.scale.y; + var v1 = new THREE.Vector3(); - if ( scene.fog && material.fog ) { + return function( object ) { - fogType = sceneFogType; + var keys = [ 'a', 'b', 'c', 'd' ]; - } else { + this.object.updateMatrixWorld( true ); - fogType = 0; + var vertices = this.geometry.vertices; - } + var verts = this.object.geometry.vertices; - if ( oldFogType !== fogType ) { + var faces = this.object.geometry.faces; - _gl.uniform1i( uniforms.fogType, fogType ); - oldFogType = fogType; + var worldMatrix = this.object.matrixWorld; - } + var idx = 0; - if ( material.map !== null ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - _gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); - _gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); + var face = faces[ i ]; - } else { + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - _gl.uniform2f( uniforms.uvOffset, 0, 0 ); - _gl.uniform2f( uniforms.uvScale, 1, 1 ); + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; - } + var tangent = face.vertexTangents[ j ]; - _gl.uniform1f( uniforms.opacity, material.opacity ); - _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - _gl.uniform1f( uniforms.rotation, material.rotation ); - _gl.uniform2fv( uniforms.scale, scale ); + v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); - _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - _renderer.setDepthTest( material.depthTest ); - _renderer.setDepthWrite( material.depthWrite ); + v1.add( vertices[ idx ] ); + idx = idx + 1; - if ( material.map && material.map.image && material.map.image.width ) { + vertices[ idx ].copy( v1 ); + idx = idx + 1; - _renderer.setTexture( material.map, 0 ); + } - } else { + } - _renderer.setTexture( _texture, 0 ); + this.geometry.verticesNeedUpdate = true; - } + return this; - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + } - } +}()); - // restore gl +// File:src/extras/helpers/WireframeHelper.js - _gl.enable( _gl.CULL_FACE ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - }; +THREE.WireframeHelper = function ( object, hex ) { - function createProgram () { + var color = ( hex !== undefined ) ? hex : 0xffffff; - var program = _gl.createProgram(); + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); - _gl.shaderSource( vertexShader, [ + if ( object.geometry instanceof THREE.Geometry ) { - 'precision ' + _renderer.getPrecision() + ' float;', + var vertices = object.geometry.vertices; + var faces = object.geometry.faces; + var numEdges = 0; - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform float rotation;', - 'uniform vec2 scale;', - 'uniform vec2 uvOffset;', - 'uniform vec2 uvScale;', + // allocate maximal size + var edges = new Uint32Array( 6 * faces.length ); - 'attribute vec2 position;', - 'attribute vec2 uv;', + for ( var i = 0, l = faces.length; i < l; i ++ ) { - 'varying vec2 vUV;', + var face = faces[ i ]; - 'void main() {', + for ( var j = 0; j < 3; j ++ ) { - 'vUV = uvOffset + uv * uvScale;', + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - 'vec2 alignedPosition = position * scale;', + var key = edge.toString(); - 'vec2 rotatedPosition;', - 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', - 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', + if ( hash[ key ] === undefined ) { - 'vec4 finalPosition;', + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', - 'finalPosition.xy += rotatedPosition;', - 'finalPosition = projectionMatrix * finalPosition;', + } - 'gl_Position = finalPosition;', + } - '}' + } - ].join( '\n' ) ); + var coords = new Float32Array( numEdges * 2 * 3 ); - _gl.shaderSource( fragmentShader, [ + for ( var i = 0, l = numEdges; i < l; i ++ ) { - 'precision ' + _renderer.getPrecision() + ' float;', + for ( var j = 0; j < 2; j ++ ) { - 'uniform vec3 color;', - 'uniform sampler2D map;', - 'uniform float opacity;', + var vertex = vertices[ edges [ 2 * i + j] ]; - 'uniform int fogType;', - 'uniform vec3 fogColor;', - 'uniform float fogDensity;', - 'uniform float fogNear;', - 'uniform float fogFar;', - 'uniform float alphaTest;', + var index = 6 * i + 3 * j; + coords[ index + 0 ] = vertex.x; + coords[ index + 1 ] = vertex.y; + coords[ index + 2 ] = vertex.z; - 'varying vec2 vUV;', + } - 'void main() {', + } - 'vec4 texture = texture2D( map, vUV );', + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - 'if ( texture.a < alphaTest ) discard;', + } else if ( object.geometry instanceof THREE.BufferGeometry ) { - 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', + if ( object.geometry.attributes.index !== undefined ) { // Indexed BufferGeometry - 'if ( fogType > 0 ) {', + var vertices = object.geometry.attributes.position.array; + var indices = object.geometry.attributes.index.array; + var drawcalls = object.geometry.drawcalls; + var numEdges = 0; - 'float depth = gl_FragCoord.z / gl_FragCoord.w;', - 'float fogFactor = 0.0;', + if ( drawcalls.length === 0 ) { - 'if ( fogType == 1 ) {', + drawcalls = [ { count : indices.length, index : 0, start : 0 } ]; - 'fogFactor = smoothstep( fogNear, fogFar, depth );', + } - '} else {', + // allocate maximal size + var edges = new Uint32Array( 2 * indices.length ); - 'const float LOG2 = 1.442695;', - 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', - 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', + for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) { - '}', + var start = drawcalls[ o ].start; + var count = drawcalls[ o ].count; + var index = drawcalls[ o ].index; - 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', + for ( var i = start, il = start + count; i < il; i += 3 ) { - '}', + for ( var j = 0; j < 3; j ++ ) { - '}' + edge[ 0 ] = index + indices[ i + j ]; + edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; + edge.sort( sortFunction ); - ].join( '\n' ) ); + var key = edge.toString(); - _gl.compileShader( vertexShader ); - _gl.compileShader( fragmentShader ); + if ( hash[ key ] === undefined ) { - _gl.attachShader( program, vertexShader ); - _gl.attachShader( program, fragmentShader ); + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - _gl.linkProgram( program ); + } - return program; + } - }; + } - function painterSortStable ( a, b ) { + } - if ( a.z !== b.z ) { + var coords = new Float32Array( numEdges * 2 * 3 ); - return b.z - a.z; + for ( var i = 0, l = numEdges; i < l; i ++ ) { - } else { + for ( var j = 0; j < 2; j ++ ) { - return b.id - a.id; + var index = 6 * i + 3 * j; + var index2 = 3 * edges[ 2 * i + j]; + coords[ index + 0 ] = vertices[ index2 ]; + coords[ index + 1 ] = vertices[ index2 + 1 ]; + coords[ index + 2 ] = vertices[ index2 + 2 ]; - } + } - }; + } -}; + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + } else { // non-indexed BufferGeometry -THREE.DepthPassPlugin = function () { + var vertices = object.geometry.attributes.position.array; + var numEdges = vertices.length / 3; + var numTris = numEdges / 3; - this.enabled = false; - this.renderTarget = null; + var coords = new Float32Array( numEdges * 2 * 3 ); - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + for ( var i = 0, l = numTris; i < l; i ++ ) { - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(); + for ( var j = 0; j < 3; j ++ ) { - this.init = function ( renderer ) { + var index = 18 * i + 6 * j; - _gl = renderer.context; - _renderer = renderer; + var index1 = 9 * i + 3 * j; + coords[ index + 0 ] = vertices[ index1 ]; + coords[ index + 1 ] = vertices[ index1 + 1 ]; + coords[ index + 2 ] = vertices[ index1 + 2 ]; - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); + coords[ index + 3 ] = vertices[ index2 ]; + coords[ index + 4 ] = vertices[ index2 + 1 ]; + coords[ index + 5 ] = vertices[ index2 + 2 ]; - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + } - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; + } - }; + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - this.render = function ( scene, camera ) { + } - if ( ! this.enabled ) return; + } - this.update( scene, camera ); + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - }; + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - this.update = function ( scene, camera ) { +}; - var i, il, j, jl, n, +THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; - program, buffer, material, - webglObject, object, light, - renderList, +// File:src/extras/objects/ImmediateRenderObject.js - fog = null; +/** + * @author alteredq / http://alteredqualia.com/ + */ - // set GL state for depth map +THREE.ImmediateRenderObject = function () { - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); + THREE.Object3D.call( this ); - _renderer.setDepthTest( true ); + this.render = function ( renderCallback ) {}; - // update scene +}; - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); +THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; - // update camera matrices and frustum +// File:src/extras/objects/MorphBlendMesh.js - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); +/** + * @author alteredq / http://alteredqualia.com/ + */ - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); +THREE.MorphBlendMesh = function( geometry, material ) { - // render depth map + THREE.Mesh.call( this, geometry, material ); - _renderer.setRenderTarget( this.renderTarget ); - _renderer.clear(); + this.animationsMap = {}; + this.animationsList = []; - // set object matrices & frustum culling + // prepare default animation + // (all frames played together in 1 second) - renderList = scene.__webglObjects; + var numFrames = this.geometry.morphTargets.length; - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + var name = "__default"; - webglObject = renderList[ j ]; - object = webglObject.object; + var startFrame = 0; + var endFrame = numFrames - 1; - webglObject.render = false; + var fps = numFrames / 1; - if ( object.visible ) { + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { +}; - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; - webglObject.render = true; +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { - } + var animation = { - } + startFrame: start, + endFrame: end, - } + length: end - start + 1, - // render regular objects + fps: fps, + duration: ( end - start ) / fps, - var objectMaterial, useMorphing, useSkinning; + lastFrame: 0, + currentFrame: 0, - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + active: false, - webglObject = renderList[ j ]; + time: 0, + direction: 1, + weight: 1, - if ( webglObject.render ) { + directionBackwards: false, + mirroredLoop: false - object = webglObject.object; - buffer = webglObject.buffer; + }; - // todo: create proper depth material for particles + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); - if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; +}; - objectMaterial = getObjectMaterial( object ); +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { - if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); + var pattern = /([a-z]+)_?(\d+)/; - useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + var firstAnimation, frameRanges = {}; - if ( object.customDepthMaterial ) { + var geometry = this.geometry; - material = object.customDepthMaterial; + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - } else if ( useSkinning ) { + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + if ( chunks && chunks.length > 1 ) { - } else if ( useMorphing ) { + var name = chunks[ 1 ]; - material = _depthMaterialMorph; + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; - } else { + var range = frameRanges[ name ]; - material = _depthMaterial; + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; - } + if ( ! firstAnimation ) firstAnimation = name; - if ( buffer instanceof THREE.BufferGeometry ) { + } - _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); + } - } else { + for ( var name in frameRanges ) { - _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); - } + } - } + this.firstAnimation = firstAnimation; - } +}; - // set matrices and render immediate objects +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - renderList = scene.__webglObjectsImmediate; + var animation = this.animationsMap[ name ]; - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + if ( animation ) { - webglObject = renderList[ j ]; - object = webglObject.object; + animation.direction = 1; + animation.directionBackwards = false; - if ( object.visible ) { + } - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); +}; - _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - } + var animation = this.animationsMap[ name ]; - } + if ( animation ) { - // restore GL state + animation.direction = - 1; + animation.directionBackwards = true; - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); + } - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); +}; - }; +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use + var animation = this.animationsMap[ name ]; - function getObjectMaterial( object ) { + if ( animation ) { - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; - }; + } }; +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + + var animation = this.animationsMap[ name ]; -/** - * @author mikael emtinger / http://gomo.se/ - */ + if ( animation ) { -THREE.ShaderFlares = { + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; - 'lensFlareVertexTexture': { + } - vertexShader: [ +}; + +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + + var animation = this.animationsMap[ name ]; - "uniform lowp int renderType;", + if ( animation ) { - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", + animation.weight = weight; - "uniform sampler2D occlusionMap;", + } - "attribute vec2 position;", - "attribute vec2 uv;", +}; + +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { - "varying vec2 vUV;", - "varying float vVisibility;", + var animation = this.animationsMap[ name ]; - "void main() {", + if ( animation ) { - "vUV = uv;", + animation.time = time; - "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 ) );", +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { - "vVisibility = visibility.r / 9.0;", - "vVisibility *= 1.0 - visibility.g / 9.0;", - "vVisibility *= visibility.b / 9.0;", - "vVisibility *= 1.0 - visibility.a / 9.0;", + var time = 0; - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + var animation = this.animationsMap[ name ]; - "}", + if ( animation ) { - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + time = animation.time; - "}" + } - ].join( "\n" ), + return time; - fragmentShader: [ +}; - "uniform lowp int renderType;", +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { - "uniform sampler2D map;", - "uniform float opacity;", - "uniform vec3 color;", + var duration = - 1; - "varying vec2 vUV;", - "varying float vVisibility;", + var animation = this.animationsMap[ name ]; - "void main() {", + if ( animation ) { - // pink square + duration = animation.duration; - "if( renderType == 0 ) {", + } - "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + return duration; - // restore +}; - "} else if( renderType == 1 ) {", +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { - "gl_FragColor = texture2D( map, vUV );", + var animation = this.animationsMap[ name ]; - // flare + if ( animation ) { - "} else {", + animation.time = 0; + animation.active = true; - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * vVisibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", + } else { - "}", + THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); - "}" - ].join( "\n" ) + } - }, +}; +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { - 'lensFlare': { + var animation = this.animationsMap[ name ]; - vertexShader: [ + if ( animation ) { - "uniform lowp int renderType;", + animation.active = false; - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", + } - "attribute vec2 position;", - "attribute vec2 uv;", +}; - "varying vec2 vUV;", +THREE.MorphBlendMesh.prototype.update = function ( delta ) { - "void main() {", + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { - "vUV = uv;", + var animation = this.animationsList[ i ]; - "vec2 pos = position;", + if ( ! animation.active ) continue; - "if( renderType == 2 ) {", + var frameTime = animation.duration / animation.length; - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + animation.time += animation.direction * delta; - "}", + if ( animation.mirroredLoop ) { - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + if ( animation.time > animation.duration || animation.time < 0 ) { - "}" + animation.direction *= - 1; - ].join( "\n" ), + if ( animation.time > animation.duration ) { - fragmentShader: [ + animation.time = animation.duration; + animation.directionBackwards = true; - "precision mediump float;", + } - "uniform lowp int renderType;", + if ( animation.time < 0 ) { - "uniform sampler2D map;", - "uniform sampler2D occlusionMap;", - "uniform float opacity;", - "uniform vec3 color;", + animation.time = 0; + animation.directionBackwards = false; - "varying vec2 vUV;", + } - "void main() {", + } - // pink square + } else { - "if( renderType == 0 ) {", + animation.time = animation.time % animation.duration; - "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", + if ( animation.time < 0 ) animation.time += animation.duration; - // restore + } - "} else if( renderType == 1 ) {", + var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; - "gl_FragColor = texture2D( map, vUV );", + if ( keyframe !== animation.currentFrame ) { - // flare + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; - "} else {", + this.morphTargetInfluences[ keyframe ] = 0; - "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", - "visibility = ( 1.0 - visibility / 4.0 );", + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * visibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", + } - "}", + var mix = ( animation.time % frameTime ) / frameTime; - "}" + if ( animation.directionBackwards ) mix = 1 - mix; - ].join( "\n" ) + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; - } + } }; + + global.THREE = THREE; + From 9a7fc33b7af6d17081afe9647f027b93dd5398d4 Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Apr 2015 02:38:11 -0400 Subject: [PATCH 07/43] don't init stats in node --- scripts/systems/physics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/systems/physics.js b/scripts/systems/physics.js index b287c62..857645c 100644 --- a/scripts/systems/physics.js +++ b/scripts/systems/physics.js @@ -14,7 +14,7 @@ elation.require(["physics.cyclone"], function() { this.system = new elation.physics.system({autostart: false}); // Only show second framerate gauge if physics system is decoupled from framerate - if (this.async) { + if (this.async && ENV_IS_BROWSER) { this.initstats(); } } From 94cd779c9bca931e1abded0beac088f183ebbe37 Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Apr 2015 02:45:32 -0400 Subject: [PATCH 08/43] make an undefined window var in engine.frame() if running in node.js --- scripts/engine.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/engine.js b/scripts/engine.js index 6174bc5..37fb565 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -86,6 +86,7 @@ elation.require(deps, function() { } })(); this.frame = function(fn) { + if (ENV_IS_NODE) var window; this.requestAnimationFrame.call(window, fn); } From 551a42c970f9cf3545833daed611599f7de3f4f5 Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 28 Apr 2015 06:04:46 -0400 Subject: [PATCH 09/43] add ability to sync things other than players (doesn't work very well right now), add websocket server --- scripts/systems/client.js | 39 +++++++-- scripts/systems/server.js | 167 ++++++++++++++++++++++++++++---------- scripts/things/ball.js | 10 ++- scripts/things/generic.js | 8 +- scripts/things/player.js | 3 +- 5 files changed, 164 insertions(+), 63 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index a95fb0e..37d0c00 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -7,14 +7,14 @@ elation.extend("engine.systems.client", function(args) { this.lastUpdate = Date.now(); this.lastMessage = null; var UPDATE_INTERVAL = 25; // ms - var MAX_EXTRAP_TIME = 200; // ms + var MAX_EXTRAP_TIME = 100; // ms this.system_attach = function(ev) { console.log('INIT: networking client'); this.world = this.engine.systems.world; console.log('this.world:', this.world); this.connection = new elation.engine.systems.client.connection({ - transport: 'webrtc', + transport: 'websocket', host: 'dev.brandonhinshaw.us', port: '9001' }); @@ -24,15 +24,34 @@ elation.extend("engine.systems.client", function(args) { }; this.onNewThing = function(ev) { - console.log('new thing', ev.data.thing); + // console.log('new thing', ev.data.thing); var thing = ev.data.thing; - console.log('hastag:',thing.hasTag('local_sync')) if (thing.hasTag('local_sync')) { - console.log('local sync'); - elation.events.add(thing, 'thing_change', elation.bind(this, this.onThingChange)); + console.log(ev.data); + if (thing.type != 'vrcadeplayer') { + var msgdata = { + type: 'add_thing', + data: { thing: thing.serialize() } + }; + console.info('sending add_thing to server:', msgdata); + this.send(msgdata); + } + else { + elation.events.add(thing, 'thing_change', elation.bind(this, this.onThingChange)); + } + thing.removeTag('local_sync'); + } + // FIXME }; + this.sendNewThing = function() { + var msg = { + type: 'new_thing', + data: 'test' + }; + } + this.onThingChange = function(ev) { var thing = ev.target; if (!thing.hasTag('thing_changed')) { @@ -52,6 +71,7 @@ elation.extend("engine.systems.client", function(args) { } }; this.send(msgdata); + this.lastUpdate = Date.now(); } } }; @@ -135,7 +155,7 @@ elation.extend('engine.systems.client.connection', function(opts) { }); elation.extend('engine.systems.client.websocket', function(opts) { - this.address = 'ws://' + opts.address + opts.port; + this.address = 'ws://' + opts.host + ':' + opts.port; this.init = function() { this.connect(); @@ -143,7 +163,7 @@ elation.extend('engine.systems.client.websocket', function(opts) { this.connect = function() { if (!this.websocket) { - this.websocket = new WebSocket(this.address); + this.websocket = new WebSocket(this.address, 'arraybuffer'); elation.events.add(this.websocket, "open", elation.bind(this, this.onOpen)); elation.events.add(this.websocket, "message", elation.bind(this, this.onMessage)); elation.events.add(this.websocket, "close", elation.bind(this, this.onClose)); @@ -158,7 +178,7 @@ elation.extend('engine.systems.client.websocket', function(opts) { }; this.send = function(data) { - this.websocket.send(data); + this.websocket.send(JSON.stringify(data)); }; this.onOpen = function(ev) { @@ -175,6 +195,7 @@ elation.extend('engine.systems.client.websocket', function(opts) { this.websocket = null; }; + this.init(); }); elation.extend('engine.systems.client.webrtc', function(socketOpts) { diff --git a/scripts/systems/server.js b/scripts/systems/server.js index e2c181c..3aa55d1 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -3,16 +3,19 @@ elation.extend("engine.systems.server", function(args) { var wrtc = require('wrtc'); this.clients = {}; this.transport = 'webrtc'; + var UPDATE_RATE = 40; // ms + this.lastUpdate = null; //ms this.system_attach = function(ev) { console.log('INIT: networking server'); this.world = this.engine.systems.world; - this.webrtc = new elation.engine.systems.server.webrtc; + // FIXME - hardcoded ws/wrtc setup, should be in a config + this.server = new elation.engine.systems.server.websocket; var events = [ - [this.webrtc, 'client_disconnected', this.onClientConnect], - [this.webrtc, 'client_connected', this.onClientConnect], - [this.world, 'world_thing_remove', this.onThingRemove], + [this.server, 'client_disconnected', this.onClientDisconnect], + [this.server, 'client_connected', this.onClientConnect], + // [this.world, 'world_thing_remove', this.onThingRemove], [this.world, 'world_thing_add', this.onThingAdd], // [this.world, 'world_thing_change', this.onThingChange] ]; @@ -35,7 +38,7 @@ elation.extend("engine.systems.server", function(args) { }; this.engine_frame = function() { - + this.sendChanges(); }; this.sendToAll = function(data) { @@ -48,7 +51,7 @@ elation.extend("engine.systems.server", function(args) { this.onClientConnect = function(ev) { var client = new elation.engine.systems.server.client({ - transport: 'webrtc', + transport: 'websocket', id: ev.data.id, socket: ev.data.channel }); @@ -56,6 +59,7 @@ elation.extend("engine.systems.server", function(args) { elation.events.add(client, 'received_id', elation.bind(this, this.sendWorldData)); elation.events.add(client, 'new_player', elation.bind(this, this.handleNewPlayer)); elation.events.add(client, 'thing_changed', elation.bind(this, this.onRemoteThingChange)); + elation.events.add(client, 'new_thing', elation.bind(this, this.onNewThing)); console.log('client connected', client.id); client.send({ type: 'id_token', data: client.id }); }; @@ -63,7 +67,11 @@ elation.extend("engine.systems.server", function(args) { this.handleNewPlayer = function(ev) { // console.log(ev); elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing}}); - } + }; + + this.handleNewThing = function(ev) { + elation.events.fire({type: 'add_thing', data: {thing: ev.data.data.thing}}); + }; this.sendWorldData = function(evt) { // console.log('got id', evt); @@ -73,28 +81,52 @@ elation.extend("engine.systems.server", function(args) { this.onThingAdd = function(ev) { console.log('thing add', ev.data.thing.name); - this.sendToAll({ type: 'thing_added', data: ev.data.thing.serialize() }); + var client_id = ev.data.thing.properties.player_id; + + var msg = { type: 'thing_added', data: ev.data.thing.serialize() }; + if (this.clients.hasOwnProperty(client_id)) { + for (var client in this.clients) { + if (this.clients.hasOwnProperty(client_id) && client != client_id ) { + this.clients[client].send(msg); + } + } + } + else { + this.sendToAll(msg); + } }; this.onThingRemove = function(ev) { - console.log('thing remove', ev.data.thing.name); - this.sendToAll({ type:'thing_removed', data: ev.data.thing.name }); + // console.log('thing remove', ev.data.thing.name); + // this.sendToAll({ type:'thing_removed', data: ev.data.thing.name }); }; this.onThingChange = function(ev) { - // console.log('world thing changed', ev.target.serialize()); - var msg = { type: 'thing_changed', data: ev.target.serialize() }; - if (this.clients.hasOwnProperty(ev.target.name)) { - for (var client in this.clients) { - if (this.clients.hasOwnProperty(client) && client != ev.target.name) { - // console.log('sending msg to', client, 'about change in', ev.target.name); - this.clients[client].send(msg); - } - } + var thing = ev.target || ev.element; + if (!thing.hasTag('thing_changed')) { + thing.addTag('thing_changed'); } - else { - // console.log('sending to all'); - this.sendToAll(msg); + }; + + this.sendChanges = function() { + if (Date.now() - this.lastUpdate > UPDATE_RATE) { + var changed = this.world.getThingsByTag('thing_changed'); + for (var i = 0; i < changed.length; i++) { + var thing = changed[i]; + thing.removeTag('thing_changed'); + var msgdata = { + type: 'thing_changed', data: thing.serialize() + }; + if (this.clients.hasOwnProperty(thing.properties.player_id)) { + for (var client in this.clients) { + if (this.clients.hasOwnProperty(client) && client != thing.properties.player_id) { + this.clients[client].send(msgdata); + } + } + } + else { this.sendToAll(msgdata); } + } + this.lastUpdate = Date.now(); } } @@ -109,8 +141,8 @@ elation.extend("engine.systems.server", function(args) { this.onClientDisconnect = function(ev) { // console.log(ev); var client = this.clients[ev.data]; - elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); - elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); + // elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); + // elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); this.removeClient(ev.data); elation.events.fire({type: 'destroy_player', data: ev.data}); console.log('Client disconnected, num clients:', Object.keys(this.clients).length); @@ -123,36 +155,81 @@ elation.extend("engine.systems.server.client", function(args) { * This object represents a client connection * */ + this.transport = args.transport; this.id = args.id; this.socket = args.socket; this.lastMessage = null; - this.send = function(data) { - if (this.socket.readyState == 'open') { - // console.log('sent a msg'); - data.timestamp = Date.now(); - this.socket.send(JSON.stringify(data)); - } - }; + this.transport = args.transport; - this.socket.onmessage = function(evt) { - var msgdata = JSON.parse(evt.data); - var timestamp = msgdata.timestamp; - if (!this.lastMessage) this.lastMessage = timestamp; - if (timestamp >= this.lastMessage) { - // only fire an event if the message is newer than the last received msg - var evdata = { - type: msgdata.type, - data: { id: this.id, data: msgdata.data } + //FIXME - make this a proper polymorphic object + if (this.transport == 'webrtc') { + this.send = function(data) { + if (this.socket.readyState == 'open') { + // console.log('sent a msg'); + data.timestamp = Date.now(); + this.socket.send(JSON.stringify(data)); + } + }; + + this.socket.onmessage = function(evt) { + var msgdata = JSON.parse(evt.data); + var timestamp = msgdata.timestamp; + if (!this.lastMessage) this.lastMessage = timestamp; + if (timestamp >= this.lastMessage) { + // only fire an event if the message is newer than the last received msg + var evdata = { + type: msgdata.type, + data: { id: this.id, data: msgdata.data } + }; + elation.events.fire(evdata); + this.lastMessage = timestamp; + } else { console.log('discarded a message'); } + }; + } + if (this.transport == 'websocket') { + this.send = function(data) { + try { + data.timestamp = Date.now(); + this.socket.send(JSON.stringify(data)); + } + catch(e) { console.log(e) } + }; + this.socket.on('message', function(msg, flags) { + var msgdata = JSON.parse(msg); + var timestamp = msgdata.timestamp; + if (!this.lastMessage) this.lastMessage = timestamp; + if (timestamp >= this.lastMessage) { + // only fire an event if the message is newer than the last received msg + var evdata = { + type: msgdata.type, + data: { id: this.id, data: msgdata.data } + }; + elation.events.fire(evdata); + this.lastMessage = timestamp; }; - elation.events.fire(evdata); - this.lastMessage = timestamp; - } else { console.log('discarded a message'); } - }; - + }); + } }); + + +// FIXME - servers should take args for port/etc +elation.extend("engine.systems.server.websocket", function() { + var wsServer = require('ws').Server, + wss = new wsServer({ port: 9001 }); + + wss.on('connection', function(ws) { + console.log('websocket conn'); + var id = Date.now(); + elation.events.fire({ type: 'client_connected', data: {id: id, channel: ws}}); + ws.on('close', function() { + elation.events.fire({type: 'client_disconnected', data: id}); + }); + }); + +}) elation.extend("engine.systems.server.webrtc", function() { var http = require('http'); var webrtc = require('wrtc'); diff --git a/scripts/things/ball.js b/scripts/things/ball.js index 5f7dee8..957f12e 100644 --- a/scripts/things/ball.js +++ b/scripts/things/ball.js @@ -6,9 +6,11 @@ elation.require(['engine.things.generic'], function() { lifetime: { type: 'float', default: 0 }, gravity: { type: 'bool', default: true }, }); + this.addTag('local_sync'); + if (this.properties.lifetime != 0) { this.age = 0; - elation.events.add(this.engine, 'engine_frame', elation.bind(this, function(ev) { this.age += ev.data.delta * this.engine.systems.physics.timescale; if (this.age > this.properties.lifetime) this.die(); })); + // elation.events.add(this.engine, 'engine_frame', elation.bind(this, function(ev) { this.age += ev.data.delta * this.engine.systems.physics.timescale; if (this.age > this.properties.lifetime) this.die(); })); } } this.createObject3D = function() { @@ -16,9 +18,9 @@ elation.require(['engine.things.generic'], function() { var mat = new THREE.MeshPhongMaterial({ color: 0xd74e2e, emissive: 0x330000, - map: elation.engine.materials.getTexture('/media/space/textures/bball.jpg'), - bumpMap: elation.engine.materials.getTexture('/media/space/textures/bball-bump.png'), - bumpScale: .05 + // map: elation.engine.materials.getTexture('/media/space/textures/bball.jpg'), + // bumpMap: elation.engine.materials.getTexture('/media/space/textures/bball-bump.png'), + // bumpScale: .05 }); var obj = new THREE.Mesh(geo, mat); obj.castShadow = true; diff --git a/scripts/things/generic.js b/scripts/things/generic.js index a1a4e27..008a6f8 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -47,7 +47,8 @@ elation.component.add("engine.things.generic", function() { 'render.collada': { type: 'string', comment: 'URL for Collada scene file' }, 'render.gltf': { type: 'string', comment: 'URL for glTF file' }, 'render.materialname': { type: 'string', comment: 'Material library name' }, - 'render.texturepath': { type: 'string', comment: 'Texture location' } + 'render.texturepath': { type: 'string', comment: 'Texture location' }, + 'player_id': { type: 'float', default: null, comment: 'Network id of the creator' } }); this.defineEvents({ 'thing_create': [], @@ -406,7 +407,7 @@ elation.component.add("engine.things.generic", function() { elation.events.fire({type: 'thing_add', element: this, data: {thing: thing}}); return true; } else { - console.log("Couldn't add ", thing, " already exists in ", this); + console.log("Couldn't add ", thing.name, " already exists in ", this.name); } return false; } @@ -424,7 +425,7 @@ elation.component.add("engine.things.generic", function() { elation.events.fire({type: 'thing_remove', element: this, data: {thing: thing}}); delete this.children[thing.id]; } else { - console.log("Couldn't remove ", thing, " doesn't exist in ", this); + console.log("Couldn't remove ", thing.name, " doesn't exist in ", this.name); } } this.reparent = function(newparent) { @@ -887,6 +888,7 @@ console.log(thispos.toArray(), otherpos.toArray(), dir.toArray(), axis.toArray() var ref = propval; propval = [ ref.type, ref.id ]; break; + } if (propval !== null && !elation.utils.isIdentical(propval, propdef.default)) { //elation.utils.arrayset(ret.properties, k, propval); diff --git a/scripts/things/player.js b/scripts/things/player.js index 39afb87..ea90bee 100644 --- a/scripts/things/player.js +++ b/scripts/things/player.js @@ -71,8 +71,7 @@ elation.require(['engine.things.generic', 'ui.progressbar', 'engine.things.ball' camdir.multiplyScalar(velocity); camdir.add(this.objects.dynamics.velocity); //console.log('pew!', velocity); - var foo = this.spawn('ball', 'ball_' + Math.round(Math.random() * 100000), { radius: .375, mass: 1, position: campos, velocity: camdir, lifetime: 30, gravity: this.usegravity }, true); - + var foo = this.spawn('ball', 'ball_' + Math.round(Math.random() * 100000), { radius: .375, mass: 1, position: campos, velocity: camdir, lifetime: 10, gravity: this.usegravity, player_id: this.properties.player_id }, true); /* if (!this.lights[this.lightnum]) { this.lights[this.lightnum] = foo.spawn('light', null, { radius: 60, intensity: 1, color: 0xffffff}); From 0c68ef51fc330e1005cc4e9f82e15e204a10dc7c Mon Sep 17 00:00:00 2001 From: bioid Date: Wed, 29 Apr 2015 03:02:47 -0400 Subject: [PATCH 10/43] add adminserver to server.js --- scripts/systems/server.js | 46 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 3aa55d1..4397085 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -11,12 +11,14 @@ elation.extend("engine.systems.server", function(args) { this.world = this.engine.systems.world; // FIXME - hardcoded ws/wrtc setup, should be in a config this.server = new elation.engine.systems.server.websocket; + this.adminServer = new elation.engine.systems.server.adminserver; var events = [ [this.server, 'client_disconnected', this.onClientDisconnect], [this.server, 'client_connected', this.onClientConnect], - // [this.world, 'world_thing_remove', this.onThingRemove], [this.world, 'world_thing_add', this.onThingAdd], + [this.adminServer, 'admin_client_connected', this.onAdminClientConnect], + // [this.world, 'world_thing_remove', this.onThingRemove], // [this.world, 'world_thing_change', this.onThingChange] ]; @@ -25,6 +27,29 @@ elation.extend("engine.systems.server", function(args) { }; }; + this.serialize_clients = function() { + var obj = {}; + for (var client in this.clients) { + if (this.clients.hasOwnProperty(client)) { + obj[client] = { + id: this.clients[client].id + } + } + } + return obj; + } + + this.onAdminClientConnect = function(ev) { + ev.data.channel.send(JSON.stringify(this.serialize_world())); + var playermsg = { + type: 'player_data', + data: this.serialize_clients() + }; + + + ev.data.channel.send(JSON.stringify(playermsg)); + } + this.addEvent = function(args) { elation.events.add(args[0], args[1], elation.bind(this, args[2])); }; @@ -219,9 +244,9 @@ elation.extend("engine.systems.server.client", function(args) { elation.extend("engine.systems.server.websocket", function() { var wsServer = require('ws').Server, wss = new wsServer({ port: 9001 }); - + console.log('websocket server running on 9001') wss.on('connection', function(ws) { - console.log('websocket conn'); + console.log('game server websocket conn'); var id = Date.now(); elation.events.fire({ type: 'client_connected', data: {id: id, channel: ws}}); ws.on('close', function() { @@ -229,6 +254,21 @@ elation.extend("engine.systems.server.websocket", function() { }); }); +}) + +elation.extend("engine.systems.server.adminserver", function() { + var wsServer = require('ws').Server, + wss = new wsServer({ port: 9002 }); + console.log('admin server running on 9002'); + wss.on('connection', function(ws) { + console.log('admin server websocket conn'); + var id = Date.now(); + elation.events.fire({ type: 'admin_client_connected', data: {id: id, channel: ws}}); + ws.on('close', function() { + elation.events.fire({type: 'admin_client_disconnected', data: id}); + }); + }); + }) elation.extend("engine.systems.server.webrtc", function() { var http = require('http'); From 2e5759bc295827e504814fb079f64752aab9e336 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 1 May 2015 00:09:40 -0400 Subject: [PATCH 11/43] fix up syncing of physics objects between clients/server --- scripts/systems/client.js | 2 +- scripts/systems/server.js | 64 +++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index 37d0c00..931f610 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -7,7 +7,7 @@ elation.extend("engine.systems.client", function(args) { this.lastUpdate = Date.now(); this.lastMessage = null; var UPDATE_INTERVAL = 25; // ms - var MAX_EXTRAP_TIME = 100; // ms + var MAX_EXTRAP_TIME = 200; // ms this.system_attach = function(ev) { console.log('INIT: networking client'); diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 4397085..6e82560 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -2,7 +2,8 @@ elation.extend("engine.systems.server", function(args) { elation.implement(this, elation.engine.systems.system); var wrtc = require('wrtc'); this.clients = {}; - this.transport = 'webrtc'; + this.adminClients = []; + this.transport = 'websocket'; var UPDATE_RATE = 40; // ms this.lastUpdate = null; //ms @@ -23,8 +24,8 @@ elation.extend("engine.systems.server", function(args) { ]; for (var i = 0; i < events.length; i++) { - this.addEvent(events[i]) - }; + this.addEvent(events[i]); + } }; this.serialize_clients = function() { @@ -33,22 +34,20 @@ elation.extend("engine.systems.server", function(args) { if (this.clients.hasOwnProperty(client)) { obj[client] = { id: this.clients[client].id - } + }; } } return obj; - } + }; this.onAdminClientConnect = function(ev) { ev.data.channel.send(JSON.stringify(this.serialize_world())); - var playermsg = { - type: 'player_data', - data: this.serialize_clients() - }; - - - ev.data.channel.send(JSON.stringify(playermsg)); - } + // var playermsg = { + // type: 'player_data', + // data: this.serialize_clients() + // }; + this.adminClients.push(ev.data.channel); + }; this.addEvent = function(args) { elation.events.add(args[0], args[1], elation.bind(this, args[2])); @@ -72,7 +71,7 @@ elation.extend("engine.systems.server", function(args) { this.clients[client].send(data); } } - } + }; this.onClientConnect = function(ev) { var client = new elation.engine.systems.server.client({ @@ -85,12 +84,12 @@ elation.extend("engine.systems.server", function(args) { elation.events.add(client, 'new_player', elation.bind(this, this.handleNewPlayer)); elation.events.add(client, 'thing_changed', elation.bind(this, this.onRemoteThingChange)); elation.events.add(client, 'new_thing', elation.bind(this, this.onNewThing)); + elation.events.add(client, 'socket_message_sent', elation.bind(this, this.onSocketSend)); console.log('client connected', client.id); client.send({ type: 'id_token', data: client.id }); }; this.handleNewPlayer = function(ev) { - // console.log(ev); elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing}}); }; @@ -99,15 +98,14 @@ elation.extend("engine.systems.server", function(args) { }; this.sendWorldData = function(evt) { - // console.log('got id', evt); var client = this.clients[evt.data.data]; client.send(this.serialize_world()); }; this.onThingAdd = function(ev) { console.log('thing add', ev.data.thing.name); + // elation.events.add(ev.data.thing, 'thing_change', this.onThingChange); var client_id = ev.data.thing.properties.player_id; - var msg = { type: 'thing_added', data: ev.data.thing.serialize() }; if (this.clients.hasOwnProperty(client_id)) { for (var client in this.clients) { @@ -122,12 +120,12 @@ elation.extend("engine.systems.server", function(args) { }; this.onThingRemove = function(ev) { - // console.log('thing remove', ev.data.thing.name); - // this.sendToAll({ type:'thing_removed', data: ev.data.thing.name }); + // TODO }; this.onThingChange = function(ev) { var thing = ev.target || ev.element; + // console.log('THING CHANGE', thing.type, thing.name, 'pos: ', thing.properties.position); if (!thing.hasTag('thing_changed')) { thing.addTag('thing_changed'); } @@ -153,11 +151,11 @@ elation.extend("engine.systems.server", function(args) { } this.lastUpdate = Date.now(); } - } + }; this.onRemoteThingChange = function(ev) { elation.events.fire('remote_thing_change', ev.data); - } + }; this.removeClient = function(id) { delete this.clients[id]; @@ -166,13 +164,24 @@ elation.extend("engine.systems.server", function(args) { this.onClientDisconnect = function(ev) { // console.log(ev); var client = this.clients[ev.data]; - // elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); - // elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); + elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); + elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); this.removeClient(ev.data); elation.events.fire({type: 'destroy_player', data: ev.data}); console.log('Client disconnected, num clients:', Object.keys(this.clients).length); }; + this.onSocketSend = function(ev) { + var msg = { + type: ev.type, + data: ev.data + }; + // console.log('sent message',msg); + this.adminServer.wss.clients.forEach(function(client){ + client.send(JSON.stringify(msg)); + }); + }; + }); elation.extend("engine.systems.server.client", function(args) { @@ -215,9 +224,11 @@ elation.extend("engine.systems.server.client", function(args) { } if (this.transport == 'websocket') { this.send = function(data) { + // console.log('foo'); try { data.timestamp = Date.now(); this.socket.send(JSON.stringify(data)); + elation.events.fire({type: 'socket_message_sent', data:{type: data.type, data: data.data, client_id: this.id, timestamp: data.timestamp}}); } catch(e) { console.log(e) } }; @@ -257,10 +268,11 @@ elation.extend("engine.systems.server.websocket", function() { }) elation.extend("engine.systems.server.adminserver", function() { - var wsServer = require('ws').Server, - wss = new wsServer({ port: 9002 }); + var wsServer = require('ws').Server; + //FIXME - port hardcoded + this.wss = new wsServer({ port: 9002 }); console.log('admin server running on 9002'); - wss.on('connection', function(ws) { + this.wss.on('connection', function(ws) { console.log('admin server websocket conn'); var id = Date.now(); elation.events.fire({ type: 'admin_client_connected', data: {id: id, channel: ws}}); From 9dbac6f01871593663de5d79f56819478770fb19 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 1 May 2015 00:22:40 -0400 Subject: [PATCH 12/43] things.generic - call this.refresh() on physics_update --- scripts/things/generic.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 008a6f8..b303aae 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -481,6 +481,7 @@ elation.component.add("engine.things.generic", function() { } } elation.events.add(this.objects['dynamics'], "physics_update,physics_collide", this); + elation.events.add(this.objects['dynamics'], "physics_update", elation.bind(this, this.refresh)); } } this.removeDynamics = function() { From b72ca883d7c68673b1f70152900dd8403bcf1ee0 Mon Sep 17 00:00:00 2001 From: bioid Date: Wed, 6 May 2015 22:05:57 -0400 Subject: [PATCH 13/43] make elation.materials.getTexture a noop in node --- scripts/materials.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/materials.js b/scripts/materials.js index 0009ab4..382ab50 100644 --- a/scripts/materials.js +++ b/scripts/materials.js @@ -33,6 +33,7 @@ elation.require(['utils.template'], function() { elation.events.fire({element: this, type: 'engine_material_add', data: { name: materialname, material: this.materiallibrary[materialname] } }); } this.getTexture = function(url, repeat, mirrored) { + if (ENV_IS_NODE) return; if (!this.texturecache[url]) { if (url.match(/^data:/)) { var img = document.createElement('IMG'); From edbed8aae3a418ed4a29615f32ec3bfc63484217 Mon Sep 17 00:00:00 2001 From: bioid Date: Wed, 6 May 2015 22:06:29 -0400 Subject: [PATCH 14/43] skip loading textures in generic.createObject3D --- scripts/things/generic.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index b303aae..d9d17c5 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -305,8 +305,10 @@ elation.component.add("engine.things.generic", function() { this.objects['3d'].add(subobj); this.colliders = this.extractColliders(subobj); - var textures = this.extractTextures(subobj, true); - this.loadTextures(textures); + if (ENV_IS_BROWSER){ + var textures = this.extractTextures(subobj, true); + this.loadTextures(textures); + } }), 0); } } From b95f594a147384465397700164aba324c9396381 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 07:21:35 -0400 Subject: [PATCH 15/43] broadcast thing removes to clients, abstract thing state broadcasts with sendThingState() --- scripts/systems/server.js | 48 ++++++++++++++------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 6e82560..1576043 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -10,7 +10,6 @@ elation.extend("engine.systems.server", function(args) { this.system_attach = function(ev) { console.log('INIT: networking server'); this.world = this.engine.systems.world; - // FIXME - hardcoded ws/wrtc setup, should be in a config this.server = new elation.engine.systems.server.websocket; this.adminServer = new elation.engine.systems.server.adminserver; @@ -19,8 +18,8 @@ elation.extend("engine.systems.server", function(args) { [this.server, 'client_connected', this.onClientConnect], [this.world, 'world_thing_add', this.onThingAdd], [this.adminServer, 'admin_client_connected', this.onAdminClientConnect], - // [this.world, 'world_thing_remove', this.onThingRemove], - // [this.world, 'world_thing_change', this.onThingChange] + [this.world, 'world_thing_remove', this.onThingRemove], + // [this.world, 'thing_change', this.onThingChange] ]; for (var i = 0; i < events.length; i++) { @@ -42,10 +41,6 @@ elation.extend("engine.systems.server", function(args) { this.onAdminClientConnect = function(ev) { ev.data.channel.send(JSON.stringify(this.serialize_world())); - // var playermsg = { - // type: 'player_data', - // data: this.serialize_clients() - // }; this.adminClients.push(ev.data.channel); }; @@ -102,30 +97,35 @@ elation.extend("engine.systems.server", function(args) { client.send(this.serialize_world()); }; - this.onThingAdd = function(ev) { - console.log('thing add', ev.data.thing.name); - // elation.events.add(ev.data.thing, 'thing_change', this.onThingChange); - var client_id = ev.data.thing.properties.player_id; - var msg = { type: 'thing_added', data: ev.data.thing.serialize() }; + this.sendThingState = function(thing, state) { + // states: 'thing_changed', 'thing_added', 'thing_removed' + var client_id = thing.properties.player_id; + var msg = { type: state, data: thing.serialize() }; if (this.clients.hasOwnProperty(client_id)) { for (var client in this.clients) { - if (this.clients.hasOwnProperty(client_id) && client != client_id ) { - this.clients[client].send(msg); + if (this.clients.hasOwnProperty(client_id) && client != client_id) { + this.clients[client].send(msg); } } } else { this.sendToAll(msg); } + } + this.onThingAdd = function(ev) { + // bind thing remove here? + console.log('thing add', ev.data.thing.name); + this.sendThingState(ev.data.thing, 'thing_added'); }; this.onThingRemove = function(ev) { // TODO + console.log('thing remove', ev.data.thing.name); + this.sendThingState(ev.data.thing, 'thing_removed'); }; this.onThingChange = function(ev) { var thing = ev.target || ev.element; - // console.log('THING CHANGE', thing.type, thing.name, 'pos: ', thing.properties.position); if (!thing.hasTag('thing_changed')) { thing.addTag('thing_changed'); } @@ -137,19 +137,9 @@ elation.extend("engine.systems.server", function(args) { for (var i = 0; i < changed.length; i++) { var thing = changed[i]; thing.removeTag('thing_changed'); - var msgdata = { - type: 'thing_changed', data: thing.serialize() - }; - if (this.clients.hasOwnProperty(thing.properties.player_id)) { - for (var client in this.clients) { - if (this.clients.hasOwnProperty(client) && client != thing.properties.player_id) { - this.clients[client].send(msgdata); - } - } - } - else { this.sendToAll(msgdata); } + this.sendThingState(thing, 'thing_changed'); + this.lastUpdate = Date.now(); } - this.lastUpdate = Date.now(); } }; @@ -162,7 +152,6 @@ elation.extend("engine.systems.server", function(args) { }; this.onClientDisconnect = function(ev) { - // console.log(ev); var client = this.clients[ev.data]; elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); @@ -176,7 +165,6 @@ elation.extend("engine.systems.server", function(args) { type: ev.type, data: ev.data }; - // console.log('sent message',msg); this.adminServer.wss.clients.forEach(function(client){ client.send(JSON.stringify(msg)); }); @@ -288,7 +276,6 @@ elation.extend("engine.systems.server.webrtc", function() { var ws = require('ws'); var net = require('net'); - // var args = require('minimist')(process.argv.slice(2)); var MAX_REQUEST_LENGTH = 1024; var pc = null, offer = null, @@ -413,7 +400,6 @@ elation.extend("engine.systems.server.webrtc", function() { }; pc.onicecandidate = function(candidate) { - // console.log('onicecandidate', candidate); ws.send(JSON.stringify( {'type': 'ice', 'sdp': {'candidate': candidate.candidate, 'sdpMid': candidate.sdpMid, 'sdpMLineIndex': candidate.sdpMLineIndex} From b9c6f67ce92a504982e3951e847506100b53fb43 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 08:23:49 -0400 Subject: [PATCH 16/43] emit events on player disconnect and removed thing --- scripts/systems/client.js | 3 +-- scripts/systems/server.js | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index 931f610..892f163 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -20,11 +20,10 @@ elation.extend("engine.systems.client", function(args) { }); elation.events.add(this.connection.socket, 'new_message', elation.bind(this, this.onNewMessage)); elation.events.add(this.world, 'world_thing_add', elation.bind(this, this.onNewThing)); - // elation.events.add(this.world, 'world_thing_remove', this.handleRemovedThing.bind(this)) + // elation.events.add(this.world, 'world_thing_remove', elation.bind(this, this.onThingRemove)); }; this.onNewThing = function(ev) { - // console.log('new thing', ev.data.thing); var thing = ev.data.thing; if (thing.hasTag('local_sync')) { console.log(ev.data); diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 1576043..c8e0c83 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -152,11 +152,11 @@ elation.extend("engine.systems.server", function(args) { }; this.onClientDisconnect = function(ev) { - var client = this.clients[ev.data]; + var client = this.clients[ev.data.id]; elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); - this.removeClient(ev.data); - elation.events.fire({type: 'destroy_player', data: ev.data}); + this.removeClient(ev.data.id); + elation.events.fire({type: 'player_disconnect', data: ev.data}); console.log('Client disconnected, num clients:', Object.keys(this.clients).length); }; @@ -249,7 +249,7 @@ elation.extend("engine.systems.server.websocket", function() { var id = Date.now(); elation.events.fire({ type: 'client_connected', data: {id: id, channel: ws}}); ws.on('close', function() { - elation.events.fire({type: 'client_disconnected', data: id}); + elation.events.fire({type: 'client_disconnected', data: {id: id}}); }); }); From 10bbd65d243c303c5c67386c1424272f8129c4a9 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 08:26:39 -0400 Subject: [PATCH 17/43] add world.getThingsByPlayer() --- scripts/systems/world.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/systems/world.js b/scripts/systems/world.js index efd59ae..6af5681 100644 --- a/scripts/systems/world.js +++ b/scripts/systems/world.js @@ -371,6 +371,16 @@ elation.require([ } return things; } + this.getThingsByPlayer = function(player) { + var things = []; + for (var k in this.children) { + if (this.children[k].getPlayer() == player) { + things.push(this.children[k]); + } + this.children[k].getChildrenByPlayer(player, things); + } + return things; + } this.getThingsByType = function(type) { } this.getThingByObject = function(obj) { From 07806324303fc9a58d296b7dfcffe2331db8b259 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 08:29:19 -0400 Subject: [PATCH 18/43] thing.generic - add setProperties (takes an object and calls .set() for each), add getChildrenByPlayer, add interp functions(broken and disabled for now) --- scripts/things/generic.js | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index d9d17c5..dd6e775 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -21,6 +21,18 @@ elation.component.add("engine.things.generic", function() { this.parttypes = {}; this.children = {}; this.tags = []; + + this.tmpvec = new THREE.Vector3(); + + this.interp = { + rate: 20, + lastTime: 0, + time: 0, + endpoint: new THREE.Vector3(), + spline: [], + active: false, + fn: this.applyInterp + }; elation.events.add(this, 'thing_create', this); this.defineActions({ @@ -240,6 +252,46 @@ elation.component.add("engine.things.generic", function() { } } } + this.setProperties = function(properties, interpolate) { + for (var prop in properties) { + if (prop == 'position' && interpolate == true ) + { + if ( this.tmpvec.fromArray(properties[prop]).distanceToSquared(this.get('position')) > 1 ) + { + // call interpolate function + // TODO: fix magic number 0.001 + this.interpolateTo(properties[prop]); + } + } + else { + this.set(prop, properties[prop], false); + } + } + this.refresh(); + } + + this.interpolateTo = function(newPos) { + this.interp.time = 0; + this.interp.endpoint.fromArray(newPos); + this.interp.spline = new THREE.SplineCurve3([this.get('position'), this.interp.endpoint]).getPoints(10); + // console.log(this.interp.spline); + elation.events.add(this.engine, 'engine_frame', elation.bind(this, this.applyInterp)); + } + + this.applyInterp = function(ev) { + this.interp.time += ev.data.delta * this.engine.systems.physics.timescale; + if (this.interp.time >= this.interp.rate) { + elation.events.remove(this, 'engine_frame', elation.bind(this, this.applyInterp)); + return; + } + console.log("DEBUG: interpolating, time:", this.interp.time); + if (this.interp.time - this.interp.lastTime >= 2) + { + this.set('position', this.interp.spline[Math.floor((this.interp.time * 10) / this.interp.rate)], false); + this.refresh(); + } + }; + this.get = function(property, defval) { if (typeof defval == 'undefined') defval = null; return elation.utils.arrayget(this.properties, property, defval); @@ -982,6 +1034,10 @@ console.log(thispos.toArray(), otherpos.toArray(), dir.toArray(), axis.toArray() } return false; } + this.getPlayer = function() { + console.log('player id:', this.get('player_id')); + return this.get('player_id'); + } this.addPart = function(name, part) { if (this.parts[name] === undefined) { this.parts[name] = part; @@ -1015,6 +1071,16 @@ console.log(thispos.toArray(), otherpos.toArray(), dir.toArray(), axis.toArray() } this.getObjectsByTag = function(tag) { } + this.getChildrenByPlayer = function(player, collection) { + if (typeof collection == 'undefined') collection = []; + for (var k in this.children) { + if (this.children[k].getPlayer() == player) { + collection.push(this.children[k]); + } + this.children[k].getChildrenByPlayer(player, collection); + } + return collection; + } this.getChildrenByTag = function(tag, collection) { if (typeof collection == 'undefined') collection = []; for (var k in this.children) { From ad1a154bf92059225e55243e5d8dba5cdadf2516 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 09:11:12 -0400 Subject: [PATCH 19/43] add elation.engine.server --- scripts/engine.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/scripts/engine.js b/scripts/engine.js index c8b059a..4b5adf9 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -240,6 +240,7 @@ elation.require(deps, function() { // Virtual stub - inherit from elation.engine.client, then override this for your app } this.startEngine = function(engine) { + this.engine = engine; this.world = this.engine.systems.world; // shortcut this.view = elation.engine.systems.render.view("main", elation.html.create({ tag: 'div', append: this }), { fullsize: 1, picking: true, engine: this.name, showstats: true } ); @@ -254,4 +255,24 @@ elation.require(deps, function() { engine.start(); } }); + + elation.component.add('engine.server', function() { + this.init = function() { + this.name = this.args.name || 'default'; + this.engine = elation.engine.create(this.name, ['physics', 'world', 'server'], elation.bind(this, this.startEngine)); + } + + this.initWorld = function() { + // Virtual stub - inherit from elation.engine.server, then override this for your app + } + + this.startEngine = function(engine) { + this.engine = engine; + this.world = this.engine.systems.world; // shortcut + this.initWorld(); + engine.start(); + } + + }); + }); From 540197b6536990542b7e9bfb7a4c7115f819d351 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 13 Jun 2015 09:31:19 -0400 Subject: [PATCH 20/43] add engine.things.shooter_server - generic template to inherit from to create an FPS-type server --- scripts/things/shooter_server.js | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 scripts/things/shooter_server.js diff --git a/scripts/things/shooter_server.js b/scripts/things/shooter_server.js new file mode 100644 index 0000000..cb3aa34 --- /dev/null +++ b/scripts/things/shooter_server.js @@ -0,0 +1,76 @@ +/* + A generic template for an FPS-type server. +*/ + +var _reqs = [ + 'engine.things.remoteplayer', + 'engine.things.generic' + ]; + + elation.require(_reqs, function() { + + elation.component.add('engine.things.shooter_server', function() { + this.players = {}; + + this.postinit = function() { + // network events + elation.events.add(this.engine.systems.server, 'add_player', elation.bind(this, this.spawnRemotePlayer)); + elation.events.add(this.engine.systems.server, 'remote_thing_change', elation.bind(this, this.remoteThingChange)); + elation.events.add(this.engine.systems.server, 'add_thing', elation.bind(this, this.spawnNewThing)); + elation.events.add(this.engine.systems.server, 'player_disconnect', elation.bind(this, this.onPlayerDisconnect)); + this.things = []; + this.world = this.engine.systems.world; + }; + + this.createObject3D = function() { + return new THREE.Object3D(); + }; + + this.createChildren = function() { + this.loadWorld(); + }; + + this.spawnRemotePlayer = function(ev) { + console.log('spawning new player'); + var thing = ev.data.thing; + this.spawn('remoteplayer', ev.data.id, thing.properties); + elation.events.add(this.players[ev.data.id], 'thing_change', elation.bind(this.engine.systems.server, this.engine.systems.server.onThingChange)); + }; + + this.onPlayerDisconnect = function(ev) { + // TODO - shouldn't destroy everything on player disconnect + // maybe we can destroy only persistent objects? + console.log('disconn', ev.data.id); + var things = this.world.getThingsByPlayer(ev.data.id); + for (var i = 0; i < things.length; i++) { + things[i].die(); + } + }; + + this.spawnNewThing = function(ev) { + var thing = ev.data.data.thing; + var newThing = this.spawn(thing.type, thing.name, thing.properties); + }; + + this.destroyRemotePlayer = function(ev) { + // console.log(ev.data.id); + // this.players[ev.data.id].die(); + }; + + this.remoteThingChange = function(ev) { + var thing = ev.data.data.thing; + if (this.children[thing.name]) { + for (var prop in thing.properties) { + this.children[thing.name].set(prop, thing.properties[prop], false); + } + this.children[thing.name].refresh(); + } + }; + + this.loadWorld = function() { + // Virtual + }; + + }, elation.engine.things.generic); + + }); \ No newline at end of file From af1d7e6c7e04771ce1b5c0d5ea16d958d9af25d3 Mon Sep 17 00:00:00 2001 From: bioid Date: Wed, 24 Jun 2015 18:06:28 -0400 Subject: [PATCH 21/43] fix append in engine.client --- scripts/engine.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/engine.js b/scripts/engine.js index 4b5adf9..93b29cc 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -233,17 +233,15 @@ elation.require(deps, function() { this.init = function() { this.name = this.args.name || 'default'; - this.engine = elation.engine.create(this.name, ["physics", "sound", "ai", "world", "render", "controls"], elation.bind(this, this.startEngine)); } this.initWorld = function() { // Virtual stub - inherit from elation.engine.client, then override this for your app } this.startEngine = function(engine) { - this.engine = engine; this.world = this.engine.systems.world; // shortcut - this.view = elation.engine.systems.render.view("main", elation.html.create({ tag: 'div', append: this }), { fullsize: 1, picking: true, engine: this.name, showstats: true } ); + this.view = elation.engine.systems.render.view("main", elation.html.create({ tag: 'div', append: document.body }), { fullsize: 1, picking: true, engine: this.name, showstats: true } ); this.initWorld(); @@ -261,18 +259,15 @@ elation.require(deps, function() { this.name = this.args.name || 'default'; this.engine = elation.engine.create(this.name, ['physics', 'world', 'server'], elation.bind(this, this.startEngine)); } - this.initWorld = function() { // Virtual stub - inherit from elation.engine.server, then override this for your app } - this.startEngine = function(engine) { this.engine = engine; this.world = this.engine.systems.world; // shortcut this.initWorld(); engine.start(); } - }); }); From 629148eb6905899caf321d32b5df3fec4143c786 Mon Sep 17 00:00:00 2001 From: bioid Date: Thu, 9 Jul 2015 23:03:07 -0400 Subject: [PATCH 22/43] fix generic.createObject3D in node --- scripts/things/generic.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 31d8d94..d34ad9b 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -1,5 +1,5 @@ elation.require([ - //"engine.external.three.ColladaLoader", + // "engine.external.three.ColladaLoader", //"engine.external.three.JSONLoader" //"engine.external.three.glTFLoader-combined" "engine.things.trigger" @@ -338,7 +338,9 @@ elation.component.add("engine.things.generic", function() { } } this.createObject3D = function() { - if (this.properties.exists === false || !ENV_IS_BROWSER) return; + // if (this.properties.exists === false || !ENV_IS_BROWSER) return; + if (this.properties.exists === false) return; + var object = null, geometry = null, material = null; if (this.properties.render) { if (this.properties.render.scene) { From 186f7116333d64686f1722bb3bd6445745ad0beb Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 10 Jul 2015 03:05:26 -0400 Subject: [PATCH 23/43] set useParentPosition to true on extractColliders() --- scripts/things/generic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index 6d876f2..3242722 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -360,7 +360,7 @@ elation.component.add("engine.things.generic", function() { this.extractEntities(subobj); this.objects['3d'].add(subobj); - this.colliders = this.extractColliders(subobj); + this.colliders = this.extractColliders(subobj, true); if (ENV_IS_BROWSER){ var textures = this.extractTextures(subobj, true); this.loadTextures(textures); From 40bebe9ec209f297471f3fe57e656e23c358b661 Mon Sep 17 00:00:00 2001 From: bioid Date: Tue, 14 Jul 2015 00:30:09 -0400 Subject: [PATCH 24/43] huh what --- scripts/systems/server.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/systems/server.js b/scripts/systems/server.js index c8e0c83..68720a1 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -75,7 +75,7 @@ elation.extend("engine.systems.server", function(args) { socket: ev.data.channel }); this.clients[ev.data.id] = client; - elation.events.add(client, 'received_id', elation.bind(this, this.sendWorldData)); + elation.events.add(client, 'received_id', elation.bind(this, this.clientReceivedId)); elation.events.add(client, 'new_player', elation.bind(this, this.handleNewPlayer)); elation.events.add(client, 'thing_changed', elation.bind(this, this.onRemoteThingChange)); elation.events.add(client, 'new_thing', elation.bind(this, this.onNewThing)); @@ -85,7 +85,7 @@ elation.extend("engine.systems.server", function(args) { }; this.handleNewPlayer = function(ev) { - elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing}}); + elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing, camera: ev.data.data.camera}}); }; this.handleNewThing = function(ev) { @@ -97,6 +97,11 @@ elation.extend("engine.systems.server", function(args) { client.send(this.serialize_world()); }; + this.clientReceivedId = function(ev) { + // elation.events.fire(ev) + elation.events.fire({type: 'client_received_id', data: ev.data.data}); + } + this.sendThingState = function(thing, state) { // states: 'thing_changed', 'thing_added', 'thing_removed' var client_id = thing.properties.player_id; @@ -115,6 +120,7 @@ elation.extend("engine.systems.server", function(args) { this.onThingAdd = function(ev) { // bind thing remove here? console.log('thing add', ev.data.thing.name); + elation.events.add(ev.data.thing, 'thing_change', elation.bind(this, this.onThingChange)); this.sendThingState(ev.data.thing, 'thing_added'); }; From 2cad72c0739f4ad21da98a25d8e7ee04b6601d47 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:46:05 -0400 Subject: [PATCH 25/43] add md5 lib, maskgenerator, and testplane --- scripts/external/md5.js | 186 ++++++++++++++++++++++++++++++++ scripts/things/maskgenerator.js | 66 ++++++++++++ scripts/things/testplane.js | 22 ++++ 3 files changed, 274 insertions(+) create mode 100644 scripts/external/md5.js create mode 100644 scripts/things/maskgenerator.js create mode 100644 scripts/things/testplane.js diff --git a/scripts/external/md5.js b/scripts/external/md5.js new file mode 100644 index 0000000..2b6802f --- /dev/null +++ b/scripts/external/md5.js @@ -0,0 +1,186 @@ +function md5cycle(x, k) { + var a = x[0], + b = x[1], + c = x[2], + d = x[3]; + + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); + + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); + + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); + + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); + + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); + +} + +function cmn(q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); +} + +function ff(a, b, c, d, x, s, t) { + return cmn((b & c) | ((~b) & d), a, b, x, s, t); +} + +function gg(a, b, c, d, x, s, t) { + return cmn((b & d) | (c & (~d)), a, b, x, s, t); +} + +function hh(a, b, c, d, x, s, t) { + return cmn(b ^ c ^ d, a, b, x, s, t); +} + +function ii(a, b, c, d, x, s, t) { + return cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +function md51(s) { + txt = ''; + var n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], + i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; +} + + +/* there needs to be support for Unicode here, + * unless we pretend that we can redefine the MD-5 + * algorithm for multi-byte characters (perhaps + * by adding every four 16-bit characters and + * shortening the sum to 32 bits). Otherwise + * I suggest performing MD-5 as if every character + * was two bytes--e.g., 0040 0025 = @%--but then + * how will an ordinary MD-5 sum be matched? + * There is no way to standardize text to something + * like UTF-8 before transformation; speed cost is + * utterly prohibitive. The JavaScript standard + * itself needs to look at this: it should start + * providing access to strings as preformed UTF-8 + * 8-bit unsigned value arrays. + */ +function md5blk(s) { /* I figured global was faster. */ + var md5blks = [], + i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24); + } + return md5blks; +} + +var hex_chr = '0123456789abcdef'.split(''); + +function rhex(n) { + var s = '', + j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; +} + +function hex(x) { + for (var i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); +} + +function md5(s) { + return hex(md51(s)); +} + +/* this function is much faster, +so if possible we use it. Some IEs +are the only ones I know of that +need the idiotic second function, +generated by an if clause. */ + +function add32(a, b) { + return (a + b) & 0xFFFFFFFF; +} + +if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') { + function add32(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } +} \ No newline at end of file diff --git a/scripts/things/maskgenerator.js b/scripts/things/maskgenerator.js new file mode 100644 index 0000000..2387c90 --- /dev/null +++ b/scripts/things/maskgenerator.js @@ -0,0 +1,66 @@ +elation.require(['engine.external.md5'], function() { + var Identicon = function(string, height, width) { + if (ENV_IS_NODE) { + var crypto = require('crypto'), + hash = crypto.createHash('md5').update(string).digest('hex'); + } + else { + var hash = md5(string) + } + + var color = hash.substr(0, 6), + pixels = []; + + for (var i = 0; i < height; i++) { + pixels.push([]); + for (var j = 0; j < width; j++) { + pixels[i][j] = (parseInt(hash.substr((i * 5) + j + 6, 1), 16).toString(10) % 2 === 0) ? 1 : 0; + } + var arr = pixels[i]; + pixels[i] = arr.concat(arr.slice(0, arr.length - 1).reverse()); + } + this.map = pixels; + this.color = this.hexToRgb(color); + }; + + Identicon.prototype.hexToRgb = function(hex) { + var r = parseInt(hex.substr(0,2), 16), + g = parseInt(hex.substr(2,2), 16), + b = parseInt(hex.substr(4,2), 16); + return "rgb(" + [r,g,b].join(',') + ")"; + } + + elation.component.add('engine.things.maskgenerator', function() { + this.postinit = function() { + this.defineProperties({ + 'seed' : { type: 'string', default: '192.168.1.1' }, + 'height' : { type: 'int', default: 6 }, + 'width' : { type: 'int', default: 3 }, + 'tilesize' : { type: 'float', default: 0.5} + }); + this.pixels = new Identicon(this.properties.seed, this.properties.height, this.properties.width); + }; + + this.createObject3D = function() { + var geometry = new THREE.Geometry(), + tilesize = this.properties.tilesize, + box = new THREE.BoxGeometry(tilesize, tilesize, tilesize), + mat = new THREE.MeshLambertMaterial({ color: new THREE.Color(this.pixels.color) }), + pos = new THREE.Vector3(0, 0, 0), + mesh = new THREE.Mesh(box); + + for (var row = 0; row < this.pixels.map.length; row++) { + for (var col = 0; col < this.pixels.map[row].length; col++) { + if (this.pixels.map[row][col] == 1) { + pos.fromArray([col * tilesize, row * tilesize, 0]); + mesh.position.copy(pos); + mesh.updateMatrix(); + geometry.merge(mesh.geometry, mesh.matrix); + } + } + } + return new THREE.Mesh(geometry, mat); + }; + }, elation.engine.things.generic); + +}); \ No newline at end of file diff --git a/scripts/things/testplane.js b/scripts/things/testplane.js new file mode 100644 index 0000000..c7abc8c --- /dev/null +++ b/scripts/things/testplane.js @@ -0,0 +1,22 @@ +elation.require(['engine.things.generic'], function() { + elation.component.add('engine.things.testplane', function() { + this.createObject3D = function() { + return new THREE.Object3D(); + }; + + this.createChildren = function() { + this.plane = this.spawn('plane', 'plane', { 'position': [0, 0, 0] }); + }; + }, elation.engine.things.generic); + + elation.component.add('engine.things.plane', function() { + this.createObject3D = function() { + var geo = new THREE.BoxGeometry(64, 2, 64), + mat = new THREE.MeshLambertMaterial({ + map: elation.engine.materials.getTexture('/media/testchamber/dirt.jpg', [20, 20]), + normalMap: elation.engine.materials.getTexture('/media/space/textures/dirt-normal.jpg'), + }); + return new THREE.Mesh(geo, mat) + } + }, elation.engine.things.generic); +}); \ No newline at end of file From 7e9d538799e4a5536969793b70f8e1f6e397d379 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:46:51 -0400 Subject: [PATCH 26/43] switch append back to this on view --- scripts/engine.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/engine.js b/scripts/engine.js index c10cb5b..da9f323 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -243,7 +243,7 @@ elation.require(deps, function() { this.startEngine = function(engine) { this.world = this.engine.systems.world; // shortcut - this.view = elation.engine.systems.render.view("main", elation.html.create({ tag: 'div', append: document.body }), { fullsize: 1, picking: true, engine: this.name, showstats: true } ); + this.view = elation.engine.systems.render.view("main", elation.html.create({ tag: 'div', append: this }), { fullsize: 1, picking: true, engine: this.name, showstats: true } ); this.initWorld(); From ed1ab8bf8b33afacb24673baa7c63c90590b7aee Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:48:00 -0400 Subject: [PATCH 27/43] fix events not firing on an element --- scripts/systems/client.js | 34 +++++++++++------------ scripts/systems/server.js | 57 ++++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index 892f163..a7030d8 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -12,7 +12,6 @@ elation.extend("engine.systems.client", function(args) { this.system_attach = function(ev) { console.log('INIT: networking client'); this.world = this.engine.systems.world; - console.log('this.world:', this.world); this.connection = new elation.engine.systems.client.connection({ transport: 'websocket', host: 'dev.brandonhinshaw.us', @@ -26,8 +25,10 @@ elation.extend("engine.systems.client", function(args) { this.onNewThing = function(ev) { var thing = ev.data.thing; if (thing.hasTag('local_sync')) { - console.log(ev.data); - if (thing.type != 'vrcadeplayer') { + console.log('local sync', thing.type); + if (thing.type != 'vrcadeplayer' && thing.type != 'camera' && thing.type != 'remoteplayer') { + var thingdata = thing.serialize(); + thingdata.properties.tags = ''; var msgdata = { type: 'add_thing', data: { thing: thing.serialize() } @@ -36,7 +37,10 @@ elation.extend("engine.systems.client", function(args) { this.send(msgdata); } else { - elation.events.add(thing, 'thing_change', elation.bind(this, this.onThingChange)); + if (thing.type != 'remoteplayer') { + console.log('adding thing_change listener for', thing.type); + elation.events.add(thing, 'thing_change', elation.bind(this, this.onThingChange)); + } } thing.removeTag('local_sync'); @@ -44,13 +48,6 @@ elation.extend("engine.systems.client", function(args) { // FIXME }; - this.sendNewThing = function() { - var msg = { - type: 'new_thing', - data: 'test' - }; - } - this.onThingChange = function(ev) { var thing = ev.target; if (!thing.hasTag('thing_changed')) { @@ -85,6 +82,7 @@ elation.extend("engine.systems.client", function(args) { thing.set('velocity', [0, 0, 0], false); thing.set('acceleration', [0, 0, 0], false); thing.set('angular', [0, 0, 0], false); + thing.set('angularacceleration', [0, 0, 0], false); thing.refresh(); thing.removeTag('extrapolating'); } @@ -98,7 +96,7 @@ elation.extend("engine.systems.client", function(args) { if (!this.lastMessage) { this.lastMessage = timestamp; } if (timestamp >= this.lastMessage) { // console.log('new message', msg, typeof(msg)); - var evdata = { type: msgdata.type, data: msgdata.data }; + var evdata = { element: this, type: msgdata.type, data: msgdata.data }; elation.events.fire(evdata); } else { console.log('discarded a message') } }; @@ -182,15 +180,15 @@ elation.extend('engine.systems.client.websocket', function(opts) { this.onOpen = function(ev) { this.connected = true; - elation.events.fire({type: 'socket_connected'}); + elation.events.fire({element: this, type: 'socket_connected'}); }; this.onMessage = function(ev) { - elation.events.fire({type: 'new_message', data: ev.data}); + elation.events.fire({element: this, type: 'new_message', data: ev.data}); }; this.onClose = function(ev) { - elation.events.fire({type: 'socket_closed'}); + elation.events.fire({element: this, type: 'socket_closed'}); this.websocket = null; }; @@ -247,7 +245,7 @@ elation.extend('engine.systems.client.webrtc', function(socketOpts) { function doComplete() { console.log('complete'); - elation.events.fire({type: 'socket_connected'}); + elation.events.fire({element: this, type: 'socket_connected'}); } function doWaitforDataChannels() { @@ -298,7 +296,7 @@ elation.extend('engine.systems.client.webrtc', function(socketOpts) { } }.bind(this); channel.onmessage = function(event) { - elation.events.fire({ type: 'new_message', data: event.data }); + elation.events.fire({ element: this, type: 'new_message', data: event.data }); // if('string' == typeof data) { // console.log('onmessage:', data); // } else { @@ -307,7 +305,7 @@ elation.extend('engine.systems.client.webrtc', function(socketOpts) { }; channel.onclose = function(event) { console.info('onclose'); - elation.events.fire({type:'socket_closed'}); + elation.events.fire({element: this, type:'socket_closed'}); }; channel.onerror = doHandleError; }); diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 68720a1..7c37260 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -69,6 +69,7 @@ elation.extend("engine.systems.server", function(args) { }; this.onClientConnect = function(ev) { + console.log('onclientconnect'); var client = new elation.engine.systems.server.client({ transport: 'websocket', id: ev.data.id, @@ -78,28 +79,31 @@ elation.extend("engine.systems.server", function(args) { elation.events.add(client, 'received_id', elation.bind(this, this.clientReceivedId)); elation.events.add(client, 'new_player', elation.bind(this, this.handleNewPlayer)); elation.events.add(client, 'thing_changed', elation.bind(this, this.onRemoteThingChange)); - elation.events.add(client, 'new_thing', elation.bind(this, this.onNewThing)); + elation.events.add(client, 'add_thing', elation.bind(this, this.handleNewThing)); elation.events.add(client, 'socket_message_sent', elation.bind(this, this.onSocketSend)); console.log('client connected', client.id); client.send({ type: 'id_token', data: client.id }); + console.log(Object.keys(this.clients)); }; this.handleNewPlayer = function(ev) { - elation.events.fire({type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing, camera: ev.data.data.camera}}); + elation.events.fire({element: this, type: 'add_player', data: {id: ev.target.id, thing: ev.data.data.thing, camera: ev.data.data.camera}}); }; this.handleNewThing = function(ev) { - elation.events.fire({type: 'add_thing', data: {thing: ev.data.data.thing}}); + console.log('thing properties', ev.data.data.thing.properties.tags) + elation.events.fire({element: this, type: 'add_thing', data: {thing: ev.data.data.thing}}); }; this.sendWorldData = function(evt) { - var client = this.clients[evt.data.data]; - client.send(this.serialize_world()); + // var client = this.clients[evt.data.data]; + // client.send(this.serialize_world()); }; this.clientReceivedId = function(ev) { // elation.events.fire(ev) - elation.events.fire({type: 'client_received_id', data: ev.data.data}); + console.log('got received_id from client') + elation.events.fire({element: this, type: 'client_received_id', data: ev.data.data}); } this.sendThingState = function(thing, state) { @@ -119,7 +123,8 @@ elation.extend("engine.systems.server", function(args) { } this.onThingAdd = function(ev) { // bind thing remove here? - console.log('thing add', ev.data.thing.name); + ev.data.thing.properties.tags = ''; // FIXME - local_sync should be moved from a tag to a property of its own, so we don't need to clear tags + console.log('thing add', ev.data.thing.name, 'tags:', ev.data.thing.properties.tags); elation.events.add(ev.data.thing, 'thing_change', elation.bind(this, this.onThingChange)); this.sendThingState(ev.data.thing, 'thing_added'); }; @@ -150,7 +155,7 @@ elation.extend("engine.systems.server", function(args) { }; this.onRemoteThingChange = function(ev) { - elation.events.fire('remote_thing_change', ev.data); + elation.events.fire({element: this, type: 'remote_thing_change', data: ev.data}); }; this.removeClient = function(id) { @@ -162,7 +167,7 @@ elation.extend("engine.systems.server", function(args) { elation.events.remove(client, 'received_id', elation.bind(this, this.sendWorldData)); elation.events.remove(client, 'new_player', elation.bind(this, this.handleNewPlayer)); this.removeClient(ev.data.id); - elation.events.fire({type: 'player_disconnect', data: ev.data}); + elation.events.fire({element: this, type: 'player_disconnect', data: ev.data}); console.log('Client disconnected, num clients:', Object.keys(this.clients).length); }; @@ -202,19 +207,21 @@ elation.extend("engine.systems.server.client", function(args) { }; this.socket.onmessage = function(evt) { + console.log('msg from client on systems.server.client'); var msgdata = JSON.parse(evt.data); var timestamp = msgdata.timestamp; if (!this.lastMessage) this.lastMessage = timestamp; if (timestamp >= this.lastMessage) { // only fire an event if the message is newer than the last received msg var evdata = { + element: this, type: msgdata.type, data: { id: this.id, data: msgdata.data } }; elation.events.fire(evdata); this.lastMessage = timestamp; } else { console.log('discarded a message'); } - }; + }.bind(this); } if (this.transport == 'websocket') { this.send = function(data) { @@ -222,7 +229,7 @@ elation.extend("engine.systems.server.client", function(args) { try { data.timestamp = Date.now(); this.socket.send(JSON.stringify(data)); - elation.events.fire({type: 'socket_message_sent', data:{type: data.type, data: data.data, client_id: this.id, timestamp: data.timestamp}}); + elation.events.fire({element: this, type: 'socket_message_sent', data:{type: data.type, data: data.data, client_id: this.id, timestamp: data.timestamp}}); } catch(e) { console.log(e) } }; @@ -233,13 +240,14 @@ elation.extend("engine.systems.server.client", function(args) { if (timestamp >= this.lastMessage) { // only fire an event if the message is newer than the last received msg var evdata = { + element: this, type: msgdata.type, data: { id: this.id, data: msgdata.data } }; elation.events.fire(evdata); this.lastMessage = timestamp; }; - }); + }.bind(this)); } }); @@ -253,11 +261,11 @@ elation.extend("engine.systems.server.websocket", function() { wss.on('connection', function(ws) { console.log('game server websocket conn'); var id = Date.now(); - elation.events.fire({ type: 'client_connected', data: {id: id, channel: ws}}); + elation.events.fire({element: this, type: 'client_connected', data: {id: id, channel: ws}}); ws.on('close', function() { - elation.events.fire({type: 'client_disconnected', data: {id: id}}); - }); - }); + elation.events.fire({element: this, type: 'client_disconnected', data: {id: id}}); + }.bind(this)); + }.bind(this)); }) @@ -269,10 +277,10 @@ elation.extend("engine.systems.server.adminserver", function() { this.wss.on('connection', function(ws) { console.log('admin server websocket conn'); var id = Date.now(); - elation.events.fire({ type: 'admin_client_connected', data: {id: id, channel: ws}}); + elation.events.fire({element: this, type: 'admin_client_connected', data: {id: id, channel: ws}}); ws.on('close', function() { - elation.events.fire({type: 'admin_client_disconnected', data: id}); - }); + elation.events.fire({element: this, type: 'admin_client_disconnected', data: id}); + }.bind(this)); }); }) @@ -342,15 +350,16 @@ elation.extend("engine.systems.server.webrtc", function() { channel.onopen = function() { self.dataChannels.push(channel); self.pendingDataChannels.splice(self.pendingDataChannels.indexOf(channel), 1); - elation.events.fire({ type: 'client_connected', data: {id: id, channel: channel}}); + elation.events.fire({element: this, type: 'client_connected', data: {id: id, channel: channel}}); doComplete(self.dataChannels[self.dataChannels.indexOf(channel)]); // } - }; + }.bind(this); channel.onmessage = function(evt) { var msgdata = JSON.parse(evt.data); console.log('onmessage:', evt.data); var evdata = { + element: this, type: msgdata.type, data: { id: id, @@ -358,13 +367,13 @@ elation.extend("engine.systems.server.webrtc", function() { } } elation.events.fire(evdata); - }; + }.bind(this); channel.onclose = function() { self.dataChannels.splice(self.dataChannels.indexOf(channel), 1); - elation.events.fire({type: 'client_disconnected', data: {id: id, channel: channel}}) + elation.events.fire({element: this, type: 'client_disconnected', data: {id: id, channel: channel}}) console.info('onclose'); - }; + }.bind(this); channel.onerror = doHandleError; }; From eff0933226ce786f1584f1bbc3b1cd6a9518af91 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:52:02 -0400 Subject: [PATCH 28/43] dont add local_sync tags to all balls --- scripts/things/ball.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/things/ball.js b/scripts/things/ball.js index f068871..77eed8f 100644 --- a/scripts/things/ball.js +++ b/scripts/things/ball.js @@ -6,18 +6,11 @@ elation.require(['engine.things.generic'], function() { lifetime: { type: 'float', default: 0 }, gravity: { type: 'bool', default: true }, }); - this.addTag('local_sync'); - if (this.properties.lifetime != 0) { this.age = 0; elation.events.add(this.engine, 'engine_frame', this); } } - - this.onFrame = function(ev) { - this.refresh(); - } - this.createObject3D = function() { var geo = new THREE.SphereGeometry(this.properties.radius, 36, 18); var mat = new THREE.MeshPhongMaterial({ From b9aa8c60dd4a706513fe8b894489530296182041 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:52:31 -0400 Subject: [PATCH 29/43] give player balls local_sync when they are thrown --- scripts/things/player.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/things/player.js b/scripts/things/player.js index 180cdb0..46f80d3 100644 --- a/scripts/things/player.js +++ b/scripts/things/player.js @@ -47,8 +47,6 @@ elation.require(['engine.things.generic', 'engine.things.camera', 'ui.progressba this.target = false; - this.addTag('player'); - elation.events.add(this.engine, 'engine_frame', elation.bind(this, this.updateHUD)); elation.events.add(this.objects.dynamics, 'physics_update', elation.bind(this, this.handleTargeting)); } @@ -77,7 +75,7 @@ elation.require(['engine.things.generic', 'engine.things.camera', 'ui.progressba camdir.multiplyScalar(velocity); camdir.add(this.objects.dynamics.velocity); //console.log('pew!', velocity); - var foo = this.spawn('ball', 'ball_' + Math.round(Math.random() * 100000), { radius: .375, mass: 1, position: campos, velocity: camdir, lifetime: 30, gravity: this.usegravity }, true); + var foo = this.spawn('ball', 'ball_' + Math.round(Math.random() * 100000), { radius: .375, mass: 1, position: campos, velocity: camdir, lifetime: 30, gravity: this.usegravity, player_id: this.properties.player_id, tags: 'local_sync' }, true); /* if (!this.lights[this.lightnum]) { @@ -145,7 +143,7 @@ elation.require(['engine.things.generic', 'engine.things.camera', 'ui.progressba this.objects.dynamics.addConstraint('axis', { axis: new THREE.Vector3(0,1,0) }); // place camera at head height - this.camera = this.spawn('camera', null, { position: [0,this.properties.height * .8,0], mass: 0.1 } ); + this.camera = this.spawn('camera', this.name + '_camera', { position: [0,this.properties.height * .8,0], mass: 0.1, player_id: this.properties.player_id } ); this.camera.objects.dynamics.addConstraint('axis', { axis: new THREE.Vector3(1,0,0), min: -Math.PI/2, max: Math.PI/2 }); } this.getGroundHeight = function() { From 817a0f60292f2e14114131de2bf42aaa99d58dc7 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:53:05 -0400 Subject: [PATCH 30/43] no real diff --- scripts/things/generic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/things/generic.js b/scripts/things/generic.js index c547e1b..c7d1f6b 100644 --- a/scripts/things/generic.js +++ b/scripts/things/generic.js @@ -62,7 +62,7 @@ elation.component.add("engine.things.generic", function() { 'render.gltf': { type: 'string', comment: 'URL for glTF file' }, 'render.materialname': { type: 'string', comment: 'Material library name' }, 'render.texturepath': { type: 'string', comment: 'Texture location' }, - 'player_id': { type: 'float', default: null, comment: 'Network id of the creator' } + 'player_id': { type: 'float', default: null, comment: 'Network id of the creator' }, 'tags': { type: 'string', comment: 'Default tags to add to this object' } }); this.defineEvents({ From 192672eaaa1e2369fc6e4e4fdc2ba01bdbf72ec1 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:53:30 -0400 Subject: [PATCH 31/43] spawn the mask on remote players --- scripts/things/remoteplayer.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/things/remoteplayer.js b/scripts/things/remoteplayer.js index 834e576..b6b2871 100644 --- a/scripts/things/remoteplayer.js +++ b/scripts/things/remoteplayer.js @@ -1,16 +1,26 @@ -elation.require(['engine.things.generic'], function() { +elation.require(['engine.things.generic', 'vrcade.maskgenerator'], function() { elation.component.add('engine.things.remoteplayer', function() { this.postinit = function() { + this.defineProperties({startposition: {type: 'vector3', default: new THREE.Vector3()}}) }; this.createObject3D = function() { - var geo = new THREE.BoxGeometry(1, 1, 1), - mat = new THREE.MeshBasicMaterial({ color: 0x00ff00 }), + var geo = new THREE.CylinderGeometry(1, 1, 4, 8), + mat = new THREE.MeshPhongMaterial({ color: 0x000000, transparent: true, opacity: 0.7 }), mesh = new THREE.Mesh(geo, mat); return mesh; }; + + this.createChildren = function() { + this.mask = this.spawn('maskgenerator', this.properties.player_id + '_mask', { + 'seed': this.properties.player_id.toString(), + 'tilesize': 0.25, + 'position': [0, 0, -1], + 'player_id': this.properties.player_id + }); + }; }, elation.engine.things.generic); }); From 19aa7811655f5f491df2fcb8c849d23b621af153 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 05:54:00 -0400 Subject: [PATCH 32/43] general fixing of things on shooter_client and shooter_server --- scripts/things/shooter_client.js | 79 ++++++++++++++++++++++++++++---- scripts/things/shooter_server.js | 35 +++++++++----- 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/scripts/things/shooter_client.js b/scripts/things/shooter_client.js index 07736c6..7587d05 100644 --- a/scripts/things/shooter_client.js +++ b/scripts/things/shooter_client.js @@ -4,15 +4,17 @@ var _reqs = [ 'engine.things.light', 'engine.things.ball', 'engine.things.remoteplayer', - 'vrcade.vrcadeplayer', - 'bball.testplane', + 'engine.things.player', + 'engine.things.testplane', 'engine.external.three.tween', + 'engine.things.maskgenerator' ]; elation.require(_reqs, function() { elation.component.add('engine.things.shooter_client', function() { - this.player_id = null; this.lastUpdate = Date.now(); - + this.player_id = null; + this.loaded = false; + // this.init = function() { // this.name = this.args.name || 'default'; // } @@ -42,16 +44,22 @@ elation.require(_reqs, function() { this.loadWorld = function(ev) { // load the world data sent by the server + if (this.loaded) return; + this.create_lights(); var world = ev.data; + console.log("received world data", ev.data) for (var k in world.things) { var thing = world.things[k]; this.spawn(thing.type, thing.name, thing.properties); } + this.loaded = true; }; this.setIdToken = function(ev) { // set the id sent by the server and acknowledge, // then create the player + if (this.player_id) return; + console.log("RECEIVED ID TOKEN", ev.data); this.player_id = ev.data; this.engine.systems.client.send({type: 'received_id', data: this.player_id}); this.createPlayer(); @@ -59,11 +67,14 @@ elation.require(_reqs, function() { this.createPlayer = function() { // create the player and let the server know we have a new player obj - this.player = this.spawn('vrcadeplayer', this.player_id, { "position":[0,2.4,0], mass: 50, collidable: false, player_id: this.player_id }); - this.player.addTag('local_sync'); + this.player = this.spawn('vrcadeplayer', this.player_id, { "position":[0,2.4,0], mass: 50, collidable: false, player_id: this.player_id, tags: 'local_sync,player' }); this.setview(this.view); this.startGame(); - this.engine.systems.client.send({type: 'new_player', data: {id: this.player_id, thing: this.player.serialize()}}); + var player = this.player.serialize(), + camera = this.player.camera.serialize(); + player.properties.tags = camera.properties.tags = ''; + console.log('serialized player', player); + this.engine.systems.client.send({type: 'new_player', data: {id: this.player_id, thing: this.player.serialize(), camera: this.player.camera.serialize()}}); }; this.sendPlayerChange = function() { @@ -76,6 +87,8 @@ elation.require(_reqs, function() { this.createRemoteObject = function(ev) { // create a new thing sent by the server var thing = ev.data; + thing.properties.tags = ''; + console.log('remote thing', thing.type, 'tags:', thing.properties.tags); this.children[thing.name] = this.spawn(thing.type, thing.name, thing.properties); console.log('spawned remote object', this.children[thing.name]); }; @@ -161,7 +174,57 @@ elation.require(_reqs, function() { this.engine.systems.controls.calibrateHMDs(); } } - + this.create_lights = function() { + var lights = []; +/* + lights.push(this.spawn('light', 'sun', { + "position":[50,30,-30], + "persist":false, + "type":"directional", + "intensity":0.6, + //"velocity":[0,0,0.05] + })); +*/ + /* + lights.push(this.spawn('light', 'sun2', { + "position":[-50,-30,-30], + "persist":false, + "type":"directional", + "intensity":0.2, + //"velocity":[0,0,0.05] + })); + */ + lights.push(this.spawn('light', 'point01', { + "position":[-10,20,10], + "persist":false, + "type":"point", + "intensity": .4, + "color":0xffffff, + })); + lights.push(this.spawn('light', 'point02', { + "position":[20,10,32], + "persist":false, + "type":"point", + "intensity": .4, + "color":0xcccccc, + })); + lights.push(this.spawn('light', 'point03', { + "position":[0,10,-30], + "persist":false, + "type":"point", + "intensity": .4, + "color":0xcccccc, + })); + lights.push(this.spawn('light', 'ambient', { + "position":[0,0,0], + "persist":false, + "type":"ambient", + "color":0xffffff, + })); + + return lights; + } + this.startGame = function() { this.player.enable(); } diff --git a/scripts/things/shooter_server.js b/scripts/things/shooter_server.js index cb3aa34..ecb1689 100644 --- a/scripts/things/shooter_server.js +++ b/scripts/things/shooter_server.js @@ -4,7 +4,8 @@ var _reqs = [ 'engine.things.remoteplayer', - 'engine.things.generic' + 'engine.things.generic', + 'engine.things.maskgenerator' ]; elation.require(_reqs, function() { @@ -14,10 +15,13 @@ var _reqs = [ this.postinit = function() { // network events - elation.events.add(this.engine.systems.server, 'add_player', elation.bind(this, this.spawnRemotePlayer)); - elation.events.add(this.engine.systems.server, 'remote_thing_change', elation.bind(this, this.remoteThingChange)); - elation.events.add(this.engine.systems.server, 'add_thing', elation.bind(this, this.spawnNewThing)); - elation.events.add(this.engine.systems.server, 'player_disconnect', elation.bind(this, this.onPlayerDisconnect)); + this.server = this.engine.systems.server; + elation.events.add(this.server, 'add_player', elation.bind(this, this.spawnRemotePlayer)); + elation.events.add(this.server, 'remote_thing_change', elation.bind(this, this.remoteThingChange)); + elation.events.add(this.server, 'add_thing', elation.bind(this, this.spawnNewThing)); + elation.events.add(this.server, 'player_disconnect', elation.bind(this, this.onPlayerDisconnect)); + elation.events.add(this.server, 'client_received_id', elation.bind(this, this.sendWorldData)); + this.things = []; this.world = this.engine.systems.world; }; @@ -30,11 +34,11 @@ var _reqs = [ this.loadWorld(); }; - this.spawnRemotePlayer = function(ev) { - console.log('spawning new player'); - var thing = ev.data.thing; - this.spawn('remoteplayer', ev.data.id, thing.properties); - elation.events.add(this.players[ev.data.id], 'thing_change', elation.bind(this.engine.systems.server, this.engine.systems.server.onThingChange)); + this.spawnRemotePlayer = function(event) { + console.log(event.type, event.data.thing.properties.player_id) + var thing = event.data.thing; + thing.properties.tags = ''; + this.things[thing.name] = this.spawn('remoteplayer', event.data.id, thing.properties); }; this.onPlayerDisconnect = function(ev) { @@ -48,7 +52,8 @@ var _reqs = [ }; this.spawnNewThing = function(ev) { - var thing = ev.data.data.thing; + console.log(ev.type, ev.data.thing.type); + var thing = ev.data.thing; var newThing = this.spawn(thing.type, thing.name, thing.properties); }; @@ -66,7 +71,13 @@ var _reqs = [ this.children[thing.name].refresh(); } }; - + + this.sendWorldData = function(ev) { + console.log(ev.type, ev.data) + var client = this.server.clients[ev.data]; + client.send(this.server.serialize_world()); + } + this.loadWorld = function() { // Virtual }; From 698cb6987a999f4460acfc7ecb3cd9aaeb35d899 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 06:23:39 -0400 Subject: [PATCH 33/43] check if this.player exists before trying to spawn menus as a child of its camera --- scripts/engine.js | 84 ++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/scripts/engine.js b/scripts/engine.js index 9a454ef..a2837ad 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -271,49 +271,51 @@ elation.require(deps, function() { this.engine.systems.controls.activateContext(this.name); } this.showMenu = function() { - if (!this.menu) { - this.menu = this.player.camera.spawn('menu', null, { - position: [0,0,-2], - items: [ - { - text: 'Intro', - callback: elation.bind(this, this.startIntro), - disabled: true - }, - { - text: 'Play', - callback: elation.bind(this, this.startGame) - }, - { - text: 'Options', - callback: elation.bind(this, this.configureOptions), - }, - { - text: 'About', - callback: elation.bind(this, this.showAbout), - }, -/* - { - text: 'Quit', - disabled: true + if (this.player){ + if (!this.menu) { + this.menu = this.player.camera.spawn('menu', null, { + position: [0,0,-2], + items: [ + { + text: 'Intro', + callback: elation.bind(this, this.startIntro), + disabled: true + }, + { + text: 'Play', + callback: elation.bind(this, this.startGame) + }, + { + text: 'Options', + callback: elation.bind(this, this.configureOptions), + }, + { + text: 'About', + callback: elation.bind(this, this.showAbout), + }, + /* + { + text: 'Quit', + disabled: true + } + */ + ], + labelcfg: { + size: .1, + lineheight: 1.5, + color: 0x999999, + hovercolor: 0x003300, + disabledcolor: 0x000000, + disabledhovercolor: 0x330000, } -*/ - ], - labelcfg: { - size: .1, - lineheight: 1.5, - color: 0x999999, - hovercolor: 0x003300, - disabledcolor: 0x000000, - disabledhovercolor: 0x330000, - } - }); - } else { - this.player.camera.add(this.menu); + }); + } else { + this.player.camera.add(this.menu); + } + this.player.disable(); + this.menu.enable(); + this.menuShowing = true; } - this.player.disable(); - this.menu.enable(); - this.menuShowing = true; } this.hideMenu = function() { if (this.menu) { From ad997c6613b7511070125b41c4f71848381932ec Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 06:24:16 -0400 Subject: [PATCH 34/43] use player instead of vrcadeplayer --- scripts/systems/client.js | 2 +- scripts/things/shooter_client.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index a7030d8..0bb62b1 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -26,7 +26,7 @@ elation.extend("engine.systems.client", function(args) { var thing = ev.data.thing; if (thing.hasTag('local_sync')) { console.log('local sync', thing.type); - if (thing.type != 'vrcadeplayer' && thing.type != 'camera' && thing.type != 'remoteplayer') { + if (thing.type != 'player' && thing.type != 'camera' && thing.type != 'remoteplayer' && thing.type !='vrcadeplayer') { var thingdata = thing.serialize(); thingdata.properties.tags = ''; var msgdata = { diff --git a/scripts/things/shooter_client.js b/scripts/things/shooter_client.js index 7587d05..3888461 100644 --- a/scripts/things/shooter_client.js +++ b/scripts/things/shooter_client.js @@ -67,7 +67,7 @@ elation.require(_reqs, function() { this.createPlayer = function() { // create the player and let the server know we have a new player obj - this.player = this.spawn('vrcadeplayer', this.player_id, { "position":[0,2.4,0], mass: 50, collidable: false, player_id: this.player_id, tags: 'local_sync,player' }); + this.player = this.spawn('player', this.player_id, { "position":[0,2.4,0], mass: 50, collidable: false, player_id: this.player_id, tags: 'local_sync,player' }); this.setview(this.view); this.startGame(); var player = this.player.serialize(), From c8372c4c20c02138fc6220530a350ad2eb034616 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:12:42 -0400 Subject: [PATCH 35/43] add package.json for node server, add makenode.js to make the node shimmed three.js --- scripts/external/makenode.js | 11 +++++++++++ scripts/external/package.json | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 scripts/external/makenode.js create mode 100644 scripts/external/package.json diff --git a/scripts/external/makenode.js b/scripts/external/makenode.js new file mode 100644 index 0000000..c8ec72a --- /dev/null +++ b/scripts/external/makenode.js @@ -0,0 +1,11 @@ +var concat = require('concatenate-files'), + fs = require('fs'); + +concat(['./three/shimthree.js', './three/three.js'], './three/nodethree.js', function(err, res) { + if (err) { console.log('PROBLEM MERGING: ', err); } + else { + fs.appendFile('./three/nodethree.js', 'global.THREE = THREE;\r\n', function(err) { + if (err) { console.log(err) } + }); + } +}); \ No newline at end of file diff --git a/scripts/external/package.json b/scripts/external/package.json new file mode 100644 index 0000000..86471cc --- /dev/null +++ b/scripts/external/package.json @@ -0,0 +1,18 @@ +{ + "name": "external", + "version": "1.0.0", + "description": "", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "canvas": "^1.2.3", + "concatenate-files": "^0.1.1", + "wrtc": "0.0.56", + "ws": "^0.7.2", + "xhr2": "^0.1.2" + } +} From fa9b74002baf527f6c2d220f4066aa6a2739a0c1 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:13:06 -0400 Subject: [PATCH 36/43] fix broken dependency in remoteplayer.js --- scripts/things/remoteplayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/things/remoteplayer.js b/scripts/things/remoteplayer.js index b6b2871..0b4d249 100644 --- a/scripts/things/remoteplayer.js +++ b/scripts/things/remoteplayer.js @@ -1,5 +1,5 @@ -elation.require(['engine.things.generic', 'vrcade.maskgenerator'], function() { +elation.require(['engine.things.generic', 'engine.things.maskgenerator'], function() { elation.component.add('engine.things.remoteplayer', function() { this.postinit = function() { From 2937059f9395595286673daac21845a6d780a74e Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:13:29 -0400 Subject: [PATCH 37/43] add shim file for nodethree.js --- scripts/external/three/shimthree.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 scripts/external/three/shimthree.js diff --git a/scripts/external/three/shimthree.js b/scripts/external/three/shimthree.js new file mode 100644 index 0000000..1ea5fba --- /dev/null +++ b/scripts/external/three/shimthree.js @@ -0,0 +1,23 @@ +var Canvas = require('canvas'); + +var self = {}; + +var ratio = 16/9.0; + +var canvasWidth = 1024; +var canvasHeight = Math.round(1024 / ratio); + +var window = { + innerWidth: canvasWidth, + innerHeight: canvasHeight + +}; +var document = { + createElement: function(name) { + if (name == "canvas") { + return new Canvas(canvasWidth, canvasHeight); + } + } +}; + + From 2e66b80b10a2615657036706ec86b96c676bfb04 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:14:52 -0400 Subject: [PATCH 38/43] gitignore for node_modules --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f901dff --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +scripts/external/node_modules From 3fc9a76d94783999c70b92b6978202ecccc16ad2 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:27:17 -0400 Subject: [PATCH 39/43] makenode.js an executable, add makenode.js as an install script in package.json --- scripts/external/makenode.js | 2 ++ scripts/external/package.json | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) mode change 100644 => 100755 scripts/external/makenode.js diff --git a/scripts/external/makenode.js b/scripts/external/makenode.js old mode 100644 new mode 100755 index c8ec72a..be756e0 --- a/scripts/external/makenode.js +++ b/scripts/external/makenode.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + var concat = require('concatenate-files'), fs = require('fs'); diff --git a/scripts/external/package.json b/scripts/external/package.json index 86471cc..8954422 100644 --- a/scripts/external/package.json +++ b/scripts/external/package.json @@ -4,7 +4,8 @@ "description": "", "main": "", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "install": "makenode.js" }, "author": "", "license": "ISC", From 91fe60fe9959fc023b58b895946fbc1d0ac8f736 Mon Sep 17 00:00:00 2001 From: bioid Date: Fri, 17 Jul 2015 22:28:50 -0400 Subject: [PATCH 40/43] remove nodethree.js --- scripts/external/three/nodethree.js | 35253 -------------------------- 1 file changed, 35253 deletions(-) delete mode 100644 scripts/external/three/nodethree.js diff --git a/scripts/external/three/nodethree.js b/scripts/external/three/nodethree.js deleted file mode 100644 index 687bf20..0000000 --- a/scripts/external/three/nodethree.js +++ /dev/null @@ -1,35253 +0,0 @@ -var Canvas = require('canvas'); - -var self = {}; - -var ratio = 16/9.0; - -var canvasWidth = 1024; -var canvasHeight = Math.round(1024 / ratio); - -var window = { - innerWidth: canvasWidth, - innerHeight: canvasHeight - -}; -var document = { - createElement: function(name) { - if (name == "canvas") { -// console.log("Creating canvas " + canvasWidth + ", " + canvasHeight); - return new Canvas(canvasWidth, canvasHeight); - } - } -}; - -// File:src/Three.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -var THREE = { REVISION: '72dev' }; - -// browserify support - -if ( typeof module === 'object' ) { - - module.exports = THREE; - -} - -// polyfills - -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; - - }; - -} - - -// set the default log handlers -THREE.log = function() { console.log.apply( console, arguments ); } -THREE.warn = function() { console.warn.apply( console, arguments ); } -THREE.error = function() { console.error.apply( console, arguments ); } - - -// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button - -THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; - -// GL STATE CONSTANTS - -THREE.CullFaceNone = 0; -THREE.CullFaceBack = 1; -THREE.CullFaceFront = 2; -THREE.CullFaceFrontBack = 3; - -THREE.FrontFaceDirectionCW = 0; -THREE.FrontFaceDirectionCCW = 1; - -// SHADOWING TYPES - -THREE.BasicShadowMap = 0; -THREE.PCFShadowMap = 1; -THREE.PCFSoftShadowMap = 2; - -// MATERIAL CONSTANTS - -// side - -THREE.FrontSide = 0; -THREE.BackSide = 1; -THREE.DoubleSide = 2; - -// shading - -THREE.NoShading = 0; -THREE.FlatShading = 1; -THREE.SmoothShading = 2; - -// colors - -THREE.NoColors = 0; -THREE.FaceColors = 1; -THREE.VertexColors = 2; - -// blending modes - -THREE.NoBlending = 0; -THREE.NormalBlending = 1; -THREE.AdditiveBlending = 2; -THREE.SubtractiveBlending = 3; -THREE.MultiplyBlending = 4; -THREE.CustomBlending = 5; - -// custom blending equations -// (numbers start from 100 not to clash with other -// mappings to OpenGL constants defined in Texture.js) - -THREE.AddEquation = 100; -THREE.SubtractEquation = 101; -THREE.ReverseSubtractEquation = 102; -THREE.MinEquation = 103; -THREE.MaxEquation = 104; - -// custom blending destination factors - -THREE.ZeroFactor = 200; -THREE.OneFactor = 201; -THREE.SrcColorFactor = 202; -THREE.OneMinusSrcColorFactor = 203; -THREE.SrcAlphaFactor = 204; -THREE.OneMinusSrcAlphaFactor = 205; -THREE.DstAlphaFactor = 206; -THREE.OneMinusDstAlphaFactor = 207; - -// custom blending source factors - -//THREE.ZeroFactor = 200; -//THREE.OneFactor = 201; -//THREE.SrcAlphaFactor = 204; -//THREE.OneMinusSrcAlphaFactor = 205; -//THREE.DstAlphaFactor = 206; -//THREE.OneMinusDstAlphaFactor = 207; -THREE.DstColorFactor = 208; -THREE.OneMinusDstColorFactor = 209; -THREE.SrcAlphaSaturateFactor = 210; - - -// TEXTURE CONSTANTS - -THREE.MultiplyOperation = 0; -THREE.MixOperation = 1; -THREE.AddOperation = 2; - -// Mapping modes - -THREE.UVMapping = 300; - -THREE.CubeReflectionMapping = 301; -THREE.CubeRefractionMapping = 302; - -THREE.EquirectangularReflectionMapping = 303; -THREE.EquirectangularRefractionMapping = 304; - -THREE.SphericalReflectionMapping = 305; - -// Wrapping modes - -THREE.RepeatWrapping = 1000; -THREE.ClampToEdgeWrapping = 1001; -THREE.MirroredRepeatWrapping = 1002; - -// Filters - -THREE.NearestFilter = 1003; -THREE.NearestMipMapNearestFilter = 1004; -THREE.NearestMipMapLinearFilter = 1005; -THREE.LinearFilter = 1006; -THREE.LinearMipMapNearestFilter = 1007; -THREE.LinearMipMapLinearFilter = 1008; - -// Data types - -THREE.UnsignedByteType = 1009; -THREE.ByteType = 1010; -THREE.ShortType = 1011; -THREE.UnsignedShortType = 1012; -THREE.IntType = 1013; -THREE.UnsignedIntType = 1014; -THREE.FloatType = 1015; -THREE.HalfFloatType = 1025; - -// Pixel types - -//THREE.UnsignedByteType = 1009; -THREE.UnsignedShort4444Type = 1016; -THREE.UnsignedShort5551Type = 1017; -THREE.UnsignedShort565Type = 1018; - -// Pixel formats - -THREE.AlphaFormat = 1019; -THREE.RGBFormat = 1020; -THREE.RGBAFormat = 1021; -THREE.LuminanceFormat = 1022; -THREE.LuminanceAlphaFormat = 1023; -// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders -THREE.RGBEFormat = THREE.RGBAFormat; //1024; - -// DDS / ST3C Compressed texture formats - -THREE.RGB_S3TC_DXT1_Format = 2001; -THREE.RGBA_S3TC_DXT1_Format = 2002; -THREE.RGBA_S3TC_DXT3_Format = 2003; -THREE.RGBA_S3TC_DXT5_Format = 2004; - - -// PVRTC compressed texture formats - -THREE.RGB_PVRTC_4BPPV1_Format = 2100; -THREE.RGB_PVRTC_2BPPV1_Format = 2101; -THREE.RGBA_PVRTC_4BPPV1_Format = 2102; -THREE.RGBA_PVRTC_2BPPV1_Format = 2103; - - -// DEPRECATED - -THREE.Projector = function () { - - THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); - - this.projectVector = function ( vector, camera ) { - - THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); - vector.project( camera ); - - }; - - this.unprojectVector = function ( vector, camera ) { - - THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); - vector.unproject( camera ); - - }; - - this.pickingRay = function ( vector, camera ) { - - THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); - - }; - -}; - -THREE.CanvasRenderer = function () { - - THREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); - - this.domElement = document.createElement( 'canvas' ); - this.clear = function () {}; - this.render = function () {}; - this.setClearColor = function () {}; - this.setSize = function () {}; - -}; - -// File:src/math/Color.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Color = function ( color ) { - - if ( arguments.length === 3 ) { - - return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); - - } - - return this.set( color ) - -}; - -THREE.Color.prototype = { - - constructor: THREE.Color, - - r: 1, g: 1, b: 1, - - set: function ( value ) { - - if ( value instanceof THREE.Color ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - 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 ( h, s, l ) { - - // h,s,l ranges are in 0.0 - 1.0 - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - var hue2rgb = function ( 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; - - }; - - 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 ) { - - // rgb(255,0,0) - - if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { - - var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); - - 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; - - return this; - - } - - // rgb(100%,0%,0%) - - if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { - - var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); - - 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; - - return this; - - } - - // #ff0000 - - if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { - - var color = /^\#([0-9a-f]{6})$/i.exec( style ); - - this.setHex( parseInt( color[ 1 ], 16 ) ); - - return this; - - } - - // #f00 - - if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { - - var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); - - this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); - - return this; - - } - - // red - - if ( /^(\w+)$/i.test( style ) ) { - - this.setHex( THREE.ColorKeywords[ style ] ); - - return this; - - } - - - }, - - 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; - - }, - - 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 ) { - - this.r = array[ 0 ]; - this.g = array[ 1 ]; - this.b = array[ 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; - }, - - clone: function () { - - return new THREE.Color().setRGB( this.r, this.g, this.b ); - - } - -}; - -THREE.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 }; - -// File:src/math/Quaternion.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Quaternion = function ( x, y, z, w ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; - -}; - -THREE.Quaternion.prototype = { - - constructor: THREE.Quaternion, - - _x: 0,_y: 0, _z: 0, _w: 0, - - 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; - - }, - - 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 instanceof THREE.Euler === false ) { - - throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a 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 ); - - if ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( euler.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 ( vFrom, vTo ) { - - if ( v1 === undefined ) v1 = new THREE.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; - - this.normalize(); - - return this; - - } - - }(), - - inverse: function () { - - this.conjugate().normalize(); - - return this; - - }, - - 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 ) { - - THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); - - } - - return this.multiplyQuaternions( this, q ); - - }, - - 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; - - }, - - multiplyVector3: function ( vector ) { - - THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( 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 halfTheta = Math.acos( cosHalfTheta ); - 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 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 () {}, - - clone: function () { - - return new THREE.Quaternion( this._x, this._y, this._z, this._w ); - - } - -}; - -THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { - - return qm.copy( qa ).slerp( qb, t ); - -} - -// File:src/math/Vector2.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author philogb / http://blog.thejit.org/ - * @author egraether / http://egraether.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -THREE.Vector2 = function ( x, y ) { - - this.x = x || 0; - this.y = y || 0; - -}; - -THREE.Vector2.prototype = { - - constructor: THREE.Vector2, - - set: function ( x, y ) { - - this.x = x; - this.y = y; - - 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 ); - - } - - }, - - 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 ); - - } - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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 ( s ) { - - this.x *= s; - this.y *= s; - - return this; - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - }, - - divideScalar: function ( scalar ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - - } - - return this; - - }, - - min: function ( v ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - 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 - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - return this; - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector2(); - max = new THREE.Vector2(); - - } - - min.set( minVal, minVal ); - max.set( maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - } )(), - - 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 ); - - }, - - normalize: function () { - - return this.divideScalar( this.length() ); - - }, - - 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; - - }, - - setLength: function ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - } - - return this; - - }, - - 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 ) { - - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - return this; - - }, - - 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; - - }, - - fromAttribute: function ( attribute, index, offset ) { - - if ( offset === undefined ) offset = 0; - - index = index * attribute.itemSize + offset; - - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - - return this; - - }, - - clone: function () { - - return new THREE.Vector2( this.x, this.y ); - - } - -}; - -// File:src/math/Vector3.js - -/** - * @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 - */ - -THREE.Vector3 = function ( x, y, z ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - -}; - -THREE.Vector3.prototype = { - - constructor: THREE.Vector3, - - set: function ( x, y, z ) { - - this.x = x; - this.y = y; - this.z = z; - - 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 ); - - } - - }, - - 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 ); - - } - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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 ) { - - THREE.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 ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - 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 ( euler ) { - - if ( euler instanceof THREE.Euler === false ) { - - THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - - } - - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - - this.applyQuaternion( quaternion.setFromEuler( euler ) ); - - return this; - - }; - - }(), - - applyAxisAngle: function () { - - var quaternion; - - return function ( axis, angle ) { - - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - - this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); - - return this; - - }; - - }(), - - applyMatrix3: function ( m ) { - - var x = this.x; - var y = this.y; - var 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 ) { - - // input: THREE.Matrix4 affine matrix - - 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 ]; - - return this; - - }, - - applyProjection: function ( m ) { - - // input: THREE.Matrix4 projection matrix - - var x = this.x, y = this.y, z = this.z; - - var e = m.elements; - var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide - - this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d; - this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d; - this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d; - - return this; - - }, - - applyQuaternion: function ( q ) { - - var x = this.x; - var y = this.y; - var z = this.z; - - var qx = q.x; - var qy = q.y; - var qz = q.z; - var 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 ( camera ) { - - if ( matrix === undefined ) matrix = new THREE.Matrix4(); - - matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); - return this.applyProjection( matrix ); - - }; - - }(), - - unproject: function () { - - var matrix; - - return function ( camera ) { - - if ( matrix === undefined ) matrix = new THREE.Matrix4(); - - matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); - return this.applyProjection( 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; - - this.normalize(); - - return this; - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - }, - - divideScalar: function ( scalar ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - - } - - return this; - - }, - - min: function ( v ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - if ( this.z > v.z ) { - - this.z = v.z; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - this.y = v.y; - - } - - if ( this.z < v.z ) { - - 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 - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - if ( this.z < min.z ) { - - this.z = min.z; - - } else if ( this.z > max.z ) { - - this.z = max.z; - - } - - return this; - - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector3(); - max = new THREE.Vector3(); - - } - - min.set( minVal, minVal, minVal ); - max.set( 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 ); - - 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 ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - } - - return this; - - }, - - 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 ) { - - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - return this; - - }, - - cross: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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 () { - - var v1, dot; - - return function ( vector ) { - - if ( v1 === undefined ) v1 = new THREE.Vector3(); - - v1.copy( vector ).normalize(); - - dot = this.dot( v1 ); - - return this.copy( v1 ).multiplyScalar( dot ); - - }; - - }(), - - projectOnPlane: function () { - - var v1; - - return function ( planeNormal ) { - - if ( v1 === undefined ) v1 = new THREE.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 ( normal ) { - - if ( v1 === undefined ) v1 = new THREE.Vector3(); - - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - } - - }(), - - angleTo: function ( v ) { - - var theta = this.dot( v ) / ( this.length() * v.length() ); - - // clamp, to handle numerical problems - - return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) ); - - }, - - distanceTo: function ( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - }, - - distanceToSquared: function ( v ) { - - var dx = this.x - v.x; - var dy = this.y - v.y; - var dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - }, - - setEulerFromRotationMatrix: function ( m, order ) { - - THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - - }, - - setEulerFromQuaternion: function ( q, order ) { - - THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - - }, - - getPositionFromMatrix: function ( m ) { - - THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - - return this.setFromMatrixPosition( m ); - - }, - - getScaleFromMatrix: function ( m ) { - - THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - - return this.setFromMatrixScale( m ); - }, - - getColumnFromMatrix: function ( index, matrix ) { - - THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - - return this.setFromMatrixColumn( index, matrix ); - - }, - - setFromMatrixPosition: function ( m ) { - - this.x = m.elements[ 12 ]; - this.y = m.elements[ 13 ]; - this.z = m.elements[ 14 ]; - - return this; - - }, - - setFromMatrixScale: function ( m ) { - - var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); - var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); - var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - }, - - setFromMatrixColumn: function ( index, matrix ) { - - var offset = index * 4; - - var me = matrix.elements; - - this.x = me[ offset ]; - this.y = me[ offset + 1 ]; - this.z = me[ offset + 2 ]; - - return this; - - }, - - 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; - - }, - - fromAttribute: function ( attribute, index, offset ) { - - if ( offset === undefined ) offset = 0; - - index = index * attribute.itemSize + offset; - - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; - - return this; - - }, - - clone: function () { - - return new THREE.Vector3( this.x, this.y, this.z ); - - } - -}; - -// File:src/math/Vector4.js - -/** - * @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 - */ - -THREE.Vector4 = function ( x, y, z, w ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; - -}; - -THREE.Vector4.prototype = { - - constructor: THREE.Vector4, - - set: function ( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - 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 ); - - } - - }, - - 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 ); - - } - - }, - - 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 ) { - - THREE.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; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.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 ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - }, - - applyMatrix4: function ( m ) { - - var x = this.x; - var y = this.y; - var z = this.z; - var 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 ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - this.w *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - - } - - return this; - - }, - - 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 ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - if ( this.z > v.z ) { - - this.z = v.z; - - } - - if ( this.w > v.w ) { - - this.w = v.w; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - this.y = v.y; - - } - - if ( this.z < v.z ) { - - this.z = v.z; - - } - - if ( this.w < v.w ) { - - 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 - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - if ( this.z < min.z ) { - - this.z = min.z; - - } else if ( this.z > max.z ) { - - this.z = max.z; - - } - - if ( this.w < min.w ) { - - this.w = min.w; - - } else if ( this.w > max.w ) { - - this.w = max.w; - - } - - return this; - - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector4(); - max = new THREE.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 ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - - } - - return this; - - }, - - 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 ) { - - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - return this; - - }, - - 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; - - }, - - fromAttribute: function ( attribute, index, offset ) { - - if ( offset === undefined ) offset = 0; - - index = index * attribute.itemSize + offset; - - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; - this.w = attribute.array[ index + 3 ]; - - return this; - - }, - - clone: function () { - - return new THREE.Vector4( this.x, this.y, this.z, this.w ); - - } - -}; - -// File:src/math/Euler.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Euler = function ( x, y, z, order ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || THREE.Euler.DefaultOrder; - -}; - -THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - -THREE.Euler.DefaultOrder = 'XYZ'; - -THREE.Euler.prototype = { - - constructor: THREE.Euler, - - _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, - - 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; - - }, - - 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 = THREE.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 { - - THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) - - } - - this._order = order; - - if ( update !== false ) this.onChangeCallback(); - - return this; - - }, - - setFromQuaternion: function () { - - var matrix; - - return function ( q, order, update ) { - - if ( matrix === undefined ) matrix = new THREE.Matrix4(); - matrix.makeRotationFromQuaternion( q ); - this.setFromRotationMatrix( matrix, order, update ); - - return this; - - }; - - }(), - - 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 THREE.Quaternion(); - - return function ( newOrder ) { - - q.setFromEuler( this ); - 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 THREE.Vector3( this._x, this._y, this._z ); - - } - - }, - - onChange: function ( callback ) { - - this.onChangeCallback = callback; - - return this; - - }, - - onChangeCallback: function () {}, - - clone: function () { - - return new THREE.Euler( this._x, this._y, this._z, this._order ); - - } - -}; - -// File:src/math/Line3.js - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Line3 = function ( start, end ) { - - this.start = ( start !== undefined ) ? start : new THREE.Vector3(); - this.end = ( end !== undefined ) ? end : new THREE.Vector3(); - -}; - -THREE.Line3.prototype = { - - constructor: THREE.Line3, - - set: function ( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - }, - - copy: function ( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - }, - - delta: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.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 THREE.Vector3(); - - return this.delta( result ).multiplyScalar( t ).add( this.start ); - - }, - - closestPointToPointParameter: function () { - - var startP = new THREE.Vector3(); - var startEnd = new THREE.Vector3(); - - return function ( 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 = THREE.Math.clamp( t, 0, 1 ); - - } - - return t; - - }; - - }(), - - closestPointToPoint: function ( point, clampToLine, optionalTarget ) { - - var t = this.closestPointToPointParameter( point, clampToLine ); - - var result = optionalTarget || new THREE.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 ); - - }, - - clone: function () { - - return new THREE.Line3().copy( this ); - - } - -}; - -// File:src/math/Box2.js - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Box2 = function ( min, max ) { - - this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity ); - -}; - -THREE.Box2.prototype = { - - constructor: THREE.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 THREE.Vector2(); - - return function ( center, size ) { - - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return 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; - - }, - - empty: 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 ); - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - size: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return 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 ) { - - if ( point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ) { - - return false; - - } - - return true; - - }, - - containsBox: function ( box ) { - - if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { - - return true; - - } - - return false; - - }, - - 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 THREE.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 ) - ); - - }, - - isIntersectionBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - - if ( box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ) { - - return false; - - } - - return true; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function () { - - var v1 = new THREE.Vector2(); - - return function ( 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 ); - - }, - - clone: function () { - - return new THREE.Box2().copy( this ); - - } - -}; - -// File:src/math/Box3.js - -/** - * @author bhouston / http://exocortex.com - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Box3 = function ( min, max ) { - - this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity ); - -}; - -THREE.Box3.prototype = { - - constructor: THREE.Box3, - - 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 THREE.Vector3(); - - return function ( 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 () { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and childrens', world transforms - - var v1 = new THREE.Vector3(); - - return function ( object ) { - - var scope = this; - - object.updateMatrixWorld( true ); - - this.makeEmpty(); - - object.traverse( function ( node ) { - - var geometry = node.geometry; - - if ( geometry !== undefined ) { - - if ( geometry instanceof THREE.Geometry ) { - - var vertices = geometry.vertices; - - for ( var i = 0, il = vertices.length; i < il; i ++ ) { - - v1.copy( vertices[ i ] ); - - v1.applyMatrix4( node.matrixWorld ); - - scope.expandByPoint( v1 ); - - } - - } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) { - - var positions = geometry.attributes[ 'position' ].array; - - for ( var i = 0, il = positions.length; i < il; i += 3 ) { - - v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - - v1.applyMatrix4( node.matrixWorld ); - - scope.expandByPoint( v1 ); - - } - - } - - } - - } ); - - return 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; - - }, - - empty: 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 ); - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - size: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return 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 ) { - - if ( 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 ) { - - return false; - - } - - return true; - - }, - - containsBox: function ( box ) { - - if ( ( 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 ) ) { - - return true; - - } - - return false; - - }, - - 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 THREE.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 ) - ); - - }, - - isIntersectionBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - - if ( 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 ) { - - return false; - - } - - return true; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function () { - - var v1 = new THREE.Vector3(); - - return function ( point ) { - - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - }; - - }(), - - getBoundingSphere: function () { - - var v1 = new THREE.Vector3(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Sphere(); - - result.center = this.center(); - result.radius = this.size( v1 ).length() * 0.5; - - return result; - - }; - - }(), - - 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; - - }, - - applyMatrix4: function () { - - var points = [ - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3() - ]; - - return function ( matrix ) { - - // 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.makeEmpty(); - 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 ); - - }, - - clone: function () { - - return new THREE.Box3().copy( this ); - - } - -}; - -// File:src/math/Matrix3.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Matrix3 = function () { - - this.elements = new Float32Array( [ - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ] ); - - if ( arguments.length > 0 ) { - - THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); - - } - -}; - -THREE.Matrix3.prototype = { - - constructor: THREE.Matrix3, - - set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - var te = this.elements; - - te[ 0 ] = n11; te[ 3 ] = n12; te[ 6 ] = n13; - te[ 1 ] = n21; te[ 4 ] = n22; te[ 7 ] = n23; - te[ 2 ] = n31; te[ 5 ] = n32; te[ 8 ] = n33; - - return this; - - }, - - identity: function () { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - }, - - 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; - - }, - - multiplyVector3: function ( vector ) { - - THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); - - }, - - multiplyVector3Array: function ( a ) { - - THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); - return this.applyToVector3Array( a ); - - }, - - applyToVector3Array: function () { - - var v1 = new THREE.Vector3(); - - return function ( array, offset, length ) { - - if ( offset === undefined ) offset = 0; - if ( length === undefined ) length = array.length; - - for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - - v1.x = array[ j ]; - v1.y = array[ j + 1 ]; - v1.z = array[ j + 2 ]; - - v1.applyMatrix3( this ); - - array[ j ] = v1.x; - array[ j + 1 ] = v1.y; - array[ j + 2 ] = v1.z; - - } - - return array; - - }; - - }(), - - 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, throwOnInvertible ) { - - // input: THREE.Matrix4 - // ( based on http://code.google.com/p/webgl-mjs/ ) - - var me = matrix.elements; - var te = this.elements; - - te[ 0 ] = me[ 10 ] * me[ 5 ] - me[ 6 ] * me[ 9 ]; - te[ 1 ] = - me[ 10 ] * me[ 1 ] + me[ 2 ] * me[ 9 ]; - te[ 2 ] = me[ 6 ] * me[ 1 ] - me[ 2 ] * me[ 5 ]; - te[ 3 ] = - me[ 10 ] * me[ 4 ] + me[ 6 ] * me[ 8 ]; - te[ 4 ] = me[ 10 ] * me[ 0 ] - me[ 2 ] * me[ 8 ]; - te[ 5 ] = - me[ 6 ] * me[ 0 ] + me[ 2 ] * me[ 4 ]; - te[ 6 ] = me[ 9 ] * me[ 4 ] - me[ 5 ] * me[ 8 ]; - te[ 7 ] = - me[ 9 ] * me[ 0 ] + me[ 1 ] * me[ 8 ]; - te[ 8 ] = me[ 5 ] * me[ 0 ] - me[ 1 ] * me[ 4 ]; - - var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; - - // no inverse - - if ( det === 0 ) { - - var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; - - if ( throwOnInvertible || false ) { - - throw new Error( msg ); - - } else { - - THREE.warn( msg ); - - } - - this.identity(); - - return this; - - } - - this.multiplyScalar( 1.0 / det ); - - 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; - - }, - - flattenToArrayOffset: function ( array, offset ) { - - 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; - - }, - - getNormalMatrix: function ( m ) { - - // input: THREE.Matrix4 - - this.getInverse( m ).transpose(); - - return this; - - }, - - 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 ) { - - this.elements.set( array ); - - return this; - - }, - - toArray: function () { - - var te = this.elements; - - return [ - te[ 0 ], te[ 1 ], te[ 2 ], - te[ 3 ], te[ 4 ], te[ 5 ], - te[ 6 ], te[ 7 ], te[ 8 ] - ]; - - }, - - clone: function () { - - return new THREE.Matrix3().fromArray( this.elements ); - - } - -}; - -// File:src/math/Matrix4.js - -/** - * @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://exocortex.com - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Matrix4 = function () { - - this.elements = new Float32Array( [ - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ] ); - - if ( arguments.length > 0 ) { - - THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - - } - -}; - -THREE.Matrix4.prototype = { - - constructor: THREE.Matrix4, - - 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; - - }, - - copy: function ( m ) { - - this.elements.set( m.elements ); - - return this; - - }, - - extractPosition: function ( m ) { - - THREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); - - }, - - 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 ) { - - var te = this.elements; - - xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] ); - yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] ); - zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] ); - - 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 = new THREE.Vector3(); - - return function ( m ) { - - var te = this.elements; - var me = m.elements; - - var scaleX = 1 / v1.set( me[ 0 ], me[ 1 ], me[ 2 ] ).length(); - var scaleY = 1 / v1.set( me[ 4 ], me[ 5 ], me[ 6 ] ).length(); - var scaleZ = 1 / v1.set( me[ 8 ], me[ 9 ], me[ 10 ] ).length(); - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - - return this; - - }; - - }(), - - makeRotationFromEuler: function ( euler ) { - - if ( euler instanceof THREE.Euler === false ) { - - THREE.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; - - }, - - setRotationFromQuaternion: function ( q ) { - - THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - - return this.makeRotationFromQuaternion( q ); - - }, - - 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 = new THREE.Vector3(); - var y = new THREE.Vector3(); - var z = new THREE.Vector3(); - - return function ( eye, target, up ) { - - var te = this.elements; - - z.subVectors( eye, target ).normalize(); - - if ( z.length() === 0 ) { - - z.z = 1; - - } - - x.crossVectors( up, z ).normalize(); - - if ( x.length() === 0 ) { - - z.x += 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 ) { - - THREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); - - } - - return this.multiplyMatrices( this, m ); - - }, - - 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; - - }, - - multiplyVector3: function ( vector ) { - - THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); - return vector.applyProjection( this ); - - }, - - multiplyVector4: function ( vector ) { - - THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - - multiplyVector3Array: function ( a ) { - - THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); - return this.applyToVector3Array( a ); - - }, - - applyToVector3Array: function () { - - var v1 = new THREE.Vector3(); - - return function ( array, offset, length ) { - - if ( offset === undefined ) offset = 0; - if ( length === undefined ) length = array.length; - - for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - - v1.x = array[ j ]; - v1.y = array[ j + 1 ]; - v1.z = array[ j + 2 ]; - - v1.applyMatrix4( this ); - - array[ j ] = v1.x; - array[ j + 1 ] = v1.y; - array[ j + 2 ] = v1.z; - - } - - return array; - - }; - - }(), - - rotateAxis: function ( v ) { - - THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - - v.transformDirection( this ); - - }, - - crossVector: function ( vector ) { - - THREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - - 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; - - }, - - flattenToArrayOffset: function ( array, offset ) { - - 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; - - }, - - getPosition: function () { - - var v1 = new THREE.Vector3(); - - return function () { - - THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - - var te = this.elements; - return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); - - }; - - }(), - - setPosition: function ( v ) { - - var te = this.elements; - - te[ 12 ] = v.x; - te[ 13 ] = v.y; - te[ 14 ] = v.z; - - return this; - - }, - - getInverse: function ( m, throwOnInvertible ) { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements; - var me = m.elements; - - var n11 = me[ 0 ], n12 = me[ 4 ], n13 = me[ 8 ], n14 = me[ 12 ]; - var n21 = me[ 1 ], n22 = me[ 5 ], n23 = me[ 9 ], n24 = me[ 13 ]; - var n31 = me[ 2 ], n32 = me[ 6 ], n33 = me[ 10 ], n34 = me[ 14 ]; - var n41 = me[ 3 ], n42 = me[ 7 ], n43 = me[ 11 ], n44 = me[ 15 ]; - - te[ 0 ] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; - te[ 4 ] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; - te[ 8 ] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; - te[ 12 ] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - te[ 1 ] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44; - te[ 5 ] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44; - te[ 9 ] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44; - te[ 13 ] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34; - te[ 2 ] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44; - te[ 6 ] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44; - te[ 10 ] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44; - te[ 14 ] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34; - te[ 3 ] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43; - te[ 7 ] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43; - te[ 11 ] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43; - te[ 15 ] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33; - - var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; - - if ( det == 0 ) { - - var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; - - if ( throwOnInvertible || false ) { - - throw new Error( msg ); - - } else { - - THREE.warn( msg ); - - } - - this.identity(); - - return this; - } - - this.multiplyScalar( 1 / det ); - - return this; - - }, - - translate: function ( v ) { - - THREE.error( 'THREE.Matrix4: .translate() has been removed.' ); - - }, - - rotateX: function ( angle ) { - - THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - - }, - - rotateY: function ( angle ) { - - THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - - }, - - rotateZ: function ( angle ) { - - THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - - }, - - rotateByAxis: function ( axis, angle ) { - - THREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - - }, - - 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, Math.max( 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; - - }, - - compose: function ( position, quaternion, scale ) { - - this.makeRotationFromQuaternion( quaternion ); - this.scale( scale ); - this.setPosition( position ); - - return this; - - }, - - decompose: function () { - - var vector = new THREE.Vector3(); - var matrix = new THREE.Matrix4(); - - return function ( position, quaternion, scale ) { - - 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; - - }; - - }(), - - makeFrustum: function ( left, right, bottom, top, near, far ) { - - 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; - - }, - - makePerspective: function ( fov, aspect, near, far ) { - - var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); - var ymin = - ymax; - var xmin = ymin * aspect; - var xmax = ymax * aspect; - - return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); - - }, - - makeOrthographic: function ( left, right, top, bottom, near, far ) { - - var te = this.elements; - var w = right - left; - var h = top - bottom; - var p = 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; - - }, - - fromArray: function ( array ) { - - this.elements.set( array ); - - return this; - - }, - - toArray: function () { - - var te = this.elements; - - return [ - te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], - te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], - te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], - te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] - ]; - - }, - - clone: function () { - - return new THREE.Matrix4().fromArray( this.elements ); - - } - -}; - -// File:src/math/Ray.js - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Ray = function ( origin, direction ) { - - this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); - this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); - -}; - -THREE.Ray.prototype = { - - constructor: THREE.Ray, - - set: function ( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - }, - - copy: function ( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - }, - - at: function ( t, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - - }, - - recast: function () { - - var v1 = new THREE.Vector3(); - - return function ( t ) { - - this.origin.copy( this.at( t, v1 ) ); - - return this; - - }; - - }(), - - closestPointToPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.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 () { - - var v1 = new THREE.Vector3(); - - return function ( point ) { - - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceTo( point ); - - } - - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - return v1.distanceTo( point ); - - }; - - }(), - - distanceSqToSegment: function () { - - var segCenter = new THREE.Vector3(); - var segDir = new THREE.Vector3(); - var diff = new THREE.Vector3(); - - return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp - // 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; - - }; - - }(), - - - isIntersectionSphere: function ( sphere ) { - - return this.distanceToPoint( sphere.center ) <= sphere.radius; - - }, - - intersectSphere: function () { - - // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/ - - var v1 = new THREE.Vector3(); - - return function ( 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 ); - - } - - }(), - - isIntersectionPlane: 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; - - }, - - 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 ); - - }, - - isIntersectionBox: function () { - - var v = new THREE.Vector3(); - - return function ( box ) { - - return this.intersectBox( box, v ) !== null; - - }; - - }(), - - intersectBox: function ( box, optionalTarget ) { - - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - - 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 ); - - }, - - intersectTriangle: function () { - - // Compute the offset origin, edges, and normal. - var diff = new THREE.Vector3(); - var edge1 = new THREE.Vector3(); - var edge2 = new THREE.Vector3(); - var normal = new THREE.Vector3(); - - return function ( a, b, c, backfaceCulling, optionalTarget ) { - - // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp - - 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 ); - - }, - - clone: function () { - - return new THREE.Ray().copy( this ); - - } - -}; - -// File:src/math/Sphere.js - -/** - * @author bhouston / http://exocortex.com - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Sphere = function ( center, radius ) { - - this.center = ( center !== undefined ) ? center : new THREE.Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; - -}; - -THREE.Sphere.prototype = { - - constructor: THREE.Sphere, - - set: function ( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - }, - - setFromPoints: function () { - - var box = new THREE.Box3(); - - return function ( points, optionalCenter ) { - - var center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - box.setFromPoints( points ).center( 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; - - }; - - }(), - - 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 ); - - }, - - clampPoint: function ( point, optionalTarget ) { - - var deltaLengthSq = this.center.distanceToSquared( point ); - - var result = optionalTarget || new THREE.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 THREE.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 ); - - }, - - clone: function () { - - return new THREE.Sphere().copy( this ); - - } - -}; - -// File:src/math/Frustum.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://exocortex.com - */ - -THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { - - this.planes = [ - - ( p0 !== undefined ) ? p0 : new THREE.Plane(), - ( p1 !== undefined ) ? p1 : new THREE.Plane(), - ( p2 !== undefined ) ? p2 : new THREE.Plane(), - ( p3 !== undefined ) ? p3 : new THREE.Plane(), - ( p4 !== undefined ) ? p4 : new THREE.Plane(), - ( p5 !== undefined ) ? p5 : new THREE.Plane() - - ]; - -}; - -THREE.Frustum.prototype = { - - constructor: THREE.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; - - }, - - 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 THREE.Sphere(); - - return function ( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.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 THREE.Vector3(), - p2 = new THREE.Vector3(); - - return function ( 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; - - }, - - clone: function () { - - return new THREE.Frustum().copy( this ); - - } - -}; - -// File:src/math/Plane.js - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Plane = function ( normal, constant ) { - - this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; - -}; - -THREE.Plane.prototype = { - - constructor: THREE.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 THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( 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; - - }; - - }(), - - - 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 THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); - - }, - - isIntersectionLine: 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 ); - - }, - - intersectLine: function () { - - var v1 = new THREE.Vector3(); - - return function ( line, optionalTarget ) { - - var result = optionalTarget || new THREE.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 ); - - }; - - }(), - - - coplanarPoint: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( - this.constant ); - - }, - - applyMatrix4: function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var m1 = new THREE.Matrix3(); - - return function ( matrix, optionalNormalMatrix ) { - - // compute new normal based on theory here: - // http://www.songho.ca/opengl/gl_normaltransform.html - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); - var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); - - var newCoplanarPoint = this.coplanarPoint( v2 ); - newCoplanarPoint.applyMatrix4( matrix ); - - this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); - - 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 ); - - }, - - clone: function () { - - return new THREE.Plane().copy( this ); - - } - -}; - -// File:src/math/Math.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Math = { - - 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 () { - - 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 value to range - - clamp: function ( x, a, b ) { - - return ( x < a ) ? a : ( ( x > b ) ? b : x ); - - }, - - // Clamp value to range to range - - mapLinear: function ( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - - }, - - // 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 float from <0, 1> with 16 bits of randomness - // (standard Math.random() creates repetitive patterns when applied over larger space) - - random16: function () { - - return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; - - }, - - // Random integer from interval - - randInt: function ( low, high ) { - - return Math.floor( this.randFloat( low, high ) ); - - }, - - // 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 () { - - var degreeToRadiansFactor = Math.PI / 180; - - return function ( degrees ) { - - return degrees * degreeToRadiansFactor; - - }; - - }(), - - radToDeg: function () { - - var radianToDegreesFactor = 180 / Math.PI; - - return function ( radians ) { - - return radians * radianToDegreesFactor; - - }; - - }(), - - isPowerOfTwo: function ( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - - }, - - nextPowerOfTwo: function ( value ) { - - value --; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value ++; - - return value; - - } - -}; - -// File:src/math/Spline.js - -/** - * Spline from Tween.js, slightly optimized (and trashed) - * http://sole.github.com/tween.js/examples/05_spline.html - * - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Spline = function ( points ) { - - this.points = points; - - var c = [], v3 = { x: 0, y: 0, z: 0 }, - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; - - this.initFromArray = function ( a ) { - - this.points = []; - - for ( var i = 0; i < a.length; i ++ ) { - - this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; - - } - - }; - - this.getPoint = function ( k ) { - - point = ( this.points.length - 1 ) * k; - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; - - pa = this.points[ c[ 0 ] ]; - pb = this.points[ c[ 1 ] ]; - pc = this.points[ c[ 2 ] ]; - pd = this.points[ c[ 3 ] ]; - - w2 = weight * weight; - w3 = weight * w2; - - v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); - v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); - v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); - - return v3; - - }; - - this.getControlPointsArray = function () { - - var i, p, l = this.points.length, - coords = []; - - for ( i = 0; i < l; i ++ ) { - - p = this.points[ i ]; - coords[ i ] = [ p.x, p.y, p.z ]; - - } - - return coords; - - }; - - // approximate length by summing linear segments - - this.getLength = function ( nSubDivisions ) { - - var i, index, nSamples, position, - point = 0, intPoint = 0, oldIntPoint = 0, - oldPosition = new THREE.Vector3(), - tmpVec = new THREE.Vector3(), - chunkLengths = [], - totalLength = 0; - - // first point has 0 length - - chunkLengths[ 0 ] = 0; - - if ( ! nSubDivisions ) nSubDivisions = 100; - - nSamples = this.points.length * nSubDivisions; - - oldPosition.copy( this.points[ 0 ] ); - - for ( i = 1; i < nSamples; i ++ ) { - - index = i / nSamples; - - position = this.getPoint( index ); - tmpVec.copy( position ); - - totalLength += tmpVec.distanceTo( oldPosition ); - - oldPosition.copy( position ); - - point = ( this.points.length - 1 ) * index; - intPoint = Math.floor( point ); - - if ( intPoint != oldIntPoint ) { - - chunkLengths[ intPoint ] = totalLength; - oldIntPoint = intPoint; - - } - - } - - // last point ends with total length - - chunkLengths[ chunkLengths.length ] = totalLength; - - return { chunks: chunkLengths, total: totalLength }; - - }; - - this.reparametrizeByArcLength = function ( samplingCoef ) { - - var i, j, - index, indexCurrent, indexNext, - realDistance, - sampling, position, - newpoints = [], - tmpVec = new THREE.Vector3(), - sl = this.getLength(); - - newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); - - for ( i = 1; i < this.points.length; i ++ ) { - - //tmpVec.copy( this.points[ i - 1 ] ); - //linearDistance = tmpVec.distanceTo( this.points[ i ] ); - - realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; - - sampling = Math.ceil( samplingCoef * realDistance / sl.total ); - - indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); - indexNext = i / ( this.points.length - 1 ); - - for ( j = 1; j < sampling - 1; j ++ ) { - - index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); - - position = this.getPoint( index ); - newpoints.push( tmpVec.copy( position ).clone() ); - - } - - newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); - - } - - this.points = newpoints; - - }; - - // Catmull-Rom - - function interpolate( p0, p1, p2, p3, t, t2, t3 ) { - - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - }; - -}; - -// File:src/math/Triangle.js - -/** - * @author bhouston / http://exocortex.com - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Triangle = function ( a, b, c ) { - - this.a = ( a !== undefined ) ? a : new THREE.Vector3(); - this.b = ( b !== undefined ) ? b : new THREE.Vector3(); - this.c = ( c !== undefined ) ? c : new THREE.Vector3(); - -}; - -THREE.Triangle.normal = function () { - - var v0 = new THREE.Vector3(); - - return function ( a, b, c, optionalTarget ) { - - var result = optionalTarget || new THREE.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 barycoordinates -// based on: http://www.blackpawn.com/texts/pointinpoly/default.html -THREE.Triangle.barycoordFromPoint = function () { - - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( 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 THREE.Vector3(); - - // colinear 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; - - // barycoordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); - - }; - -}(); - -THREE.Triangle.containsPoint = function () { - - var v1 = new THREE.Vector3(); - - return function ( point, a, b, c ) { - - var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); - - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - - }; - -}(); - -THREE.Triangle.prototype = { - - constructor: THREE.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; - - }, - - 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 THREE.Vector3(); - var v1 = new THREE.Vector3(); - - return function () { - - 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 THREE.Vector3(); - return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - }, - - normal: function ( optionalTarget ) { - - return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); - - }, - - plane: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Plane(); - - return result.setFromCoplanarPoints( this.a, this.b, this.c ); - - }, - - barycoordFromPoint: function ( point, optionalTarget ) { - - return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); - - }, - - containsPoint: function ( point ) { - - return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); - - }, - - equals: function ( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - }, - - clone: function () { - - return new THREE.Triangle().copy( this ); - - } - -}; - -// File:src/core/Clock.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Clock = function ( autoStart ) { - - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - -}; - -THREE.Clock.prototype = { - - constructor: THREE.Clock, - - start: function () { - - this.startTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); - - this.oldTime = this.startTime; - 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 = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); - - diff = 0.001 * ( newTime - this.oldTime ); - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - -}; - -// File:src/core/EventDispatcher.js - -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -THREE.EventDispatcher = function () {} - -THREE.EventDispatcher.prototype = { - - constructor: THREE.EventDispatcher, - - apply: function ( object ) { - - object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; - object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; - object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; - object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; - - }, - - 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; - - if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { - - return true; - - } - - return false; - - }, - - 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 = []; - var length = listenerArray.length; - - for ( var i = 0; i < length; i ++ ) { - - array[ i ] = listenerArray[ i ]; - - } - - for ( var i = 0; i < length; i ++ ) { - - array[ i ].call( this, event ); - - } - - } - - } - -}; - -// File:src/core/Raycaster.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://exocortex.com/ - * @author stephomi / http://stephaneginier.com/ - */ - -( function ( THREE ) { - - THREE.Raycaster = function ( origin, direction, near, far ) { - - this.ray = new THREE.Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near || 0; - this.far = far || Infinity; - - this.params = { - Sprite: {}, - Mesh: {}, - PointCloud: { threshold: 1 }, - LOD: {}, - Line: {} - }; - - }; - - var descSort = function ( a, b ) { - - return a.distance - b.distance; - - }; - - var intersectObject = function ( object, raycaster, intersects, recursive ) { - - 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 ); - - } - - } - - }; - - // - - THREE.Raycaster.prototype = { - - constructor: THREE.Raycaster, - - precision: 0.0001, - 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 ) { - - // camera is assumed _not_ to be a child of a transformed object - - if ( camera instanceof THREE.PerspectiveCamera ) { - - this.ray.origin.copy( camera.position ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( camera.position ).normalize(); - - } else if ( camera instanceof THREE.OrthographicCamera ) { - - this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - - } else { - - THREE.error( 'THREE.Raycaster: Unsupported camera type.' ); - - } - - }, - - intersectObject: function ( object, recursive ) { - - var intersects = []; - - intersectObject( object, this, intersects, recursive ); - - intersects.sort( descSort ); - - return intersects; - - }, - - intersectObjects: function ( objects, recursive ) { - - var intersects = []; - - if ( objects instanceof Array === false ) { - - THREE.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( descSort ); - - return intersects; - - } - - }; - -}( THREE ) ); - -// File:src/core/Object3D.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Object3D = function () { - - Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } ); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.type = 'Object3D'; - - this.parent = undefined; - this.children = []; - - this.up = THREE.Object3D.DefaultUp.clone(); - - var position = new THREE.Vector3(); - var rotation = new THREE.Euler(); - var quaternion = new THREE.Quaternion(); - var scale = new THREE.Vector3( 1, 1, 1 ); - - var onRotationChange = function () { - quaternion.setFromEuler( rotation, false ); - }; - - var onQuaternionChange = function () { - rotation.setFromQuaternion( quaternion, undefined, false ); - }; - - rotation.onChange( onRotationChange ); - quaternion.onChange( onQuaternionChange ); - - Object.defineProperties( this, { - position: { - enumerable: true, - configurable: true, - value: position - }, - rotation: { - enumerable: true, - configurable: true, - value: rotation - }, - quaternion: { - enumerable: true, - configurable: true, - value: quaternion - }, - scale: { - enumerable: true, - configurable: true, - value: scale - } - } ); - - this.rotationAutoUpdate = true; - - this.matrix = new THREE.Matrix4(); - this.matrixWorld = new THREE.Matrix4(); - - this.matrixAutoUpdate = true; - this.matrixWorldNeedsUpdate = false; - - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - this.renderOrder = 0; - - this.userData = {}; - -}; - -THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 ); - -THREE.Object3D.prototype = { - - constructor: THREE.Object3D, - - get eulerOrder () { - - THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - - return this.rotation.order; - - }, - - set eulerOrder ( value ) { - - THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - - this.rotation.order = value; - - }, - - get useQuaternion () { - - THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - set useQuaternion ( value ) { - - THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - 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 THREE.Quaternion(); - - return function ( axis, angle ) { - - q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( q1 ); - - return this; - - } - - }(), - - rotateX: function () { - - var v1 = new THREE.Vector3( 1, 0, 0 ); - - return function ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateY: function () { - - var v1 = new THREE.Vector3( 0, 1, 0 ); - - return function ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateZ: function () { - - var v1 = new THREE.Vector3( 0, 0, 1 ); - - return function ( 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 THREE.Vector3(); - - return function ( axis, distance ) { - - v1.copy( axis ).applyQuaternion( this.quaternion ); - - this.position.add( v1.multiplyScalar( distance ) ); - - return this; - - } - - }(), - - translate: function ( distance, axis ) { - - THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); - return this.translateOnAxis( axis, distance ); - - }, - - translateX: function () { - - var v1 = new THREE.Vector3( 1, 0, 0 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateY: function () { - - var v1 = new THREE.Vector3( 0, 1, 0 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateZ: function () { - - var v1 = new THREE.Vector3( 0, 0, 1 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - localToWorld: function ( vector ) { - - return vector.applyMatrix4( this.matrixWorld ); - - }, - - worldToLocal: function () { - - var m1 = new THREE.Matrix4(); - - return function ( 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 THREE.Matrix4(); - - return function ( 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 ) { - - THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); - return this; - - } - - if ( object instanceof THREE.Object3D ) { - - if ( object.parent !== undefined ) { - - object.parent.remove( object ); - - } - - object.parent = this; - object.dispatchEvent( { type: 'added' } ); - - this.children.push( object ); - - } else { - - THREE.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 = undefined; - - object.dispatchEvent( { type: 'removed' } ); - - this.children.splice( index, 1 ); - - } - - }, - - getChildByName: function ( name ) { - - THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name ); - - }, - - 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 THREE.Vector3(); - - this.updateMatrixWorld( true ); - - return result.setFromMatrixPosition( this.matrixWorld ); - - }, - - getWorldQuaternion: function () { - - var position = new THREE.Vector3(); - var scale = new THREE.Vector3(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Quaternion(); - - this.updateMatrixWorld( true ); - - this.matrixWorld.decompose( position, result, scale ); - - return result; - - } - - }(), - - getWorldRotation: function () { - - var quaternion = new THREE.Quaternion(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Euler(); - - this.getWorldQuaternion( quaternion ); - - return result.setFromQuaternion( quaternion, this.rotation.order, false ); - - } - - }(), - - getWorldScale: function () { - - var position = new THREE.Vector3(); - var quaternion = new THREE.Quaternion(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - this.updateMatrixWorld( true ); - - this.matrixWorld.decompose( position, quaternion, result ); - - return result; - - } - - }(), - - getWorldDirection: function () { - - var quaternion = new THREE.Quaternion(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - this.getWorldQuaternion( quaternion ); - - return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); - - } - - }(), - - raycast: function () {}, - - traverse: function ( callback ) { - - callback( this ); - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].traverse( callback ); - - } - - }, - - traverseVisible: function ( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].traverseVisible( callback ); - - } - - }, - - traverseAncestors: function ( callback ) { - - if ( this.parent ) { - - callback( this.parent ); - - this.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 === undefined ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].updateMatrixWorld( force ); - - } - - }, - - toJSON: function () { - - var output = { - metadata: { - version: 4.3, - type: 'Object', - generator: 'ObjectExporter' - } - }; - - // - - var geometries = {}; - - var parseGeometry = function ( geometry ) { - - if ( output.geometries === undefined ) { - - output.geometries = []; - - } - - if ( geometries[ geometry.uuid ] === undefined ) { - - var json = geometry.toJSON(); - - delete json.metadata; - - geometries[ geometry.uuid ] = json; - - output.geometries.push( json ); - - } - - return geometry.uuid; - - }; - - // - - var materials = {}; - - var parseMaterial = function ( material ) { - - if ( output.materials === undefined ) { - - output.materials = []; - - } - - if ( materials[ material.uuid ] === undefined ) { - - var json = material.toJSON(); - - delete json.metadata; - - materials[ material.uuid ] = json; - - output.materials.push( json ); - - } - - return material.uuid; - - }; - - // - - var parseObject = function ( object ) { - - var data = {}; - - data.uuid = object.uuid; - data.type = object.type; - - if ( object.name !== '' ) data.name = object.name; - if ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData; - if ( object.visible !== true ) data.visible = object.visible; - - if ( object instanceof THREE.PerspectiveCamera ) { - - data.fov = object.fov; - data.aspect = object.aspect; - data.near = object.near; - data.far = object.far; - - } else if ( object instanceof THREE.OrthographicCamera ) { - - data.left = object.left; - data.right = object.right; - data.top = object.top; - data.bottom = object.bottom; - data.near = object.near; - data.far = object.far; - - } else if ( object instanceof THREE.AmbientLight ) { - - data.color = object.color.getHex(); - - } else if ( object instanceof THREE.DirectionalLight ) { - - data.color = object.color.getHex(); - data.intensity = object.intensity; - - } else if ( object instanceof THREE.PointLight ) { - - data.color = object.color.getHex(); - data.intensity = object.intensity; - data.distance = object.distance; - data.decay = object.decay; - - } else if ( object instanceof THREE.SpotLight ) { - - data.color = object.color.getHex(); - data.intensity = object.intensity; - data.distance = object.distance; - data.angle = object.angle; - data.exponent = object.exponent; - data.decay = object.decay; - - } else if ( object instanceof THREE.HemisphereLight ) { - - data.color = object.color.getHex(); - data.groundColor = object.groundColor.getHex(); - - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { - - data.geometry = parseGeometry( object.geometry ); - data.material = parseMaterial( object.material ); - - if ( object instanceof THREE.Line ) data.mode = object.mode; - - } else if ( object instanceof THREE.Sprite ) { - - data.material = parseMaterial( object.material ); - - } - - data.matrix = object.matrix.toArray(); - - if ( object.children.length > 0 ) { - - data.children = []; - - for ( var i = 0; i < object.children.length; i ++ ) { - - data.children.push( parseObject( object.children[ i ] ) ); - - } - - } - - return data; - - } - - output.object = parseObject( this ); - - return output; - - }, - - clone: function ( object, recursive ) { - - if ( object === undefined ) object = new THREE.Object3D(); - if ( recursive === undefined ) recursive = true; - - object.name = this.name; - - object.up.copy( this.up ); - - object.position.copy( this.position ); - object.quaternion.copy( this.quaternion ); - object.scale.copy( this.scale ); - - object.rotationAutoUpdate = this.rotationAutoUpdate; - - object.matrix.copy( this.matrix ); - object.matrixWorld.copy( this.matrixWorld ); - - object.matrixAutoUpdate = this.matrixAutoUpdate; - object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; - - object.visible = this.visible; - - object.castShadow = this.castShadow; - object.receiveShadow = this.receiveShadow; - - object.frustumCulled = this.frustumCulled; - - object.userData = JSON.parse( JSON.stringify( this.userData ) ); - - if ( recursive === true ) { - - for ( var i = 0; i < this.children.length; i ++ ) { - - var child = this.children[ i ]; - object.add( child.clone() ); - - } - - } - - return object; - - }, - - bindPosition: function( position ) { - - delete this.position; - Object.defineProperty( this, "position", { - enumerable: true, - configurable: true, - value: position - }); - - }, - - bindQuaternion: function( quaternion ) { - - delete this.quaternion; - Object.defineProperty( this, "quaternion", { - enumerable: true, - configurable: true, - value: quaternion - }); - - var rotation = this.rotation; - - quaternion.onChange( function () { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } ); - - rotation.onChange( function () { - - quaternion.setFromEuler( rotation, false ); - - } ); - - - }, - - bindRotation: function( rotation ) { - - delete this.rotation; - Object.defineProperty( this, "rotation", { - enumerable: true, - configurable: true, - value: rotation - }); - - var quaternion = this.quaternion; - - // Remember the last callback, since Object3D needs this to keep this.quaternion in sync - var lastcallback = rotation.onChangeCallback; - - rotation.onChange( function () { - - quaternion.setFromEuler( rotation, false ); - lastcallback(); - - } ); - - quaternion.onChange( function () { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } ); - - }, - - bindObjectRotation: function( object ) { - - delete this.rotation; - delete this.quaternion; - - Object.defineProperty( this, "rotation", { - enumerable: true, - configurable: true, - value: object.rotation - }); - Object.defineProperty( this, "quaternion", { - enumerable: true, - configurable: true, - value: object.quaternion - }); - - }, - - bindScale: function( scale ) { - - delete this.scale; - Object.defineProperty( this, "scale", { - enumerable: true, - configurable: true, - value: scale - }); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); - -THREE.Object3DIdCount = 0; - -// File:src/core/Face3.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { - - this.a = a; - this.b = b; - this.c = c; - - this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); - this.vertexNormals = normal instanceof Array ? normal : []; - - this.color = color instanceof THREE.Color ? color : new THREE.Color(); - this.vertexColors = color instanceof Array ? color : []; - - this.vertexTangents = []; - - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - -}; - -THREE.Face3.prototype = { - - constructor: THREE.Face3, - - clone: function () { - - var face = new THREE.Face3( this.a, this.b, this.c ); - - face.normal.copy( this.normal ); - face.color.copy( this.color ); - - face.materialIndex = this.materialIndex; - - for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) { - - face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - - } - - for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) { - - face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - - } - - for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) { - - face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); - - } - - return face; - - } - -}; - -// File:src/core/Face4.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - - THREE.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ) - return new THREE.Face3( a, b, c, normal, color, materialIndex ); - -}; - -// File:src/core/BufferAttribute.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BufferAttribute = function ( array, itemSize ) { - - this.array = array; - this.itemSize = itemSize; - - this.needsUpdate = false; - -}; - -THREE.BufferAttribute.prototype = { - - constructor: THREE.BufferAttribute, - - get length () { - - return this.array.length; - - }, - - 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; - - }, - - set: function ( value, offset ) { - - if ( offset === undefined ) offset = 0; - - this.array.set( value, offset ); - - return this; - - }, - - setX: function ( index, x ) { - - this.array[ index * this.itemSize ] = x; - - return this; - - }, - - setY: function ( index, y ) { - - this.array[ index * this.itemSize + 1 ] = y; - - return this; - - }, - - setZ: function ( index, z ) { - - this.array[ index * this.itemSize + 2 ] = z; - - return this; - - }, - - setXY: function ( index, x, y ) { - - index *= this.itemSize; - - this.array[ index ] = x; - this.array[ index + 1 ] = y; - - return this; - - }, - - setXYZ: function ( index, x, y, z ) { - - index *= this.itemSize; - - this.array[ index ] = 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 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; - - return this; - - }, - - clone: function () { - - return new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - - } - -}; - -// - -THREE.Int8Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Uint8Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Uint8ClampedAttribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - - -}; - -THREE.Int16Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Uint16Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Int32Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Uint32Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Float32Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -THREE.Float64Attribute = function ( data, itemSize ) { - - THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); - return new THREE.BufferAttribute( data, itemSize ); - -}; - -// File:src/core/DynamicBufferAttribute.js - -/** - * @author benaadams / https://twitter.com/ben_a_adams - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.DynamicBufferAttribute = function ( array, itemSize ) { - - THREE.BufferAttribute.call( this, array, itemSize ); - - this.updateRange = { offset: 0, count: -1 }; - -}; - -THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); -THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; - -THREE.DynamicBufferAttribute.prototype.clone = function () { - - return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - -}; - -// File:src/core/BufferGeometry.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BufferGeometry = function () { - - Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.type = 'BufferGeometry'; - - this.attributes = {}; - this.attributesKeys = []; - - this.drawcalls = []; - this.offsets = this.drawcalls; // backwards compatibility - - this.boundingBox = null; - this.boundingSphere = null; - -}; - -THREE.BufferGeometry.prototype = { - - constructor: THREE.BufferGeometry, - - addAttribute: function ( name, attribute ) { - - if ( attribute instanceof THREE.BufferAttribute === false ) { - - THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - - this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; - - return; - - } - - this.attributes[ name ] = attribute; - this.attributesKeys = Object.keys( this.attributes ); - - }, - - getAttribute: function ( name ) { - - return this.attributes[ name ]; - - }, - - addDrawCall: function ( start, count, indexOffset ) { - - this.drawcalls.push( { - - start: start, - count: count, - index: indexOffset !== undefined ? indexOffset : 0 - - } ); - - }, - - applyMatrix: function ( matrix ) { - - var position = this.attributes.position; - - if ( position !== undefined ) { - - matrix.applyToVector3Array( position.array ); - position.needsUpdate = true; - - } - - var normal = this.attributes.normal; - - if ( normal !== undefined ) { - - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - - normalMatrix.applyToVector3Array( normal.array ); - normal.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - }, - - center: function () { - - this.computeBoundingBox(); - - var offset = this.boundingBox.center().negate(); - - this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - - return offset; - - }, - - fromGeometry: function ( geometry, settings ) { - - settings = settings || { 'vertexColors': THREE.NoColors }; - - var vertices = geometry.vertices; - var faces = geometry.faces; - var faceVertexUvs = geometry.faceVertexUvs; - var vertexColors = settings.vertexColors; - var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0; - var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3; - - var positions = new Float32Array( faces.length * 3 * 3 ); - this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); - - var normals = new Float32Array( faces.length * 3 * 3 ); - this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); - - if ( vertexColors !== THREE.NoColors ) { - - var colors = new Float32Array( faces.length * 3 * 3 ); - this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - - } - - if ( hasFaceVertexUv === true ) { - - var uvs = new Float32Array( faces.length * 3 * 2 ); - this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - - } - - for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) { - - var face = faces[ i ]; - - var a = vertices[ face.a ]; - var b = vertices[ face.b ]; - var c = vertices[ face.c ]; - - positions[ i3 ] = a.x; - positions[ i3 + 1 ] = a.y; - positions[ i3 + 2 ] = a.z; - - positions[ i3 + 3 ] = b.x; - positions[ i3 + 4 ] = b.y; - positions[ i3 + 5 ] = b.z; - - positions[ i3 + 6 ] = c.x; - positions[ i3 + 7 ] = c.y; - positions[ i3 + 8 ] = c.z; - - if ( hasFaceVertexNormals === true ) { - - var na = face.vertexNormals[ 0 ]; - var nb = face.vertexNormals[ 1 ]; - var nc = face.vertexNormals[ 2 ]; - - normals[ i3 ] = na.x; - normals[ i3 + 1 ] = na.y; - normals[ i3 + 2 ] = na.z; - - normals[ i3 + 3 ] = nb.x; - normals[ i3 + 4 ] = nb.y; - normals[ i3 + 5 ] = nb.z; - - normals[ i3 + 6 ] = nc.x; - normals[ i3 + 7 ] = nc.y; - normals[ i3 + 8 ] = nc.z; - - } else { - - var n = face.normal; - - normals[ i3 ] = n.x; - normals[ i3 + 1 ] = n.y; - normals[ i3 + 2 ] = n.z; - - normals[ i3 + 3 ] = n.x; - normals[ i3 + 4 ] = n.y; - normals[ i3 + 5 ] = n.z; - - normals[ i3 + 6 ] = n.x; - normals[ i3 + 7 ] = n.y; - normals[ i3 + 8 ] = n.z; - - } - - if ( vertexColors === THREE.FaceColors ) { - - var fc = face.color; - - colors[ i3 ] = fc.r; - colors[ i3 + 1 ] = fc.g; - colors[ i3 + 2 ] = fc.b; - - colors[ i3 + 3 ] = fc.r; - colors[ i3 + 4 ] = fc.g; - colors[ i3 + 5 ] = fc.b; - - colors[ i3 + 6 ] = fc.r; - colors[ i3 + 7 ] = fc.g; - colors[ i3 + 8 ] = fc.b; - - } else if ( vertexColors === THREE.VertexColors ) { - - var vca = face.vertexColors[ 0 ]; - var vcb = face.vertexColors[ 1 ]; - var vcc = face.vertexColors[ 2 ]; - - colors[ i3 ] = vca.r; - colors[ i3 + 1 ] = vca.g; - colors[ i3 + 2 ] = vca.b; - - colors[ i3 + 3 ] = vcb.r; - colors[ i3 + 4 ] = vcb.g; - colors[ i3 + 5 ] = vcb.b; - - colors[ i3 + 6 ] = vcc.r; - colors[ i3 + 7 ] = vcc.g; - colors[ i3 + 8 ] = vcc.b; - - } - - if ( hasFaceVertexUv === true ) { - - var uva = faceVertexUvs[ 0 ][ i ][ 0 ]; - var uvb = faceVertexUvs[ 0 ][ i ][ 1 ]; - var uvc = faceVertexUvs[ 0 ][ i ][ 2 ]; - - uvs[ i2 ] = uva.x; - uvs[ i2 + 1 ] = uva.y; - - uvs[ i2 + 2 ] = uvb.x; - uvs[ i2 + 3 ] = uvb.y; - - uvs[ i2 + 4 ] = uvc.x; - uvs[ i2 + 5 ] = uvc.y; - - } - - } - - this.computeBoundingSphere() - - return this; - - }, - - computeBoundingBox: function () { - - var vector = new THREE.Vector3(); - - return function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new THREE.Box3(); - - } - - var positions = this.attributes.position.array; - - if ( positions ) { - - var bb = this.boundingBox; - bb.makeEmpty(); - - for ( var i = 0, il = positions.length; i < il; i += 3 ) { - - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - bb.expandByPoint( vector ); - - } - - } - - if ( positions === undefined || positions.length === 0 ) { - - this.boundingBox.min.set( 0, 0, 0 ); - this.boundingBox.max.set( 0, 0, 0 ); - - } - - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - - THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); - - } - - } - - }(), - - computeBoundingSphere: function () { - - var box = new THREE.Box3(); - var vector = new THREE.Vector3(); - - return function () { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new THREE.Sphere(); - - } - - var positions = this.attributes.position.array; - - if ( positions ) { - - box.makeEmpty(); - - var center = this.boundingSphere.center; - - for ( var i = 0, il = positions.length; i < il; i += 3 ) { - - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - box.expandByPoint( vector ); - - } - - box.center( 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 = positions.length; i < il; i += 3 ) { - - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); - - } - - } - - } - - }(), - - computeFaceNormals: function () { - - // backwards compatibility - - }, - - computeVertexNormals: function () { - - var attributes = this.attributes; - - if ( attributes.position ) { - - var positions = attributes.position.array; - - if ( attributes.normal === undefined ) { - - this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) ); - - } else { - - // reset existing normals to zero - - var normals = attributes.normal.array; - - for ( var i = 0, il = normals.length; i < il; i ++ ) { - - normals[ i ] = 0; - - } - - } - - var normals = attributes.normal.array; - - var vA, vB, vC, - - pA = new THREE.Vector3(), - pB = new THREE.Vector3(), - pC = new THREE.Vector3(), - - cb = new THREE.Vector3(), - ab = new THREE.Vector3(); - - // indexed elements - - if ( attributes.index ) { - - var indices = attributes.index.array; - - var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] ); - - for ( var j = 0, jl = offsets.length; j < jl; ++ j ) { - - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - vA = ( index + indices[ i ] ) * 3; - vB = ( index + indices[ i + 1 ] ) * 3; - vC = ( index + 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; - - } - - }, - - computeTangents: function () { - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( this.attributes.index === undefined || - this.attributes.position === undefined || - this.attributes.normal === undefined || - this.attributes.uv === undefined ) { - - THREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); - return; - - } - - var indices = this.attributes.index.array; - var positions = this.attributes.position.array; - var normals = this.attributes.normal.array; - var uvs = this.attributes.uv.array; - - var nVertices = positions.length / 3; - - if ( this.attributes.tangent === undefined ) { - - this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - - } - - var tangents = this.attributes.tangent.array; - - var tan1 = [], tan2 = []; - - for ( var k = 0; k < nVertices; k ++ ) { - - tan1[ k ] = new THREE.Vector3(); - tan2[ k ] = new THREE.Vector3(); - - } - - var vA = new THREE.Vector3(), - vB = new THREE.Vector3(), - vC = new THREE.Vector3(), - - uvA = new THREE.Vector2(), - uvB = new THREE.Vector2(), - uvC = new THREE.Vector2(), - - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r; - - var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); - - function handleTriangle( a, b, c ) { - - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); - - uvA.fromArray( uvs, a * 2 ); - uvB.fromArray( uvs, b * 2 ); - uvC.fromArray( uvs, c * 2 ); - - x1 = vB.x - vA.x; - x2 = vC.x - vA.x; - - y1 = vB.y - vA.y; - y2 = vC.y - vA.y; - - z1 = vB.z - vA.z; - z2 = vC.z - vA.z; - - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; - - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; - - r = 1.0 / ( s1 * t2 - s2 * t1 ); - - sdir.set( - ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r - ); - - tdir.set( - ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r - ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - var i, il; - var j, jl; - var iA, iB, iC; - - if ( this.drawcalls.length === 0 ) { - - this.addDrawCall( 0, indices.length, 0 ); - - } - - var drawcalls = this.drawcalls; - - for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { - - var start = drawcalls[ j ].start; - var count = drawcalls[ j ].count; - var index = drawcalls[ j ].index; - - for ( i = start, il = start + count; i < il; i += 3 ) { - - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; - - handleTriangle( iA, iB, iC ); - - } - - } - - var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); - var n = new THREE.Vector3(), n2 = new THREE.Vector3(); - var w, t, test; - - function handleVertex( v ) { - - n.fromArray( normals, v * 3 ); - n2.copy( n ); - - t = tan1[ v ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( n2, t ); - test = tmp2.dot( tan2[ v ] ); - w = ( test < 0.0 ) ? - 1.0 : 1.0; - - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; - - } - - for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { - - var start = drawcalls[ j ].start; - var count = drawcalls[ j ].count; - var index = drawcalls[ j ].index; - - for ( i = start, il = start + count; i < il; i += 3 ) { - - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; - - handleVertex( iA ); - handleVertex( iB ); - handleVertex( iC ); - - } - - } - - }, - - /* - Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. - This method will effectively rewrite the index buffer and remap all attributes to match the new indices. - WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. - size - Defaults to 65535, but allows for larger or smaller chunks. - */ - computeOffsets: function ( size ) { - - if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit. - - var indices = this.attributes.index.array; - var vertices = this.attributes.position.array; - - var facesCount = ( indices.length / 3 ); - - /* - console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); - console.log("Faces to process: "+(indices.length/3)); - console.log("Reordering "+verticesCount+" vertices."); - */ - - var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers - var indexPtr = 0; - var vertexPtr = 0; - - var offsets = [ { start:0, count:0, index:0 } ]; - var offset = offsets[ 0 ]; - - var duplicatedVertices = 0; - var newVerticeMaps = 0; - var faceVertices = new Int32Array( 6 ); - var vertexMap = new Int32Array( vertices.length ); - var revVertexMap = new Int32Array( vertices.length ); - for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; } - - /* - Traverse every face and reorder vertices in the proper offsets of 65k. - We can have more than 65k entries in the index buffer per offset, but only reference 65k values. - */ - for ( var findex = 0; findex < facesCount; findex ++ ) { - newVerticeMaps = 0; - - for ( var vo = 0; vo < 3; vo ++ ) { - var vid = indices[ findex * 3 + vo ]; - if ( vertexMap[ vid ] == - 1 ) { - //Unmapped vertice - faceVertices[ vo * 2 ] = vid; - faceVertices[ vo * 2 + 1 ] = - 1; - newVerticeMaps ++; - } else if ( vertexMap[ vid ] < offset.index ) { - //Reused vertices from previous block (duplicate) - faceVertices[ vo * 2 ] = vid; - faceVertices[ vo * 2 + 1 ] = - 1; - duplicatedVertices ++; - } else { - //Reused vertice in the current block - faceVertices[ vo * 2 ] = vid; - faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ]; - } - } - - var faceMax = vertexPtr + newVerticeMaps; - if ( faceMax > ( offset.index + size ) ) { - var new_offset = { start:indexPtr, count:0, index:vertexPtr }; - offsets.push( new_offset ); - offset = new_offset; - - //Re-evaluate reused vertices in light of new offset. - for ( var v = 0; v < 6; v += 2 ) { - var new_vid = faceVertices[ v + 1 ]; - if ( new_vid > - 1 && new_vid < offset.index ) - faceVertices[ v + 1 ] = - 1; - } - } - - //Reindex the face. - for ( var v = 0; v < 6; v += 2 ) { - var vid = faceVertices[ v ]; - var new_vid = faceVertices[ v + 1 ]; - - if ( new_vid === - 1 ) - new_vid = vertexPtr ++; - - vertexMap[ vid ] = new_vid; - revVertexMap[ new_vid ] = vid; - sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit - offset.count ++; - } - } - - /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ - this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr ); - this.offsets = offsets; // TODO: Deprecate - this.drawcalls = offsets; - - /* - var orderTime = Date.now(); - console.log("Reorder time: "+(orderTime-s)+"ms"); - console.log("Duplicated "+duplicatedVertices+" vertices."); - console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); - console.log("Draw offsets: "+offsets.length); - */ - - return offsets; - - }, - - merge: function ( geometry, offset ) { - - if ( geometry instanceof THREE.BufferGeometry === false ) { - - THREE.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; - - } - - }, - - /* - reoderBuffers: - Reorder attributes based on a new indexBuffer and indexMap. - indexBuffer - Uint16Array of the new ordered indices. - indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. - vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). - */ - reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) { - - /* Create a copy of all attributes for reordering. */ - var sortedAttributes = {}; - for ( var attr in this.attributes ) { - if ( attr == 'index' ) - continue; - var sourceArray = this.attributes[ attr ].array; - sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount ); - } - - /* Move attribute positions based on the new index map */ - for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) { - var vid = indexMap[ new_vid ]; - for ( var attr in this.attributes ) { - if ( attr == 'index' ) - continue; - var attrArray = this.attributes[ attr ].array; - var attrSize = this.attributes[ attr ].itemSize; - var sortedAttr = sortedAttributes[ attr ]; - for ( var k = 0; k < attrSize; k ++ ) - sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; - } - } - - /* Carry the new sorted buffers locally */ - this.attributes[ 'index' ].array = indexBuffer; - for ( var attr in this.attributes ) { - if ( attr == 'index' ) - continue; - this.attributes[ attr ].array = sortedAttributes[ attr ]; - this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount; - } - }, - - toJSON: function () { - - var output = { - metadata: { - version: 4.0, - type: 'BufferGeometry', - generator: 'BufferGeometryExporter' - }, - uuid: this.uuid, - type: this.type, - data: { - attributes: {} - } - }; - - var attributes = this.attributes; - var offsets = this.offsets; - var boundingSphere = this.boundingSphere; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - - var array = Array.prototype.slice.call( attribute.array ); - - output.data.attributes[ key ] = { - itemSize: attribute.itemSize, - type: attribute.array.constructor.name, - array: array - } - - } - - if ( offsets.length > 0 ) { - - output.data.offsets = JSON.parse( JSON.stringify( offsets ) ); - - } - - if ( boundingSphere !== null ) { - - output.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - } - - } - - return output; - - }, - - clone: function () { - - var geometry = new THREE.BufferGeometry(); - - for ( var attr in this.attributes ) { - - var sourceAttr = this.attributes[ attr ]; - geometry.addAttribute( attr, sourceAttr.clone() ); - - } - - for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { - - var offset = this.offsets[ i ]; - - geometry.offsets.push( { - - start: offset.start, - index: offset.index, - count: offset.count - - } ); - - } - - return geometry; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); - -// File:src/core/Geometry.js - -/** - * @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://exocortex.com - */ - -THREE.Geometry = function () { - - Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.type = 'Geometry'; - - this.vertices = []; - this.colors = []; // one-to-one vertex colors, used in Points and Line - - this.faces = []; - - this.faceVertexUvs = [ [] ]; - - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; - - this.skinWeights = []; - this.skinIndices = []; - - this.lineDistances = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.hasTangents = false; - - this.dynamic = true; // the intermediate typed arrays will be deleted when set to false - - // update flags - - this.verticesNeedUpdate = false; - this.elementsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.tangentsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; - - this.groupsNeedUpdate = false; - -}; - -THREE.Geometry.prototype = { - - constructor: THREE.Geometry, - - applyMatrix: function ( matrix ) { - - var normalMatrix = new THREE.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; - - }, - - fromBufferGeometry: function ( geometry ) { - - var scope = this; - - var attributes = geometry.attributes; - - var vertices = attributes.position.array; - var indices = attributes.index !== undefined ? attributes.index.array : undefined; - 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 tempNormals = []; - var tempUVs = []; - - for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) { - - scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - - if ( normals !== undefined ) { - - tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); - - } - - if ( colors !== undefined ) { - - scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); - - } - - if ( uvs !== undefined ) { - - tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) ); - - } - - } - - var addFace = function ( a, b, c ) { - - 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() ] : []; - - scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) ); - - if ( uvs !== undefined ) { - - scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - - } - - }; - - if ( indices !== undefined ) { - - var drawcalls = geometry.drawcalls; - - if ( drawcalls.length > 0 ) { - - for ( var i = 0; i < drawcalls.length; i ++ ) { - - var drawcall = drawcalls[ i ]; - - var start = drawcall.start; - var count = drawcall.count; - var index = drawcall.index; - - for ( var j = start, jl = start + count; j < jl; j += 3 ) { - - addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] ); - - } - - } - - } 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 < vertices.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.center().negate(); - - this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - - return offset; - - }, - - computeFaceNormals: function () { - - var cb = new THREE.Vector3(), ab = new THREE.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 ) { - - 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 THREE.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 THREE.Vector3(), ab = new THREE.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 { - - 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 ]; - - face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); - face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); - face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); - - } - - }, - - 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 THREE.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 THREE.Vector3(); - vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.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; - - } - - }, - - computeTangents: function () { - - // based on http://www.terathon.com/code/tangent.html - // tangents go to vertices - - var f, fl, v, vl, i, vertexIndex, - face, uv, vA, vB, vC, uvA, uvB, uvC, - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r, t, test, - tan1 = [], tan2 = [], - sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), - tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), - n = new THREE.Vector3(), w; - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - tan1[ v ] = new THREE.Vector3(); - tan2[ v ] = new THREE.Vector3(); - - } - - function handleTriangle( context, a, b, c, ua, ub, uc ) { - - vA = context.vertices[ a ]; - vB = context.vertices[ b ]; - vC = context.vertices[ c ]; - - uvA = uv[ ua ]; - uvB = uv[ ub ]; - uvC = uv[ uc ]; - - x1 = vB.x - vA.x; - x2 = vC.x - vA.x; - y1 = vB.y - vA.y; - y2 = vC.y - vA.y; - z1 = vB.z - vA.z; - z2 = vC.z - vA.z; - - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; - - r = 1.0 / ( s1 * t2 - s2 * t1 ); - sdir.set( ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r ); - tdir.set( ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents - - handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); - - } - - var faceIndex = [ 'a', 'b', 'c', 'd' ]; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) { - - n.copy( face.vertexNormals[ i ] ); - - vertexIndex = face[ faceIndex[ i ] ]; - - t = tan1[ vertexIndex ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( face.vertexNormals[ i ], t ); - test = tmp2.dot( tan2[ vertexIndex ] ); - w = ( test < 0.0 ) ? - 1.0 : 1.0; - - face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); - - } - - } - - this.hasTangents = true; - - }, - - 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 THREE.Box3(); - - } - - this.boundingBox.setFromPoints( this.vertices ); - - }, - - computeBoundingSphere: function () { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new THREE.Sphere(); - - } - - this.boundingSphere.setFromPoints( this.vertices ); - - }, - - merge: function ( geometry, matrix, materialIndexOffset ) { - - if ( geometry instanceof THREE.Geometry === false ) { - - THREE.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 ]; - - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - - if ( matrix !== undefined ) { - - normalMatrix = new THREE.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 ); - - } - - // 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 THREE.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 instanceof THREE.Mesh === false ) { - - THREE.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 vertice by position coordinates (and making sure they are unique) - var unique = [], changes = []; - - var v, key; - var precisionPoints = 4; // number of decimal points, eg. 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 ]; - - var dupIndex = - 1; - - // 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 ] ) { - - dupIndex = n; - 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; - - }, - - toJSON: function () { - - var output = { - metadata: { - version: 4.0, - type: 'BufferGeometry', - generator: 'BufferGeometryExporter' - }, - uuid: this.uuid, - type: this.type - }; - - if ( this.name !== "" ) output.name = this.name; - - if ( this.parameters !== undefined ) { - - var parameters = this.parameters; - - for ( var key in parameters ) { - - if ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ]; - - } - - return output; - - } - - 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 = false; // face.materialIndex !== undefined; - 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 ); - 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 ); - - - /* - if ( hasMaterial ) { - - 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 ]; - - } - - output.data = {}; - - output.data.vertices = vertices; - output.data.normals = normals; - if ( colors.length > 0 ) output.data.colors = colors; - if ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility - output.data.faces = faces; - - // - - return output; - - }, - - clone: function () { - - var geometry = new THREE.Geometry(); - - var vertices = this.vertices; - - for ( var i = 0, il = vertices.length; i < il; i ++ ) { - - geometry.vertices.push( vertices[ i ].clone() ); - - } - - var faces = this.faces; - - for ( var i = 0, il = faces.length; i < il; i ++ ) { - - geometry.faces.push( faces[ i ].clone() ); - - } - - for ( var i = 0, il = this.faceVertexUvs.length; i < il; i ++ ) { - - var faceVertexUvs = this.faceVertexUvs[ i ]; - - if ( geometry.faceVertexUvs[ i ] === undefined ) { - - geometry.faceVertexUvs[ i ] = []; - - } - - for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - - var uvs = faceVertexUvs[ j ], uvsCopy = []; - - for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { - - var uv = uvs[ k ]; - - uvsCopy.push( uv.clone() ); - - } - - geometry.faceVertexUvs[ i ].push( uvsCopy ); - - } - - } - - return geometry; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - -THREE.GeometryIdCount = 0; - -// File:src/cameras/Camera.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.Camera = function () { - - THREE.Object3D.call( this ); - - this.type = 'Camera'; - - this.matrixWorldInverse = new THREE.Matrix4(); - this.projectionMatrix = new THREE.Matrix4(); - -}; - -THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Camera.prototype.constructor = THREE.Camera; - -THREE.Camera.prototype.getWorldDirection = function () { - - var quaternion = new THREE.Quaternion(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - this.getWorldQuaternion( quaternion ); - - return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - - } - -}(); - -THREE.Camera.prototype.lookAt = function () { - - // This routine does not support cameras with rotated and/or translated parent(s) - - var m1 = new THREE.Matrix4(); - - return function ( vector ) { - - m1.lookAt( this.position, vector, this.up ); - - this.quaternion.setFromRotationMatrix( m1 ); - - }; - -}(); - -THREE.Camera.prototype.clone = function ( camera ) { - - if ( camera === undefined ) camera = new THREE.Camera(); - - THREE.Object3D.prototype.clone.call( this, camera ); - - camera.matrixWorldInverse.copy( this.matrixWorldInverse ); - camera.projectionMatrix.copy( this.projectionMatrix ); - - return camera; -}; - -// File:src/cameras/CubeCamera.js - -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.CubeCamera = function ( near, far, cubeResolution ) { - - THREE.Object3D.call( this ); - - this.type = 'CubeCamera'; - - var fov = 90, aspect = 1; - - var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); - - var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) ); - this.add( cameraNX ); - - var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); - - var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) ); - this.add( cameraNY ); - - var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); - - var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) ); - this.add( cameraNZ ); - - this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); - - this.updateCubeMap = function ( renderer, scene ) { - - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.generateMipmaps; - - renderTarget.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.generateMipmaps = generateMipmaps; - - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); - - }; - -}; - -THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); -THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; - -// File:src/cameras/OrthographicCamera.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { - - THREE.Camera.call( this ); - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - - 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(); - -}; - -THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); -THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; - -THREE.OrthographicCamera.prototype.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; - - this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far ); - -}; - -THREE.OrthographicCamera.prototype.clone = function () { - - var camera = new THREE.OrthographicCamera(); - - THREE.Camera.prototype.clone.call( this, camera ); - - camera.zoom = this.zoom; - - camera.left = this.left; - camera.right = this.right; - camera.top = this.top; - camera.bottom = this.bottom; - - camera.near = this.near; - camera.far = this.far; - - camera.projectionMatrix.copy( this.projectionMatrix ); - - return camera; -}; - -// File:src/cameras/PerspectiveCamera.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { - - THREE.Camera.call( this ); - - this.type = 'PerspectiveCamera'; - - this.zoom = 1; - - this.fov = fov !== undefined ? fov : 50; - this.aspect = aspect !== undefined ? aspect : 1; - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; - - this.updateProjectionMatrix(); - -}; - -THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); -THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; - - -/** - * Uses Focal Length (in mm) to estimate and set FOV - * 35mm (fullframe) camera is used if frame size is not specified; - * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html - */ - -THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { - - if ( frameHeight === undefined ) frameHeight = 24; - - this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); - this.updateProjectionMatrix(); - -} - - -/** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * var w = 1920; - * var h = 1080; - * var fullWidth = w * 3; - * var fullHeight = h * 2; - * - * --A-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - -THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { - - this.fullWidth = fullWidth; - this.fullHeight = fullHeight; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - - this.updateProjectionMatrix(); - -}; - - -THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { - - var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) ); - - if ( this.fullWidth ) { - - var aspect = this.fullWidth / this.fullHeight; - var top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near; - var bottom = - top; - var left = aspect * bottom; - var right = aspect * top; - var width = Math.abs( right - left ); - var height = Math.abs( top - bottom ); - - this.projectionMatrix.makeFrustum( - left + this.x * width / this.fullWidth, - left + ( this.x + this.width ) * width / this.fullWidth, - top - ( this.y + this.height ) * height / this.fullHeight, - top - this.y * height / this.fullHeight, - this.near, - this.far - ); - - } else { - - this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far ); - - } - -}; - -THREE.PerspectiveCamera.prototype.clone = function () { - - var camera = new THREE.PerspectiveCamera(); - - THREE.Camera.prototype.clone.call( this, camera ); - - camera.zoom = this.zoom; - - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; - - camera.projectionMatrix.copy( this.projectionMatrix ); - - return camera; - -}; - -// File:src/lights/Light.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Light = function ( color ) { - - THREE.Object3D.call( this ); - - this.type = 'Light'; - - this.color = new THREE.Color( color ); - -}; - -THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Light.prototype.constructor = THREE.Light; - -THREE.Light.prototype.clone = function ( light ) { - - if ( light === undefined ) light = new THREE.Light(); - - THREE.Object3D.prototype.clone.call( this, light ); - - light.color.copy( this.color ); - - return light; - -}; - -// File:src/lights/AmbientLight.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.AmbientLight = function ( color ) { - - THREE.Light.call( this, color ); - - this.type = 'AmbientLight'; - -}; - -THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); -THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; - -THREE.AmbientLight.prototype.clone = function () { - - var light = new THREE.AmbientLight(); - - THREE.Light.prototype.clone.call( this, light ); - - return light; - -}; - -// File:src/lights/AreaLight.js - -/** - * @author MPanknin / http://www.redplant.de/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.AreaLight = function ( color, intensity ) { - - THREE.Light.call( this, color ); - - this.type = 'AreaLight'; - - this.normal = new THREE.Vector3( 0, - 1, 0 ); - this.right = new THREE.Vector3( 1, 0, 0 ); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - - this.width = 1.0; - this.height = 1.0; - - this.constantAttenuation = 1.5; - this.linearAttenuation = 0.5; - this.quadraticAttenuation = 0.1; - -}; - -THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); -THREE.AreaLight.prototype.constructor = THREE.AreaLight; - - -// File:src/lights/DirectionalLight.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DirectionalLight = function ( color, intensity ) { - - THREE.Light.call( this, color ); - - this.type = 'DirectionalLight'; - - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - - this.castShadow = false; - this.onlyShadow = false; - - // - - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - - this.shadowCameraLeft = - 500; - this.shadowCameraRight = 500; - this.shadowCameraTop = 500; - this.shadowCameraBottom = - 500; - - this.shadowCameraVisible = false; - - this.shadowBias = 0; - this.shadowDarkness = 0.5; - - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; - - // - - this.shadowCascade = false; - - this.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 ); - this.shadowCascadeCount = 2; - - this.shadowCascadeBias = [ 0, 0, 0 ]; - this.shadowCascadeWidth = [ 512, 512, 512 ]; - this.shadowCascadeHeight = [ 512, 512, 512 ]; - - this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; - - this.shadowCascadeArray = []; - - // - - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; - -}; - -THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); -THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; - -THREE.DirectionalLight.prototype.clone = function () { - - var light = new THREE.DirectionalLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.target = this.target.clone(); - - light.intensity = this.intensity; - - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; - - // - - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; - - light.shadowCameraLeft = this.shadowCameraLeft; - light.shadowCameraRight = this.shadowCameraRight; - light.shadowCameraTop = this.shadowCameraTop; - light.shadowCameraBottom = this.shadowCameraBottom; - - light.shadowCameraVisible = this.shadowCameraVisible; - - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; - - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; - - // - - light.shadowCascade = this.shadowCascade; - - light.shadowCascadeOffset.copy( this.shadowCascadeOffset ); - light.shadowCascadeCount = this.shadowCascadeCount; - - light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 ); - light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 ); - light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 ); - - light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 ); - light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 ); - - return light; - -}; - -// File:src/lights/HemisphereLight.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { - - THREE.Light.call( this, skyColor ); - - this.type = 'HemisphereLight'; - - this.position.set( 0, 100, 0 ); - - this.groundColor = new THREE.Color( groundColor ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; - -}; - -THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); -THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; - -THREE.HemisphereLight.prototype.clone = function () { - - var light = new THREE.HemisphereLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.groundColor.copy( this.groundColor ); - light.intensity = this.intensity; - - return light; - -}; - -// File:src/lights/PointLight.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.PointLight = function ( color, intensity, distance, decay ) { - - THREE.Light.call( this, color ); - - this.type = 'PointLight'; - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - -}; - -THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); -THREE.PointLight.prototype.constructor = THREE.PointLight; - -THREE.PointLight.prototype.clone = function () { - - var light = new THREE.PointLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.intensity = this.intensity; - light.distance = this.distance; - light.decay = this.decay; - - return light; - -}; - -// File:src/lights/SpotLight.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { - - THREE.Light.call( this, color ); - - this.type = 'SpotLight'; - - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.exponent = ( exponent !== undefined ) ? exponent : 10; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - - this.castShadow = false; - this.onlyShadow = false; - - // - - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - this.shadowCameraFov = 50; - - this.shadowCameraVisible = false; - - this.shadowBias = 0; - this.shadowDarkness = 0.5; - - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; - - // - - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; - -}; - -THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); -THREE.SpotLight.prototype.constructor = THREE.SpotLight; - -THREE.SpotLight.prototype.clone = function () { - - var light = new THREE.SpotLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.target = this.target.clone(); - - light.intensity = this.intensity; - light.distance = this.distance; - light.angle = this.angle; - light.exponent = this.exponent; - light.decay = this.decay; - - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; - - // - - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; - light.shadowCameraFov = this.shadowCameraFov; - - light.shadowCameraVisible = this.shadowCameraVisible; - - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; - - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; - - return light; - -}; - -// File:src/loaders/Cache.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Cache = { - - files: {}, - - add: function ( key, file ) { - - // console.log( 'THREE.Cache', 'Adding key:', key ); - - this.files[ key ] = file; - - }, - - get: function ( key ) { - - // console.log( 'THREE.Cache', 'Checking key:', key ); - - return this.files[ key ]; - - }, - - remove: function ( key ) { - - delete this.files[ key ]; - - }, - - clear: function () { - - this.files = {} - - } - -}; - -// File:src/loaders/Loader.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Loader = function ( showStatus ) { - - this.showStatus = showStatus; - this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; - - this.imageLoader = new THREE.ImageLoader(); - - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; - -}; - -THREE.Loader.prototype = { - - constructor: THREE.Loader, - - crossOrigin: undefined, - - addStatusElement: function () { - - var e = document.createElement( 'div' ); - - e.style.position = 'absolute'; - e.style.right = '0px'; - e.style.top = '0px'; - e.style.fontSize = '0.8em'; - e.style.textAlign = 'left'; - e.style.background = 'rgba(0,0,0,0.25)'; - e.style.color = '#fff'; - e.style.width = '120px'; - e.style.padding = '0.5em 0.5em 0.5em 0.5em'; - e.style.zIndex = 1000; - - e.innerHTML = 'Loading ...'; - - return e; - - }, - - updateProgress: function ( progress ) { - - var message = 'Loaded '; - - if ( progress.total ) { - - message += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%'; - - - } else { - - message += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB'; - - } - - this.statusDomElement.innerHTML = message; - - }, - - extractUrlBase: function ( url ) { - - var parts = url.split( '/' ); - - if ( parts.length === 1 ) return './'; - - parts.pop(); - - return parts.join( '/' ) + '/'; - - }, - - initMaterials: function ( materials, texturePath ) { - - var array = []; - - for ( var i = 0; i < materials.length; ++ i ) { - - array[ i ] = this.createMaterial( materials[ i ], texturePath ); - - } - - return array; - - }, - - needsTangents: function ( materials ) { - - for ( var i = 0, il = materials.length; i < il; i ++ ) { - - var m = materials[ i ]; - - if ( m instanceof THREE.ShaderMaterial ) return true; - - } - - return false; - - }, - - createMaterial: function ( m, texturePath ) { - - var scope = this; - - function nearest_pow2( n ) { - - var l = Math.log( n ) / Math.LN2; - return Math.pow( 2, Math.round( l ) ); - - } - - function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - - var fullPath = texturePath + sourceFile; - - var texture; - - var loader = THREE.Loader.Handlers.get( fullPath ); - - if ( loader !== null ) { - - texture = loader.load( fullPath ); - - } else { - - texture = new THREE.Texture(); - - loader = scope.imageLoader; - loader.crossOrigin = scope.crossOrigin; - loader.load( fullPath, function ( image ) { - - if ( THREE.Math.isPowerOfTwo( image.width ) === false || - THREE.Math.isPowerOfTwo( image.height ) === false ) { - - var width = nearest_pow2( image.width ); - var height = nearest_pow2( image.height ); - - var canvas = document.createElement( 'canvas' ); - canvas.width = width; - canvas.height = height; - - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, width, height ); - - texture.image = canvas; - - } else { - - texture.image = image; - - } - - texture.needsUpdate = true; - - } ); - - } - - texture.sourceFile = sourceFile; - - if ( repeat ) { - - texture.repeat.set( repeat[ 0 ], repeat[ 1 ] ); - - if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - - } - - if ( offset ) { - - texture.offset.set( offset[ 0 ], offset[ 1 ] ); - - } - - if ( wrap ) { - - var wrapMap = { - 'repeat': THREE.RepeatWrapping, - 'mirror': THREE.MirroredRepeatWrapping - } - - if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ]; - if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ]; - - } - - if ( anisotropy ) { - - texture.anisotropy = anisotropy; - - } - - where[ name ] = texture; - - } - - function rgb2hex( rgb ) { - - return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; - - } - - // defaults - - var mtype = 'MeshLambertMaterial'; - var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; - - // parameters from model file - - if ( m.shading ) { - - var shading = m.shading.toLowerCase(); - - if ( shading === 'phong' ) mtype = 'MeshPhongMaterial'; - else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial'; - - } - - if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { - - mpars.blending = THREE[ m.blending ]; - - } - - if ( m.transparent !== undefined ) { - - mpars.transparent = m.transparent; - - } - - if ( m.opacity !== undefined && m.opacity < 1.0 ) { - - mpars.transparent = true; - - } - - if ( m.depthTest !== undefined ) { - - mpars.depthTest = m.depthTest; - - } - - if ( m.depthWrite !== undefined ) { - - mpars.depthWrite = m.depthWrite; - - } - - if ( m.visible !== undefined ) { - - mpars.visible = m.visible; - - } - - if ( m.flipSided !== undefined ) { - - mpars.side = THREE.BackSide; - - } - - if ( m.doubleSided !== undefined ) { - - mpars.side = THREE.DoubleSide; - - } - - if ( m.wireframe !== undefined ) { - - mpars.wireframe = m.wireframe; - - } - - if ( m.vertexColors !== undefined ) { - - if ( m.vertexColors === 'face' ) { - - mpars.vertexColors = THREE.FaceColors; - - } else if ( m.vertexColors ) { - - mpars.vertexColors = THREE.VertexColors; - - } - - } - - // colors - - if ( m.colorDiffuse ) { - - mpars.color = rgb2hex( m.colorDiffuse ); - - } else if ( m.DbgColor ) { - - mpars.color = m.DbgColor; - - } - - if ( m.colorSpecular ) { - - mpars.specular = rgb2hex( m.colorSpecular ); - - } - - if ( m.colorEmissive ) { - - mpars.emissive = rgb2hex( m.colorEmissive ); - - } - - // modifiers - - if ( m.transparency !== undefined ) { - - console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); - m.opacity = m.transparency; - - } - - if ( m.opacity !== undefined ) { - - mpars.opacity = m.opacity; - - } - - if ( m.specularCoef ) { - - mpars.shininess = m.specularCoef; - - } - - // textures - - if ( m.mapDiffuse && texturePath ) { - - create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - - } - - if ( m.mapLight && texturePath ) { - - create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - - } - - if ( m.mapBump && texturePath ) { - - create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - - } - - if ( m.mapNormal && texturePath ) { - - create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - - } - - if ( m.mapSpecular && texturePath ) { - - create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - - } - - if ( m.mapAlpha && texturePath ) { - - create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - - } - - // - - if ( m.mapBumpScale ) { - - mpars.bumpScale = m.mapBumpScale; - - } - - if ( m.mapNormalFactor ) { - - mpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor ); - - } - - var material = new THREE[ mtype ]( mpars ); - - if ( m.DbgName !== undefined ) material.name = m.DbgName; - - return material; - - } - -}; - -THREE.Loader.Handlers = { - - handlers: [], - - add: function ( regex, loader ) { - - this.handlers.push( regex, loader ); - - }, - - get: function ( file ) { - - for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) { - - var regex = this.handlers[ i ]; - var loader = this.handlers[ i + 1 ]; - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - } - -}; - -// File:src/loaders/XHRLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.XHRLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.XHRLoader.prototype = { - - constructor: THREE.XHRLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var cached = THREE.Cache.get( url ); - - if ( cached !== undefined ) { - - if ( onLoad ) onLoad( cached ); - return; - - } - - var request = new XMLHttpRequest(); - request.open( 'GET', url, true ); - - request.addEventListener( 'load', function ( event ) { - - THREE.Cache.add( url, this.response ); - - if ( onLoad ) onLoad( this.response ); - - scope.manager.itemEnd( url ); - - }, false ); - - if ( onProgress !== undefined ) { - - request.addEventListener( 'progress', function ( event ) { - - onProgress( event ); - - }, false ); - - } - - if ( onError !== undefined ) { - - request.addEventListener( 'error', function ( event ) { - - onError( event ); - - }, false ); - - } - - if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; - if ( this.responseType !== undefined ) request.responseType = this.responseType; - - request.send( null ); - - scope.manager.itemStart( url ); - - }, - - setResponseType: function ( value ) { - - this.responseType = value; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; - -// File:src/loaders/ImageLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ImageLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.ImageLoader.prototype = { - - constructor: THREE.ImageLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var cached = THREE.Cache.get( url ); - - if ( cached !== undefined ) { - - onLoad( cached ); - return; - - } - - var image = document.createElement( 'img' ); - - image.addEventListener( 'load', function ( event ) { - - THREE.Cache.add( url, this ); - - if ( onLoad ) onLoad( this ); - - scope.manager.itemEnd( url ); - - }, false ); - - if ( onProgress !== undefined ) { - - image.addEventListener( 'progress', function ( event ) { - - onProgress( event ); - - }, false ); - - } - - if ( onError !== undefined ) { - - image.addEventListener( 'error', function ( event ) { - - onError( event ); - - }, false ); - - } - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - image.src = url; - - scope.manager.itemStart( url ); - - return image; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -} - -// File:src/loaders/JSONLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.JSONLoader = function ( showStatus ) { - - THREE.Loader.call( this, showStatus ); - - this.withCredentials = false; - -}; - -THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); -THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; - -THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { - - // todo: unify load API to for easier SceneLoader use - - texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url ); - - this.onLoadStart(); - this.loadAjaxJSON( this, url, callback, texturePath ); - -}; - -THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { - - var xhr = new XMLHttpRequest(); - - var length = 0; - - xhr.onreadystatechange = function () { - - if ( xhr.readyState === xhr.DONE ) { - - if ( xhr.status === 200 || xhr.status === 0 ) { - - if ( xhr.responseText ) { - - var json = JSON.parse( xhr.responseText ); - var metadata = json.metadata; - - if ( metadata !== undefined ) { - - if ( metadata.type === 'object' ) { - - THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; - - } - - if ( metadata.type === 'scene' ) { - - THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' ); - return; - - } - - } - - var result = context.parse( json, texturePath ); - callback( result.geometry, result.materials ); - - } else { - - THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' ); - - } - - // in context of more complex asset initialization - // do not block on single failed file - // maybe should go even one more level up - - context.onLoadComplete(); - - } else { - - THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' ); - - } - - } else if ( xhr.readyState === xhr.LOADING ) { - - if ( callbackProgress ) { - - if ( length === 0 ) { - - length = xhr.getResponseHeader( 'Content-Length' ); - - } - - callbackProgress( { total: length, loaded: xhr.responseText.length } ); - - } - - } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { - - if ( callbackProgress !== undefined ) { - - length = xhr.getResponseHeader( 'Content-Length' ); - - } - - } - - }; - - xhr.open( 'GET', url, true ); - xhr.withCredentials = this.withCredentials; - xhr.send( null ); - -}; - -THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - - var geometry = new THREE.Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; - - parseModel( scale ); - - parseSkin(); - parseMorphing( scale ); - - 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 THREE.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 THREE.Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; - - faceB = new THREE.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 THREE.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 THREE.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 THREE.Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); - - } - - } - - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); - - } else { - - face = new THREE.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 THREE.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 THREE.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 THREE.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 THREE.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 THREE.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 ) ) { - - THREE.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - - } - - - // could change this to json.animations[0] or remove completely - - geometry.animation = json.animation; - geometry.animations = json.animations; - - }; - - function parseMorphing( scale ) { - - if ( json.morphTargets !== undefined ) { - - var i, l, v, vl, dstVertices, srcVertices; - - for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { - - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; - - dstVertices = geometry.morphTargets[ i ].vertices; - srcVertices = json.morphTargets [ i ].vertices; - - for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - - var vertex = new THREE.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 ) { - - var i, l, c, cl, dstColors, srcColors, color; - - for ( i = 0, l = json.morphColors.length; i < l; i ++ ) { - - geometry.morphColors[ i ] = {}; - geometry.morphColors[ i ].name = json.morphColors[ i ].name; - geometry.morphColors[ i ].colors = []; - - dstColors = geometry.morphColors[ i ].colors; - srcColors = json.morphColors [ i ].colors; - - for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { - - color = new THREE.Color( 0xffaa00 ); - color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); - dstColors.push( color ); - - } - - } - - } - - }; - - if ( json.materials === undefined || json.materials.length === 0 ) { - - return { geometry: geometry }; - - } else { - - var materials = this.initMaterials( json.materials, texturePath ); - - if ( this.needsTangents( materials ) ) { - - geometry.computeTangents(); - - } - - return { geometry: geometry, materials: materials }; - - } - -}; - -// File:src/loaders/LoadingManager.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LoadingManager = function ( onLoad, onProgress, onError ) { - - var scope = this; - - var loaded = 0, total = 0; - - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - total ++; - - }; - - this.itemEnd = function ( url ) { - - loaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, loaded, total ); - - } - - if ( loaded === total && scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - }; - -}; - -THREE.DefaultLoadingManager = new THREE.LoadingManager(); - -// File:src/loaders/BufferGeometryLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BufferGeometryLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.BufferGeometryLoader.prototype = { - - constructor: THREE.BufferGeometryLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - }, onProgress, onError ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var geometry = new THREE.BufferGeometry(); - - var attributes = json.data.attributes; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - var typedArray = new self[ attribute.type ]( attribute.array ); - - geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) ); - - } - - var offsets = json.data.offsets; - - if ( offsets !== undefined ) { - - geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); - - } - - var boundingSphere = json.data.boundingSphere; - - if ( boundingSphere !== undefined ) { - - var center = new THREE.Vector3(); - - if ( boundingSphere.center !== undefined ) { - - center.fromArray( boundingSphere.center ); - - } - - geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius ); - - } - - return geometry; - - } - -}; - -// File:src/loaders/MaterialLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MaterialLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.MaterialLoader.prototype = { - - constructor: THREE.MaterialLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - }, onProgress, onError ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var material = new THREE[ json.type ]; - - if ( json.color !== undefined ) material.color.setHex( json.color ); - 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.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.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.wireframe !== undefined ) material.wireframe = json.wireframe; - - // for PointCloudMaterial - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - - 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; - - } - -}; - -// File:src/loaders/ObjectLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ObjectLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - this.texturePath = ''; - -}; - -THREE.ObjectLoader.prototype = { - - constructor: THREE.ObjectLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - if ( this.texturePath === '' ) { - - this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - - } - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - scope.parse( JSON.parse( text ), 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.images === undefined || json.images.length === 0 ) { - - if ( onLoad !== undefined ) onLoad( object ); - - } - - return object; - - }, - - parseGeometries: function ( json ) { - - var geometries = {}; - - if ( json !== undefined ) { - - var geometryLoader = new THREE.JSONLoader(); - var bufferGeometryLoader = new THREE.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 THREE[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); - - break; - - case 'BoxGeometry': - case 'CubeGeometry': // backwards compatible - - geometry = new THREE.BoxGeometry( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); - - break; - - case 'CircleGeometry': - - geometry = new THREE.CircleGeometry( - data.radius, - data.segments - ); - - break; - - case 'CylinderGeometry': - - geometry = new THREE.CylinderGeometry( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded - ); - - break; - - case 'SphereGeometry': - - geometry = new THREE.SphereGeometry( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'IcosahedronGeometry': - - geometry = new THREE.IcosahedronGeometry( - data.radius, - data.detail - ); - - break; - - case 'TorusGeometry': - - geometry = new THREE.TorusGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); - - break; - - case 'TorusKnotGeometry': - - geometry = new THREE.TorusKnotGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.p, - data.q, - data.heightScale - ); - - break; - - case 'BufferGeometry': - - geometry = bufferGeometryLoader.parse( data ); - - break; - - case 'Geometry': - - geometry = geometryLoader.parse( data.data ).geometry; - - break; - - } - - 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 getTexture = function ( name ) { - - if ( textures[ name ] === undefined ) { - - THREE.warn( 'THREE.ObjectLoader: Undefined texture', name ); - - } - - return textures[ name ]; - - }; - - var loader = new THREE.MaterialLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - var material = loader.parse( data ); - - material.uuid = data.uuid; - - if ( data.name !== undefined ) material.name = data.name; - - if ( data.map !== undefined ) { - - material.map = getTexture( data.map ); - - } - - if ( data.bumpMap !== undefined ) { - - material.bumpMap = getTexture( data.bumpMap ); - if ( data.bumpScale ) { - material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale ); - } - - } - - if ( data.alphaMap !== undefined ) { - - material.alphaMap = getTexture( data.alphaMap ); - - } - - if ( data.envMap !== undefined ) { - - material.envMap = getTexture( data.envMap ); - - } - - if ( data.normalMap !== undefined ) { - - material.normalMap = getTexture( data.normalMap ); - if ( data.normalScale ) { - material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale ); - } - - } - - if ( data.lightMap !== undefined ) { - - material.lightMap = getTexture( data.lightMap ); - - } - - if ( data.specularMap !== undefined ) { - - material.specularMap = getTexture( data.specularMap ); - - } - - materials[ data.uuid ] = material; - - } - - } - - return materials; - - }, - - parseImages: function ( json, onLoad ) { - - var scope = this; - var images = {}; - - if ( json !== undefined && json.length > 0 ) { - - var manager = new THREE.LoadingManager( onLoad ); - - var loader = new THREE.ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); - - var loadImage = function ( url ) { - - scope.manager.itemStart( url ); - - return loader.load( url, function () { - - scope.manager.itemEnd( url ); - - } ); - - }; - - 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 textures = {}; - - if ( json !== undefined ) { - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - - if ( data.image === undefined ) { - - THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid ); - - } - - if ( images[ data.image ] === undefined ) { - - THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - - } - - var texture = new THREE.Texture( images[ data.image ] ); - texture.needsUpdate = true; - - texture.uuid = data.uuid; - - if ( data.name !== undefined ) texture.name = data.name; - if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); - if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ]; - if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ]; - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - if ( data.wrap instanceof Array ) { - - texture.wrapS = THREE[ data.wrap[ 0 ] ]; - texture.wrapT = THREE[ data.wrap[ 1 ] ]; - - } - - textures[ data.uuid ] = texture; - - } - - } - - return textures; - - }, - - parseObject: function () { - - var matrix = new THREE.Matrix4(); - - return function ( data, geometries, materials ) { - - var object; - - var getGeometry = function ( name ) { - - if ( geometries[ name ] === undefined ) { - - THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - - } - - return geometries[ name ]; - - }; - - var getMaterial = function ( name ) { - - if ( materials[ name ] === undefined ) { - - THREE.warn( 'THREE.ObjectLoader: Undefined material', name ); - - } - - return materials[ name ]; - - }; - - switch ( data.type ) { - - case 'Scene': - - object = new THREE.Scene(); - - break; - - case 'PerspectiveCamera': - - object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - break; - - case 'OrthographicCamera': - - object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - break; - - case 'AmbientLight': - - object = new THREE.AmbientLight( data.color ); - - break; - - case 'DirectionalLight': - - object = new THREE.DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay ); - - break; - - case 'SpotLight': - - object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay ); - - break; - - case 'HemisphereLight': - - object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'Mesh': - - object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Line': - - object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - - break; - - case 'PointCloud': - - object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Sprite': - - object = new THREE.Sprite( getMaterial( data.material ) ); - - break; - - case 'Group': - - object = new THREE.Group(); - - break; - - default: - - object = new THREE.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.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - 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 ) ); - - } - - } - - return object; - - } - - }() - -}; - -// File:src/loaders/TextureLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.TextureLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.TextureLoader.prototype = { - - constructor: THREE.TextureLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.ImageLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( image ) { - - var texture = new THREE.Texture( image ); - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - }, onProgress, onError ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; - -// File:src/loaders/BinaryTextureLoader.js - -/** - * @author Nikos M. / https://github.com/foo123/ - * - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - */ - -THREE.DataTextureLoader = THREE.BinaryTextureLoader = function () { - - // override in sub classes - this._parser = null; - -}; - -THREE.BinaryTextureLoader.prototype = { - - constructor: THREE.BinaryTextureLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var texture = new THREE.DataTexture( ); - - var loader = new THREE.XHRLoader(); - 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 : THREE.ClampToEdgeWrapping; - texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; - - texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; - texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.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 = THREE.LinearFilter; - - } - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture, texData ); - - }, onProgress, onError ); - - - return texture; - - } - -}; - -// File:src/loaders/CompressedTextureLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - * - * Abstract Base class to block based textures loader (dds, pvr, ...) - */ - -THREE.CompressedTextureLoader = function () { - - // override in sub classes - this._parser = null; - -}; - - -THREE.CompressedTextureLoader.prototype = { - - constructor: THREE.CompressedTextureLoader, - - load: function ( url, onLoad, onError ) { - - var scope = this; - - var images = []; - - var texture = new THREE.CompressedTexture(); - texture.image = images; - - var loader = new THREE.XHRLoader(); - loader.setResponseType( 'arraybuffer' ); - - if ( url instanceof Array ) { - - var loaded = 0; - - var loadTexture = function ( 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 = THREE.LinearFilter; - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - } ); - - }; - - 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 = THREE.LinearFilter; - - } - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } ); - - } - - return texture; - - } - -}; - -// File:src/materials/Material.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Material = function () { - - Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } ); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.type = 'Material'; - - this.side = THREE.FrontSide; - - this.opacity = 1; - this.transparent = false; - - this.blending = THREE.NormalBlending; - - this.blendSrc = THREE.SrcAlphaFactor; - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; - - this.depthTest = true; - this.depthWrite = true; - - this.colorWrite = true; - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.alphaTest = 0; - - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - - this.visible = true; - - this._needsUpdate = true; - -}; - -THREE.Material.prototype = { - - constructor: THREE.Material, - - 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 ) { - - THREE.warn( "THREE.Material: '" + key + "' parameter is undefined." ); - continue; - - } - - if ( key in this ) { - - var currentValue = this[ key ]; - - if ( currentValue instanceof THREE.Color ) { - - currentValue.set( newValue ); - - } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { - - currentValue.copy( newValue ); - - } else if ( key == 'overdraw' ) { - - // ensure overdraw is backwards-compatable with legacy boolean type - this[ key ] = Number( newValue ); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - }, - - toJSON: function () { - - var output = { - metadata: { - version: 4.2, - type: 'material', - generator: 'MaterialExporter' - }, - uuid: this.uuid, - type: this.type - }; - - if ( this.name !== "" ) output.name = this.name; - - if ( this instanceof THREE.MeshBasicMaterial ) { - - output.color = this.color.getHex(); - if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - if ( this.side !== THREE.FrontSide ) output.side = this.side; - - } else if ( this instanceof THREE.MeshLambertMaterial ) { - - output.color = this.color.getHex(); - output.emissive = this.emissive.getHex(); - if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; - if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - if ( this.side !== THREE.FrontSide ) output.side = this.side; - - } else if ( this instanceof THREE.MeshPhongMaterial ) { - - output.color = this.color.getHex(); - output.emissive = this.emissive.getHex(); - output.specular = this.specular.getHex(); - output.shininess = this.shininess; - if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; - if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - if ( this.side !== THREE.FrontSide ) output.side = this.side; - - } else if ( this instanceof THREE.MeshNormalMaterial ) { - - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - if ( this.side !== THREE.FrontSide ) output.side = this.side; - - } else if ( this instanceof THREE.MeshDepthMaterial ) { - - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - if ( this.side !== THREE.FrontSide ) output.side = this.side; - - } else if ( this instanceof THREE.PointCloudMaterial ) { - - output.size = this.size; - output.sizeAttenuation = this.sizeAttenuation; - output.color = this.color.getHex(); - - if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; - if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - - } else if ( this instanceof THREE.ShaderMaterial ) { - - output.uniforms = this.uniforms; - output.vertexShader = this.vertexShader; - output.fragmentShader = this.fragmentShader; - - } else if ( this instanceof THREE.SpriteMaterial ) { - - output.color = this.color.getHex(); - - } - - if ( this.opacity < 1 ) output.opacity = this.opacity; - if ( this.transparent !== false ) output.transparent = this.transparent; - if ( this.wireframe !== false ) output.wireframe = this.wireframe; - - return output; - - }, - - clone: function ( material ) { - - if ( material === undefined ) material = new THREE.Material(); - - material.name = this.name; - - material.side = this.side; - - material.opacity = this.opacity; - material.transparent = this.transparent; - - material.blending = this.blending; - - material.blendSrc = this.blendSrc; - material.blendDst = this.blendDst; - material.blendEquation = this.blendEquation; - material.blendSrcAlpha = this.blendSrcAlpha; - material.blendDstAlpha = this.blendDstAlpha; - material.blendEquationAlpha = this.blendEquationAlpha; - - material.depthTest = this.depthTest; - material.depthWrite = this.depthWrite; - - material.polygonOffset = this.polygonOffset; - material.polygonOffsetFactor = this.polygonOffsetFactor; - material.polygonOffsetUnits = this.polygonOffsetUnits; - - material.alphaTest = this.alphaTest; - - material.overdraw = this.overdraw; - - material.visible = this.visible; - - return material; - - }, - - update: function () { - - this.dispatchEvent( { type: 'update' } ); - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - -THREE.MaterialIdCount = 0; - -// File:src/materials/LineBasicMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round", - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'LineBasicMaterial'; - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; - -THREE.LineBasicMaterial.prototype.clone = function () { - - var material = new THREE.LineBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - material.linecap = this.linecap; - material.linejoin = this.linejoin; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -// File:src/materials/LineDashedMaterial.js - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: , - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineDashedMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'LineDashedMaterial'; - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial; - -THREE.LineDashedMaterial.prototype.clone = function () { - - var material = new THREE.LineDashedMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - - material.scale = this.scale; - material.dashSize = this.dashSize; - material.gapSize = this.gapSize; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -// File:src/materials/MeshBasicMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * lightMap: 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: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * - * fog: - * } - */ - -THREE.MeshBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'MeshBasicMaterial'; - - this.color = new THREE.Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; - -THREE.MeshBasicMaterial.prototype.clone = function () { - - var material = new THREE.MeshBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.alphaMap = this.alphaMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - - return material; - -}; - -// File:src/materials/MeshLambertMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * emissive: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: 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: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshLambertMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'MeshLambertMaterial'; - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.emissive = new THREE.Color( 0x000000 ); - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial; - -THREE.MeshLambertMaterial.prototype.clone = function () { - - var material = new THREE.MeshLambertMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.emissive.copy( this.emissive ); - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.alphaMap = this.alphaMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -// File:src/materials/MeshPhongMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * emissive: , - * specular: , - * shininess: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * 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, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshPhongMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'MeshPhongMaterial'; - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.emissive = new THREE.Color( 0x000000 ); - this.specular = new THREE.Color( 0x111111 ); - this.shininess = 30; - - this.metal = false; - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - - this.lightMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new THREE.Vector2( 1, 1 ); - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; - -THREE.MeshPhongMaterial.prototype.clone = function () { - - var material = new THREE.MeshPhongMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.emissive.copy( this.emissive ); - material.specular.copy( this.specular ); - material.shininess = this.shininess; - - material.metal = this.metal; - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; - - material.normalMap = this.normalMap; - material.normalScale.copy( this.normalScale ); - - material.specularMap = this.specularMap; - - material.alphaMap = this.alphaMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -// File:src/materials/MeshDepthMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshDepthMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'MeshDepthMaterial'; - - this.morphTargets = false; - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.setValues( parameters ); - -}; - -THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial; - -THREE.MeshDepthMaterial.prototype.clone = function () { - - var material = new THREE.MeshDepthMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -// File:src/materials/MeshNormalMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * opacity: , - * - * shading: THREE.FlatShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshNormalMaterial = function ( parameters ) { - - THREE.Material.call( this, parameters ); - - this.type = 'MeshNormalMaterial'; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial; - -THREE.MeshNormalMaterial.prototype.clone = function () { - - var material = new THREE.MeshNormalMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -// File:src/materials/MeshFaceMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MeshFaceMaterial = function ( materials ) { - - this.uuid = THREE.Math.generateUUID(); - - this.type = 'MeshFaceMaterial'; - - this.materials = materials instanceof Array ? materials : []; - -}; - -THREE.MeshFaceMaterial.prototype = { - - constructor: THREE.MeshFaceMaterial, - - toJSON: function () { - - var output = { - metadata: { - version: 4.2, - type: 'material', - generator: 'MaterialExporter' - }, - uuid: this.uuid, - type: this.type, - materials: [] - }; - - for ( var i = 0, l = this.materials.length; i < l; i ++ ) { - - output.materials.push( this.materials[ i ].toJSON() ); - - } - - return output; - - }, - - clone: function () { - - var material = new THREE.MeshFaceMaterial(); - - for ( var i = 0; i < this.materials.length; i ++ ) { - - material.materials.push( this.materials[ i ].clone() ); - - } - - return material; - - } - -}; - -// File:src/materials/PointCloudMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * sizeAttenuation: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * vertexColors: , - * - * fog: - * } - */ - -THREE.PointCloudMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'PointCloudMaterial'; - - this.color = new THREE.Color( 0xffffff ); - - this.map = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.vertexColors = THREE.NoColors; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial; - -THREE.PointCloudMaterial.prototype.clone = function () { - - var material = new THREE.PointCloudMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.size = this.size; - material.sizeAttenuation = this.sizeAttenuation; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -// backwards compatibility - -THREE.ParticleBasicMaterial = function ( parameters ) { - - THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); - return new THREE.PointCloudMaterial( parameters ); - -}; - -THREE.ParticleSystemMaterial = function ( parameters ) { - - THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); - return new THREE.PointCloudMaterial( parameters ); - -}; - -// File:src/materials/ShaderMaterial.js - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * defines: { "label" : "value" }, - * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, - * - * fragmentShader: , - * vertexShader: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.ShaderMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'ShaderMaterial'; - - this.defines = {}; - this.uniforms = {}; - this.attributes = null; - - 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.shading = THREE.SmoothShading; - - 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.vertexColors = THREE.NoColors; // set to use "color" attribute stream - - 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 - - // 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; - - this.setValues( parameters ); - -}; - -THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial; - -THREE.ShaderMaterial.prototype.clone = function () { - - var material = new THREE.ShaderMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.fragmentShader = this.fragmentShader; - material.vertexShader = this.vertexShader; - - material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); - - material.attributes = this.attributes; - material.defines = this.defines; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - material.fog = this.fog; - - material.lights = this.lights; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -// File:src/materials/RawShaderMaterial.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RawShaderMaterial = function ( parameters ) { - - THREE.ShaderMaterial.call( this, parameters ); - - this.type = 'RawShaderMaterial'; - -}; - -THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); -THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial; - -THREE.RawShaderMaterial.prototype.clone = function () { - - var material = new THREE.RawShaderMaterial(); - - THREE.ShaderMaterial.prototype.clone.call( this, material ); - - return material; - -}; - -// File:src/materials/SpriteMaterial.js - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2(), - * - * fog: - * } - */ - -THREE.SpriteMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.type = 'SpriteMaterial'; - - this.color = new THREE.Color( 0xffffff ); - this.map = null; - - this.rotation = 0; - - this.fog = false; - - // set parameters - - this.setValues( parameters ); - -}; - -THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); -THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; - -THREE.SpriteMaterial.prototype.clone = function () { - - var material = new THREE.SpriteMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.map = this.map; - - material.rotation = this.rotation; - - material.fog = this.fog; - - return material; - -}; - -// File:src/textures/Texture.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ - -THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } ); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.sourceFile = ''; - - this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; - this.mipmaps = []; - - this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; - - this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; - - this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; - - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - - this.format = format !== undefined ? format : THREE.RGBAFormat; - this.type = type !== undefined ? type : THREE.UnsignedByteType; - - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.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) - - this._needsUpdate = false; - this.onUpdate = null; - -}; - -THREE.Texture.DEFAULT_IMAGE = undefined; -THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; - -THREE.Texture.prototype = { - - constructor: THREE.Texture, - - get needsUpdate () { - - return this._needsUpdate; - - }, - - set needsUpdate ( value ) { - - if ( value === true ) this.update(); - - this._needsUpdate = value; - - }, - - clone: function ( texture ) { - - if ( texture === undefined ) texture = new THREE.Texture(); - - texture.image = this.image; - texture.mipmaps = this.mipmaps.slice( 0 ); - - texture.mapping = this.mapping; - - texture.wrapS = this.wrapS; - texture.wrapT = this.wrapT; - - texture.magFilter = this.magFilter; - texture.minFilter = this.minFilter; - - texture.anisotropy = this.anisotropy; - - texture.format = this.format; - texture.type = this.type; - - texture.offset.copy( this.offset ); - texture.repeat.copy( this.repeat ); - - texture.generateMipmaps = this.generateMipmaps; - texture.premultiplyAlpha = this.premultiplyAlpha; - texture.flipY = this.flipY; - texture.unpackAlignment = this.unpackAlignment; - - return texture; - - }, - - update: function () { - - this.dispatchEvent( { type: 'update' } ); - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); - -THREE.TextureIdCount = 0; - -// File:src/textures/CubeTexture.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; - - THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.images = images; - -}; - -THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype ); -THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; - -THREE.CubeTexture.clone = function ( texture ) { - - if ( texture === undefined ) texture = new THREE.CubeTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - texture.images = this.images; - - return texture; - -}; - -// File:src/textures/CompressedTexture.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - 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; - -}; - -THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); -THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture; - -THREE.CompressedTexture.prototype.clone = function () { - - var texture = new THREE.CompressedTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -// File:src/textures/DataTexture.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { data: data, width: width, height: height }; - -}; - -THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); -THREE.DataTexture.prototype.constructor = THREE.DataTexture; - -THREE.DataTexture.prototype.clone = function () { - - var texture = new THREE.DataTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -// File:src/textures/VideoTexture.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.generateMipmaps = false; - - var scope = this; - - var update = function () { - - requestAnimationFrame( update ); - - if ( video.readyState === video.HAVE_ENOUGH_DATA ) { - - scope.needsUpdate = true; - - } - - }; - - update(); - -}; - -THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype ); -THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; - -// File:src/objects/Group.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Group = function () { - - THREE.Object3D.call( this ); - - this.type = 'Group'; - -}; - -THREE.Group.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Group.prototype.constructor = THREE.Group; - -// File:src/objects/PointCloud.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.PointCloud = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.type = 'PointCloud'; - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } ); - -}; - -THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype ); -THREE.PointCloud.prototype.constructor = THREE.PointCloud; - -THREE.PointCloud.prototype.raycast = ( function () { - - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); - - return function ( raycaster, intersects ) { - - var object = this; - var geometry = object.geometry; - var threshold = raycaster.params.PointCloud.threshold; - - inverseMatrix.getInverse( this.matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - if ( geometry.boundingBox !== null ) { - - if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - - return; - - } - - } - - var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var position = new THREE.Vector3(); - - var testPoint = function ( point, index ) { - - var rayPointDistance = ray.distanceToPoint( point ); - - if ( rayPointDistance < localThreshold ) { - - var intersectPoint = ray.closestPointToPoint( point ); - intersectPoint.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - intersects.push( { - - distance: distance, - distanceToRay: rayPointDistance, - point: intersectPoint.clone(), - index: index, - face: null, - object: object - - } ); - - } - - }; - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - var positions = attributes.position.array; - - if ( attributes.index !== undefined ) { - - var indices = attributes.index.array; - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - var offset = { - start: 0, - count: indices.length, - index: 0 - }; - - offsets = [ offset ]; - - } - - for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; - - for ( var i = start, il = start + count; i < il; i ++ ) { - - var a = index + indices[ i ]; - - position.fromArray( positions, a * 3 ); - - testPoint( position, a ); - - } - - } - - } else { - - var pointCount = positions.length / 3; - - for ( var i = 0; i < pointCount; i ++ ) { - - position.set( - positions[ 3 * i ], - positions[ 3 * i + 1 ], - positions[ 3 * i + 2 ] - ); - - testPoint( position, i ); - - } - - } - - } else { - - var vertices = this.geometry.vertices; - - for ( var i = 0; i < vertices.length; i ++ ) { - - testPoint( vertices[ i ], i ); - - } - - } - - }; - -}() ); - -THREE.PointCloud.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -// Backwards compatibility - -THREE.ParticleSystem = function ( geometry, material ) { - - THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); - return new THREE.PointCloud( geometry, material ); - -}; - -// File:src/objects/Line.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Line = function ( geometry, material, mode ) { - - THREE.Object3D.call( this ); - - this.type = 'Line'; - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.mode = mode !== undefined ? mode : THREE.LineStrip; - -}; - -THREE.LineStrip = 0; -THREE.LinePieces = 1; - -THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Line.prototype.constructor = THREE.Line; - -THREE.Line.prototype.raycast = ( function () { - - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); - var sphere = new THREE.Sphere(); - - return function ( raycaster, intersects ) { - - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; - - var geometry = this.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - // Checking boundingSphere distance to ray - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( this.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - - return; - - } - - inverseMatrix.getInverse( this.matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - var vStart = new THREE.Vector3(); - var vEnd = new THREE.Vector3(); - var interSegment = new THREE.Vector3(); - var interRay = new THREE.Vector3(); - var step = this.mode === THREE.LineStrip ? 1 : 2; - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - - if ( attributes.index !== undefined ) { - - var indices = attributes.index.array; - var positions = attributes.position.array; - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - offsets = [ { start: 0, count: indices.length, index: 0 } ]; - - } - - for ( var oi = 0; oi < offsets.length; oi ++) { - - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; - - for ( var i = start; i < start + count - 1; i += step ) { - - var a = index + indices[ i ]; - var b = index + 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; - - var distance = 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, - offsetIndex: oi, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - } else { - - var positions = attributes.position.array; - - for ( var i = 0; i < positions.length / 3 - 1; 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; - - var distance = 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 instanceof THREE.Geometry ) { - - 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; - - var distance = 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 - - } ); - - } - - } - - }; - -}() ); - -THREE.Line.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -// File:src/objects/Mesh.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ - -THREE.Mesh = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.type = 'Mesh'; - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.updateMorphTargets(); - -}; - -THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Mesh.prototype.constructor = THREE.Mesh; - -THREE.Mesh.prototype.updateMorphTargets = function () { - - if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - - this.morphTargetBase = - 1; - this.morphTargetForcedOrder = []; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - - } - - } - -}; - -THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - - if ( this.morphTargetDictionary[ name ] !== undefined ) { - - return this.morphTargetDictionary[ name ]; - - } - - THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); - - return 0; - -}; - - -THREE.Mesh.prototype.raycast = ( function () { - - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); - var sphere = new THREE.Sphere(); - - var vA = new THREE.Vector3(); - var vB = new THREE.Vector3(); - var vC = new THREE.Vector3(); - - return function ( raycaster, intersects ) { - - var geometry = this.geometry; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( this.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - - return; - - } - - // Check boundingBox before continuing - - inverseMatrix.getInverse( this.matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - if ( geometry.boundingBox !== null ) { - - if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - - return; - - } - - } - - if ( geometry instanceof THREE.BufferGeometry ) { - - var material = this.material; - - if ( material === undefined ) return; - - var attributes = geometry.attributes; - - var a, b, c; - var precision = raycaster.precision; - - if ( attributes.index !== undefined ) { - - var indices = attributes.index.array; - var positions = attributes.position.array; - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - offsets = [ { start: 0, count: indices.length, index: 0 } ]; - - } - - for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - a = index + indices[ i ]; - b = index + indices[ i + 1 ]; - c = index + indices[ i + 2 ]; - - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - - } else { - - var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( this.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), - faceIndex: null, - object: this - - } ); - - } - - } - - } else { - - var positions = attributes.position.array; - - for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) { - - a = i; - b = i + 1; - c = i + 2; - - vA.fromArray( positions, j ); - vB.fromArray( positions, j + 3 ); - vC.fromArray( positions, j + 6 ); - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - - } else { - - var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( this.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), - faceIndex: null, - object: this - - } ); - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; - var objectMaterials = isFaceMaterial === true ? this.material.materials : null; - - var a, b, c; - var precision = raycaster.precision; - - var vertices = geometry.vertices; - - for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - - var face = geometry.faces[ f ]; - - var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material; - - if ( material === undefined ) continue; - - a = vertices[ face.a ]; - b = vertices[ face.b ]; - c = vertices[ face.c ]; - - if ( material.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.x += ( targets[ face.a ].x - a.x ) * influence; - vA.y += ( targets[ face.a ].y - a.y ) * influence; - vA.z += ( targets[ face.a ].z - a.z ) * influence; - - vB.x += ( targets[ face.b ].x - b.x ) * influence; - vB.y += ( targets[ face.b ].y - b.y ) * influence; - vB.z += ( targets[ face.b ].z - b.z ) * influence; - - vC.x += ( targets[ face.c ].x - c.x ) * influence; - vC.y += ( targets[ face.c ].y - c.y ) * influence; - vC.z += ( targets[ face.c ].z - c.z ) * influence; - - } - - vA.add( a ); - vB.add( b ); - vC.add( c ); - - a = vA; - b = vB; - c = vC; - - } - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = ray.intersectTriangle( c, b, a, true ); - - } else { - - var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( this.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - face: face, - faceIndex: f, - object: this - - } ); - - } - - } - - }; - -}() ); - -THREE.Mesh.prototype.clone = function ( object, recursive ) { - - if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); - - THREE.Object3D.prototype.clone.call( this, object, recursive ); - - return object; - -}; - -// File:src/objects/Bone.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ - -THREE.Bone = function ( skin ) { - - THREE.Object3D.call( this ); - - this.type = 'Bone'; - - this.skin = skin; - -}; - -THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Bone.prototype.constructor = THREE.Bone; - -// File:src/objects/Skeleton.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author michael guerrero / http://realitymeltdown.com - * @author ikerr / http://verold.com - */ - -THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { - - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - - this.identityMatrix = new THREE.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 (8 * 8 / 4) - // 16x16 pixel texture max 64 bones (16 * 16 / 4) - // 32x32 pixel texture max 256 bones (32 * 32 / 4) - // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - - var size; - - if ( this.bones.length > 256 ) - size = 64; - else if ( this.bones.length > 64 ) - size = 32; - else if ( this.bones.length > 16 ) - size = 16; - else - size = 8; - - this.boneTextureWidth = size; - this.boneTextureHeight = size; - - this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel - this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); - this.boneTexture.minFilter = THREE.NearestFilter; - this.boneTexture.magFilter = THREE.NearestFilter; - this.boneTexture.generateMipmaps = false; - this.boneTexture.flipY = false; - - } 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 { - - THREE.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 THREE.Matrix4() ); - - } - - } - - } - -}; - -THREE.Skeleton.prototype.calculateInverses = function () { - - this.boneInverses = []; - - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - - var inverse = new THREE.Matrix4(); - - if ( this.bones[ b ] ) { - - inverse.getInverse( this.bones[ b ].matrixWorld ); - - } - - this.boneInverses.push( inverse ); - - } - -}; - -THREE.Skeleton.prototype.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.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 ); - - } - - } - -}; - -THREE.Skeleton.prototype.update = ( function () { - - var offsetMatrix = new THREE.Matrix4(); - - return function () { - - // 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.flattenToArrayOffset( this.boneMatrices, b * 16 ); - - } - - if ( this.useVertexTexture ) { - - this.boneTexture.needsUpdate = true; - - } - - }; - -} )(); - - -// File:src/objects/SkinnedMesh.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ - -THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - - THREE.Mesh.call( this, geometry, material ); - - this.type = 'SkinnedMesh'; - - this.bindMode = "attached"; - this.bindMatrix = new THREE.Matrix4(); - this.bindMatrixInverse = new THREE.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, p, q, s; - - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - - gbone = this.geometry.bones[ b ]; - - p = gbone.pos; - q = gbone.rotq; - s = gbone.scl; - - bone = new THREE.Bone( this ); - bones.push( bone ); - - bone.name = gbone.name; - bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] ); - bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] ); - - if ( s !== undefined ) { - - bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] ); - - } else { - - bone.scale.set( 1, 1, 1 ); - - } - - } - - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - - gbone = this.geometry.bones[ b ]; - - if ( gbone.parent !== - 1 ) { - - bones[ gbone.parent ].add( bones[ b ] ); - - } else { - - this.add( bones[ b ] ); - - } - - } - - } - - this.normalizeSkinWeights(); - - this.updateMatrixWorld( true ); - this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) ); - -}; - - -THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); -THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; - -THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { - - this.skeleton = skeleton; - - if ( bindMatrix === undefined ) { - - this.updateMatrixWorld( true ); - - bindMatrix = this.matrixWorld; - - } - - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.getInverse( bindMatrix ); - -}; - -THREE.SkinnedMesh.prototype.pose = function () { - - this.skeleton.pose(); - -}; - -THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - - if ( this.geometry instanceof THREE.Geometry ) { - - for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - - var sw = this.geometry.skinWeights[ i ]; - - var scale = 1.0 / sw.lengthManhattan(); - - if ( scale !== Infinity ) { - - sw.multiplyScalar( scale ); - - } else { - - sw.set( 1 ); // this will be normalized by the shader anyway - - } - - } - - } else { - - // skinning weights assumed to be normalized for THREE.BufferGeometry - - } - -}; - -THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { - - THREE.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 { - - THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); - - } - -}; - -THREE.SkinnedMesh.prototype.clone = function( object ) { - - if ( object === undefined ) { - - object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); - - } - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - - -// File:src/objects/MorphAnimMesh.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphAnimMesh = function ( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); - - this.type = 'MorphAnimMesh'; - - // API - - this.duration = 1000; // milliseconds - this.mirroredLoop = false; - this.time = 0; - - // internals - - this.lastKeyframe = 0; - this.currentKeyframe = 0; - - this.direction = 1; - this.directionBackwards = false; - - this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); - -}; - -THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); -THREE.MorphAnimMesh.prototype.constructor = THREE.MorphAnimMesh; - -THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { - - this.startKeyframe = start; - this.endKeyframe = end; - - this.length = this.endKeyframe - this.startKeyframe + 1; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - - this.direction = 1; - this.directionBackwards = false; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - - this.direction = - 1; - this.directionBackwards = true; - -}; - -THREE.MorphAnimMesh.prototype.parseAnimations = function () { - - var geometry = this.geometry; - - if ( ! geometry.animations ) geometry.animations = {}; - - var firstAnimation, animations = geometry.animations; - - var pattern = /([a-z]+)_?(\d+)/; - - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - - var morph = geometry.morphTargets[ i ]; - var parts = morph.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - var label = parts[ 1 ]; - - if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity }; - - var animation = animations[ label ]; - - if ( i < animation.start ) animation.start = i; - if ( i > animation.end ) animation.end = i; - - if ( ! firstAnimation ) firstAnimation = label; - - } - - } - - geometry.firstAnimation = firstAnimation; - -}; - -THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { - - if ( ! this.geometry.animations ) this.geometry.animations = {}; - - this.geometry.animations[ label ] = { start: start, end: end }; - -}; - -THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { - - var animation = this.geometry.animations[ label ]; - - if ( animation ) { - - this.setFrameRange( animation.start, animation.end ); - this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); - this.time = 0; - - } else { - - THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' ); - - } - -}; - -THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { - - var frameTime = this.duration / this.length; - - this.time += this.direction * delta; - - if ( this.mirroredLoop ) { - - if ( this.time > this.duration || this.time < 0 ) { - - this.direction *= - 1; - - if ( this.time > this.duration ) { - - this.time = this.duration; - this.directionBackwards = true; - - } - - if ( this.time < 0 ) { - - this.time = 0; - this.directionBackwards = false; - - } - - } - - } else { - - this.time = this.time % this.duration; - - if ( this.time < 0 ) this.time += this.duration; - - } - - var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); - - if ( keyframe !== this.currentKeyframe ) { - - this.morphTargetInfluences[ this.lastKeyframe ] = 0; - this.morphTargetInfluences[ this.currentKeyframe ] = 1; - - this.morphTargetInfluences[ keyframe ] = 0; - - this.lastKeyframe = this.currentKeyframe; - this.currentKeyframe = keyframe; - - } - - var mix = ( this.time % frameTime ) / frameTime; - - if ( this.directionBackwards ) { - - mix = 1 - mix; - - } - - this.morphTargetInfluences[ this.currentKeyframe ] = mix; - this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; - -}; - -THREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) { - - var influences = this.morphTargetInfluences; - - for ( var i = 0, l = influences.length; i < l; i ++ ) { - - influences[ i ] = 0; - - } - - if ( a > -1 ) influences[ a ] = 1 - t; - if ( b > -1 ) influences[ b ] = t; - -}; - -THREE.MorphAnimMesh.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); - - object.duration = this.duration; - object.mirroredLoop = this.mirroredLoop; - object.time = this.time; - - object.lastKeyframe = this.lastKeyframe; - object.currentKeyframe = this.currentKeyframe; - - object.direction = this.direction; - object.directionBackwards = this.directionBackwards; - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - -// File:src/objects/LOD.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LOD = function () { - - THREE.Object3D.call( this ); - - this.objects = []; - -}; - - -THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); -THREE.LOD.prototype.constructor = THREE.LOD; - -THREE.LOD.prototype.addLevel = function ( object, distance ) { - - if ( distance === undefined ) distance = 0; - - distance = Math.abs( distance ); - - for ( var l = 0; l < this.objects.length; l ++ ) { - - if ( distance < this.objects[ l ].distance ) { - - break; - - } - - } - - this.objects.splice( l, 0, { distance: distance, object: object } ); - this.add( object ); - -}; - -THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance < this.objects[ i ].distance ) { - - break; - - } - - } - - return this.objects[ i - 1 ].object; - -}; - -THREE.LOD.prototype.raycast = ( function () { - - var matrixPosition = new THREE.Vector3(); - - return function ( raycaster, intersects ) { - - matrixPosition.setFromMatrixPosition( this.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - - }; - -}() ); - -THREE.LOD.prototype.update = function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( camera ) { - - if ( this.objects.length > 1 ) { - - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); - - var distance = v1.distanceTo( v2 ); - - this.objects[ 0 ].object.visible = true; - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance >= this.objects[ i ].distance ) { - - this.objects[ i - 1 ].object.visible = false; - this.objects[ i ].object.visible = true; - - } else { - - break; - - } - - } - - for ( ; i < l; i ++ ) { - - this.objects[ i ].object.visible = false; - - } - - } - - }; - -}(); - -THREE.LOD.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.LOD(); - - THREE.Object3D.prototype.clone.call( this, object ); - - for ( var i = 0, l = this.objects.length; i < l; i ++ ) { - var x = this.objects[ i ].object.clone(); - x.visible = i === 0; - object.addLevel( x, this.objects[ i ].distance ); - } - - return object; - -}; - -// File:src/objects/Sprite.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Sprite = ( function () { - - var indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); - var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] ); - var uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] ); - - var geometry = new THREE.BufferGeometry(); - geometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); - geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - - return function ( material ) { - - THREE.Object3D.call( this ); - - this.type = 'Sprite'; - - this.geometry = geometry; - this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - - }; - -} )(); - -THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Sprite.prototype.constructor = THREE.Sprite; - -THREE.Sprite.prototype.raycast = ( function () { - - var matrixPosition = new THREE.Vector3(); - - return function ( raycaster, intersects ) { - - matrixPosition.setFromMatrixPosition( this.matrixWorld ); - - var distance = raycaster.ray.distanceToPoint( matrixPosition ); - - if ( distance > this.scale.x ) { - - return; - - } - - intersects.push( { - - distance: distance, - point: this.position, - face: null, - object: this - - } ); - - }; - -}() ); - -THREE.Sprite.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Sprite( this.material ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -// Backwards compatibility - -THREE.Particle = THREE.Sprite; - -// File:src/objects/LensFlare.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.LensFlare = function ( texture, size, distance, blending, color ) { - - THREE.Object3D.call( this ); - - this.lensFlares = []; - - this.positionScreen = new THREE.Vector3(); - this.customUpdateCallback = undefined; - - if ( texture !== undefined ) { - - this.add( texture, size, distance, blending, color ); - - } - -}; - -THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); -THREE.LensFlare.prototype.constructor = THREE.LensFlare; - - -/* - * Add: adds another flare - */ - -THREE.LensFlare.prototype.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 THREE.Color( 0xffffff ); - if ( blending === undefined ) blending = THREE.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 ontop z = 1 is back - scale: 1, // scale - rotation: 1, // 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. - */ - -THREE.LensFlare.prototype.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; - - } - -}; - - -// File:src/scenes/Scene.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Scene = function () { - - THREE.Object3D.call( this ); - - this.type = 'Scene'; - - this.fog = null; - this.overrideMaterial = null; - - this.autoUpdate = true; // checked by the renderer - -}; - -THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Scene.prototype.constructor = THREE.Scene; - -THREE.Scene.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Scene(); - - THREE.Object3D.prototype.clone.call( this, object ); - - if ( this.fog !== null ) object.fog = this.fog.clone(); - if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); - - object.autoUpdate = this.autoUpdate; - object.matrixAutoUpdate = this.matrixAutoUpdate; - - return object; - -}; - -// File:src/scenes/Fog.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Fog = function ( color, near, far ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; - -}; - -THREE.Fog.prototype.clone = function () { - - return new THREE.Fog( this.color.getHex(), this.near, this.far ); - -}; - -// File:src/scenes/FogExp2.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.FogExp2 = function ( color, density ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; - -}; - -THREE.FogExp2.prototype.clone = function () { - - return new THREE.FogExp2( this.color.getHex(), this.density ); - -}; - -// File:src/renderers/shaders/ShaderChunk.js - -THREE.ShaderChunk = {}; - -// File:src/renderers/shaders/ShaderChunk/common.glsl - -THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n float distance = dot( planeNormal, point-pointOnPlane );\n return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n if ( decayExponent > 0.0 ) {\n return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n }\n return 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\n"; - -// File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl - -THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl - -THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, dirVector );\n vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n #endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n float dotProduct = dot( transformedNormal, lVector );\n\n vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n #endif\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float dotProduct = dot( transformedNormal, lVector );\n vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n #endif\n\n }\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, lVector );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n #endif\n\n }\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n vLightBack += ambientLightColor;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl - -THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform vec4 offsetRepeat;\n uniform sampler2D map;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl - -THREE.ShaderChunk[ 'default_vertex'] = "#ifdef USE_SKINNING\n\n vec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n vec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; - -// File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl - -THREE.ShaderChunk[ 'map_pars_fragment'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n uniform sampler2D map;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl - -THREE.ShaderChunk[ 'skinnormal_vertex'] = "#ifdef USE_SKINNING\n\n mat4 skinMatrix = mat4( 0.0 );\n skinMatrix += skinWeight.x * boneMatX;\n skinMatrix += skinWeight.y * boneMatY;\n skinMatrix += skinWeight.z * boneMatZ;\n skinMatrix += skinWeight.w * boneMatW;\n skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\n #ifdef USE_MORPHNORMALS\n\n vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n #else\n\n vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl - -THREE.ShaderChunk[ 'logdepthbuf_pars_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n varying float vFragDepth;\n\n #endif\n\n uniform float logDepthBufFC;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl - -THREE.ShaderChunk[ 'lightmap_pars_vertex'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl - -THREE.ShaderChunk[ 'lights_phong_fragment'] = "#ifndef FLAT_SHADED\n\n vec3 normal = normalize( vNormal );\n\n #ifdef DOUBLE_SIDED\n\n normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n #endif\n\n#else\n\n vec3 fdx = dFdx( vViewPosition );\n vec3 fdy = dFdy( vViewPosition );\n vec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n // specular\n\n vec3 pointHalfVector = normalize( lVector + viewPosition );\n float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n // specular\n\n vec3 spotHalfVector = normalize( lVector + viewPosition );\n float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n }\n\n }\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, dirVector );\n\n #ifdef WRAP_AROUND\n\n float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n // specular\n\n vec3 dirHalfVector = normalize( dirVector + viewPosition );\n float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n /*\n // fresnel term from skin shader\n const float F0 = 0.128;\n\n float base = 1.0 - dot( viewPosition, dirHalfVector );\n float exponential = pow( base, 5.0 );\n\n float fresnel = exponential + F0 * ( 1.0 - exponential );\n */\n\n /*\n // fresnel term from fresnel shader\n const float mFresnelBias = 0.08;\n const float mFresnelScale = 0.3;\n const float mFresnelPower = 5.0;\n\n float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n */\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n // dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n totalDiffuseLight += hemiColor;\n\n // specular (sky light)\n\n vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n // specular (ground light)\n\n vec3 lVectorGround = -lVector;\n\n vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n float dotProductGround = dot( normal, lVectorGround );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n }\n\n#endif\n\n#ifdef METAL\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl - -THREE.ShaderChunk[ 'fog_pars_fragment'] = "#ifdef USE_FOG\n\n uniform vec3 fogColor;\n\n #ifdef FOG_EXP2\n\n uniform float fogDensity;\n\n #else\n\n uniform float fogNear;\n uniform float fogFar;\n #endif\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl - -THREE.ShaderChunk[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n vec3 morphedNormal = vec3( 0.0 );\n\n morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n morphedNormal += normal;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n uniform float reflectivity;\n #ifdef ENVMAP_TYPE_CUBE\n uniform samplerCube envMap;\n #else\n uniform sampler2D envMap;\n #endif\n uniform float flipEnvMap;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n uniform float refractionRatio;\n\n #else\n\n varying vec3 vReflect;\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl - -THREE.ShaderChunk[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform vec2 normalScale;\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( vUv.st );\n vec2 st1 = dFdy( vUv.st );\n\n vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n vec3 N = normalize( surf_norm );\n\n vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n mapN.xy = normalScale * mapN.xy;\n mat3 tsn = mat3( S, T, N );\n return normalize( tsn * mapN );\n\n }\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl - -THREE.ShaderChunk[ 'lights_phong_pars_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n uniform sampler2D lightMap;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl - -THREE.ShaderChunk[ 'shadowmap_vertex'] = "#ifdef USE_SHADOWMAP\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n }\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl - -THREE.ShaderChunk[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n vWorldPosition = worldPosition.xyz;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/map_fragment.glsl - -THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n vec4 texelColor = texture2D( map, vUv );\n\n texelColor.xyz = inputToLinear( texelColor.xyz );\n\n diffuseColor *= texelColor;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl - -THREE.ShaderChunk[ 'lightmap_vertex'] = "#ifdef USE_LIGHTMAP\n\n vUv2 = uv2;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl - -THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl - -THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/color_vertex.glsl - -THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n vColor.xyz = inputToLinear( color.xyz );\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl - -THREE.ShaderChunk[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n #ifdef USE_MORPHTARGETS\n\n vec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n #endif\n\n vec4 skinned = vec4( 0.0 );\n skinned += boneMatX * skinVertex * skinWeight.x;\n skinned += boneMatY * skinVertex * skinWeight.y;\n skinned += boneMatZ * skinVertex * skinWeight.z;\n skinned += boneMatW * skinVertex * skinWeight.w;\n skinned = bindMatrixInverse * skinned;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl - -THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n varying vec3 vReflect;\n\n uniform float refractionRatio;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl - -THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n outgoingLight = linearToOutput( outgoingLight );\n"; - -// File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl - -THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl - -THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl - -THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n uniform vec4 offsetRepeat;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl - -THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // Transforming Normal Vectors with the Inverse Transformation\n vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n #else\n\n vec3 reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n #else\n float flipNormal = 1.0;\n #endif\n\n #ifdef ENVMAP_TYPE_CUBE\n vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #elif defined( ENVMAP_TYPE_EQUIREC )\n vec2 sampleUV;\n sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n vec4 envColor = texture2D( envMap, sampleUV );\n\n #elif defined( ENVMAP_TYPE_SPHERE )\n vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n #endif\n\n envColor.xyz = inputToLinear( envColor.xyz );\n\n #ifdef ENVMAP_BLENDING_MULTIPLY\n\n outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_MIX )\n\n outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_ADD )\n\n outgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n uniform sampler2D specularMap;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl - -THREE.ShaderChunk[ 'logdepthbuf_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n vFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n #endif\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl - -THREE.ShaderChunk[ 'morphtarget_pars_vertex'] = "#ifdef USE_MORPHTARGETS\n\n #ifndef USE_MORPHNORMALS\n\n uniform float morphTargetInfluences[ 8 ];\n\n #else\n\n uniform float morphTargetInfluences[ 4 ];\n\n #endif\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl - -THREE.ShaderChunk[ 'specularmap_fragment'] = "float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n vec4 texelSpecular = texture2D( specularMap, vUv );\n specularStrength = texelSpecular.r;\n\n#else\n\n specularStrength = 1.0;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl - -THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n #else\n\n float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n #endif\n\n #ifdef FOG_EXP2\n\n float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n fogFactor = whiteCompliment( fogFactor );\n\n #else\n\n float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n #endif\n \n outgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n uniform sampler2D bumpMap;\n uniform float bumpScale;\n\n // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n vec2 dHdxy_fwd() {\n\n vec2 dSTdx = dFdx( vUv );\n vec2 dSTdy = dFdy( vUv );\n\n float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n return vec2( dBx, dBy );\n\n }\n\n vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n vec3 vSigmaX = dFdx( surf_pos );\n vec3 vSigmaY = dFdy( surf_pos );\n vec3 vN = surf_norm; // normalized\n\n vec3 R1 = cross( vSigmaY, vN );\n vec3 R2 = cross( vN, vSigmaX );\n\n float fDet = dot( vSigmaX, R1 );\n\n vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n return normalize( abs( fDet ) * surf_norm - vGrad );\n\n }\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl - -THREE.ShaderChunk[ 'defaultnormal_vertex'] = "#ifdef USE_SKINNING\n\n vec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n vec3 objectNormal = morphedNormal;\n\n#else\n\n vec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n objectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; - -// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl - -THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n varying vec3 vNormal;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl - -THREE.ShaderChunk[ 'skinbase_vertex'] = "#ifdef USE_SKINNING\n\n mat4 boneMatX = getBoneMatrix( skinIndex.x );\n mat4 boneMatY = getBoneMatrix( skinIndex.y );\n mat4 boneMatZ = getBoneMatrix( skinIndex.z );\n mat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/map_vertex.glsl - -THREE.ShaderChunk[ 'map_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n vUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl - -THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl - -THREE.ShaderChunk[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n uniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/color_fragment.glsl - -THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n diffuseColor.rgb *= vColor;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl - -THREE.ShaderChunk[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n vec3 morphed = vec3( 0.0 );\n morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n #ifndef USE_MORPHNORMALS\n\n morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n #endif\n\n morphed += position;\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl - -THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n vec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vReflect = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl - -THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n #ifdef SHADOWMAP_DEBUG\n\n vec3 frustumColors[3];\n frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n #endif\n\n #ifdef SHADOWMAP_CASCADE\n\n int inFrustumCount = 0;\n\n #endif\n\n float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n // if ( something && something ) breaks ATI OpenGL shader compiler\n // if ( all( something, something ) ) using this instead\n\n bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n bool inFrustum = all( inFrustumVec );\n\n // don't shadow pixels outside of light frustum\n // use just first frustum (for cascades)\n // don't shadow pixels behind far plane of light frustum\n\n #ifdef SHADOWMAP_CASCADE\n\n inFrustumCount += int( inFrustum );\n bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n #else\n\n bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n #endif\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest ) {\n\n shadowCoord.z += shadowBias[ i ];\n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\n\n for ( float y = -1.25; y <= 1.25; y += 1.25 )\n for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n\n }\n\n shadow /= 9.0;\n\n */\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.25 * xPixelOffset;\n float dy0 = -1.25 * yPixelOffset;\n float dx1 = 1.25 * xPixelOffset;\n float dy1 = 1.25 * yPixelOffset;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.0 * xPixelOffset;\n float dy0 = -1.0 * yPixelOffset;\n float dx1 = 1.0 * xPixelOffset;\n float dy1 = 1.0 * yPixelOffset;\n\n mat3 shadowKernel;\n mat3 depthKernel;\n\n depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n vec3 shadowZ = vec3( shadowCoord.z );\n shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n shadowKernel[0] *= vec3(0.25);\n\n shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n shadowKernel[1] *= vec3(0.25);\n\n shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n shadowKernel[2] *= vec3(0.25);\n\n vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n vec4 shadowValues;\n shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n shadow = dot( shadowValues, vec4( 1.0 ) );\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #else\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n\n // spot with multiple shadows is darker\n\n shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n #ifdef SHADOWMAP_CASCADE\n\n if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n #else\n\n if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n #endif\n\n #endif\n\n }\n\n // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n shadowColor = inputToLinear( shadowColor );\n\n outgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl - -THREE.ShaderChunk[ 'worldpos_vertex'] = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n #ifdef USE_SKINNING\n\n vec4 worldPosition = modelMatrix * skinned;\n\n #elif defined( USE_MORPHTARGETS )\n\n vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl - -THREE.ShaderChunk[ 'shadowmap_pars_fragment'] = "#ifdef USE_SHADOWMAP\n\n uniform sampler2D shadowMap[ MAX_SHADOWS ];\n uniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n uniform float shadowDarkness[ MAX_SHADOWS ];\n uniform float shadowBias[ MAX_SHADOWS ];\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n float unpackDepth( const in vec4 rgba_depth ) {\n\n const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n float depth = dot( rgba_depth, bit_shift );\n return depth;\n\n }\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl - -THREE.ShaderChunk[ 'skinning_pars_vertex'] = "#ifdef USE_SKINNING\n\n uniform mat4 bindMatrix;\n uniform mat4 bindMatrixInverse;\n\n #ifdef BONE_TEXTURE\n\n uniform sampler2D boneTexture;\n uniform int boneTextureWidth;\n uniform int boneTextureHeight;\n\n mat4 getBoneMatrix( const in float i ) {\n\n float j = i * 4.0;\n float x = mod( j, float( boneTextureWidth ) );\n float y = floor( j / float( boneTextureWidth ) );\n\n float dx = 1.0 / float( boneTextureWidth );\n float dy = 1.0 / float( boneTextureHeight );\n\n y = dy * ( y + 0.5 );\n\n vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n mat4 bone = mat4( v1, v2, v3, v4 );\n\n return bone;\n\n }\n\n #else\n\n uniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n mat4 getBoneMatrix( const in float i ) {\n\n mat4 bone = boneGlobalMatrices[ int(i) ];\n return bone;\n\n }\n\n #endif\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl - -THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n uniform float logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n #extension GL_EXT_frag_depth : enable\n varying float vFragDepth;\n\n #endif\n\n#endif"; - -// File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl - -THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; - -// File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl - -THREE.ShaderChunk[ 'alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n uniform sampler2D alphaMap;\n\n#endif\n"; - -// File:src/renderers/shaders/UniformsUtils.js - -/** - * Uniform Utilities - */ - -THREE.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 instanceof THREE.Color || - parameter_src instanceof THREE.Vector2 || - parameter_src instanceof THREE.Vector3 || - parameter_src instanceof THREE.Vector4 || - parameter_src instanceof THREE.Matrix4 || - parameter_src instanceof THREE.Texture ) { - - uniforms_dst[ u ][ p ] = parameter_src.clone(); - - } else if ( parameter_src instanceof Array ) { - - uniforms_dst[ u ][ p ] = parameter_src.slice(); - - } else { - - uniforms_dst[ u ][ p ] = parameter_src; - - } - - } - - } - - return uniforms_dst; - - } - -}; - -// File:src/renderers/shaders/UniformsLib.js - -/** - * Uniforms library for shared webgl shaders - */ - -THREE.UniformsLib = { - - common: { - - "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - - "map" : { type: "t", value: null }, - "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - - "lightMap" : { type: "t", value: null }, - "specularMap" : { type: "t", value: null }, - "alphaMap" : { type: "t", value: null }, - - "envMap" : { type: "t", value: null }, - "flipEnvMap" : { type: "f", value: - 1 }, - "reflectivity" : { type: "f", value: 1.0 }, - "refractionRatio" : { type: "f", value: 0.98 }, - - "morphTargetInfluences" : { type: "f", value: 0 } - - }, - - bump: { - - "bumpMap" : { type: "t", value: null }, - "bumpScale" : { type: "f", value: 1 } - - }, - - normalmap: { - - "normalMap" : { type: "t", value: null }, - "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } - }, - - fog : { - - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - - }, - - lights: { - - "ambientLightColor" : { type: "fv", value: [] }, - - "directionalLightDirection" : { type: "fv", value: [] }, - "directionalLightColor" : { type: "fv", value: [] }, - - "hemisphereLightDirection" : { type: "fv", value: [] }, - "hemisphereLightSkyColor" : { type: "fv", value: [] }, - "hemisphereLightGroundColor" : { type: "fv", value: [] }, - - "pointLightColor" : { type: "fv", value: [] }, - "pointLightPosition" : { type: "fv", value: [] }, - "pointLightDistance" : { type: "fv1", value: [] }, - "pointLightDecay" : { type: "fv1", value: [] }, - - "spotLightColor" : { type: "fv", value: [] }, - "spotLightPosition" : { type: "fv", value: [] }, - "spotLightDirection" : { type: "fv", value: [] }, - "spotLightDistance" : { type: "fv1", value: [] }, - "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] }, - "spotLightDecay" : { type: "fv1", value: [] } - - }, - - particle: { - - "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - "size" : { type: "f", value: 1.0 }, - "scale" : { type: "f", value: 1.0 }, - "map" : { type: "t", value: null }, - "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - - }, - - shadowmap: { - - "shadowMap": { type: "tv", value: [] }, - "shadowMapSize": { type: "v2v", value: [] }, - - "shadowBias" : { type: "fv1", value: [] }, - "shadowDarkness": { type: "fv1", value: [] }, - - "shadowMatrix" : { type: "m4v", value: [] } - - } - -}; - -// File:src/renderers/shaders/ShaderLib.js - -/** - * Webgl Shader Library for three.js - * - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - */ - - -THREE.ShaderLib = { - - 'basic': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "shadowmap" ] - - ] ), - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - - " #ifdef USE_ENVMAP", - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - " #endif", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 diffuse;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "alphamap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "alphamap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - - " outgoingLight = diffuseColor.rgb;", // simple shader - - THREE.ShaderChunk[ "lightmap_fragment" ], // TODO: Light map on an otherwise unlit surface doesn't make sense. - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], // TODO: Shadows on an otherwise unlit surface doesn't make sense. - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'lambert': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - - { - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } - - ] ), - - vertexShader: [ - - "#define LAMBERT", - - "varying vec3 vLightFront;", - - "#ifdef DOUBLE_SIDED", - - " varying vec3 vLightBack;", - - "#endif", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_lambert_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - "uniform float opacity;", - - "varying vec3 vLightFront;", - - "#ifdef DOUBLE_SIDED", - - " varying vec3 vLightBack;", - - "#endif", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "alphamap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "alphamap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - - " #ifdef DOUBLE_SIDED", - - //"float isFront = float( gl_FrontFacing );", - //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", - - " if ( gl_FrontFacing )", - " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - " else", - " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", - - " #else", - - " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - - " #endif", - - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'phong': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bump" ], - THREE.UniformsLib[ "normalmap" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - - { - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, - "shininess": { type: "f", value: 30 }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } - - ] ), - - vertexShader: [ - - "#define PHONG", - - "varying vec3 vViewPosition;", - - "#ifndef FLAT_SHADED", - - " varying vec3 vNormal;", - - "#endif", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_phong_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED - - " vNormal = normalize( transformedNormal );", - - "#endif", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - " vViewPosition = -mvPosition.xyz;", - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_phong_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "#define PHONG", - - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "alphamap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "lights_phong_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "alphamap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - - THREE.ShaderChunk[ "lights_phong_fragment" ], - - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'particle_basic': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "particle" ], - THREE.UniformsLib[ "shadowmap" ] - - ] ), - - vertexShader: [ - - "uniform float size;", - "uniform float scale;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "color_vertex" ], - - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - - " #ifdef USE_SIZEATTENUATION", - " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", - " #else", - " gl_PointSize = size;", - " #endif", - - " gl_Position = projectionMatrix * mvPosition;", - - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 psColor;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_particle_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( psColor, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - - " outgoingLight = diffuseColor.rgb;", // simple shader - - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'dashed': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - - { - "scale" : { type: "f", value: 1 }, - "dashSize" : { type: "f", value: 1 }, - "totalSize": { type: "f", value: 2 } - } - - ] ), - - vertexShader: [ - - "uniform float scale;", - "attribute float lineDistance;", - - "varying float vLineDistance;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "color_vertex" ], - - " vLineDistance = scale * lineDistance;", - - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * mvPosition;", - - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 diffuse;", - "uniform float opacity;", - - "uniform float dashSize;", - "uniform float totalSize;", - - "varying float vLineDistance;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " if ( mod( vLineDistance, totalSize ) > dashSize ) {", - - " discard;", - - " }", - - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - - " outgoingLight = diffuseColor.rgb;", // simple shader - - THREE.ShaderChunk[ "fog_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'depth': { - - uniforms: { - - "mNear": { type: "f", value: 1.0 }, - "mFar" : { type: "f", value: 2000.0 }, - "opacity" : { type: "f", value: 1.0 } - - }, - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float mNear;", - "uniform float mFar;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - - " #ifdef USE_LOGDEPTHBUF_EXT", - - " float depth = gl_FragDepthEXT / gl_FragCoord.w;", - - " #else", - - " float depth = gl_FragCoord.z / gl_FragCoord.w;", - - " #endif", - - " float color = 1.0 - smoothstep( mNear, mFar, depth );", - " gl_FragColor = vec4( vec3( color ), opacity );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - - "}" - - ].join("\n") - - }, - - 'normal': { - - uniforms: { - - "opacity" : { type: "f", value: 1.0 } - - }, - - vertexShader: [ - - "varying vec3 vNormal;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - " vNormal = normalize( normalMatrix * normal );", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float opacity;", - "varying vec3 vNormal;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - - "}" - - ].join("\n") - - }, - - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - 'cube': { - - uniforms: { "tCube": { type: "t", value: null }, - "tFlip": { type: "f", value: - 1 } }, - - vertexShader: [ - - "varying vec3 vWorldPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - " vWorldPosition = transformDirection( position, modelMatrix );", - - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform samplerCube tCube;", - "uniform float tFlip;", - - "varying vec3 vWorldPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - - "}" - - ].join("\n") - - }, - - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - 'equirect': { - - uniforms: { "tEquirect": { type: "t", value: null }, - "tFlip": { type: "f", value: - 1 } }, - - vertexShader: [ - - "varying vec3 vWorldPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - " vWorldPosition = transformDirection( position, modelMatrix );", - - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform sampler2D tEquirect;", - "uniform float tFlip;", - - "varying vec3 vWorldPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "void main() {", - - // " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", - "vec3 direction = normalize( vWorldPosition );", - "vec2 sampleUV;", - "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", - "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", - "gl_FragColor = texture2D( tEquirect, sampleUV );", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - - "}" - - ].join("\n") - - }, - - /* Depth encoding into RGBA texture - * - * based on SpiderGL shadow map example - * http://spidergl.org/example.php?id=6 - * - * originally from - * http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD - * - * see also - * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ - */ - - 'depthRGBA': { - - uniforms: {}, - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - - "vec4 pack_depth( const in float depth ) {", - - " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", - " res -= res.xxyz * bit_mask;", - " return res;", - - "}", - - "void main() {", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - - " #ifdef USE_LOGDEPTHBUF_EXT", - - " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", - - " #else", - - " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", - - " #endif", - - //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", - //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", - //"gl_FragData[ 0 ] = pack_depth( z );", - //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", - - "}" - - ].join("\n") - - } - -}; - -// File:src/renderers/WebGLRenderer.js - -/** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ - -THREE.WebGLRenderer = function ( parameters ) { - - console.log( 'THREE.WebGLRenderer', THREE.REVISION ); - - parameters = parameters || {}; - - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), - _context = parameters.context !== undefined ? parameters.context : null, - - pixelRatio = 1, - - _precision = parameters.precision !== undefined ? parameters.precision : 'highp', - - _alpha = parameters.alpha !== undefined ? parameters.alpha : false, - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, - - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0; - - var lights = []; - - var _webglObjects = {}; - var _webglObjectsImmediate = []; - - var opaqueObjects = []; - var transparentObjects = []; - - 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; - - // physically based shading - - this.gammaFactor = 2.0; // for backwards compatibility - this.gammaInput = false; - this.gammaOutput = false; - - // shadow map - - this.shadowMapEnabled = false; - this.shadowMapType = THREE.PCFShadowMap; - this.shadowMapCullFace = THREE.CullFaceFront; - this.shadowMapDebug = false; - this.shadowMapCascade = false; - - // morphs - - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; - - // flags - - this.autoScaleCubemaps = true; - - // info - - this.info = { - - memory: { - - programs: 0, - geometries: 0, - textures: 0 - - }, - - render: { - - calls: 0, - vertices: 0, - faces: 0, - points: 0 - - } - - }; - - // internal properties - - var _this = this, - - _programs = [], - - // internal state cache - - _currentProgram = null, - _currentFramebuffer = null, - _currentMaterialId = - 1, - _currentGeometryProgram = '', - _currentCamera = null, - - _usedTextureUnits = 0, - - _viewportX = 0, - _viewportY = 0, - _viewportWidth = _canvas.width, - _viewportHeight = _canvas.height, - _currentWidth = 0, - _currentHeight = 0, - - // frustum - - _frustum = new THREE.Frustum(), - - // camera matrices cache - - _projScreenMatrix = new THREE.Matrix4(), - - _vector3 = new THREE.Vector3(), - - // light arrays cache - - _direction = new THREE.Vector3(), - - _lightsNeedUpdate = true, - - _lights = { - - ambient: [ 0, 0, 0 ], - directional: { length: 0, colors:[], positions: [] }, - point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, - spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, - hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } - - }; - - // initialize - - var _gl; - - try { - - var attributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer - }; - - _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); - - if ( _gl === null ) { - - if ( _canvas.getContext( 'webgl') !== null ) { - - throw 'Error creating WebGL context with your selected attributes.'; - - } else { - - throw 'Error creating WebGL context.'; - - } - - } - - _canvas.addEventListener( 'webglcontextlost', function ( event ) { - - event.preventDefault(); - - resetGLState(); - setDefaultGLState(); - - _webglObjects = {}; - - }, false); - - } catch ( error ) { - - THREE.error( 'THREE.WebGLRenderer: ' + error ); - - } - - var state = new THREE.WebGLState( _gl, paramThreeToGL ); - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function () { - - return { - 'rangeMin': 1, - 'rangeMax': 1, - 'precision': 1 - }; - - } - - } - - var extensions = new THREE.WebGLExtensions( _gl ); - - extensions.get( 'OES_texture_float' ); - extensions.get( 'OES_texture_float_linear' ); - extensions.get( 'OES_texture_half_float' ); - extensions.get( 'OES_texture_half_float_linear' ); - extensions.get( 'OES_standard_derivatives' ); - - if ( _logarithmicDepthBuffer ) { - - extensions.get( 'EXT_frag_depth' ); - - } - - // - - var glClearColor = function ( r, g, b, a ) { - - if ( _premultipliedAlpha === true ) { - - r *= a; g *= a; b *= a; - - } - - _gl.clearColor( r, g, b, a ); - - }; - - var setDefaultGLState = function () { - - _gl.clearColor( 0, 0, 0, 1 ); - _gl.clearDepth( 1 ); - _gl.clearStencil( 0 ); - - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthFunc( _gl.LEQUAL ); - - _gl.frontFace( _gl.CCW ); - _gl.cullFace( _gl.BACK ); - _gl.enable( _gl.CULL_FACE ); - - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); - - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - - glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - - }; - - var resetGLState = function () { - - _currentProgram = null; - _currentCamera = null; - - _currentGeometryProgram = ''; - _currentMaterialId = - 1; - - _lightsNeedUpdate = true; - - state.reset(); - - }; - - setDefaultGLState(); - - this.context = _gl; - this.state = state; - - // GPU capabilities - - var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); - var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); - var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - - var _supportsVertexTextures = _maxVertexTextures > 0; - var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' ); - - // - - var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); - var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); - - var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); - var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); - - var getCompressedTextureFormats = ( function () { - - var array; - - return function () { - - if ( array !== undefined ) { - - return array; - - } - - array = []; - - if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { - - var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); - - for ( var i = 0; i < formats.length; i ++ ) { - - array.push( formats[ i ] ); - - } - - } - - return array; - - }; - - } )(); - - // clamp precision to maximum available - - var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; - var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; - - if ( _precision === 'highp' && ! highpAvailable ) { - - if ( mediumpAvailable ) { - - _precision = 'mediump'; - THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); - - } else { - - _precision = 'lowp'; - THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); - - } - - } - - if ( _precision === 'mediump' && ! mediumpAvailable ) { - - _precision = 'lowp'; - THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); - - } - - // Plugins - - var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate ); - - var spritePlugin = new THREE.SpritePlugin( this, sprites ); - var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.forceContextLoss = function () { - - extensions.get( 'WEBGL_lose_context' ).loseContext(); - - }; - - this.supportsVertexTextures = function () { - - return _supportsVertexTextures; - - }; - - this.supportsFloatTextures = function () { - - return extensions.get( 'OES_texture_float' ); - - }; - - this.supportsHalfFloatTextures = function () { - - return extensions.get( 'OES_texture_half_float' ); - - }; - - this.supportsStandardDerivatives = function () { - - return extensions.get( 'OES_standard_derivatives' ); - - }; - - this.supportsCompressedTextureS3TC = function () { - - return extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - }; - - this.supportsCompressedTexturePVRTC = function () { - - return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - }; - - this.supportsBlendMinMax = function () { - - return extensions.get( 'EXT_blend_minmax' ); - - }; - - this.getMaxAnisotropy = ( function () { - - var value; - - return function () { - - if ( value !== undefined ) { - - return value; - - } - - var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; - - return value; - - } - - } )(); - - this.getPrecision = function () { - - return _precision; - - }; - - this.getPixelRatio = function () { - - return pixelRatio; - - }; - - this.setPixelRatio = function ( value ) { - - pixelRatio = value; - - }; - - this.setSize = function ( width, height, updateStyle ) { - - _canvas.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 ) { - - _viewportX = x * pixelRatio; - _viewportY = y * pixelRatio; - - _viewportWidth = width * pixelRatio; - _viewportHeight = height * pixelRatio; - - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - _gl.scissor( - x * pixelRatio, - y * pixelRatio, - width * pixelRatio, - height * pixelRatio - ); - - }; - - this.enableScissorTest = function ( enable ) { - - enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); - - }; - - // Clearing - - this.getClearColor = function () { - - return _clearColor; - - }; - - this.setClearColor = function ( color, alpha ) { - - _clearColor.set( color ); - - _clearAlpha = alpha !== undefined ? alpha : 1; - - glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - - }; - - this.getClearAlpha = function () { - - return _clearAlpha; - - }; - - this.setClearAlpha = function ( alpha ) { - - _clearAlpha = alpha; - - glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - - }; - - this.clear = function ( color, depth, stencil ) { - - var bits = 0; - - if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; - if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - _gl.clear( _gl.COLOR_BUFFER_BIT ); - - }; - - this.clearDepth = function () { - - _gl.clear( _gl.DEPTH_BUFFER_BIT ); - - }; - - this.clearStencil = function () { - - _gl.clear( _gl.STENCIL_BUFFER_BIT ); - - }; - - this.clearTarget = function ( renderTarget, color, depth, stencil ) { - - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); - - }; - - // Reset - - this.resetGLState = resetGLState; - - // Buffer allocation - - function createParticleBuffers ( geometry ) { - - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); - - _this.info.memory.geometries ++; - - }; - - function createLineBuffers ( geometry ) { - - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); - geometry.__webglLineDistanceBuffer = _gl.createBuffer(); - - _this.info.memory.geometries ++; - - }; - - function createMeshBuffers ( geometryGroup ) { - - geometryGroup.__webglVertexBuffer = _gl.createBuffer(); - geometryGroup.__webglNormalBuffer = _gl.createBuffer(); - geometryGroup.__webglTangentBuffer = _gl.createBuffer(); - geometryGroup.__webglColorBuffer = _gl.createBuffer(); - geometryGroup.__webglUVBuffer = _gl.createBuffer(); - geometryGroup.__webglUV2Buffer = _gl.createBuffer(); - - geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); - geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); - - geometryGroup.__webglFaceBuffer = _gl.createBuffer(); - geometryGroup.__webglLineBuffer = _gl.createBuffer(); - - var numMorphTargets = geometryGroup.numMorphTargets; - - if ( numMorphTargets ) { - - geometryGroup.__webglMorphTargetsBuffers = []; - - for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { - - geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); - - } - - } - - var numMorphNormals = geometryGroup.numMorphNormals; - - if ( numMorphNormals ) { - - geometryGroup.__webglMorphNormalsBuffers = []; - - for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { - - geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); - - } - - } - - _this.info.memory.geometries ++; - - }; - - // Events - - var onObjectRemoved = function ( event ) { - - var object = event.target; - - object.traverse( function ( child ) { - - child.removeEventListener( 'remove', onObjectRemoved ); - - removeObject( child ); - - } ); - - }; - - var onGeometryDispose = function ( event ) { - - var geometry = event.target; - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - deallocateGeometry( geometry ); - - }; - - var onTextureDispose = function ( event ) { - - var texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - _this.info.memory.textures --; - - - }; - - var onRenderTargetDispose = function ( event ) { - - var renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - _this.info.memory.textures --; - - }; - - var onMaterialDispose = function ( event ) { - - var material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - }; - - // Buffer deallocation - - var deleteBuffers = function ( geometry ) { - - var buffers = [ - '__webglVertexBuffer', - '__webglNormalBuffer', - '__webglTangentBuffer', - '__webglColorBuffer', - '__webglUVBuffer', - '__webglUV2Buffer', - - '__webglSkinIndicesBuffer', - '__webglSkinWeightsBuffer', - - '__webglFaceBuffer', - '__webglLineBuffer', - - '__webglLineDistanceBuffer' - ]; - - for ( var i = 0, l = buffers.length; i < l; i ++ ) { - - var name = buffers[ i ]; - - if ( geometry[ name ] !== undefined ) { - - _gl.deleteBuffer( geometry[ name ] ); - - delete geometry[ name ]; - - } - - } - - // custom attributes - - if ( geometry.__webglCustomAttributesList !== undefined ) { - - for ( var name in geometry.__webglCustomAttributesList ) { - - _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer ); - - } - - delete geometry.__webglCustomAttributesList; - - } - - _this.info.memory.geometries --; - - }; - - var deallocateGeometry = function ( geometry ) { - - delete geometry.__webglInit; - - if ( geometry instanceof THREE.BufferGeometry ) { - - for ( var name in geometry.attributes ) { - - var attribute = geometry.attributes[ name ]; - - if ( attribute.buffer !== undefined ) { - - _gl.deleteBuffer( attribute.buffer ); - - delete attribute.buffer; - - } - - } - - _this.info.memory.geometries --; - - } else { - - var geometryGroupsList = geometryGroups[ geometry.id ]; - - if ( geometryGroupsList !== undefined ) { - - for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) { - - var geometryGroup = geometryGroupsList[ i ]; - - if ( geometryGroup.numMorphTargets !== undefined ) { - - for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { - - _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); - - } - - delete geometryGroup.__webglMorphTargetsBuffers; - - } - - if ( geometryGroup.numMorphNormals !== undefined ) { - - for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { - - _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); - - } - - delete geometryGroup.__webglMorphNormalsBuffers; - - } - - deleteBuffers( geometryGroup ); - - } - - delete geometryGroups[ geometry.id ]; - - } else { - - deleteBuffers( geometry ); - - } - - } - - // TOFIX: Workaround for deleted geometry being currently bound - - _currentGeometryProgram = ''; - - }; - - var deallocateTexture = function ( texture ) { - - if ( texture.image && texture.image.__webglTextureCube ) { - - // cube texture - - _gl.deleteTexture( texture.image.__webglTextureCube ); - - delete texture.image.__webglTextureCube; - - } else { - - // 2D texture - - if ( texture.__webglInit === undefined ) return; - - _gl.deleteTexture( texture.__webglTexture ); - - delete texture.__webglTexture; - delete texture.__webglInit; - - } - - }; - - var deallocateRenderTarget = function ( renderTarget ) { - - if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return; - - _gl.deleteTexture( renderTarget.__webglTexture ); - - delete renderTarget.__webglTexture; - - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - - for ( var i = 0; i < 6; i ++ ) { - - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); - - } - - } else { - - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); - - } - - delete renderTarget.__webglFramebuffer; - delete renderTarget.__webglRenderbuffer; - - }; - - var deallocateMaterial = function ( material ) { - - var program = material.program.program; - - if ( program === undefined ) return; - - material.program = undefined; - - // only deallocate GL program if this was the last use of shared program - // assumed there is only single copy of any program in the _programs list - // (that's how it's constructed) - - var i, il, programInfo; - var deleteProgram = false; - - for ( i = 0, il = _programs.length; i < il; i ++ ) { - - programInfo = _programs[ i ]; - - if ( programInfo.program === program ) { - - programInfo.usedTimes --; - - if ( programInfo.usedTimes === 0 ) { - - deleteProgram = true; - - } - - break; - - } - - } - - if ( deleteProgram === true ) { - - // avoid using array.splice, this is costlier than creating new array from scratch - - var newPrograms = []; - - for ( i = 0, il = _programs.length; i < il; i ++ ) { - - programInfo = _programs[ i ]; - - if ( programInfo.program !== program ) { - - newPrograms.push( programInfo ); - - } - - } - - _programs = newPrograms; - - _gl.deleteProgram( program ); - - _this.info.memory.programs --; - - } - - }; - - // Buffer initialization - - function initCustomAttributes ( object ) { - - var geometry = object.geometry; - var material = object.material; - - var nvertices = geometry.vertices.length; - - if ( material.attributes ) { - - if ( geometry.__webglCustomAttributesList === undefined ) { - - geometry.__webglCustomAttributesList = []; - - } - - for ( var name in material.attributes ) { - - var attribute = material.attributes[ name ]; - - if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { - - attribute.__webglInitialized = true; - - var size = 1; // "f" and "i" - - if ( attribute.type === 'v2' ) size = 2; - else if ( attribute.type === 'v3' ) size = 3; - else if ( attribute.type === 'v4' ) size = 4; - else if ( attribute.type === 'c' ) size = 3; - - attribute.size = size; - - attribute.array = new Float32Array( nvertices * size ); - - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = name; - - attribute.needsUpdate = true; - - } - - geometry.__webglCustomAttributesList.push( attribute ); - - } - - } - - }; - - function initParticleBuffers ( geometry, object ) { - - var nvertices = geometry.vertices.length; - - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); - - geometry.__webglParticleCount = nvertices; - - initCustomAttributes( object ); - - }; - - function initLineBuffers ( geometry, object ) { - - var nvertices = geometry.vertices.length; - - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); - - geometry.__webglLineCount = nvertices; - - initCustomAttributes( object ); - - }; - - function initMeshBuffers ( geometryGroup, object ) { - - var geometry = object.geometry, - faces3 = geometryGroup.faces3, - - nvertices = faces3.length * 3, - ntris = faces3.length * 1, - nlines = faces3.length * 3, - - material = getBufferMaterial( object, geometryGroup ); - - geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); - geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); - geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); - geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); - - if ( geometry.faceVertexUvs.length > 1 ) { - - geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); - - } - - if ( geometry.hasTangents ) { - - geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); - - } - - if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { - - geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); - geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); - - } - - var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 - - geometryGroup.__typeArray = UintArray; - geometryGroup.__faceArray = new UintArray( ntris * 3 ); - geometryGroup.__lineArray = new UintArray( nlines * 2 ); - - var numMorphTargets = geometryGroup.numMorphTargets; - - if ( numMorphTargets ) { - - geometryGroup.__morphTargetsArrays = []; - - for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { - - geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); - - } - - } - - var numMorphNormals = geometryGroup.numMorphNormals; - - if ( numMorphNormals ) { - - geometryGroup.__morphNormalsArrays = []; - - for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { - - geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); - - } - - } - - geometryGroup.__webglFaceCount = ntris * 3; - geometryGroup.__webglLineCount = nlines * 2; - - - // custom attributes - - if ( material.attributes ) { - - if ( geometryGroup.__webglCustomAttributesList === undefined ) { - - geometryGroup.__webglCustomAttributesList = []; - - } - - for ( var name in material.attributes ) { - - // Do a shallow copy of the attribute object so different geometryGroup chunks use different - // attribute buffers which are correctly indexed in the setMeshBuffers function - - var originalAttribute = material.attributes[ name ]; - - var attribute = {}; - - for ( var property in originalAttribute ) { - - attribute[ property ] = originalAttribute[ property ]; - - } - - if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { - - attribute.__webglInitialized = true; - - var size = 1; // "f" and "i" - - if ( attribute.type === 'v2' ) size = 2; - else if ( attribute.type === 'v3' ) size = 3; - else if ( attribute.type === 'v4' ) size = 4; - else if ( attribute.type === 'c' ) size = 3; - - attribute.size = size; - - attribute.array = new Float32Array( nvertices * size ); - - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = name; - - originalAttribute.needsUpdate = true; - attribute.__original = originalAttribute; - - } - - geometryGroup.__webglCustomAttributesList.push( attribute ); - - } - - } - - geometryGroup.__inittedArrays = true; - - }; - - function getBufferMaterial( object, geometryGroup ) { - - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ geometryGroup.materialIndex ] - : object.material; - - } - - function materialNeedsFaceNormals ( material ) { - - return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading; - - } - - // Buffer setting - - function setParticleBuffers ( geometry, hint, object ) { - - var v, c, vertex, offset, color, - - vertices = geometry.vertices, - vl = vertices.length, - - colors = geometry.colors, - cl = colors.length, - - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - - customAttributes = geometry.__webglCustomAttributesList, - i, il, - ca, cal, value, - customAttribute; - - if ( dirtyVertices ) { - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyColors ) { - - for ( c = 0; c < cl; c ++ ) { - - color = colors[ c ]; - - offset = c * 3; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { - - cal = customAttribute.value.length; - - offset = 0; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - customAttribute.array[ ca ] = customAttribute.value[ ca ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === 'c' ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - customAttribute.needsUpdate = false; - - } - - } - - } - - function setLineBuffers ( geometry, hint ) { - - var v, c, d, vertex, offset, color, - - vertices = geometry.vertices, - colors = geometry.colors, - lineDistances = geometry.lineDistances, - - vl = vertices.length, - cl = colors.length, - dl = lineDistances.length, - - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, - lineDistanceArray = geometry.__lineDistanceArray, - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyLineDistances = geometry.lineDistancesNeedUpdate, - - customAttributes = geometry.__webglCustomAttributesList, - - i, il, - ca, cal, value, - customAttribute; - - if ( dirtyVertices ) { - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyColors ) { - - for ( c = 0; c < cl; c ++ ) { - - color = colors[ c ]; - - offset = c * 3; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - if ( dirtyLineDistances ) { - - for ( d = 0; d < dl; d ++ ) { - - lineDistanceArray[ d ] = lineDistances[ d ]; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { - - offset = 0; - - cal = customAttribute.value.length; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - customAttribute.array[ ca ] = customAttribute.value[ ca ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === 'c' ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - customAttribute.needsUpdate = false; - - } - - } - - } - - } - - function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { - - if ( ! geometryGroup.__inittedArrays ) { - - return; - - } - - var needsFaceNormals = materialNeedsFaceNormals( material ); - - var f, fl, fi, face, - vertexNormals, faceNormal, - vertexColors, faceColor, - vertexTangents, - uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3, - c1, c2, c3, - sw1, sw2, sw3, - si1, si2, si3, - i, il, - vn, uvi, uv2i, - vk, vkl, vka, - nka, chf, faceVertexNormals, - - vertexIndex = 0, - - offset = 0, - offset_uv = 0, - offset_uv2 = 0, - offset_face = 0, - offset_normal = 0, - offset_tangent = 0, - offset_line = 0, - offset_color = 0, - offset_skin = 0, - offset_morphTarget = 0, - offset_custom = 0, - - value, - - vertexArray = geometryGroup.__vertexArray, - uvArray = geometryGroup.__uvArray, - uv2Array = geometryGroup.__uv2Array, - normalArray = geometryGroup.__normalArray, - tangentArray = geometryGroup.__tangentArray, - colorArray = geometryGroup.__colorArray, - - skinIndexArray = geometryGroup.__skinIndexArray, - skinWeightArray = geometryGroup.__skinWeightArray, - - morphTargetsArrays = geometryGroup.__morphTargetsArrays, - morphNormalsArrays = geometryGroup.__morphNormalsArrays, - - customAttributes = geometryGroup.__webglCustomAttributesList, - customAttribute, - - faceArray = geometryGroup.__faceArray, - lineArray = geometryGroup.__lineArray, - - geometry = object.geometry, // this is shared for all chunks - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, - dirtyUvs = geometry.uvsNeedUpdate, - dirtyNormals = geometry.normalsNeedUpdate, - dirtyTangents = geometry.tangentsNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyMorphTargets = geometry.morphTargetsNeedUpdate, - - vertices = geometry.vertices, - chunk_faces3 = geometryGroup.faces3, - obj_faces = geometry.faces, - - obj_uvs = geometry.faceVertexUvs[ 0 ], - obj_uvs2 = geometry.faceVertexUvs[ 1 ], - - obj_skinIndices = geometry.skinIndices, - obj_skinWeights = geometry.skinWeights, - - morphTargets = geometry.morphTargets, - morphNormals = geometry.morphNormals; - - if ( dirtyVertices ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = vertices[ face.a ]; - v2 = vertices[ face.b ]; - v3 = vertices[ face.c ]; - - vertexArray[ offset ] = v1.x; - vertexArray[ offset + 1 ] = v1.y; - vertexArray[ offset + 2 ] = v1.z; - - vertexArray[ offset + 3 ] = v2.x; - vertexArray[ offset + 4 ] = v2.y; - vertexArray[ offset + 5 ] = v2.z; - - vertexArray[ offset + 6 ] = v3.x; - vertexArray[ offset + 7 ] = v3.y; - vertexArray[ offset + 8 ] = v3.z; - - offset += 9; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyMorphTargets ) { - - for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { - - offset_morphTarget = 0; - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - chf = chunk_faces3[ f ]; - face = obj_faces[ chf ]; - - // morph positions - - v1 = morphTargets[ vk ].vertices[ face.a ]; - v2 = morphTargets[ vk ].vertices[ face.b ]; - v3 = morphTargets[ vk ].vertices[ face.c ]; - - vka = morphTargetsArrays[ vk ]; - - vka[ offset_morphTarget ] = v1.x; - vka[ offset_morphTarget + 1 ] = v1.y; - vka[ offset_morphTarget + 2 ] = v1.z; - - vka[ offset_morphTarget + 3 ] = v2.x; - vka[ offset_morphTarget + 4 ] = v2.y; - vka[ offset_morphTarget + 5 ] = v2.z; - - vka[ offset_morphTarget + 6 ] = v3.x; - vka[ offset_morphTarget + 7 ] = v3.y; - vka[ offset_morphTarget + 8 ] = v3.z; - - // morph normals - - if ( material.morphNormals ) { - - if ( needsFaceNormals ) { - - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; - - } else { - - faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; - - n1 = faceVertexNormals.a; - n2 = faceVertexNormals.b; - n3 = faceVertexNormals.c; - - } - - nka = morphNormalsArrays[ vk ]; - - nka[ offset_morphTarget ] = n1.x; - nka[ offset_morphTarget + 1 ] = n1.y; - nka[ offset_morphTarget + 2 ] = n1.z; - - nka[ offset_morphTarget + 3 ] = n2.x; - nka[ offset_morphTarget + 4 ] = n2.y; - nka[ offset_morphTarget + 5 ] = n2.z; - - nka[ offset_morphTarget + 6 ] = n3.x; - nka[ offset_morphTarget + 7 ] = n3.y; - nka[ offset_morphTarget + 8 ] = n3.z; - - } - - // - - offset_morphTarget += 9; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); - - if ( material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); - - } - - } - - } - - if ( obj_skinWeights.length ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - // weights - - sw1 = obj_skinWeights[ face.a ]; - sw2 = obj_skinWeights[ face.b ]; - sw3 = obj_skinWeights[ face.c ]; - - skinWeightArray[ offset_skin ] = sw1.x; - skinWeightArray[ offset_skin + 1 ] = sw1.y; - skinWeightArray[ offset_skin + 2 ] = sw1.z; - skinWeightArray[ offset_skin + 3 ] = sw1.w; - - skinWeightArray[ offset_skin + 4 ] = sw2.x; - skinWeightArray[ offset_skin + 5 ] = sw2.y; - skinWeightArray[ offset_skin + 6 ] = sw2.z; - skinWeightArray[ offset_skin + 7 ] = sw2.w; - - skinWeightArray[ offset_skin + 8 ] = sw3.x; - skinWeightArray[ offset_skin + 9 ] = sw3.y; - skinWeightArray[ offset_skin + 10 ] = sw3.z; - skinWeightArray[ offset_skin + 11 ] = sw3.w; - - // indices - - si1 = obj_skinIndices[ face.a ]; - si2 = obj_skinIndices[ face.b ]; - si3 = obj_skinIndices[ face.c ]; - - skinIndexArray[ offset_skin ] = si1.x; - skinIndexArray[ offset_skin + 1 ] = si1.y; - skinIndexArray[ offset_skin + 2 ] = si1.z; - skinIndexArray[ offset_skin + 3 ] = si1.w; - - skinIndexArray[ offset_skin + 4 ] = si2.x; - skinIndexArray[ offset_skin + 5 ] = si2.y; - skinIndexArray[ offset_skin + 6 ] = si2.z; - skinIndexArray[ offset_skin + 7 ] = si2.w; - - skinIndexArray[ offset_skin + 8 ] = si3.x; - skinIndexArray[ offset_skin + 9 ] = si3.y; - skinIndexArray[ offset_skin + 10 ] = si3.z; - skinIndexArray[ offset_skin + 11 ] = si3.w; - - offset_skin += 12; - - } - - if ( offset_skin > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); - - } - - } - - if ( dirtyColors ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexColors = face.vertexColors; - faceColor = face.color; - - if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) { - - c1 = vertexColors[ 0 ]; - c2 = vertexColors[ 1 ]; - c3 = vertexColors[ 2 ]; - - } else { - - c1 = faceColor; - c2 = faceColor; - c3 = faceColor; - - } - - colorArray[ offset_color ] = c1.r; - colorArray[ offset_color + 1 ] = c1.g; - colorArray[ offset_color + 2 ] = c1.b; - - colorArray[ offset_color + 3 ] = c2.r; - colorArray[ offset_color + 4 ] = c2.g; - colorArray[ offset_color + 5 ] = c2.b; - - colorArray[ offset_color + 6 ] = c3.r; - colorArray[ offset_color + 7 ] = c3.g; - colorArray[ offset_color + 8 ] = c3.b; - - offset_color += 9; - - } - - if ( offset_color > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - } - - if ( dirtyTangents && geometry.hasTangents ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexTangents = face.vertexTangents; - - t1 = vertexTangents[ 0 ]; - t2 = vertexTangents[ 1 ]; - t3 = vertexTangents[ 2 ]; - - tangentArray[ offset_tangent ] = t1.x; - tangentArray[ offset_tangent + 1 ] = t1.y; - tangentArray[ offset_tangent + 2 ] = t1.z; - tangentArray[ offset_tangent + 3 ] = t1.w; - - tangentArray[ offset_tangent + 4 ] = t2.x; - tangentArray[ offset_tangent + 5 ] = t2.y; - tangentArray[ offset_tangent + 6 ] = t2.z; - tangentArray[ offset_tangent + 7 ] = t2.w; - - tangentArray[ offset_tangent + 8 ] = t3.x; - tangentArray[ offset_tangent + 9 ] = t3.y; - tangentArray[ offset_tangent + 10 ] = t3.z; - tangentArray[ offset_tangent + 11 ] = t3.w; - - offset_tangent += 12; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); - - } - - if ( dirtyNormals ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexNormals = face.vertexNormals; - faceNormal = face.normal; - - if ( vertexNormals.length === 3 && needsFaceNormals === false ) { - - for ( i = 0; i < 3; i ++ ) { - - vn = vertexNormals[ i ]; - - normalArray[ offset_normal ] = vn.x; - normalArray[ offset_normal + 1 ] = vn.y; - normalArray[ offset_normal + 2 ] = vn.z; - - offset_normal += 3; - - } - - } else { - - for ( i = 0; i < 3; i ++ ) { - - normalArray[ offset_normal ] = faceNormal.x; - normalArray[ offset_normal + 1 ] = faceNormal.y; - normalArray[ offset_normal + 2 ] = faceNormal.z; - - offset_normal += 3; - - } - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); - - } - - if ( dirtyUvs && obj_uvs ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - fi = chunk_faces3[ f ]; - - uv = obj_uvs[ fi ]; - - if ( uv === undefined ) continue; - - for ( i = 0; i < 3; i ++ ) { - - uvi = uv[ i ]; - - uvArray[ offset_uv ] = uvi.x; - uvArray[ offset_uv + 1 ] = uvi.y; - - offset_uv += 2; - - } - - } - - if ( offset_uv > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); - - } - - } - - if ( dirtyUvs && obj_uvs2 ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - fi = chunk_faces3[ f ]; - - uv2 = obj_uvs2[ fi ]; - - if ( uv2 === undefined ) continue; - - for ( i = 0; i < 3; i ++ ) { - - uv2i = uv2[ i ]; - - uv2Array[ offset_uv2 ] = uv2i.x; - uv2Array[ offset_uv2 + 1 ] = uv2i.y; - - offset_uv2 += 2; - - } - - } - - if ( offset_uv2 > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); - - } - - } - - if ( dirtyElements ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - faceArray[ offset_face ] = vertexIndex; - faceArray[ offset_face + 1 ] = vertexIndex + 1; - faceArray[ offset_face + 2 ] = vertexIndex + 2; - - offset_face += 3; - - lineArray[ offset_line ] = vertexIndex; - lineArray[ offset_line + 1 ] = vertexIndex + 1; - - lineArray[ offset_line + 2 ] = vertexIndex; - lineArray[ offset_line + 3 ] = vertexIndex + 2; - - lineArray[ offset_line + 4 ] = vertexIndex + 1; - lineArray[ offset_line + 5 ] = vertexIndex + 2; - - offset_line += 6; - - vertexIndex += 3; - - } - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( ! customAttribute.__original.needsUpdate ) continue; - - offset_custom = 0; - - if ( customAttribute.size === 1 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; - customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; - customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; - - offset_custom += 3; - - } - - } else if ( customAttribute.boundTo === 'faces' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - customAttribute.array[ offset_custom ] = value; - customAttribute.array[ offset_custom + 1 ] = value; - customAttribute.array[ offset_custom + 2 ] = value; - - offset_custom += 3; - - } - - } - - } else if ( customAttribute.size === 2 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; - - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; - - offset_custom += 6; - - } - - } else if ( customAttribute.boundTo === 'faces' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; - - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; - - offset_custom += 6; - - } - - } - - } else if ( customAttribute.size === 3 ) { - - var pp; - - if ( customAttribute.type === 'c' ) { - - pp = [ 'r', 'g', 'b' ]; - - } else { - - pp = [ 'x', 'y', 'z' ]; - - } - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } else if ( customAttribute.boundTo === 'faces' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } else if ( customAttribute.boundTo === 'faceVertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } else if ( customAttribute.boundTo === 'faces' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } else if ( customAttribute.boundTo === 'faceVertices' ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - } - - } - - if ( dispose ) { - - delete geometryGroup.__inittedArrays; - delete geometryGroup.__colorArray; - delete geometryGroup.__normalArray; - delete geometryGroup.__tangentArray; - delete geometryGroup.__uvArray; - delete geometryGroup.__uv2Array; - delete geometryGroup.__faceArray; - delete geometryGroup.__vertexArray; - delete geometryGroup.__lineArray; - delete geometryGroup.__skinIndexArray; - delete geometryGroup.__skinWeightArray; - - } - - }; - - // Buffer rendering - - this.renderBufferImmediate = function ( object, program, material ) { - - state.initAttributes(); - - if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); - if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); - if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); - if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); - - if ( object.hasPositions ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( program.attributes.position ); - - _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - - if ( material instanceof THREE.MeshPhongMaterial === false && - material.shading === THREE.FlatShading ) { - - var nx, ny, nz, - nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, - normalArray, - i, il = object.count * 3; - - for ( i = 0; i < il; i += 9 ) { - - normalArray = object.normalArray; - - nax = normalArray[ i ]; - nay = normalArray[ i + 1 ]; - naz = normalArray[ i + 2 ]; - - nbx = normalArray[ i + 3 ]; - nby = normalArray[ i + 4 ]; - nbz = normalArray[ i + 5 ]; - - ncx = normalArray[ i + 6 ]; - ncy = normalArray[ i + 7 ]; - ncz = normalArray[ i + 8 ]; - - nx = ( nax + nbx + ncx ) / 3; - ny = ( nay + nby + ncy ) / 3; - nz = ( naz + nbz + ncz ) / 3; - - normalArray[ i ] = nx; - normalArray[ i + 1 ] = ny; - normalArray[ i + 2 ] = nz; - - normalArray[ i + 3 ] = nx; - normalArray[ i + 4 ] = ny; - normalArray[ i + 5 ] = nz; - - normalArray[ i + 6 ] = nx; - normalArray[ i + 7 ] = ny; - normalArray[ i + 8 ] = nz; - - } - - } - - _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( program.attributes.normal ); - - _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasUvs && material.map ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( program.attributes.uv ); - - _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( program.attributes.color ); - - _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } - - state.disableUnusedAttributes(); - - _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); - - object.count = 0; - - }; - - function setupVertexAttributes( material, program, geometry, startIndex ) { - - var geometryAttributes = geometry.attributes; - - var programAttributes = program.attributes; - var programAttributesKeys = program.attributesKeys; - - for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) { - - var key = programAttributesKeys[ i ]; - var programAttribute = programAttributes[ key ]; - - if ( programAttribute >= 0 ) { - - var geometryAttribute = geometryAttributes[ key ]; - - if ( geometryAttribute !== undefined ) { - - var size = geometryAttribute.itemSize; - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); - - state.enableAttribute( programAttribute ); - - _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 - - } else if ( material.defaultAttributeValues !== undefined ) { - - if ( material.defaultAttributeValues[ key ].length === 2 ) { - - _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] ); - - } else if ( material.defaultAttributeValues[ key ].length === 3 ) { - - _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] ); - - } - - } - - } - - } - - state.disableUnusedAttributes(); - - } - - this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { - - if ( material.visible === false ) return; - - updateObject( object ); - - var program = setProgram( camera, lights, fog, material, object ); - - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit; - - if ( geometryProgram !== _currentGeometryProgram ) { - - _currentGeometryProgram = geometryProgram; - updateBuffers = true; - - } - - if ( updateBuffers ) { - - state.initAttributes(); - - } - - // render mesh - - if ( object instanceof THREE.Mesh ) { - - var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES; - - var index = geometry.attributes.index; - - if ( index ) { - - // indexed triangles - - var type, size; - - if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - - type = _gl.UNSIGNED_INT; - size = 4; - - } else { - - type = _gl.UNSIGNED_SHORT; - size = 2; - - } - - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - _gl.drawElements( mode, index.array.length, type, 0 ); - - _this.info.render.calls ++; - _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared - _this.info.render.faces += index.array.length / 3; - - } else { - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, startIndex ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed triangles - - _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - _this.info.render.faces += offsets[ i ].count / 3; - - } - - } - - } else { - - // non-indexed triangles - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - - } - - var position = geometry.attributes[ 'position' ]; - - // render non-indexed triangles - - _gl.drawArrays( mode, 0, position.array.length / position.itemSize ); - - _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / position.itemSize; - _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); - - } - - } else if ( object instanceof THREE.PointCloud ) { - - // render particles - - var mode = _gl.POINTS; - - var index = geometry.attributes.index; - - if ( index ) { - - // indexed points - - var type, size; - - if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - - type = _gl.UNSIGNED_INT; - size = 4; - - } else { - - type = _gl.UNSIGNED_SHORT; - size = 2; - - } - - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - _gl.drawElements( mode, index.array.length, type, 0); - - _this.info.render.calls ++; - _this.info.render.points += index.array.length; - - } else { - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - if ( offsets.length > 1 ) updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, startIndex ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed points - - _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - - _this.info.render.calls ++; - _this.info.render.points += offsets[ i ].count; - - } - - } - - } else { - - // non-indexed points - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - - } - - var position = geometry.attributes.position; - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - _gl.drawArrays( mode, 0, position.array.length / 3 ); - - _this.info.render.calls ++; - _this.info.render.points += position.array.length / 3; - - } else { - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - - _this.info.render.calls ++; - _this.info.render.points += offsets[ i ].count; - - } - - } - - } - - } else if ( object instanceof THREE.Line ) { - - var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - - state.setLineWidth( material.linewidth * pixelRatio ); - - var index = geometry.attributes.index; - - if ( index ) { - - // indexed lines - - var type, size; - - if ( index.array instanceof Uint32Array ) { - - type = _gl.UNSIGNED_INT; - size = 4; - - } else { - - type = _gl.UNSIGNED_SHORT; - size = 2; - - } - - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - _gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array - - _this.info.render.calls ++; - _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared - - } else { - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - if ( offsets.length > 1 ) updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, startIndex ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed lines - - _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - - } - - } - - } else { - - // non-indexed lines - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry, 0 ); - - } - - var position = geometry.attributes.position; - var offsets = geometry.offsets; - - if ( offsets.length === 0 ) { - - _gl.drawArrays( mode, 0, position.array.length / 3 ); - - _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / 3; - - } else { - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; - - } - - } - - } - - } - - }; - - this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { - - if ( material.visible === false ) return; - - updateObject( object ); - - var program = setProgram( camera, lights, fog, material, object ); - - var attributes = program.attributes; - - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit; - - if ( geometryProgram !== _currentGeometryProgram ) { - - _currentGeometryProgram = geometryProgram; - updateBuffers = true; - - } - - if ( updateBuffers ) { - - state.initAttributes(); - - } - - // vertices - - if ( ! material.morphTargets && attributes.position >= 0 ) { - - if ( updateBuffers ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - - state.enableAttribute( attributes.position ); - - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - } else { - - if ( object.morphTargetBase ) { - - setupMorphTargets( material, geometryGroup, object ); - - } - - } - - - if ( updateBuffers ) { - - // custom attributes - - // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers - - if ( geometryGroup.__webglCustomAttributesList ) { - - for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { - - var attribute = geometryGroup.__webglCustomAttributesList[ i ]; - - if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - - state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - - _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); - - } - - } - - } - - - // colors - - if ( attributes.color >= 0 ) { - - if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - - state.enableAttribute( attributes.color ); - - _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues !== undefined ) { - - - _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); - - } - - } - - // normals - - if ( attributes.normal >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - - state.enableAttribute( attributes.normal ); - - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - - } - - // tangents - - if ( attributes.tangent >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - - state.enableAttribute( attributes.tangent ); - - _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); - - } - - // uvs - - if ( attributes.uv >= 0 ) { - - if ( object.geometry.faceVertexUvs[ 0 ] ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - - state.enableAttribute( attributes.uv ); - - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues !== undefined ) { - - - _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); - - } - - } - - if ( attributes.uv2 >= 0 ) { - - if ( object.geometry.faceVertexUvs[ 1 ] ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - - state.enableAttribute( attributes.uv2 ); - - _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues !== undefined ) { - - - _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); - - } - - } - - if ( material.skinning && - attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - - state.enableAttribute( attributes.skinIndex ); - - _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - - state.enableAttribute( attributes.skinWeight ); - - _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); - - } - - // line distances - - if ( attributes.lineDistance >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - - state.enableAttribute( attributes.lineDistance ); - - _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); - - } - - } - - state.disableUnusedAttributes(); - - // render mesh - - if ( object instanceof THREE.Mesh ) { - - var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; - - // wireframe - - if ( material.wireframe ) { - - state.setLineWidth( material.wireframeLinewidth * pixelRatio ); - - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); - - // triangles - - } else { - - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 ); - - } - - _this.info.render.calls ++; - _this.info.render.vertices += geometryGroup.__webglFaceCount; - _this.info.render.faces += geometryGroup.__webglFaceCount / 3; - - // render lines - - } else if ( object instanceof THREE.Line ) { - - var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - - state.setLineWidth( material.linewidth * pixelRatio ); - - _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); - - _this.info.render.calls ++; - - // render particles - - } else if ( object instanceof THREE.PointCloud ) { - - _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); - - _this.info.render.calls ++; - _this.info.render.points += geometryGroup.__webglParticleCount; - - } - - }; - - function setupMorphTargets ( material, geometryGroup, object ) { - - // set base - - var attributes = material.program.attributes; - - if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - - state.enableAttribute( attributes.position ); - - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } else if ( attributes.position >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - - state.enableAttribute( attributes.position ); - - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.morphTargetForcedOrder.length ) { - - // set forced order - - var m = 0; - var order = object.morphTargetForcedOrder; - var influences = object.morphTargetInfluences; - - var attribute; - - while ( m < material.numSupportedMorphTargets && m < order.length ) { - - attribute = attributes[ 'morphTarget' + m ]; - - if ( attribute >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - - state.enableAttribute( attribute ); - - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - - } - - attribute = attributes[ 'morphNormal' + m ]; - - if ( attribute >= 0 && material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - - state.enableAttribute( attribute ); - - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - - } - - object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; - - m ++; - - } - - } else { - - // find the most influencing - - var activeInfluenceIndices = []; - var influences = object.morphTargetInfluences; - var morphTargets = object.geometry.morphTargets; - - if ( influences.length > morphTargets.length ) { - - console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' ); - influences.length = morphTargets.length; - - } - - for ( var i = 0, il = influences.length; i < il; i ++ ) { - - var influence = influences[ i ]; - - activeInfluenceIndices.push( [ influence, i ] ); - - } - - if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { - - activeInfluenceIndices.sort( numericalSort ); - activeInfluenceIndices.length = material.numSupportedMorphTargets; - - } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { - - activeInfluenceIndices.sort( numericalSort ); - - } else if ( activeInfluenceIndices.length === 0 ) { - - activeInfluenceIndices.push( [ 0, 0 ] ); - - } - - var attribute; - - for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) { - - if ( activeInfluenceIndices[ m ] ) { - - var influenceIndex = activeInfluenceIndices[ m ][ 1 ]; - - attribute = attributes[ 'morphTarget' + m ]; - - if ( attribute >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - - state.enableAttribute( attribute ); - - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - - } - - attribute = attributes[ 'morphNormal' + m ]; - - if ( attribute >= 0 && material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - - state.enableAttribute( attribute ); - - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - - } - - object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; - - } else { - - /* - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - if ( material.morphNormals ) { - - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - } - */ - - object.__webglMorphTargetInfluences[ m ] = 0; - - } - - } - - } - - // load updated influences uniform - - if ( material.program.uniforms.morphTargetInfluences !== null ) { - - _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); - - } - - } - - // Sorting - - function painterSortStable ( a, b ) { - - if ( a.object.renderOrder !== b.object.renderOrder ) { - - return a.object.renderOrder - b.object.renderOrder; - - } else if ( a.material.id !== b.material.id ) { - - return a.material.id - b.material.id; - - } else if ( a.z !== b.z ) { - - return a.z - b.z; - - } else { - - return a.id - b.id; - - } - - } - - function reversePainterSortStable ( a, b ) { - - if ( a.object.renderOrder !== b.object.renderOrder ) { - - return a.object.renderOrder - b.object.renderOrder; - - } if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - - } - - function numericalSort ( a, b ) { - - return b[ 0 ] - a[ 0 ]; - - } - - // Rendering - - this.render = function ( scene, camera, renderTarget, forceClear ) { - - if ( camera instanceof THREE.Camera === false ) { - - THREE.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - var fog = scene.fog; - - // reset caching for this frame - - _currentGeometryProgram = ''; - _currentMaterialId = - 1; - _currentCamera = null; - _lightsNeedUpdate = true; - - // update scene graph - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === undefined ) camera.updateMatrixWorld(); - - // update Skeleton objects - - scene.traverse( function ( object ) { - - if ( object instanceof THREE.SkinnedMesh ) { - - object.skeleton.update(); - - } - - } ); - - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - lights.length = 0; - opaqueObjects.length = 0; - transparentObjects.length = 0; - - sprites.length = 0; - lensFlares.length = 0; - - projectObject( scene ); - - if ( _this.sortObjects === true ) { - - opaqueObjects.sort( painterSortStable ); - transparentObjects.sort( reversePainterSortStable ); - - } - - // custom render plugins (pre pass) - - shadowMapPlugin.render( scene, camera ); - - // - - _this.info.render.calls = 0; - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - _this.info.render.points = 0; - - this.setRenderTarget( renderTarget ); - - if ( this.autoClear || forceClear ) { - - this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); - - } - - // set matrices for immediate objects - - for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) { - - var webglObject = _webglObjectsImmediate[ i ]; - var object = webglObject.object; - - if ( object.visible ) { - - setupMatrices( object, camera ); - - unrollImmediateBufferMaterial( webglObject ); - - } - - } - - if ( scene.overrideMaterial ) { - - var overrideMaterial = scene.overrideMaterial; - - setMaterial( overrideMaterial ); - - renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); - renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); - renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial ); - - } else { - - // opaque pass (front-to-back order) - - state.setBlending( THREE.NoBlending ); - - renderObjects( opaqueObjects, camera, lights, fog, null ); - renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null ); - - // transparent pass (back-to-front order) - - renderObjects( transparentObjects, camera, lights, fog, null ); - renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null ); - - } - - // custom render plugins (post pass) - - spritePlugin.render( scene, camera ); - lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); - - // Generate mipmap if we're using any kind of mipmap filtering - - if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { - - updateRenderTargetMipmap( renderTarget ); - - } - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - state.setDepthTest( true ); - state.setDepthWrite( true ); - state.setColorWrite( true ); - - // _gl.finish(); - - }; - - function projectObject( object ) { - - if ( object.visible === false ) return; - - if ( object instanceof THREE.Scene || object instanceof THREE.Group ) { - - // skip - - } else { - - initObject( object ); - - if ( object instanceof THREE.Light ) { - - lights.push( object ); - - } else if ( object instanceof THREE.Sprite ) { - - sprites.push( object ); - - } else if ( object instanceof THREE.LensFlare ) { - - lensFlares.push( object ); - - } else { - - var webglObjects = _webglObjects[ object.id ]; - - if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { - - for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - - var webglObject = webglObjects[ i ]; - - unrollBufferMaterial( webglObject ); - - webglObject.render = true; - - if ( _this.sortObjects === true ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyProjection( _projScreenMatrix ); - - webglObject.z = _vector3.z; - - } - - } - - } - - } - - } - - for ( var i = 0, l = object.children.length; i < l; i ++ ) { - - projectObject( object.children[ i ] ); - - } - - } - - function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { - - var material; - - for ( var i = 0, l = renderList.length; i < l; i ++ ) { - - var webglObject = renderList[ i ]; - - var object = webglObject.object; - var buffer = webglObject.buffer; - - setupMatrices( object, camera ); - - if ( overrideMaterial ) { - - material = overrideMaterial; - - } else { - - material = webglObject.material; - - if ( ! material ) continue; - - setMaterial( material ); - - } - - _this.setMaterialFaces( material ); - - if ( buffer instanceof THREE.BufferGeometry ) { - - _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); - - } else { - - _this.renderBuffer( camera, lights, fog, material, buffer, object ); - - } - - } - - } - - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) { - - var material; - - for ( var i = 0, l = renderList.length; i < l; i ++ ) { - - var webglObject = renderList[ i ]; - var object = webglObject.object; - - if ( object.visible ) { - - if ( overrideMaterial ) { - - material = overrideMaterial; - - } else { - - material = webglObject[ materialType ]; - - if ( ! material ) continue; - - setMaterial( material ); - - } - - _this.renderImmediateObject( camera, lights, fog, material, object ); - - } - - } - - } - - this.renderImmediateObject = function ( camera, lights, fog, material, object ) { - - var program = setProgram( camera, lights, fog, material, object ); - - _currentGeometryProgram = ''; - - _this.setMaterialFaces( material ); - - if ( object.immediateRenderCallback ) { - - object.immediateRenderCallback( program, _gl, _frustum ); - - } else { - - object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } ); - - } - - }; - - function unrollImmediateBufferMaterial ( globject ) { - - var object = globject.object, - material = object.material; - - if ( material.transparent ) { - - globject.transparent = material; - globject.opaque = null; - - } else { - - globject.opaque = material; - globject.transparent = null; - - } - - } - - function unrollBufferMaterial ( globject ) { - - var object = globject.object; - var buffer = globject.buffer; - - var geometry = object.geometry; - var material = object.material; - - if ( material instanceof THREE.MeshFaceMaterial ) { - - var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; - - material = material.materials[ materialIndex ]; - - globject.material = material; - - if ( material.transparent ) { - - transparentObjects.push( globject ); - - } else { - - opaqueObjects.push( globject ); - - } - - } else if ( material ) { - - globject.material = material; - - if ( material.transparent ) { - - transparentObjects.push( globject ); - - } else { - - opaqueObjects.push( globject ); - - } - - } - - } - - function initObject( object ) { - - if ( object.__webglInit === undefined ) { - - object.__webglInit = true; - object._modelViewMatrix = new THREE.Matrix4(); - object._normalMatrix = new THREE.Matrix3(); - - object.addEventListener( 'removed', onObjectRemoved ); - - } - - var geometry = object.geometry; - - if ( geometry === undefined ) { - - // ImmediateRenderObject - - } else if ( geometry.__webglInit === undefined ) { - - geometry.__webglInit = true; - geometry.addEventListener( 'dispose', onGeometryDispose ); - - if ( geometry instanceof THREE.BufferGeometry ) { - - _this.info.memory.geometries ++; - - } else if ( object instanceof THREE.Mesh ) { - - initGeometryGroups( object, geometry ); - - } else if ( object instanceof THREE.Line ) { - - if ( geometry.__webglVertexBuffer === undefined ) { - - createLineBuffers( geometry ); - initLineBuffers( geometry, object ); - - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - geometry.lineDistancesNeedUpdate = true; - - } - - } else if ( object instanceof THREE.PointCloud ) { - - if ( geometry.__webglVertexBuffer === undefined ) { - - createParticleBuffers( geometry ); - initParticleBuffers( geometry, object ); - - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - - } - - } - - } - - if ( object.__webglActive === undefined) { - - object.__webglActive = true; - - if ( object instanceof THREE.Mesh ) { - - if ( geometry instanceof THREE.BufferGeometry ) { - - addBuffer( _webglObjects, geometry, object ); - - } else if ( geometry instanceof THREE.Geometry ) { - - var geometryGroupsList = geometryGroups[ geometry.id ]; - - for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) { - - addBuffer( _webglObjects, geometryGroupsList[ i ], object ); - - } - - } - - } else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) { - - addBuffer( _webglObjects, geometry, object ); - - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - - addBufferImmediate( _webglObjectsImmediate, object ); - - } - - } - - } - - // Geometry splitting - - var geometryGroups = {}; - var geometryGroupCounter = 0; - - function makeGroups( geometry, usesFaceMaterial ) { - - var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535; - - var groupHash, hash_map = {}; - - var numMorphTargets = geometry.morphTargets.length; - var numMorphNormals = geometry.morphNormals.length; - - var group; - var groups = {}; - var groupsList = []; - - for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - - var face = geometry.faces[ f ]; - var materialIndex = usesFaceMaterial ? face.materialIndex : 0; - - if ( ! ( materialIndex in hash_map ) ) { - - hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 }; - - } - - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - - if ( ! ( groupHash in groups ) ) { - - group = { - id: geometryGroupCounter ++, - faces3: [], - materialIndex: materialIndex, - vertices: 0, - numMorphTargets: numMorphTargets, - numMorphNormals: numMorphNormals - }; - - groups[ groupHash ] = group; - groupsList.push( group ); - - } - - if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { - - hash_map[ materialIndex ].counter += 1; - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - - if ( ! ( groupHash in groups ) ) { - - group = { - id: geometryGroupCounter ++, - faces3: [], - materialIndex: materialIndex, - vertices: 0, - numMorphTargets: numMorphTargets, - numMorphNormals: numMorphNormals - }; - - groups[ groupHash ] = group; - groupsList.push( group ); - - } - - } - - groups[ groupHash ].faces3.push( f ); - groups[ groupHash ].vertices += 3; - - } - - return groupsList; - - } - - function initGeometryGroups( object, geometry ) { - - var material = object.material, addBuffers = false; - - if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) { - - delete _webglObjects[ object.id ]; - - geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial ); - - geometry.groupsNeedUpdate = false; - - } - - var geometryGroupsList = geometryGroups[ geometry.id ]; - - // create separate VBOs per geometry chunk - - for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - - var geometryGroup = geometryGroupsList[ i ]; - - // initialise VBO on the first access - - if ( geometryGroup.__webglVertexBuffer === undefined ) { - - createMeshBuffers( geometryGroup ); - initMeshBuffers( geometryGroup, object ); - - geometry.verticesNeedUpdate = true; - geometry.morphTargetsNeedUpdate = true; - geometry.elementsNeedUpdate = true; - geometry.uvsNeedUpdate = true; - geometry.normalsNeedUpdate = true; - geometry.tangentsNeedUpdate = true; - geometry.colorsNeedUpdate = true; - - addBuffers = true; - - } else { - - addBuffers = false; - - } - - if ( addBuffers || object.__webglActive === undefined ) { - - addBuffer( _webglObjects, geometryGroup, object ); - - } - - } - - object.__webglActive = true; - - } - - function addBuffer( objlist, buffer, object ) { - - var id = object.id; - objlist[id] = objlist[id] || []; - objlist[id].push( - { - id: id, - buffer: buffer, - object: object, - material: null, - z: 0 - } - ); - - }; - - function addBufferImmediate( objlist, object ) { - - objlist.push( - { - id: null, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); - - }; - - // Objects updates - - function updateObject( object ) { - - var geometry = object.geometry; - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - var attributesKeys = geometry.attributesKeys; - - for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) { - - var key = attributesKeys[ i ]; - var attribute = attributes[ key ]; - var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; - - if ( attribute.buffer === undefined ) { - - attribute.buffer = _gl.createBuffer(); - _gl.bindBuffer( bufferType, attribute.buffer ); - _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW ); - - attribute.needsUpdate = false; - - } else if ( attribute.needsUpdate === true ) { - - _gl.bindBuffer( bufferType, attribute.buffer ); - - if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges - - _gl.bufferSubData( bufferType, 0, attribute.array ); - - } else if ( attribute.updateRange.count === 0 ) { - - console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' ); - - } else { - - _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT, - attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) ); - - attribute.updateRange.count = 0; // reset range - - } - - attribute.needsUpdate = false; - - } - - } - - } else if ( object instanceof THREE.Mesh ) { - - // check all geometry groups - - if ( geometry.groupsNeedUpdate === true ) { - - initGeometryGroups( object, geometry ); - - } - - var geometryGroupsList = geometryGroups[ geometry.id ]; - - for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - - var geometryGroup = geometryGroupsList[ i ]; - var material = getBufferMaterial( object, geometryGroup ); - - var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || - geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || - geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { - - setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material ); - - } - - } - - geometry.verticesNeedUpdate = false; - geometry.morphTargetsNeedUpdate = false; - geometry.elementsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.tangentsNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } else if ( object instanceof THREE.Line ) { - - var material = getBufferMaterial( object, geometry ); - var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { - - setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); - - } - - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.lineDistancesNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } else if ( object instanceof THREE.PointCloud ) { - - var material = getBufferMaterial( object, geometry ); - var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) { - - setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); - - } - - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } - - } - - // Objects updates - custom attributes check - - function areCustomAttributesDirty( material ) { - - for ( var name in material.attributes ) { - - if ( material.attributes[ name ].needsUpdate ) return true; - - } - - return false; - - } - - function clearCustomAttributes( material ) { - - for ( var name in material.attributes ) { - - material.attributes[ name ].needsUpdate = false; - - } - - } - - // Objects removal - - function removeObject( object ) { - - if ( object instanceof THREE.Mesh || - object instanceof THREE.PointCloud || - object instanceof THREE.Line ) { - - delete _webglObjects[ object.id ]; - - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - - removeInstances( _webglObjectsImmediate, object ); - - } - - delete object.__webglInit; - delete object._modelViewMatrix; - delete object._normalMatrix; - - delete object.__webglActive; - - } - - function removeInstances( objlist, object ) { - - for ( var o = objlist.length - 1; o >= 0; o -- ) { - - if ( objlist[ o ].object === object ) { - - objlist.splice( o, 1 ); - - } - - } - - } - - // Materials - - var shaderIDs = { - MeshDepthMaterial: 'depth', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointCloudMaterial: 'particle_basic' - }; - - function initMaterial( material, lights, fog, object ) { - - material.addEventListener( 'dispose', onMaterialDispose ); - - var shaderID = shaderIDs[ material.type ]; - - if ( shaderID ) { - - var shader = THREE.ShaderLib[ shaderID ]; - - material.__webglShader = { - uniforms: THREE.UniformsUtils.clone( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader - } - - } else { - - material.__webglShader = { - uniforms: material.uniforms, - vertexShader: material.vertexShader, - fragmentShader: material.fragmentShader - } - - } - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - var maxLightCount = allocateLights( lights ); - var maxShadows = allocateShadows( lights ); - var maxBones = allocateBones( object ); - - var parameters = { - - precision: _precision, - supportsVertexTextures: _supportsVertexTextures, - - map: !! material.map, - envMap: !! material.envMap, - envMapMode: material.envMap && material.envMap.mapping, - lightMap: !! material.lightMap, - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - specularMap: !! material.specularMap, - alphaMap: !! material.alphaMap, - - combine: material.combine, - - vertexColors: material.vertexColors, - - fog: fog, - useFog: material.fog, - fogExp: fog instanceof THREE.FogExp2, - - flatShading: material.shading === THREE.FlatShading, - - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: _logarithmicDepthBuffer, - - skinning: material.skinning, - maxBones: maxBones, - useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture, - - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: _this.maxMorphTargets, - maxMorphNormals: _this.maxMorphNormals, - - maxDirLights: maxLightCount.directional, - maxPointLights: maxLightCount.point, - maxSpotLights: maxLightCount.spot, - maxHemiLights: maxLightCount.hemi, - - maxShadows: maxShadows, - shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, - shadowMapType: _this.shadowMapType, - shadowMapDebug: _this.shadowMapDebug, - shadowMapCascade: _this.shadowMapCascade, - - alphaTest: material.alphaTest, - metal: material.metal, - wrapAround: material.wrapAround, - doubleSided: material.side === THREE.DoubleSide, - flipSided: material.side === THREE.BackSide - - }; - - // Generate code - - var chunks = []; - - if ( shaderID ) { - - chunks.push( shaderID ); - - } else { - - chunks.push( material.fragmentShader ); - chunks.push( material.vertexShader ); - - } - - if ( material.defines !== undefined ) { - - for ( var name in material.defines ) { - - chunks.push( name ); - chunks.push( material.defines[ name ] ); - - } - - } - - for ( var name in parameters ) { - - chunks.push( name ); - chunks.push( parameters[ name ] ); - - } - - var code = chunks.join(); - - var program; - - // Check if code has been already compiled - - for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { - - var programInfo = _programs[ p ]; - - if ( programInfo.code === code ) { - - program = programInfo; - program.usedTimes ++; - - break; - - } - - } - - if ( program === undefined ) { - - program = new THREE.WebGLProgram( _this, code, material, parameters ); - _programs.push( program ); - - _this.info.memory.programs = _programs.length; - - } - - material.program = program; - - var attributes = program.attributes; - - if ( material.morphTargets ) { - - material.numSupportedMorphTargets = 0; - - var id, base = 'morphTarget'; - - for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - - id = base + i; - - if ( attributes[ id ] >= 0 ) { - - material.numSupportedMorphTargets ++; - - } - - } - - } - - if ( material.morphNormals ) { - - material.numSupportedMorphNormals = 0; - - var id, base = 'morphNormal'; - - for ( i = 0; i < _this.maxMorphNormals; i ++ ) { - - id = base + i; - - if ( attributes[ id ] >= 0 ) { - - material.numSupportedMorphNormals ++; - - } - - } - - } - - material.uniformsList = []; - - for ( var u in material.__webglShader.uniforms ) { - - var location = material.program.uniforms[ u ]; - - if ( location ) { - material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] ); - } - - } - - } - - function setMaterial( material ) { - - if ( material.transparent === true ) { - - state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - - } else { - - state.setBlending( THREE.NoBlending ); - - } - - state.setDepthTest( material.depthTest ); - state.setDepthWrite( material.depthWrite ); - state.setColorWrite( material.colorWrite ); - state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - } - - function setProgram( camera, lights, fog, material, object ) { - - _usedTextureUnits = 0; - - if ( material.needsUpdate ) { - - if ( material.program ) deallocateMaterial( material ); - - initMaterial( material, lights, fog, object ); - material.needsUpdate = false; - - } - - if ( material.morphTargets ) { - - if ( ! object.__webglMorphTargetInfluences ) { - - object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); - - } - - } - - var refreshProgram = false; - var refreshMaterial = false; - var refreshLights = false; - - var program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.__webglShader.uniforms; - - if ( program.id !== _currentProgram ) { - - _gl.useProgram( program.program ); - _currentProgram = program.id; - - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; - - } - - if ( material.id !== _currentMaterialId ) { - - if ( _currentMaterialId === -1 ) refreshLights = true; - _currentMaterialId = material.id; - - refreshMaterial = true; - - } - - if ( refreshProgram || camera !== _currentCamera ) { - - _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - - if ( _logarithmicDepthBuffer ) { - - _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - - } - - - if ( camera !== _currentCamera ) _currentCamera = camera; - - // load material specific uniforms - // (shader material also gets them for the sake of genericity) - - if ( material instanceof THREE.ShaderMaterial || - material instanceof THREE.MeshPhongMaterial || - material.envMap ) { - - if ( p_uniforms.cameraPosition !== null ) { - - _vector3.setFromMatrixPosition( camera.matrixWorld ); - _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); - - } - - } - - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.ShaderMaterial || - material.skinning ) { - - if ( p_uniforms.viewMatrix !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); - - } - - } - - } - - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen - - if ( material.skinning ) { - - if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); - - } - - if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); - - } - - if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) { - - if ( p_uniforms.boneTexture !== null ) { - - var textureUnit = getTextureUnit(); - - _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); - _this.setTexture( object.skeleton.boneTexture, textureUnit ); - - } - - if ( p_uniforms.boneTextureWidth !== null ) { - - _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); - - } - - if ( p_uniforms.boneTextureHeight !== null ) { - - _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); - - } - - } else if ( object.skeleton && object.skeleton.boneMatrices ) { - - if ( p_uniforms.boneGlobalMatrices !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices ); - - } - - } - - } - - if ( refreshMaterial ) { - - // refresh uniforms common to several materials - - if ( fog && material.fog ) { - - refreshUniformsFog( m_uniforms, fog ); - - } - - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material.lights ) { - - if ( _lightsNeedUpdate ) { - - refreshLights = true; - setupLights( lights ); - _lightsNeedUpdate = false; - } - - if ( refreshLights ) { - refreshUniformsLights( m_uniforms, _lights ); - markUniformsLightsNeedsUpdate( m_uniforms, true ); - } else { - markUniformsLightsNeedsUpdate( m_uniforms, false ); - } - - } - - if ( material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - - } - - // refresh single material specific uniforms - - if ( material instanceof THREE.LineBasicMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - - } else if ( material instanceof THREE.LineDashedMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - refreshUniformsDash( m_uniforms, material ); - - } else if ( material instanceof THREE.PointCloudMaterial ) { - - refreshUniformsParticle( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshPhongMaterial ) { - - refreshUniformsPhong( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshLambertMaterial ) { - - refreshUniformsLambert( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshDepthMaterial ) { - - m_uniforms.mNear.value = camera.near; - m_uniforms.mFar.value = camera.far; - m_uniforms.opacity.value = material.opacity; - - } else if ( material instanceof THREE.MeshNormalMaterial ) { - - m_uniforms.opacity.value = material.opacity; - - } - - if ( object.receiveShadow && ! material._shadowPass ) { - - refreshUniformsShadow( m_uniforms, lights ); - - } - - // load common uniforms - - loadUniformsGeneric( material.uniformsList ); - - } - - loadUniformsMatrices( p_uniforms, object ); - - if ( p_uniforms.modelMatrix !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); - - } - - return program; - - } - - // Uniforms (refresh uniforms objects) - - function refreshUniformsCommon ( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value = material.color; - - uniforms.map.value = material.map; - uniforms.lightMap.value = material.lightMap; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - - var uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; - - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - - } - - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; - - } - - function refreshUniformsLine ( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - - } - - function refreshUniformsDash ( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsParticle ( uniforms, material ) { - - uniforms.psColor.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size; - uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. - - uniforms.map.value = material.map; - - if ( material.map !== null ) { - - var offset = material.map.offset; - var repeat = material.map.repeat; - - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - - } - - } - - function refreshUniformsFog ( uniforms, fog ) { - - uniforms.fogColor.value = fog.color; - - if ( fog instanceof THREE.Fog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog instanceof THREE.FogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - } - - function refreshUniformsPhong ( uniforms, material ) { - - uniforms.shininess.value = material.shininess; - - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; - - if ( material.wrapAround ) { - - uniforms.wrapRGB.value.copy( material.wrapRGB ); - - } - - } - - function refreshUniformsLambert ( uniforms, material ) { - - uniforms.emissive.value = material.emissive; - - if ( material.wrapAround ) { - - uniforms.wrapRGB.value.copy( material.wrapRGB ); - - } - - } - - function refreshUniformsLights ( uniforms, lights ) { - - uniforms.ambientLightColor.value = lights.ambient; - - uniforms.directionalLightColor.value = lights.directional.colors; - uniforms.directionalLightDirection.value = lights.directional.positions; - - uniforms.pointLightColor.value = lights.point.colors; - uniforms.pointLightPosition.value = lights.point.positions; - uniforms.pointLightDistance.value = lights.point.distances; - uniforms.pointLightDecay.value = lights.point.decays; - - uniforms.spotLightColor.value = lights.spot.colors; - uniforms.spotLightPosition.value = lights.spot.positions; - uniforms.spotLightDistance.value = lights.spot.distances; - uniforms.spotLightDirection.value = lights.spot.directions; - uniforms.spotLightAngleCos.value = lights.spot.anglesCos; - uniforms.spotLightExponent.value = lights.spot.exponents; - uniforms.spotLightDecay.value = lights.spot.decays; - - uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; - uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; - uniforms.hemisphereLightDirection.value = lights.hemi.positions; - - } - - // If uniforms are marked as clean, they don't need to be loaded to the GPU. - - function markUniformsLightsNeedsUpdate ( uniforms, value ) { - - uniforms.ambientLightColor.needsUpdate = value; - - uniforms.directionalLightColor.needsUpdate = value; - uniforms.directionalLightDirection.needsUpdate = value; - - uniforms.pointLightColor.needsUpdate = value; - uniforms.pointLightPosition.needsUpdate = value; - uniforms.pointLightDistance.needsUpdate = value; - uniforms.pointLightDecay.needsUpdate = value; - - uniforms.spotLightColor.needsUpdate = value; - uniforms.spotLightPosition.needsUpdate = value; - uniforms.spotLightDistance.needsUpdate = value; - uniforms.spotLightDirection.needsUpdate = value; - uniforms.spotLightAngleCos.needsUpdate = value; - uniforms.spotLightExponent.needsUpdate = value; - uniforms.spotLightDecay.needsUpdate = value; - - uniforms.hemisphereLightSkyColor.needsUpdate = value; - uniforms.hemisphereLightGroundColor.needsUpdate = value; - uniforms.hemisphereLightDirection.needsUpdate = value; - - } - - function refreshUniformsShadow ( uniforms, lights ) { - - if ( uniforms.shadowMatrix ) { - - var j = 0; - - for ( var i = 0, il = lights.length; i < il; i ++ ) { - - var light = lights[ i ]; - - if ( ! light.castShadow ) continue; - - if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { - - uniforms.shadowMap.value[ j ] = light.shadowMap; - uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; - - uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; - - uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; - uniforms.shadowBias.value[ j ] = light.shadowBias; - - j ++; - - } - - } - - } - - } - - // Uniforms (load to GPU) - - function loadUniformsMatrices ( uniforms, object ) { - - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); - - if ( uniforms.normalMatrix ) { - - _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); - - } - - } - - function getTextureUnit() { - - var textureUnit = _usedTextureUnits; - - if ( textureUnit >= _maxTextures ) { - - THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); - - } - - _usedTextureUnits += 1; - - return textureUnit; - - } - - function loadUniformsGeneric ( uniforms ) { - - var texture, textureUnit, offset; - - for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { - - var uniform = uniforms[ j ][ 0 ]; - - // needsUpdate property is not added to all uniforms. - if ( uniform.needsUpdate === false ) continue; - - var type = uniform.type; - var value = uniform.value; - var location = uniforms[ j ][ 1 ]; - - switch ( type ) { - - case '1i': - _gl.uniform1i( location, value ); - break; - - case '1f': - _gl.uniform1f( location, value ); - break; - - case '2f': - _gl.uniform2f( location, value[ 0 ], value[ 1 ] ); - break; - - case '3f': - _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); - break; - - case '4f': - _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); - break; - - case '1iv': - _gl.uniform1iv( location, value ); - break; - - case '3iv': - _gl.uniform3iv( location, value ); - break; - - case '1fv': - _gl.uniform1fv( location, value ); - break; - - case '2fv': - _gl.uniform2fv( location, value ); - break; - - case '3fv': - _gl.uniform3fv( location, value ); - break; - - case '4fv': - _gl.uniform4fv( location, value ); - break; - - case 'Matrix3fv': - _gl.uniformMatrix3fv( location, false, value ); - break; - - case 'Matrix4fv': - _gl.uniformMatrix4fv( location, false, value ); - break; - - // - - case 'i': - - // single integer - _gl.uniform1i( location, value ); - - break; - - case 'f': - - // single float - _gl.uniform1f( location, value ); - - break; - - case 'v2': - - // single THREE.Vector2 - _gl.uniform2f( location, value.x, value.y ); - - break; - - case 'v3': - - // single THREE.Vector3 - _gl.uniform3f( location, value.x, value.y, value.z ); - - break; - - case 'v4': - - // single THREE.Vector4 - _gl.uniform4f( location, value.x, value.y, value.z, value.w ); - - break; - - case 'c': - - // single THREE.Color - _gl.uniform3f( location, value.r, value.g, value.b ); - - break; - - case 'iv1': - - // flat array of integers (JS or typed array) - _gl.uniform1iv( location, value ); - - break; - - case 'iv': - - // flat array of integers with 3 x N size (JS or typed array) - _gl.uniform3iv( location, value ); - - break; - - case 'fv1': - - // flat array of floats (JS or typed array) - _gl.uniform1fv( location, value ); - - break; - - case 'fv': - - // flat array of floats with 3 x N size (JS or typed array) - _gl.uniform3fv( location, value ); - - break; - - case 'v2v': - - // array of THREE.Vector2 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 2 * value.length ); - - } - - for ( var i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 2; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - - } - - _gl.uniform2fv( location, uniform._array ); - - break; - - case 'v3v': - - // array of THREE.Vector3 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 3 * value.length ); - - } - - for ( var i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 3; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - - } - - _gl.uniform3fv( location, uniform._array ); - - break; - - case 'v4v': - - // array of THREE.Vector4 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 4 * value.length ); - - } - - for ( var i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 4; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - uniform._array[ offset + 3 ] = value[ i ].w; - - } - - _gl.uniform4fv( location, uniform._array ); - - break; - - case 'm3': - - // single THREE.Matrix3 - _gl.uniformMatrix3fv( location, false, value.elements ); - - break; - - case 'm3v': - - // array of THREE.Matrix3 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 9 * value.length ); - - } - - for ( var i = 0, il = value.length; i < il; i ++ ) { - - value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); - - } - - _gl.uniformMatrix3fv( location, false, uniform._array ); - - break; - - case 'm4': - - // single THREE.Matrix4 - _gl.uniformMatrix4fv( location, false, value.elements ); - - break; - - case 'm4v': - - // array of THREE.Matrix4 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 16 * value.length ); - - } - - for ( var i = 0, il = value.length; i < il; i ++ ) { - - value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); - - } - - _gl.uniformMatrix4fv( location, false, uniform._array ); - - break; - - case 't': - - // single THREE.Texture (2d or cube) - - texture = value; - textureUnit = getTextureUnit(); - - _gl.uniform1i( location, textureUnit ); - - if ( ! texture ) continue; - - if ( texture instanceof THREE.CubeTexture || - ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ - - setCubeTexture( texture, textureUnit ); - - } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - - setCubeTextureDynamic( texture, textureUnit ); - - } else { - - _this.setTexture( texture, textureUnit ); - - } - - break; - - case 'tv': - - // array of THREE.Texture (2d) - - if ( uniform._array === undefined ) { - - uniform._array = []; - - } - - for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - - uniform._array[ i ] = getTextureUnit(); - - } - - _gl.uniform1iv( location, uniform._array ); - - for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - - texture = uniform.value[ i ]; - textureUnit = uniform._array[ i ]; - - if ( ! texture ) continue; - - _this.setTexture( texture, textureUnit ); - - } - - break; - - default: - - THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); - - } - - } - - } - - function setupMatrices ( object, camera ) { - - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); - - } - - function setColorLinear( array, offset, color, intensity ) { - - array[ offset ] = color.r * intensity; - array[ offset + 1 ] = color.g * intensity; - array[ offset + 2 ] = color.b * intensity; - - } - - function setupLights ( lights ) { - - var l, ll, light, - r = 0, g = 0, b = 0, - color, skyColor, groundColor, - intensity, - distance, - - zlights = _lights, - - dirColors = zlights.directional.colors, - dirPositions = zlights.directional.positions, - - pointColors = zlights.point.colors, - pointPositions = zlights.point.positions, - pointDistances = zlights.point.distances, - pointDecays = zlights.point.decays, - - spotColors = zlights.spot.colors, - spotPositions = zlights.spot.positions, - spotDistances = zlights.spot.distances, - spotDirections = zlights.spot.directions, - spotAnglesCos = zlights.spot.anglesCos, - spotExponents = zlights.spot.exponents, - spotDecays = zlights.spot.decays, - - hemiSkyColors = zlights.hemi.skyColors, - hemiGroundColors = zlights.hemi.groundColors, - hemiPositions = zlights.hemi.positions, - - dirLength = 0, - pointLength = 0, - spotLength = 0, - hemiLength = 0, - - dirCount = 0, - pointCount = 0, - spotCount = 0, - hemiCount = 0, - - dirOffset = 0, - pointOffset = 0, - spotOffset = 0, - hemiOffset = 0; - - for ( l = 0, ll = lights.length; l < ll; l ++ ) { - - light = lights[ l ]; - - if ( light.onlyShadow ) continue; - - color = light.color; - intensity = light.intensity; - distance = light.distance; - - if ( light instanceof THREE.AmbientLight ) { - - if ( ! light.visible ) continue; - - r += color.r; - g += color.g; - b += color.b; - - } else if ( light instanceof THREE.DirectionalLight ) { - - dirCount += 1; - - if ( ! light.visible ) continue; - - _direction.setFromMatrixPosition( light.matrixWorld ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); - - dirOffset = dirLength * 3; - - dirPositions[ dirOffset ] = _direction.x; - dirPositions[ dirOffset + 1 ] = _direction.y; - dirPositions[ dirOffset + 2 ] = _direction.z; - - setColorLinear( dirColors, dirOffset, color, intensity ); - - dirLength += 1; - - } else if ( light instanceof THREE.PointLight ) { - - pointCount += 1; - - if ( ! light.visible ) continue; - - pointOffset = pointLength * 3; - - setColorLinear( pointColors, pointOffset, color, intensity ); - - _vector3.setFromMatrixPosition( light.matrixWorld ); - - pointPositions[ pointOffset ] = _vector3.x; - pointPositions[ pointOffset + 1 ] = _vector3.y; - pointPositions[ pointOffset + 2 ] = _vector3.z; - - // distance is 0 if decay is 0, because there is no attenuation at all. - pointDistances[ pointLength ] = distance; - pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - - pointLength += 1; - - } else if ( light instanceof THREE.SpotLight ) { - - spotCount += 1; - - if ( ! light.visible ) continue; - - spotOffset = spotLength * 3; - - setColorLinear( spotColors, spotOffset, color, intensity ); - - _direction.setFromMatrixPosition( light.matrixWorld ); - - spotPositions[ spotOffset ] = _direction.x; - spotPositions[ spotOffset + 1 ] = _direction.y; - spotPositions[ spotOffset + 2 ] = _direction.z; - - spotDistances[ spotLength ] = distance; - - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); - - spotDirections[ spotOffset ] = _direction.x; - spotDirections[ spotOffset + 1 ] = _direction.y; - spotDirections[ spotOffset + 2 ] = _direction.z; - - spotAnglesCos[ spotLength ] = Math.cos( light.angle ); - spotExponents[ spotLength ] = light.exponent; - spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - - spotLength += 1; - - } else if ( light instanceof THREE.HemisphereLight ) { - - hemiCount += 1; - - if ( ! light.visible ) continue; - - _direction.setFromMatrixPosition( light.matrixWorld ); - _direction.normalize(); - - hemiOffset = hemiLength * 3; - - hemiPositions[ hemiOffset ] = _direction.x; - hemiPositions[ hemiOffset + 1 ] = _direction.y; - hemiPositions[ hemiOffset + 2 ] = _direction.z; - - skyColor = light.color; - groundColor = light.groundColor; - - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - - hemiLength += 1; - - } - - } - - // null eventual remains from removed lights - // (this is to avoid if in shader) - - for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; - for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; - for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; - - zlights.directional.length = dirLength; - zlights.point.length = pointLength; - zlights.spot.length = spotLength; - zlights.hemi.length = hemiLength; - - zlights.ambient[ 0 ] = r; - zlights.ambient[ 1 ] = g; - zlights.ambient[ 2 ] = b; - - } - - // GL state setting - - this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - - if ( cullFace === THREE.CullFaceNone ) { - - _gl.disable( _gl.CULL_FACE ); - - } else { - - if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { - - _gl.frontFace( _gl.CW ); - - } else { - - _gl.frontFace( _gl.CCW ); - - } - - if ( cullFace === THREE.CullFaceBack ) { - - _gl.cullFace( _gl.BACK ); - - } else if ( cullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.FRONT ); - - } else { - - _gl.cullFace( _gl.FRONT_AND_BACK ); - - } - - _gl.enable( _gl.CULL_FACE ); - - } - - }; - - this.setMaterialFaces = function ( material ) { - - state.setDoubleSided( material.side === THREE.DoubleSide ); - state.setFlipSided( material.side === THREE.BackSide ); - - }; - - // Textures - - function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { - - var extension; - - if ( isImagePowerOfTwo ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); - - } else { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - - if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { - - THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - - if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { - - THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); - - } - - } - - extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) { - - if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) { - - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); - texture.__currentAnisotropy = texture.anisotropy; - - } - - } - - } - - this.uploadTexture = function ( texture ) { - - if ( texture.__webglInit === undefined ) { - - texture.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - texture.__webglTexture = _gl.createTexture(); - - _this.info.memory.textures ++; - - } - - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - - texture.image = clampToMaxSize( texture.image, _maxTextureSize ); - - var image = texture.image, - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); - - var mipmap, mipmaps = texture.mipmaps; - - if ( texture instanceof THREE.DataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - texture.generateMipmaps = false; - - } else { - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - - } - - } else if ( texture instanceof THREE.CompressedTexture ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - - if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { - - _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); - - } - - } else { - - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } else { // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - - } - - texture.generateMipmaps = false; - - } else { - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); - - } - - } - - if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - - texture.needsUpdate = false; - - if ( texture.onUpdate ) texture.onUpdate(); - - }; - - this.setTexture = function ( texture, slot ) { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - - if ( texture.needsUpdate ) { - - _this.uploadTexture( texture ); - - } else { - - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - - } - - }; - - function clampToMaxSize ( image, maxSize ) { - - if ( image.width > maxSize || image.height > maxSize ) { - - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. - - var scale = maxSize / Math.max( image.width, image.height ); - - var canvas = document.createElement( '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 ); - - THREE.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 setCubeTexture ( texture, slot ) { - - if ( texture.image.length === 6 ) { - - if ( texture.needsUpdate ) { - - if ( ! texture.image.__webglTextureCube ) { - - texture.addEventListener( 'dispose', onTextureDispose ); - - texture.image.__webglTextureCube = _gl.createTexture(); - - _this.info.memory.textures ++; - - } - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - - var isCompressed = texture instanceof THREE.CompressedTexture; - var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; - - var cubeImage = []; - - for ( var i = 0; i < 6; i ++ ) { - - if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { - - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); - - } else { - - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - - } - - } - - var image = cubeImage[ 0 ], - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); - - for ( var i = 0; i < 6; i ++ ) { - - if ( ! isCompressed ) { - - if ( isDataTexture ) { - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - - } else { - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - - } - - } else { - - var mipmap, mipmaps = cubeImage[ i ].mipmaps; - - for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - - mipmap = mipmaps[ j ]; - - if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - - if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { - - _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); - - } - - } else { - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - if ( texture.generateMipmaps && isImagePowerOfTwo ) { - - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - texture.needsUpdate = false; - - if ( texture.onUpdate ) texture.onUpdate(); - - } else { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - - } - - } - - } - - function setCubeTextureDynamic ( texture, slot ) { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); - - } - - // Render targets - - function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); - - } - - function setupRenderBuffer ( renderbuffer, renderTarget ) { - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - /* For some reason this is not working. Defaulting to RGBA4. - } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - */ - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); - - } - - } - - this.setRenderTarget = function ( renderTarget ) { - - var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - - if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) { - - if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; - if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - renderTarget.__webglTexture = _gl.createTexture(); - - _this.info.memory.textures ++; - - // Setup texture, create render and frame buffers - - var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), - glFormat = paramThreeToGL( renderTarget.format ), - glType = paramThreeToGL( renderTarget.type ); - - if ( isCube ) { - - renderTarget.__webglFramebuffer = []; - renderTarget.__webglRenderbuffer = []; - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); - - for ( var i = 0; i < 6; i ++ ) { - - renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - - setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); - setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); - - } - - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } else { - - renderTarget.__webglFramebuffer = _gl.createFramebuffer(); - - if ( renderTarget.shareDepthFrom ) { - - renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; - - } else { - - renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); - - } - - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - - setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); - - if ( renderTarget.shareDepthFrom ) { - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - - } - - } else { - - setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); - - } - - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - - } - - // Release everything - - if ( isCube ) { - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - - } else { - - _gl.bindTexture( _gl.TEXTURE_2D, null ); - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - var framebuffer, width, height, vx, vy; - - if ( renderTarget ) { - - if ( isCube ) { - - framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; - - } else { - - framebuffer = renderTarget.__webglFramebuffer; - - } - - width = renderTarget.width; - height = renderTarget.height; - - vx = 0; - vy = 0; - - } else { - - framebuffer = null; - - width = _viewportWidth; - height = _viewportHeight; - - vx = _viewportX; - vy = _viewportY; - - } - - if ( framebuffer !== _currentFramebuffer ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.viewport( vx, vy, width, height ); - - _currentFramebuffer = framebuffer; - - } - - _currentWidth = width; - _currentHeight = height; - - }; - - this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { - - if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; - - } - - if ( renderTarget.__webglFramebuffer ) { - - if ( renderTarget.format !== THREE.RGBAFormat ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); - return; - - } - - var restore = false; - - if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); - - restore = true; - - } - - if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - - _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); - - } else { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - - } - - if ( restore ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - - } - - } - - }; - - function updateRenderTargetMipmap ( renderTarget ) { - - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - - } else { - - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_2D ); - _gl.bindTexture( _gl.TEXTURE_2D, null ); - - } - - } - - // Fallback filters for non-power-of-2 textures - - function filterFallback ( f ) { - - if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { - - return _gl.NEAREST; - - } - - return _gl.LINEAR; - - } - - // Map three.js constants to WebGL constants - - function paramThreeToGL ( p ) { - - var extension; - - if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; - if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; - if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; - - if ( p === THREE.NearestFilter ) return _gl.NEAREST; - if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; - if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; - - if ( p === THREE.LinearFilter ) return _gl.LINEAR; - if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; - if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; - - if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; - if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; - if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; - - if ( p === THREE.ByteType ) return _gl.BYTE; - if ( p === THREE.ShortType ) return _gl.SHORT; - if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; - if ( p === THREE.IntType ) return _gl.INT; - if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; - if ( p === THREE.FloatType ) return _gl.FLOAT; - - extension = extensions.get( 'OES_texture_half_float' ); - - if ( extension !== null ) { - - if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; - - } - - if ( p === THREE.AlphaFormat ) return _gl.ALPHA; - if ( p === THREE.RGBFormat ) return _gl.RGB; - if ( p === THREE.RGBAFormat ) return _gl.RGBA; - if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; - if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; - - if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; - if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; - if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; - - if ( p === THREE.ZeroFactor ) return _gl.ZERO; - if ( p === THREE.OneFactor ) return _gl.ONE; - if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; - if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; - if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; - if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; - if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; - if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; - - if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; - if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; - if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - if ( extension !== null ) { - - if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } - - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - if ( extension !== null ) { - - if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - - } - - extension = extensions.get( 'EXT_blend_minmax' ); - - if ( extension !== null ) { - - if ( p === THREE.MinEquation ) return extension.MIN_EXT; - if ( p === THREE.MaxEquation ) return extension.MAX_EXT; - - } - - return 0; - - } - - // Allocations - - function allocateBones ( object ) { - - if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { - - return 1024; - - } else { - - // default for when object is not specified - // ( for example when prebuilding shader - // to be used with multiple objects ) - // - // - leave some extra space for other uniforms - // - limit here is ANGLE's 254 max uniform vectors - // (up to 54 should be safe) - - var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); - var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - - var maxBones = nVertexMatrices; - - if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { - - maxBones = Math.min( object.skeleton.bones.length, maxBones ); - - if ( maxBones < object.skeleton.bones.length ) { - - THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); - - } - - } - - return maxBones; - - } - - } - - function allocateLights( lights ) { - - var dirLights = 0; - var pointLights = 0; - var spotLights = 0; - var hemiLights = 0; - - for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - - var light = lights[ l ]; - - if ( light.onlyShadow || light.visible === false ) continue; - - if ( light instanceof THREE.DirectionalLight ) dirLights ++; - if ( light instanceof THREE.PointLight ) pointLights ++; - if ( light instanceof THREE.SpotLight ) spotLights ++; - if ( light instanceof THREE.HemisphereLight ) hemiLights ++; - - } - - return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights }; - - } - - function allocateShadows( lights ) { - - var maxShadows = 0; - - for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - - var light = lights[ l ]; - - if ( ! light.castShadow ) continue; - - if ( light instanceof THREE.SpotLight ) maxShadows ++; - if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; - - } - - return maxShadows; - - } - - // DEPRECATED - - this.initMaterial = function () { - - THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); - - }; - - this.addPrePlugin = function () { - - THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - - }; - - this.addPostPlugin = function () { - - THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); - - }; - - this.updateShadowMap = function () { - - THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - - }; - -}; - -// File:src/renderers/WebGLRenderTarget.js - -/** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.WebGLRenderTarget = function ( width, height, options ) { - - this.width = width; - this.height = height; - - options = options || {}; - - this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; - - this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; - this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; - - this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; - - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.Vector2( 1, 1 ); - - this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; - this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; - - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - - this.generateMipmaps = true; - - this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; - -}; - -THREE.WebGLRenderTarget.prototype = { - - constructor: THREE.WebGLRenderTarget, - - setSize: function ( width, height ) { - - this.width = width; - this.height = height; - - }, - - clone: function () { - - var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); - - tmp.wrapS = this.wrapS; - tmp.wrapT = this.wrapT; - - tmp.magFilter = this.magFilter; - tmp.minFilter = this.minFilter; - - tmp.anisotropy = this.anisotropy; - - tmp.offset.copy( this.offset ); - tmp.repeat.copy( this.repeat ); - - tmp.format = this.format; - tmp.type = this.type; - - tmp.depthBuffer = this.depthBuffer; - tmp.stencilBuffer = this.stencilBuffer; - - tmp.generateMipmaps = this.generateMipmaps; - - tmp.shareDepthFrom = this.shareDepthFrom; - - return tmp; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); - -// File:src/renderers/WebGLRenderTargetCube.js - -/** - * @author alteredq / http://alteredqualia.com - */ - -THREE.WebGLRenderTargetCube = function ( width, height, options ) { - - THREE.WebGLRenderTarget.call( this, width, height, options ); - - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - -}; - -THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); -THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; - -// File:src/renderers/webgl/WebGLExtensions.js - -/** -* @author mrdoob / http://mrdoob.com/ -*/ - -THREE.WebGLExtensions = function ( gl ) { - - var extensions = {}; - - this.get = function ( name ) { - - if ( extensions[ name ] !== undefined ) { - - return extensions[ name ]; - - } - - var extension; - - switch ( name ) { - - 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; - - default: - extension = gl.getExtension( name ); - - } - - if ( extension === null ) { - - THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - - } - - extensions[ name ] = extension; - - return extension; - - }; - -}; - -// File:src/renderers/webgl/WebGLProgram.js - -THREE.WebGLProgram = ( function () { - - var programIdCount = 0; - - var generateDefines = function ( defines ) { - - var value, chunk, chunks = []; - - for ( var d in defines ) { - - value = defines[ d ]; - if ( value === false ) continue; - - chunk = '#define ' + d + ' ' + value; - chunks.push( chunk ); - - } - - return chunks.join( '\n' ); - - }; - - var cacheUniformLocations = function ( gl, program, identifiers ) { - - var uniforms = {}; - - for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - - var id = identifiers[ i ]; - uniforms[ id ] = gl.getUniformLocation( program, id ); - - } - - return uniforms; - - }; - - var cacheAttributeLocations = function ( gl, program, identifiers ) { - - var attributes = {}; - - for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - - var id = identifiers[ i ]; - attributes[ id ] = gl.getAttribLocation( program, id ); - - } - - return attributes; - - }; - - return function ( renderer, code, material, parameters ) { - - var _this = renderer; - var _gl = _this.context; - - var defines = material.defines; - var uniforms = material.__webglShader.uniforms; - var attributes = material.attributes; - - var vertexShader = material.__webglShader.vertexShader; - var fragmentShader = material.__webglShader.fragmentShader; - - var index0AttributeName = material.index0AttributeName; - - if ( index0AttributeName === undefined && parameters.morphTargets === true ) { - - // programs with morphTargets displace position out of attribute 0 - - index0AttributeName = 'position'; - - } - - var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - - if ( parameters.shadowMapType === THREE.PCFShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - - } else if ( parameters.shadowMapType === THREE.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 THREE.CubeReflectionMapping: - case THREE.CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; - - case THREE.EquirectangularReflectionMapping: - case THREE.EquirectangularRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; - break; - - case THREE.SphericalReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; - break; - - } - - switch ( material.envMap.mapping ) { - - case THREE.CubeRefractionMapping: - case THREE.EquirectangularRefractionMapping: - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; - - } - - switch ( material.combine ) { - - case THREE.MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; - - case THREE.MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; - - case THREE.AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; - - } - - } - - var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - - // console.log( 'building new program ' ); - - // - - var customDefines = generateDefines( defines ); - - // - - var program = _gl.createProgram(); - - var prefix_vertex, prefix_fragment; - - if ( material instanceof THREE.RawShaderMaterial ) { - - prefix_vertex = ''; - prefix_fragment = ''; - - } else { - - prefix_vertex = [ - - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', - - customDefines, - - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - _this.gammaInput ? '#define GAMMA_INPUT' : '', - _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', - '#define GAMMA_FACTOR ' + gammaFactorDefine, - - '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, - '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, - '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, - '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - - '#define MAX_SHADOWS ' + parameters.maxShadows, - - '#define MAX_BONES ' + parameters.maxBones, - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - 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 ? '#define USE_MORPHNORMALS' : '', - parameters.wrapAround ? '#define WRAP_AROUND' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', - parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', - - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - //_this._glExtensionFragDepth ? '#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;', - 'attribute vec2 uv2;', - - '#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', - - '' - - ].join( '\n' ); - - prefix_fragment = [ - - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', - - ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', - - customDefines, - - '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, - '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, - '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, - '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - - '#define MAX_SHADOWS ' + parameters.maxShadows, - - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', - - _this.gammaInput ? '#define GAMMA_INPUT' : '', - _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', - '#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.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - - parameters.flatShading ? '#define FLAT_SHADED': '', - - parameters.metal ? '#define METAL' : '', - parameters.wrapAround ? '#define WRAP_AROUND' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', - parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - //_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - '' - - ].join( '\n' ); - - } - - var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader ); - var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader ); - - _gl.attachShader( program, glVertexShader ); - _gl.attachShader( program, glFragmentShader ); - - if ( index0AttributeName !== undefined ) { - - // Force a particular attribute to index 0. - // because potentially expensive emulation is done by browser if attribute 0 is disabled. - // And, color, for example is often automatically bound to index 0 so disabling it - - _gl.bindAttribLocation( program, 0, index0AttributeName ); - - } - - _gl.linkProgram( program ); - - var programLogInfo = _gl.getProgramInfoLog( program ); - - if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - - THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo ); - - } - - if ( programLogInfo !== '' ) { - - THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo ); - // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); - // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); - - } - - // clean up - - _gl.deleteShader( glVertexShader ); - _gl.deleteShader( glFragmentShader ); - - // cache uniform locations - - var identifiers = [ - - 'viewMatrix', - 'modelViewMatrix', - 'projectionMatrix', - 'normalMatrix', - 'modelMatrix', - 'cameraPosition', - 'morphTargetInfluences', - 'bindMatrix', - 'bindMatrixInverse' - - ]; - - if ( parameters.useVertexTexture ) { - - identifiers.push( 'boneTexture' ); - identifiers.push( 'boneTextureWidth' ); - identifiers.push( 'boneTextureHeight' ); - - } else { - - identifiers.push( 'boneGlobalMatrices' ); - - } - - if ( parameters.logarithmicDepthBuffer ) { - - identifiers.push('logDepthBufFC'); - - } - - - for ( var u in uniforms ) { - - identifiers.push( u ); - - } - - this.uniforms = cacheUniformLocations( _gl, program, identifiers ); - - // cache attributes locations - - identifiers = [ - - 'position', - 'normal', - 'uv', - 'uv2', - 'tangent', - 'color', - 'skinIndex', - 'skinWeight', - 'lineDistance' - - ]; - - for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) { - - identifiers.push( 'morphTarget' + i ); - - } - - for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) { - - identifiers.push( 'morphNormal' + i ); - - } - - for ( var a in attributes ) { - - identifiers.push( a ); - - } - - this.attributes = cacheAttributeLocations( _gl, program, identifiers ); - this.attributesKeys = Object.keys( this.attributes ); - - // - - this.id = programIdCount ++; - this.code = code; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; - - return this; - - }; - -} )(); - -// File:src/renderers/webgl/WebGLShader.js - -THREE.WebGLShader = ( function () { - - var addLineNumbers = function ( string ) { - - var lines = string.split( '\n' ); - - for ( var i = 0; i < lines.length; i ++ ) { - - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - - } - - return lines.join( '\n' ); - - }; - - return function ( gl, type, string ) { - - var shader = gl.createShader( type ); - - gl.shaderSource( shader, string ); - gl.compileShader( shader ); - - if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - - THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); - - } - - if ( gl.getShaderInfoLog( shader ) !== '' ) { - - THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); - - } - - // --enable-privileged-webgl-extension - // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - - return shader; - - }; - -} )(); - -// File:src/renderers/webgl/WebGLState.js - -/** -* @author mrdoob / http://mrdoob.com/ -*/ - -THREE.WebGLState = function ( gl, paramThreeToGL ) { - - var newAttributes = new Uint8Array( 16 ); - var enabledAttributes = new Uint8Array( 16 ); - - var currentBlending = null; - var currentBlendEquation = null; - var currentBlendSrc = null; - var currentBlendDst = null; - var currentBlendEquationAlpha = null; - var currentBlendSrcAlpha = null; - var currentBlendDstAlpha = null; - - var currentDepthTest = null; - var currentDepthWrite = null; - - var currentColorWrite = null; - - var currentDoubleSided = null; - var currentFlipSided = null; - - var currentLineWidth = null; - - var currentPolygonOffset = null; - var currentPolygonOffsetFactor = null; - var currentPolygonOffsetUnits = null; - - this.initAttributes = function () { - - for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { - - newAttributes[ i ] = 0; - - } - - }; - - this.enableAttribute = function ( attribute ) { - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - }; - - this.disableUnusedAttributes = function () { - - for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { - - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - }; - - this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - - if ( blending !== currentBlending ) { - - if ( blending === THREE.NoBlending ) { - - gl.disable( gl.BLEND ); - - } else if ( blending === THREE.AdditiveBlending ) { - - gl.enable( gl.BLEND ); - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - - } else if ( blending === THREE.SubtractiveBlending ) { - - // TODO: Find blendFuncSeparate() combination - gl.enable( gl.BLEND ); - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); - - } else if ( blending === THREE.MultiplyBlending ) { - - // TODO: Find blendFuncSeparate() combination - gl.enable( gl.BLEND ); - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - - } else if ( blending === THREE.CustomBlending ) { - - gl.enable( gl.BLEND ); - - } else { - - gl.enable( gl.BLEND ); - 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; - - } - - if ( blending === THREE.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; - - } - - }; - - this.setDepthTest = function ( depthTest ) { - - if ( currentDepthTest !== depthTest ) { - - if ( depthTest ) { - - gl.enable( gl.DEPTH_TEST ); - - } else { - - gl.disable( gl.DEPTH_TEST ); - - } - - currentDepthTest = depthTest; - - } - - }; - - this.setDepthWrite = function ( depthWrite ) { - - if ( currentDepthWrite !== depthWrite ) { - - gl.depthMask( depthWrite ); - currentDepthWrite = depthWrite; - - } - - }; - - this.setColorWrite = function ( colorWrite ) { - - if ( currentColorWrite !== colorWrite ) { - - gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); - currentColorWrite = colorWrite; - - } - - }; - - this.setDoubleSided = function ( doubleSided ) { - - if ( currentDoubleSided !== doubleSided ) { - - if ( doubleSided ) { - - gl.disable( gl.CULL_FACE ); - - } else { - - gl.enable( gl.CULL_FACE ); - - } - - currentDoubleSided = doubleSided; - - } - - }; - - this.setFlipSided = function ( flipSided ) { - - if ( currentFlipSided !== flipSided ) { - - if ( flipSided ) { - - gl.frontFace( gl.CW ); - - } else { - - gl.frontFace( gl.CCW ); - - } - - currentFlipSided = flipSided; - - } - - }; - - this.setLineWidth = function ( width ) { - - if ( width !== currentLineWidth ) { - - gl.lineWidth( width ); - - currentLineWidth = width; - - } - - }; - - this.setPolygonOffset = function ( polygonoffset, factor, units ) { - - if ( currentPolygonOffset !== polygonoffset ) { - - if ( polygonoffset ) { - - gl.enable( gl.POLYGON_OFFSET_FILL ); - - } else { - - gl.disable( gl.POLYGON_OFFSET_FILL ); - - } - - currentPolygonOffset = polygonoffset; - - } - - if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { - - gl.polygonOffset( factor, units ); - - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; - - } - - }; - - this.reset = function () { - - for ( var i = 0; i < enabledAttributes.length; i ++ ) { - - enabledAttributes[ i ] = 0; - - } - - currentBlending = null; - currentDepthTest = null; - currentDepthWrite = null; - currentColorWrite = null; - currentDoubleSided = null; - currentFlipSided = null; - - }; - -}; - -// File:src/renderers/webgl/plugins/LensFlarePlugin.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.LensFlarePlugin = function ( renderer, flares ) { - - var gl = renderer.context; - - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; - var hasVertexTexture; - - var tempTexture, occlusionTexture; - - var init = function () { - - 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(); - - gl.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 ); - - gl.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 ); - - hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0; - - var shader; - - if ( hasVertexTexture ) { - - 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" ) - - }; - - } else { - - shader = { - - vertexShader: [ - - "uniform lowp int renderType;", - - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", - - "attribute vec2 position;", - "attribute vec2 uv;", - - "varying vec2 vUV;", - - "void main() {", - - "vUV = uv;", - - "vec2 pos = position;", - - "if( renderType == 2 ) {", - - "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: [ - - "precision mediump float;", - - "uniform lowp int renderType;", - - "uniform sampler2D map;", - "uniform sampler2D occlusionMap;", - "uniform float opacity;", - "uniform vec3 color;", - - "varying vec2 vUV;", - - "void main() {", - - // pink square - - "if( renderType == 0 ) {", - - "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", - - // restore - - "} else if( renderType == 1 ) {", - - "gl_FragColor = texture2D( map, vUV );", - - // flare - - "} else {", - - "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", - "visibility = ( 1.0 - visibility / 4.0 );", - - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * visibility;", - "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, viewportWidth, viewportHeight ) { - - if ( flares.length === 0 ) return; - - var tempPosition = new THREE.Vector3(); - - var invAspect = viewportHeight / viewportWidth, - halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; - - var size = 16 / viewportHeight, - scale = new THREE.Vector2( size * invAspect, size ); - - var screenPosition = new THREE.Vector3( 1, 1, 0 ), - screenPositionPixels = new THREE.Vector2( 1, 1 ); - - if ( program === undefined ) { - - init(); - - } - - gl.useProgram( program ); - - gl.enableVertexAttribArray( attributes.vertex ); - gl.enableVertexAttribArray( attributes.uv ); - - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/unforms - - 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 ); - - gl.disable( gl.CULL_FACE ); - gl.depthMask( false ); - - for ( var i = 0, l = flares.length; i < l; i ++ ) { - - size = 16 / viewportHeight; - 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.applyProjection( camera.projectionMatrix ); - - // setup arrays for gl programs - - screenPosition.copy( tempPosition ) - - screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; - screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; - - // screen cull - - if ( hasVertexTexture || ( - screenPositionPixels.x > 0 && - screenPositionPixels.x < viewportWidth && - screenPositionPixels.y > 0 && - screenPositionPixels.y < viewportHeight ) ) { - - // save current RGB to temp texture - - gl.activeTexture( gl.TEXTURE1 ); - gl.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 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 ); - - gl.disable( gl.BLEND ); - gl.enable( gl.DEPTH_TEST ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - - // copy result to occlusionMap - - gl.activeTexture( gl.TEXTURE0 ); - gl.bindTexture( gl.TEXTURE_2D, occlusionTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - - - // restore graphics - - gl.uniform1i( uniforms.renderType, 1 ); - gl.disable( gl.DEPTH_TEST ); - - gl.activeTexture( gl.TEXTURE1 ); - gl.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 ); - gl.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 / viewportHeight; - - 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 ); - - renderer.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - renderer.setTexture( sprite.texture, 1 ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - } - - } - - } - - } - - // restore gl - - gl.enable( gl.CULL_FACE ); - gl.enable( gl.DEPTH_TEST ); - gl.depthMask( 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; - - } - -}; - -// File:src/renderers/webgl/plugins/ShadowMapPlugin.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) { - - var _gl = _renderer.context; - - var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, - - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(), - - _min = new THREE.Vector3(), - _max = new THREE.Vector3(), - - _matrixPosition = new THREE.Vector3(), - - _renderList = []; - - // init - - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); - - _depthMaterial = new THREE.ShaderMaterial( { - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader - } ); - - _depthMaterialMorph = new THREE.ShaderMaterial( { - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - morphTargets: true - } ); - - _depthMaterialSkin = new THREE.ShaderMaterial( { - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - skinning: true - } ); - - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - morphTargets: true, - skinning: true - } ); - - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; - - this.render = function ( scene, camera ) { - - if ( _renderer.shadowMapEnabled === false ) return; - - var i, il, j, jl, n, - - shadowMap, shadowMatrix, shadowCamera, - buffer, material, - webglObject, object, light, - - lights = [], - k = 0, - - fog = null; - - // set GL state for depth map - - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); - - _gl.enable( _gl.CULL_FACE ); - _gl.frontFace( _gl.CCW ); - - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.FRONT ); - - } else { - - _gl.cullFace( _gl.BACK ); - - } - - _renderer.state.setDepthTest( true ); - - // preprocess lights - // - skip lights that are not casting shadows - // - create virtual lights for cascaded shadow maps - - for ( i = 0, il = _lights.length; i < il; i ++ ) { - - light = _lights[ i ]; - - if ( ! light.castShadow ) continue; - - if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { - - for ( n = 0; n < light.shadowCascadeCount; n ++ ) { - - var virtualLight; - - if ( ! light.shadowCascadeArray[ n ] ) { - - virtualLight = createVirtualLight( light, n ); - virtualLight.originalCamera = camera; - - var gyro = new THREE.Gyroscope(); - gyro.position.copy( light.shadowCascadeOffset ); - - gyro.add( virtualLight ); - gyro.add( virtualLight.target ); - - camera.add( gyro ); - - light.shadowCascadeArray[ n ] = virtualLight; - - //console.log( "Created virtualLight", virtualLight ); - - } else { - - virtualLight = light.shadowCascadeArray[ n ]; - - } - - updateVirtualLight( light, n ); - - lights[ k ] = virtualLight; - k ++; - - } - - } else { - - lights[ k ] = light; - k ++; - - } - - } - - // render depth map - - for ( i = 0, il = lights.length; i < il; i ++ ) { - - light = lights[ i ]; - - if ( ! light.shadowMap ) { - - var shadowFilter = THREE.LinearFilter; - - if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { - - shadowFilter = THREE.NearestFilter; - - } - - var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; - - light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); - light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); - - light.shadowMatrix = new THREE.Matrix4(); - - } - - if ( ! light.shadowCamera ) { - - if ( light instanceof THREE.SpotLight ) { - - light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); - - } else if ( light instanceof THREE.DirectionalLight ) { - - light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); - - } else { - - THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); - continue; - - } - - scene.add( light.shadowCamera ); - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - } - - if ( light.shadowCameraVisible && ! light.cameraHelper ) { - - light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); - scene.add( light.cameraHelper ); - - } - - if ( light.isVirtual && virtualLight.originalCamera == camera ) { - - updateShadowCamera( camera, light ); - - } - - shadowMap = light.shadowMap; - shadowMatrix = light.shadowMatrix; - shadowCamera = light.shadowCamera; - - // - - shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); - _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _matrixPosition ); - shadowCamera.updateMatrixWorld(); - - shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); - - // - - if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; - if ( light.shadowCameraVisible ) light.cameraHelper.update(); - - // 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 ); - - // render shadow map - - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); - - // set object matrices & frustum culling - - _renderList.length = 0; - - projectObject( scene, scene, shadowCamera ); - - - // render regular objects - - var objectMaterial, useMorphing, useSkinning; - - for ( j = 0, jl = _renderList.length; j < jl; j ++ ) { - - webglObject = _renderList[ j ]; - - object = webglObject.object; - buffer = webglObject.buffer; - - // culling is overriden globally for all objects - // while rendering depth map - - // need to deal with MeshFaceMaterial somehow - // in that case just use the first of material.materials for now - // (proper solution would require to break objects by materials - // similarly to regular rendering and then set corresponding - // depth materials per each chunk instead of just once per object) - - objectMaterial = getObjectMaterial( object ); - - useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; - - if ( object.customDepthMaterial ) { - - material = object.customDepthMaterial; - - } else if ( useSkinning ) { - - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; - - } else if ( useMorphing ) { - - material = _depthMaterialMorph; - - } else { - - material = _depthMaterial; - - } - - _renderer.setMaterialFaces( objectMaterial ); - - if ( buffer instanceof THREE.BufferGeometry ) { - - _renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object ); - - } else { - - _renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object ); - - } - - } - - // set matrices and render immediate objects - - for ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) { - - webglObject = _webglObjectsImmediate[ j ]; - object = webglObject.object; - - if ( object.visible && object.castShadow ) { - - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - _renderer.renderImmediateObject( shadowCamera, _lights, fog, _depthMaterial, object ); - - } - - } - - } - - // restore GL state - - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); - - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); - - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.BACK ); - - } - - _renderer.resetGLState(); - - }; - - function projectObject( scene, object, shadowCamera ) { - - if ( object.visible ) { - - var webglObjects = _webglObjects[ object.id ]; - - if ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) { - - for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - - var webglObject = webglObjects[ i ]; - - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - _renderList.push( webglObject ); - - } - - } - - for ( var i = 0, l = object.children.length; i < l; i ++ ) { - - projectObject( scene, object.children[ i ], shadowCamera ); - - } - - } - - } - - function createVirtualLight( light, cascade ) { - - var virtualLight = new THREE.DirectionalLight(); - - virtualLight.isVirtual = true; - - virtualLight.onlyShadow = true; - virtualLight.castShadow = true; - - virtualLight.shadowCameraNear = light.shadowCameraNear; - virtualLight.shadowCameraFar = light.shadowCameraFar; - - virtualLight.shadowCameraLeft = light.shadowCameraLeft; - virtualLight.shadowCameraRight = light.shadowCameraRight; - virtualLight.shadowCameraBottom = light.shadowCameraBottom; - virtualLight.shadowCameraTop = light.shadowCameraTop; - - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - - virtualLight.shadowDarkness = light.shadowDarkness; - - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; - virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; - - virtualLight.pointsWorld = []; - virtualLight.pointsFrustum = []; - - var pointsWorld = virtualLight.pointsWorld, - pointsFrustum = virtualLight.pointsFrustum; - - for ( var i = 0; i < 8; i ++ ) { - - pointsWorld[ i ] = new THREE.Vector3(); - pointsFrustum[ i ] = new THREE.Vector3(); - - } - - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; - - pointsFrustum[ 0 ].set( - 1, - 1, nearZ ); - pointsFrustum[ 1 ].set( 1, - 1, nearZ ); - pointsFrustum[ 2 ].set( - 1, 1, nearZ ); - pointsFrustum[ 3 ].set( 1, 1, nearZ ); - - pointsFrustum[ 4 ].set( - 1, - 1, farZ ); - pointsFrustum[ 5 ].set( 1, - 1, farZ ); - pointsFrustum[ 6 ].set( - 1, 1, farZ ); - pointsFrustum[ 7 ].set( 1, 1, farZ ); - - return virtualLight; - - } - - // Synchronize virtual light with the original light - - function updateVirtualLight( light, cascade ) { - - var virtualLight = light.shadowCascadeArray[ cascade ]; - - virtualLight.position.copy( light.position ); - virtualLight.target.position.copy( light.target.position ); - virtualLight.lookAt( virtualLight.target ); - - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - virtualLight.shadowDarkness = light.shadowDarkness; - - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; - - var pointsFrustum = virtualLight.pointsFrustum; - - pointsFrustum[ 0 ].z = nearZ; - pointsFrustum[ 1 ].z = nearZ; - pointsFrustum[ 2 ].z = nearZ; - pointsFrustum[ 3 ].z = nearZ; - - pointsFrustum[ 4 ].z = farZ; - pointsFrustum[ 5 ].z = farZ; - pointsFrustum[ 6 ].z = farZ; - pointsFrustum[ 7 ].z = farZ; - - } - - // Fit shadow camera's ortho frustum to camera frustum - - function updateShadowCamera( camera, light ) { - - var shadowCamera = light.shadowCamera, - pointsFrustum = light.pointsFrustum, - pointsWorld = light.pointsWorld; - - _min.set( Infinity, Infinity, Infinity ); - _max.set( - Infinity, - Infinity, - Infinity ); - - for ( var i = 0; i < 8; i ++ ) { - - var p = pointsWorld[ i ]; - - p.copy( pointsFrustum[ i ] ); - p.unproject( camera ); - - p.applyMatrix4( shadowCamera.matrixWorldInverse ); - - if ( p.x < _min.x ) _min.x = p.x; - if ( p.x > _max.x ) _max.x = p.x; - - if ( p.y < _min.y ) _min.y = p.y; - if ( p.y > _max.y ) _max.y = p.y; - - if ( p.z < _min.z ) _min.z = p.z; - if ( p.z > _max.z ) _max.z = p.z; - - } - - shadowCamera.left = _min.x; - shadowCamera.right = _max.x; - shadowCamera.top = _max.y; - shadowCamera.bottom = _min.y; - - // can't really fit near/far - //shadowCamera.near = _min.z; - //shadowCamera.far = _max.z; - - shadowCamera.updateProjectionMatrix(); - - } - - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use for shadow maps - - function getObjectMaterial( object ) { - - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; - - }; - -}; - -// File:src/renderers/webgl/plugins/SpritePlugin.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SpritePlugin = function ( renderer, sprites ) { - - var gl = renderer.context; - - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; - - var texture; - - // decompose matrixWorld - - var spritePosition = new THREE.Vector3(); - var spriteRotation = new THREE.Quaternion(); - var spriteScale = new THREE.Vector3(); - - var init = function () { - - 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.createElement( 'canvas' ); - canvas.width = 8; - canvas.height = 8; - - var context = canvas.getContext( '2d' ); - context.fillStyle = 'white'; - context.fillRect( 0, 0, 8, 8 ); - - texture = new THREE.Texture( canvas ); - texture.needsUpdate = true; - - }; - - this.render = function ( scene, camera ) { - - if ( sprites.length === 0 ) return; - - // setup gl - - if ( program === undefined ) { - - init(); - - } - - gl.useProgram( program ); - - gl.enableVertexAttribArray( attributes.position ); - gl.enableVertexAttribArray( attributes.uv ); - - gl.disable( gl.CULL_FACE ); - gl.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 ); - - gl.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 instanceof THREE.Fog ) { - - gl.uniform1f( uniforms.fogNear, fog.near ); - gl.uniform1f( uniforms.fogFar, fog.far ); - - gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; - - } else if ( fog instanceof THREE.FogExp2 ) { - - 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; - - 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 ); - - renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - renderer.state.setDepthTest( material.depthTest ); - renderer.state.setDepthWrite( material.depthWrite ); - - if ( material.map && material.map.image && material.map.image.width ) { - - renderer.setTexture( material.map, 0 ); - - } else { - - renderer.setTexture( texture, 0 ); - - } - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - } - - // restore gl - - gl.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;', - 'float 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.z !== b.z ) { - - return b.z - a.z; - - } else { - - return b.id - a.id; - - } - - }; - -}; - -// File:src/extras/GeometryUtils.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.GeometryUtils = { - - merge: function ( geometry1, geometry2, materialIndexOffset ) { - - THREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); - - var matrix; - - if ( geometry2 instanceof THREE.Mesh ) { - - geometry2.matrixAutoUpdate && geometry2.updateMatrix(); - - matrix = geometry2.matrix; - geometry2 = geometry2.geometry; - - } - - geometry1.merge( geometry2, matrix, materialIndexOffset ); - - }, - - center: function ( geometry ) { - - THREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); - return geometry.center(); - - } - -}; - -// File:src/extras/ImageUtils.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author Daosheng Mu / https://github.com/DaoshengMu/ - */ - -THREE.ImageUtils = { - - crossOrigin: undefined, - - loadTexture: function ( url, mapping, onLoad, onError ) { - - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; - - var texture = new THREE.Texture( undefined, mapping ); - - loader.load( url, function ( image ) { - - texture.image = image; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, undefined, function ( event ) { - - if ( onError ) onError( event ); - - } ); - - texture.sourceFile = url; - - return texture; - - }, - - loadTextureCube: function ( array, mapping, onLoad, onError ) { - - var images = []; - - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; - - var texture = new THREE.CubeTexture( images, mapping ); - - // no flipping needed for cube textures - - texture.flipY = false; - - var loaded = 0; - - var loadTexture = function ( i ) { - - loader.load( array[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded += 1; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, undefined, onError ); - - } - - for ( var i = 0, il = array.length; i < il; ++ i ) { - - loadTexture( i ); - - } - - return texture; - - }, - - loadCompressedTexture: function () { - - THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) - - }, - - loadCompressedTextureCube: function () { - - THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) - - }, - - getNormalMap: function ( image, depth ) { - - // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ - - var cross = function ( a, b ) { - - return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; - - } - - var subtract = function ( a, b ) { - - return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; - - } - - var normalize = function ( a ) { - - var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); - return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; - - } - - depth = depth | 1; - - var width = image.width; - var height = image.height; - - var canvas = document.createElement( 'canvas' ); - canvas.width = width; - canvas.height = height; - - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0 ); - - var data = context.getImageData( 0, 0, width, height ).data; - var imageData = context.createImageData( width, height ); - var output = imageData.data; - - for ( var x = 0; x < width; x ++ ) { - - for ( var y = 0; y < height; y ++ ) { - - var ly = y - 1 < 0 ? 0 : y - 1; - var uy = y + 1 > height - 1 ? height - 1 : y + 1; - var lx = x - 1 < 0 ? 0 : x - 1; - var ux = x + 1 > width - 1 ? width - 1 : x + 1; - - var points = []; - var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; - points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); - - var normals = []; - var num_points = points.length; - - for ( var i = 0; i < num_points; i ++ ) { - - var v1 = points[ i ]; - var v2 = points[ ( i + 1 ) % num_points ]; - v1 = subtract( v1, origin ); - v2 = subtract( v2, origin ); - normals.push( normalize( cross( v1, v2 ) ) ); - - } - - var normal = [ 0, 0, 0 ]; - - for ( var i = 0; i < normals.length; i ++ ) { - - normal[ 0 ] += normals[ i ][ 0 ]; - normal[ 1 ] += normals[ i ][ 1 ]; - normal[ 2 ] += normals[ i ][ 2 ]; - - } - - normal[ 0 ] /= normals.length; - normal[ 1 ] /= normals.length; - normal[ 2 ] /= normals.length; - - var idx = ( y * width + x ) * 4; - - output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; - output[ idx + 3 ] = 255; - - } - - } - - context.putImageData( imageData, 0, 0 ); - - return canvas; - - }, - - generateDataTexture: function ( width, height, color ) { - - var size = width * height; - var data = new Uint8Array( 3 * size ); - - var r = Math.floor( color.r * 255 ); - var g = Math.floor( color.g * 255 ); - var b = Math.floor( color.b * 255 ); - - for ( var i = 0; i < size; i ++ ) { - - data[ i * 3 ] = r; - data[ i * 3 + 1 ] = g; - data[ i * 3 + 2 ] = b; - - } - - var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); - texture.needsUpdate = true; - - return texture; - - } - -}; - -// File:src/extras/SceneUtils.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SceneUtils = { - - createMultiMaterialObject: function ( geometry, materials ) { - - var group = new THREE.Object3D(); - - for ( var i = 0, l = materials.length; i < l; i ++ ) { - - group.add( new THREE.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 THREE.Matrix4(); - matrixWorldInverse.getInverse( parent.matrixWorld ); - child.applyMatrix( matrixWorldInverse ); - - scene.remove( child ); - parent.add( child ); - - } - -}; - -// File:src/extras/FontUtils.js - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For Text operations in three.js (See TextGeometry) - * - * It uses techniques used in: - * - * typeface.js and canvastext - * For converting fonts and rendering with javascript - * http://typeface.neocracy.org - * - * Triangulation ported from AS3 - * Simple Polygon Triangulation - * http://actionsnippet.com/?p=1462 - * - * A Method to triangulate shapes with holes - * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ - * - */ - -THREE.FontUtils = { - - faces: {}, - - // Just for now. face[weight][style] - - face: 'helvetiker', - weight: 'normal', - style: 'normal', - size: 150, - divisions: 10, - - getFace: function () { - - try { - - return this.faces[ this.face ][ this.weight ][ this.style ]; - - } catch (e) { - - throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." - - }; - - }, - - loadFace: function ( data ) { - - var family = data.familyName.toLowerCase(); - - var ThreeFont = this; - - ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; - - ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; - ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - - ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - - return data; - - }, - - drawText: function ( text ) { - - // RenderText - - var i, - face = this.getFace(), - scale = this.size / face.resolution, - offset = 0, - chars = String( text ).split( '' ), - length = chars.length; - - var fontPaths = []; - - for ( i = 0; i < length; i ++ ) { - - var path = new THREE.Path(); - - var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); - offset += ret.offset; - - fontPaths.push( ret.path ); - - } - - // get the width - - var width = offset / 2; - // - // for ( p = 0; p < allPts.length; p++ ) { - // - // allPts[ p ].x -= width; - // - // } - - //var extract = this.extractPoints( allPts, characterPts ); - //extract.contour = allPts; - - //extract.paths = fontPaths; - //extract.offset = width; - - return { paths: fontPaths, offset: width }; - - }, - - - - - extractGlyphPoints: function ( c, face, scale, offset, path ) { - - var pts = []; - - var i, i2, divisions, - outline, action, length, - scaleX, scaleY, - x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, - laste, - glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; - - if ( ! glyph ) return; - - if ( glyph.o ) { - - outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - length = outline.length; - - scaleX = scale; - scaleY = scale; - - for ( i = 0; i < length; ) { - - action = outline[ i ++ ]; - - //console.log( action ); - - switch ( action ) { - - case 'm': - - // Move To - - x = outline[ i ++ ] * scaleX + offset; - y = outline[ i ++ ] * scaleY; - - path.moveTo( x, y ); - break; - - case 'l': - - // Line To - - x = outline[ i ++ ] * scaleX + offset; - y = outline[ i ++ ] * scaleY; - path.lineTo( x, y ); - break; - - case 'q': - - // QuadraticCurveTo - - cpx = outline[ i ++ ] * scaleX + offset; - cpy = outline[ i ++ ] * scaleY; - cpx1 = outline[ i ++ ] * scaleX + offset; - cpy1 = outline[ i ++ ] * scaleY; - - path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - } - - } - - break; - - case 'b': - - // Cubic Bezier Curve - - cpx = outline[ i ++ ] * scaleX + offset; - cpy = outline[ i ++ ] * scaleY; - cpx1 = outline[ i ++ ] * scaleX + offset; - cpy1 = outline[ i ++ ] * scaleY; - cpx2 = outline[ i ++ ] * scaleX + offset; - cpy2 = outline[ i ++ ] * scaleY; - - path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - - } - - } - - break; - - } - - } - } - - - - return { offset: glyph.ha * scale, path:path }; - } - -}; - - -THREE.FontUtils.generateShapes = function ( text, parameters ) { - - // Parameters - - parameters = parameters || {}; - - var size = parameters.size !== undefined ? parameters.size : 100; - var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; - - var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; - var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; - var style = parameters.style !== undefined ? parameters.style : 'normal'; - - THREE.FontUtils.size = size; - THREE.FontUtils.divisions = curveSegments; - - THREE.FontUtils.face = font; - THREE.FontUtils.weight = weight; - THREE.FontUtils.style = style; - - // Get a Font data json object - - var data = THREE.FontUtils.drawText( text ); - - var paths = data.paths; - var shapes = []; - - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - - } - - return shapes; - -}; - - -/** - * 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 ( namespace ) { - - var EPSILON = 0.0000000001; - - // takes in an contour array and returns - - var process = function ( 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 ( 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. - THREE.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); - - 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; - - }; - - // calculate area of the contour polygon - - var 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; - - }; - - var snip = function ( 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 ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) 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 >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false; - - } - - return true; - - }; - - - namespace.Triangulate = process; - namespace.Triangulate.area = area; - - return namespace; - -} )( THREE.FontUtils ); - -// To use the typeface.js face files, hook up the API -self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; -THREE.typeface_js = self._typeface_js; - -// File:src/extras/audio/Audio.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Audio = function ( listener ) { - - THREE.Object3D.call( this ); - - this.type = 'Audio'; - - this.context = listener.context; - this.source = this.context.createBufferSource(); - this.source.onended = this.onEnded.bind(this); - - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); - - this.panner = this.context.createPanner(); - this.panner.connect( this.gain ); - - this.autoplay = false; - - this.startTime = 0; - this.isPlaying = false; - -}; - -THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Audio.prototype.constructor = THREE.Audio; - -THREE.Audio.prototype.load = function ( file ) { - - var scope = this; - - var request = new XMLHttpRequest(); - request.open( 'GET', file, true ); - request.responseType = 'arraybuffer'; - request.onload = function ( e ) { - - scope.context.decodeAudioData( this.response, function ( buffer ) { - - scope.source.buffer = buffer; - - if( scope.autoplay ) scope.play(); - - } ); - - }; - request.send(); - - return this; - -}; - -THREE.Audio.prototype.play = function () { - - if ( this.isPlaying === true ) { - - THREE.warn( 'THREE.Audio: Audio is already playing.' ); - return; - - } - - var source = this.context.createBufferSource(); - - source.buffer = this.source.buffer; - source.loop = this.source.loop; - source.onended = this.source.onended; - source.connect( this.panner ); - source.start( 0, this.startTime ); - - this.isPlaying = true; - - this.source = source; - -}; - -THREE.Audio.prototype.pause = function () { - - this.source.stop(); - this.startTime = this.context.currentTime; - -}; - -THREE.Audio.prototype.stop = function () { - - this.source.stop(); - this.startTime = 0; - -}; - -THREE.Audio.prototype.onEnded = function() { - - this.isPlaying = false; - -}; - -THREE.Audio.prototype.setLoop = function ( value ) { - - this.source.loop = value; - -}; - -THREE.Audio.prototype.setRefDistance = function ( value ) { - - this.panner.refDistance = value; - -}; - -THREE.Audio.prototype.setRolloffFactor = function ( value ) { - - this.panner.rolloffFactor = value; - -}; - -THREE.Audio.prototype.setVolume = function ( value ) { - - this.gain.gain.value = value; - -}; - -THREE.Audio.prototype.updateMatrixWorld = ( function () { - - var position = new THREE.Vector3(); - - return function ( force ) { - - THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); - - position.setFromMatrixPosition( this.matrixWorld ); - - this.panner.setPosition( position.x, position.y, position.z ); - - }; - -} )(); - -// File:src/extras/audio/AudioListener.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.AudioListener = function () { - - THREE.Object3D.call( this ); - - this.type = 'AudioListener'; - - this.context = new ( window.AudioContext || window.webkitAudioContext )(); - -}; - -THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype ); -THREE.AudioListener.prototype.constructor = THREE.AudioListener; - -THREE.AudioListener.prototype.updateMatrixWorld = ( function () { - - var position = new THREE.Vector3(); - var quaternion = new THREE.Quaternion(); - var scale = new THREE.Vector3(); - - var orientation = new THREE.Vector3(); - - return function ( force ) { - - THREE.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 ); - - listener.setPosition( position.x, position.y, position.z ); - listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); - - }; - -} )(); - -// File:src/extras/core/Curve.js - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of Curve methods - * .getPoint(t), getTangent(t) - * .getPointAt(u), getTagentAt(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.SplineCurve3 - * THREE.ClosedSplineCurve3 - * - * A series of curves can be represented as a THREE.CurvePath - * - **/ - -/************************************************************** - * Abstract Curve base class - **************************************************************/ - -THREE.Curve = function () { - -}; - -// Virtual base class method to overwrite and implement in subclasses -// - t [0 .. 1] - -THREE.Curve.prototype.getPoint = function ( t ) { - - THREE.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); - return null; - -}; - -// Get point at relative position in curve according to arc length -// - u [0 .. 1] - -THREE.Curve.prototype.getPointAt = function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getPoint( t ); - -}; - -// Get sequence of points using getPoint( t ) - -THREE.Curve.prototype.getPoints = function ( divisions ) { - - if ( ! divisions ) divisions = 5; - - var d, pts = []; - - for ( d = 0; d <= divisions; d ++ ) { - - pts.push( this.getPoint( d / divisions ) ); - - } - - return pts; - -}; - -// Get sequence of points using getPointAt( u ) - -THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { - - if ( ! divisions ) divisions = 5; - - var d, pts = []; - - for ( d = 0; d <= divisions; d ++ ) { - - pts.push( this.getPointAt( d / divisions ) ); - - } - - return pts; - -}; - -// Get total curve arc length - -THREE.Curve.prototype.getLength = function () { - - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - -}; - -// Get list of cumulative segment lengths - -THREE.Curve.prototype.getLengths = function ( divisions ) { - - if ( ! 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. - -}; - - -THREE.Curve.prototype.updateArcLengths = function() { - this.needsUpdate = true; - this.getLengths(); -}; - -// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance - -THREE.Curve.prototype.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 interpolatation 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 - -THREE.Curve.prototype.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(); - -}; - - -THREE.Curve.prototype.getTangentAt = function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); - -}; - - - - - -/************************************************************** - * Utils - **************************************************************/ - -THREE.Curve.Utils = { - - tangentQuadraticBezier: function ( t, p0, p1, p2 ) { - - return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); - - }, - - // Puay Bing, thanks for helping with this derivative! - - tangentCubicBezier: function (t, p0, p1, p2, p3 ) { - - return - 3 * p0 * (1 - t) * (1 - t) + - 3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) + - 6 * t * p2 * (1 - t) - 3 * t * t * p2 + - 3 * t * t * p3; - - }, - - tangentSpline: function ( t, p0, p1, p2, p3 ) { - - // To check if my formulas are correct - - var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 - var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t - var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2 - var h11 = 3 * t * t - 2 * t; // t3 − t2 - - return h00 + h10 + h01 + h11; - - }, - - // Catmull-Rom - - interpolate: function( p0, p1, p2, p3, t ) { - - 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; - - } - -}; - - -// TODO: Transformation for Curves? - -/************************************************************** - * 3D Curves - **************************************************************/ - -// A Factory method for creating new curve subclasses - -THREE.Curve.create = function ( constructor, getPointFunc ) { - - constructor.prototype = Object.create( THREE.Curve.prototype ); - constructor.prototype.constructor = constructor; - constructor.prototype.getPoint = getPointFunc; - - return constructor; - -}; - -// File:src/extras/core/CurvePath.js - -/** - * @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 - **************************************************************/ - -THREE.CurvePath = function () { - - this.curves = []; - this.bends = []; - - this.autoClose = false; // Automatically closes the path -}; - -THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); -THREE.CurvePath.prototype.constructor = THREE.CurvePath; - -THREE.CurvePath.prototype.add = function ( curve ) { - - this.curves.push( curve ); - -}; - -THREE.CurvePath.prototype.checkConnection = function() { - // TODO - // If the ending of curve is not connected to the starting - // or the next curve, then, this is not a real path -}; - -THREE.CurvePath.prototype.closePath = function() { - // TODO Test - // and verify for vector3 (needs to implement equals) - // 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 THREE.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') - -THREE.CurvePath.prototype.getPoint = function( t ) { - - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0, diff, curve; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - diff = curveLengths[ i ] - d; - curve = this.curves[ i ]; - - var u = 1 - diff / curve.getLength(); - - return curve.getPointAt( u ); - - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; - else if ( p.x < minX ) minX = p.x; - - if ( p.y > maxY ) maxY = p.y; - else if ( p.y < minY ) minY = p.y; - - if ( v3 ) { - - if ( p.z > maxZ ) maxZ = p.z; - else if ( p.z < minZ ) minZ = p.z; - - } - - sum.add( p ); - - } - - var ret = { - - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY - - }; - - if ( v3 ) { - - ret.maxZ = maxZ; - ret.minZ = minZ; - - } - - return ret; - -}; - -/************************************************************** - * Create Geometries Helpers - **************************************************************/ - -/// Generate geometry from path points (for Line or Points objects) - -THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { - - var pts = this.getPoints( divisions, true ); - return this.createGeometry( pts ); - -}; - -// Generate geometry from equidistance sampling along the path - -THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { - - var pts = this.getSpacedPoints( divisions, true ); - return this.createGeometry( pts ); - -}; - -THREE.CurvePath.prototype.createGeometry = function( points ) { - - var geometry = new THREE.Geometry(); - - for ( var i = 0; i < points.length; i ++ ) { - - geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); - - } - - return geometry; - -}; - - -/************************************************************** - * Bend / Wrap Helper Methods - **************************************************************/ - -// Wrap path / Bend modifiers? - -THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { - - this.bends.push( bendpath ); - -}; - -THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { - - var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints - var i, il; - - if ( ! bends ) { - - bends = this.bends; - - } - - for ( i = 0, il = bends.length; i < il; i ++ ) { - - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - - } - - return oldPts; - -}; - -THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { - - var oldPts = this.getSpacedPoints( segments ); - - var i, il; - - if ( ! bends ) { - - bends = this.bends; - - } - - for ( i = 0, il = bends.length; i < il; i ++ ) { - - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - - } - - return oldPts; - -}; - -// This returns getPoints() bend/wrapped around the contour of a path. -// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html - -THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { - - var bounds = this.getBoundingBox(); - - var i, il, p, oldX, oldY, xNorm; - - for ( i = 0, il = oldPts.length; i < il; i ++ ) { - - p = oldPts[ i ]; - - oldX = p.x; - oldY = p.y; - - xNorm = oldX / bounds.maxX; - - // If using actual distance, for length > path, requires line extrusions - //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance - - xNorm = path.getUtoTmapping( xNorm, oldX ); - - // check for out of bounds? - - var pathPt = path.getPoint( xNorm ); - var normal = path.getTangent( xNorm ); - normal.set( - normal.y, normal.x ).multiplyScalar( oldY ); - - p.x = pathPt.x + normal.x; - p.y = pathPt.y + normal.y; - - } - - return oldPts; - -}; - - -// File:src/extras/core/Gyroscope.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Gyroscope = function () { - - THREE.Object3D.call( this ); - -}; - -THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); -THREE.Gyroscope.prototype.constructor = THREE.Gyroscope; - -THREE.Gyroscope.prototype.updateMatrixWorld = ( function () { - - var translationObject = new THREE.Vector3(); - var quaternionObject = new THREE.Quaternion(); - var scaleObject = new THREE.Vector3(); - - var translationWorld = new THREE.Vector3(); - var quaternionWorld = new THREE.Quaternion(); - var scaleWorld = new THREE.Vector3(); - - return function ( force ) { - - this.matrixAutoUpdate && this.updateMatrix(); - - // update matrixWorld - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent ) { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld ); - this.matrix.decompose( translationObject, quaternionObject, scaleObject ); - - this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld ); - - - } else { - - this.matrixWorld.copy( this.matrix ); - - } - - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].updateMatrixWorld( force ); - - } - - }; - -}() ); - -// File:src/extras/core/Path.js - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - * - **/ - -THREE.Path = function ( points ) { - - THREE.CurvePath.call(this); - - this.actions = []; - - if ( points ) { - - this.fromPoints( points ); - - } - -}; - -THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); -THREE.Path.prototype.constructor = THREE.Path; - -THREE.PathActions = { - - MOVE_TO: 'moveTo', - LINE_TO: 'lineTo', - QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve - BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve - CSPLINE_THRU: 'splineThru', // Catmull-rom spline - ARC: 'arc', // Circle - ELLIPSE: 'ellipse' -}; - -// TODO Clean up PATH API - -// Create path using straight lines to connect all points -// - vectors: array of Vector2 - -THREE.Path.prototype.fromPoints = function ( vectors ) { - - this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - - for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { - - this.lineTo( vectors[ v ].x, vectors[ v ].y ); - - }; - -}; - -// startPath() endPath()? - -THREE.Path.prototype.moveTo = function ( x, y ) { - - var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); - -}; - -THREE.Path.prototype.lineTo = function ( x, y ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); - -}; - -THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCPx, aCPy ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); - -}; - -THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCP1x, aCP1y ), - new THREE.Vector2( aCP2x, aCP2y ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); - -}; - -THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { - - var args = Array.prototype.slice.call( arguments ); - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; -//--- - var npts = [ new THREE.Vector2( x0, y0 ) ]; - Array.prototype.push.apply( npts, pts ); - - var curve = new THREE.SplineCurve( npts ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); - -}; - -// FUTURE: Change the API or follow canvas API? - -THREE.Path.prototype.arc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - this.absarc(aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - }; - - THREE.Path.prototype.absarc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); - }; - -THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - this.absellipse(aX + x0, aY + y0, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - - }; - - -THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var args = Array.prototype.slice.call( arguments ); - var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - this.curves.push( curve ); - - var lastPoint = curve.getPoint(1); - args.push(lastPoint.x); - args.push(lastPoint.y); - - this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); - - }; - -THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { - - if ( ! divisions ) divisions = 40; - - var points = []; - - for ( var i = 0; i < divisions; i ++ ) { - - points.push( this.getPoint( i / divisions ) ); - - //if( !this.getPoint( i / divisions ) ) throw "DIE"; - - } - - // if ( closedPath ) { - // - // points.push( points[ 0 ] ); - // - // } - - return points; - -}; - -/* Return an array of vectors based on contour of the path */ - -THREE.Path.prototype.getPoints = function( divisions, closedPath ) { - - if (this.useSpacedPoints) { - console.log('tata'); - return this.getSpacedPoints( divisions, closedPath ); - } - - divisions = divisions || 12; - - var points = []; - - var i, il, item, action, args; - var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, - laste, j, - t, tx, ty; - - for ( i = 0, il = this.actions.length; i < il; i ++ ) { - - item = this.actions[ i ]; - - action = item.action; - args = item.args; - - switch ( action ) { - - case THREE.PathActions.MOVE_TO: - - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - - break; - - case THREE.PathActions.LINE_TO: - - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - - break; - - case THREE.PathActions.QUADRATIC_CURVE_TO: - - cpx = args[ 2 ]; - cpy = args[ 3 ]; - - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; - - if ( points.length > 0 ) { - - laste = points[ points.length - 1 ]; - - cpx0 = laste.x; - cpy0 = laste.y; - - } else { - - laste = this.actions[ i - 1 ].args; - - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; - - } - - for ( j = 1; j <= divisions; j ++ ) { - - t = j / divisions; - - tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - break; - - case THREE.PathActions.BEZIER_CURVE_TO: - - cpx = args[ 4 ]; - cpy = args[ 5 ]; - - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; - - cpx2 = args[ 2 ]; - cpy2 = args[ 3 ]; - - if ( points.length > 0 ) { - - laste = points[ points.length - 1 ]; - - cpx0 = laste.x; - cpy0 = laste.y; - - } else { - - laste = this.actions[ i - 1 ].args; - - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; - - } - - - for ( j = 1; j <= divisions; j ++ ) { - - t = j / divisions; - - tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - break; - - case THREE.PathActions.CSPLINE_THRU: - - laste = this.actions[ i - 1 ].args; - - var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); - var spts = [ last ]; - - var n = divisions * args[ 0 ].length; - - spts = spts.concat( args[ 0 ] ); - - var spline = new THREE.SplineCurve( spts ); - - for ( j = 1; j <= n; j ++ ) { - - points.push( spline.getPointAt( j / n ) ) ; - - } - - break; - - case THREE.PathActions.ARC: - - var aX = args[ 0 ], aY = args[ 1 ], - aRadius = args[ 2 ], - aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], - aClockwise = !! args[ 5 ]; - - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; - - for ( j = 1; j <= tdivisions; j ++ ) { - - t = j / tdivisions; - - if ( ! aClockwise ) { - - t = 1 - t; - - } - - angle = aStartAngle + t * deltaAngle; - - tx = aX + aRadius * Math.cos( angle ); - ty = aY + aRadius * Math.sin( angle ); - - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - //console.log(points); - - break; - - case THREE.PathActions.ELLIPSE: - - var aX = args[ 0 ], aY = args[ 1 ], - xRadius = args[ 2 ], - yRadius = args[ 3 ], - aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], - aClockwise = !! args[ 6 ]; - - - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; - - for ( j = 1; j <= tdivisions; j ++ ) { - - t = j / tdivisions; - - if ( ! aClockwise ) { - - t = 1 - t; - - } - - angle = aStartAngle + t * deltaAngle; - - tx = aX + xRadius * Math.cos( angle ); - ty = aY + yRadius * Math.sin( angle ); - - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - //console.log(points); - - break; - - } // end switch - - } - - - - // Normalize to remove the closing point by default. - var lastPoint = points[ points.length - 1]; - var EPSILON = 0.0000000001; - if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && - Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) - points.splice( points.length - 1, 1); - if ( closedPath ) { - - points.push( points[ 0 ] ); - - } - - return points; - -}; - -// -// Breaks path into shapes -// -// Assumptions (if parameter isCCW==true the opposite holds): -// - solid shapes are defined clockwise (CW) -// - holes are defined counterclockwise (CCW) -// -// If parameter noHoles==true: -// - all subPaths are regarded as solid shapes -// - definition order CW/CCW has no relevance -// - -THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { - - function extractSubpaths( inActions ) { - - var i, il, item, action, args; - - var subPaths = [], lastPath = new THREE.Path(); - - for ( i = 0, il = inActions.length; i < il; i ++ ) { - - item = inActions[ i ]; - - args = item.args; - action = item.action; - - if ( action == THREE.PathActions.MOVE_TO ) { - - if ( lastPath.actions.length != 0 ) { - - subPaths.push( lastPath ); - lastPath = new THREE.Path(); - - } - - } - - lastPath[ action ].apply( lastPath, args ); - - } - - if ( lastPath.actions.length != 0 ) { - - subPaths.push( lastPath ); - - } - - // console.log(subPaths); - - return subPaths; - } - - function toShapesNoHoles( inSubpaths ) { - - var shapes = []; - - for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) { - - var tmpPath = inSubpaths[ i ]; - - var tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - - shapes.push( tmpShape ); - } - - //console.log("shape", shapes); - - return shapes; - }; - - function isPointInsidePolygon( inPt, inPolygon ) { - var EPSILON = 0.0000000001; - - 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) > 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 colinear - if ( inPt.y != edgeLowPt.y ) continue; // parallel - // egde 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 subPaths = extractSubpaths( this.actions ); - 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 THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - var holesFirst = ! THREE.Shape.Utils.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] = []; - - var i, il; - - for ( i = 0, il = subPaths.length; i < il; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = THREE.Shape.Utils.isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; - - if ( solid ) { - - if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx ++; - - newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; - newShapes[mainIdx].s.actions = tmpPath.actions; - 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 ambigious = 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 { - ambigious = true; - } - } - } - if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } - } - } - // console.log("ambigious: ", ambigious); - if ( toChange.length > 0 ) { - // console.log("to change: ", toChange); - if (! ambigious) newShapeHoles = betterShapeHoles; - } - } - - var tmpHoles, j, jl; - for ( i = 0, il = newShapes.length; i < il; i ++ ) { - tmpShape = newShapes[i].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[i]; - for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - tmpShape.holes.push( tmpHoles[j].h ); - } - } - - //console.log("shape", shapes); - - return shapes; - -}; - -// File:src/extras/core/Shape.js - -/** - * @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. - -THREE.Shape = function () { - - THREE.Path.apply( this, arguments ); - this.holes = []; - -}; - -THREE.Shape.prototype = Object.create( THREE.Path.prototype ); -THREE.Shape.prototype.constructor = THREE.Shape; - -// Convenience method to return ExtrudeGeometry - -THREE.Shape.prototype.extrude = function ( options ) { - - var extruded = new THREE.ExtrudeGeometry( this, options ); - return extruded; - -}; - -// Convenience method to return ShapeGeometry - -THREE.Shape.prototype.makeGeometry = function ( options ) { - - var geometry = new THREE.ShapeGeometry( this, options ); - return geometry; - -}; - -// Get points of holes - -THREE.Shape.prototype.getPointsHoles = function ( divisions ) { - - var i, il = this.holes.length, holesPts = []; - - for ( i = 0; i < il; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); - - } - - return holesPts; - -}; - -// Get points of holes (spaced by regular distance) - -THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { - - var i, il = this.holes.length, holesPts = []; - - for ( i = 0; i < il; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); - - } - - return holesPts; - -}; - - -// Get points of shape and holes (keypoints based on segments parameter) - -THREE.Shape.prototype.extractAllPoints = function ( divisions ) { - - return { - - shape: this.getTransformedPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - -}; - -THREE.Shape.prototype.extractPoints = function ( divisions ) { - - if (this.useSpacedPoints) { - return this.extractAllSpacedPoints(divisions); - } - - return this.extractAllPoints(divisions); - -}; - -// -// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { -// -// return { -// -// shape: this.transform( bend, divisions ), -// holes: this.getPointsHoles( divisions, bend ) -// -// }; -// -// }; - -// Get points of shape and holes (spaced by regular distance) - -THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { - - return { - - shape: this.getTransformedSpacedPoints( divisions ), - holes: this.getSpacedPointsHoles( divisions ) - - }; - -}; - -/************************************************************** - * Utils - **************************************************************/ - -THREE.Shape.Utils = { - - triangulateShape: function ( contour, holes ) { - - function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { - // inOtherPt needs to be colinear 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 EPSILON = 0.0000000001; - - 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) > 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 colinear - if ( ( perpSeg1 != 0 ) || - ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; - - // they are collinear or degenerate - var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? - var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist 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 - - var EPSILON = 0.0000000001; - - // 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) > 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 ) { - - THREE.warn( "THREE.Shape: Duplicate point", key ); - - } - - allPointsMap[ key ] = i; - - } - - // remove holes by cutting paths to holes and adding them to the shape - var shapeWithoutHoles = removeHoles( contour, holes ); - - var triangles = THREE.FontUtils.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 THREE.FontUtils.Triangulate.area( pts ) < 0; - - }, - - // Bezier Curves formulas obtained from - // http://en.wikipedia.org/wiki/B%C3%A9zier_curve - - // Quad Bezier Functions - - b2p0: function ( t, p ) { - - var k = 1 - t; - return k * k * p; - - }, - - b2p1: function ( t, p ) { - - return 2 * ( 1 - t ) * t * p; - - }, - - b2p2: function ( t, p ) { - - return t * t * p; - - }, - - b2: function ( t, p0, p1, p2 ) { - - return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); - - }, - - // Cubic Bezier Functions - - b3p0: function ( t, p ) { - - var k = 1 - t; - return k * k * k * p; - - }, - - b3p1: function ( t, p ) { - - var k = 1 - t; - return 3 * k * k * t * p; - - }, - - b3p2: function ( t, p ) { - - var k = 1 - t; - return 3 * k * t * t * p; - - }, - - b3p3: function ( t, p ) { - - return t * t * t * p; - - }, - - b3: function ( t, p0, p1, p2, p3 ) { - - return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); - - } - -}; - - -// File:src/extras/curves/LineCurve.js - -/************************************************************** - * Line - **************************************************************/ - -THREE.LineCurve = function ( v1, v2 ) { - - this.v1 = v1; - this.v2 = v2; - -}; - -THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); -THREE.LineCurve.prototype.constructor = THREE.LineCurve; - -THREE.LineCurve.prototype.getPoint = function ( t ) { - - 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 - -THREE.LineCurve.prototype.getPointAt = function ( u ) { - - return this.getPoint( u ); - -}; - -THREE.LineCurve.prototype.getTangent = function( t ) { - - var tangent = this.v2.clone().sub(this.v1); - - return tangent.normalize(); - -}; - -// File:src/extras/curves/QuadraticBezierCurve.js - -/************************************************************** - * Quadratic Bezier curve - **************************************************************/ - - -THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - -}; - -THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); -THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; - - -THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { - - var vector = new THREE.Vector2(); - - vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - - return vector; - -}; - - -THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { - - var vector = new THREE.Vector2(); - - vector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); - vector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); - - // returns unit vector - - return vector.normalize(); - -}; - -// File:src/extras/curves/CubicBezierCurve.js - -/************************************************************** - * Cubic Bezier curve - **************************************************************/ - -THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - -}; - -THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); -THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; - -THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { - - var tx, ty; - - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - - return new THREE.Vector2( tx, ty ); - -}; - -THREE.CubicBezierCurve.prototype.getTangent = function( t ) { - - var tx, ty; - - tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); - - return tangent; - -}; - -// File:src/extras/curves/SplineCurve.js - -/************************************************************** - * Spline curve - **************************************************************/ - -THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - - this.points = ( points == undefined ) ? [] : points; - -}; - -THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); -THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; - -THREE.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 ] - - var vector = new THREE.Vector2(); - - vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); - vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); - - return vector; - -}; - -// File:src/extras/curves/EllipseCurve.js - -/************************************************************** - * Ellipse curve - **************************************************************/ - -THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - -}; - -THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); -THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; - -THREE.EllipseCurve.prototype.getPoint = function ( t ) { - - var deltaAngle = this.aEndAngle - this.aStartAngle; - - if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; - if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; - - var angle; - - if ( this.aClockwise === true ) { - - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); - - } else { - - angle = this.aStartAngle + t * deltaAngle; - - } - - var vector = new THREE.Vector2(); - - vector.x = this.aX + this.xRadius * Math.cos( angle ); - vector.y = this.aY + this.yRadius * Math.sin( angle ); - - return vector; - -}; - -// File:src/extras/curves/ArcCurve.js - -/************************************************************** - * Arc curve - **************************************************************/ - -THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); -}; - -THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); -THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; - -// File:src/extras/curves/LineCurve3.js - -/************************************************************** - * Line3D - **************************************************************/ - -THREE.LineCurve3 = THREE.Curve.create( - - function ( v1, v2 ) { - - this.v1 = v1; - this.v2 = v2; - - }, - - function ( t ) { - - var vector = new THREE.Vector3(); - - vector.subVectors( this.v2, this.v1 ); // diff - vector.multiplyScalar( t ); - vector.add( this.v1 ); - - return vector; - - } - -); - -// File:src/extras/curves/QuadraticBezierCurve3.js - -/************************************************************** - * Quadratic Bezier 3D curve - **************************************************************/ - -THREE.QuadraticBezierCurve3 = THREE.Curve.create( - - function ( v0, v1, v2 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - }, - - function ( t ) { - - var vector = new THREE.Vector3(); - - vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - vector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); - - return vector; - - } - -); - -// File:src/extras/curves/CubicBezierCurve3.js - -/************************************************************** - * Cubic Bezier 3D curve - **************************************************************/ - -THREE.CubicBezierCurve3 = THREE.Curve.create( - - function ( v0, v1, v2, v3 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - }, - - function ( t ) { - - var vector = new THREE.Vector3(); - - vector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - vector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - vector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); - - return vector; - - } - -); - -// File:src/extras/curves/SplineCurve3.js - -/************************************************************** - * Spline 3D curve - **************************************************************/ - - -THREE.SplineCurve3 = THREE.Curve.create( - - function ( points /* array of Vector3 */) { - - this.points = ( points == undefined ) ? [] : points; - - }, - - 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 ]; - - var vector = new THREE.Vector3(); - - vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); - vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); - vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - - return vector; - - } - -); - -// File:src/extras/curves/ClosedSplineCurve3.js - -/************************************************************** - * Closed Spline 3D curve - **************************************************************/ - - -THREE.ClosedSplineCurve3 = THREE.Curve.create( - - function ( points /* array of Vector3 */) { - - this.points = ( points == undefined ) ? [] : points; - - }, - - function ( t ) { - - var points = this.points; - var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 - - var intPoint = Math.floor( point ); - var weight = point - intPoint; - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - - var point0 = points[ ( intPoint - 1 ) % points.length ]; - var point1 = points[ ( intPoint ) % points.length ]; - var point2 = points[ ( intPoint + 1 ) % points.length ]; - var point3 = points[ ( intPoint + 2 ) % points.length ]; - - var vector = new THREE.Vector3(); - - vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); - vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); - vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - - return vector; - - } - -); - -// File:src/extras/animation/AnimationHandler.js - -/** - * @author mikael emtinger / http://gomo.se/ - */ - -THREE.AnimationHandler = { - - LINEAR: 0, - CATMULLROM: 1, - CATMULLROM_FORWARD: 2, - - // - - add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, - get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, - remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, - - // - - animations: [], - - init: function ( data ) { - - if ( data.initialized === true ) return data; - - // loop through all keys - - for ( var h = 0; h < data.hierarchy.length; h ++ ) { - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - // remove minus times - - if ( data.hierarchy[ h ].keys[ k ].time < 0 ) { - - data.hierarchy[ h ].keys[ k ].time = 0; - - } - - // create quaternions - - if ( data.hierarchy[ h ].keys[ k ].rot !== undefined && - ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { - - var quat = data.hierarchy[ h ].keys[ k ].rot; - data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat ); - - } - - } - - // prepare morph target keys - - if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { - - // get all used - - var usedMorphTargets = {}; - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - - var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; - usedMorphTargets[ morphTargetName ] = - 1; - - } - - } - - data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; - - - // set all used on all frames - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - var influences = {}; - - for ( var morphTargetName in usedMorphTargets ) { - - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - - if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { - - influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; - break; - - } - - } - - if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { - - influences[ morphTargetName ] = 0; - - } - - } - - data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; - - } - - } - - - // remove all keys that are on the same time - - for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { - - if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { - - data.hierarchy[ h ].keys.splice( k, 1 ); - k --; - - } - - } - - - // set index - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - data.hierarchy[ h ].keys[ k ].index = k; - - } - - } - - data.initialized = true; - - return data; - - }, - - parse: function ( root ) { - - var parseRecurseHierarchy = function ( root, hierarchy ) { - - hierarchy.push( root ); - - for ( var c = 0; c < root.children.length; c ++ ) - parseRecurseHierarchy( root.children[ c ], hierarchy ); - - }; - - // setup hierarchy - - var hierarchy = []; - - if ( root instanceof THREE.SkinnedMesh ) { - - for ( var b = 0; b < root.skeleton.bones.length; b ++ ) { - - hierarchy.push( root.skeleton.bones[ b ] ); - - } - - } else { - - parseRecurseHierarchy( root, hierarchy ); - - } - - return hierarchy; - - }, - - play: function ( animation ) { - - if ( this.animations.indexOf( animation ) === - 1 ) { - - this.animations.push( animation ); - - } - - }, - - stop: function ( animation ) { - - var index = this.animations.indexOf( animation ); - - if ( index !== - 1 ) { - - this.animations.splice( index, 1 ); - - } - - }, - - update: function ( deltaTimeMS ) { - - for ( var i = 0; i < this.animations.length; i ++ ) { - - this.animations[ i ].resetBlendWeights( ); - - } - - for ( var i = 0; i < this.animations.length; i ++ ) { - - this.animations[ i ].update( deltaTimeMS ); - - } - - } - -}; - -// File:src/extras/animation/Animation.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Animation = function ( root, data ) { - - this.root = root; - this.data = THREE.AnimationHandler.init( data ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - - this.currentTime = 0; - this.timeScale = 1; - - this.isPlaying = false; - this.loop = true; - this.weight = 0; - - this.interpolationType = THREE.AnimationHandler.LINEAR; - -}; - -THREE.Animation.prototype = { - - constructor: THREE.Animation, - - keyTypes: [ "pos", "rot", "scl" ], - - play: function ( startTime, weight ) { - - this.currentTime = startTime !== undefined ? startTime : 0; - this.weight = weight !== undefined ? weight : 1; - - this.isPlaying = true; - - this.reset(); - - THREE.AnimationHandler.play( this ); - - }, - - stop: function() { - - this.isPlaying = false; - - THREE.AnimationHandler.stop( this ); - - }, - - reset: function () { - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - - if ( object.animationCache === undefined ) { - - object.animationCache = { - animations: {}, - blending: { - positionWeight: 0.0, - quaternionWeight: 0.0, - scaleWeight: 0.0 - } - }; - } - - var name = this.data.name; - var animations = object.animationCache.animations; - var animationCache = animations[ name ]; - - if ( animationCache === undefined ) { - - animationCache = { - prevKey: { pos: 0, rot: 0, scl: 0 }, - nextKey: { pos: 0, rot: 0, scl: 0 }, - originalMatrix: object.matrix - }; - - animations[ name ] = animationCache; - - } - - // Get keys to match our current time - - for ( var t = 0; t < 3; t ++ ) { - - var type = this.keyTypes[ t ]; - - var prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - var nextKey = this.getNextKeyWith( type, h, 1 ); - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - - } - - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; - - } - - } - - }, - - resetBlendWeights: function () { - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - var animationCache = object.animationCache; - - if ( animationCache !== undefined ) { - - var blending = animationCache.blending; - - blending.positionWeight = 0.0; - blending.quaternionWeight = 0.0; - blending.scaleWeight = 0.0; - - } - - } - - }, - - update: ( function() { - - var points = []; - var target = new THREE.Vector3(); - var newVector = new THREE.Vector3(); - var newQuat = new THREE.Quaternion(); - - // Catmull-Rom spline - - var interpolateCatmullRom = function ( points, scale ) { - - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; - - point = ( points.length - 1 ) * scale; - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - - pa = points[ c[ 0 ] ]; - pb = points[ c[ 1 ] ]; - pc = points[ c[ 2 ] ]; - pd = points[ c[ 3 ] ]; - - w2 = weight * weight; - w3 = weight * w2; - - v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); - v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); - v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); - - return v3; - - }; - - var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { - - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - }; - - return function ( delta ) { - - if ( this.isPlaying === false ) return; - - this.currentTime += delta * this.timeScale; - - if ( this.weight === 0 ) - return; - - // - - var duration = this.data.length; - - if ( this.currentTime > duration || this.currentTime < 0 ) { - - if ( this.loop ) { - - this.currentTime %= duration; - - if ( this.currentTime < 0 ) - this.currentTime += duration; - - this.reset(); - - } else { - - this.stop(); - - } - - } - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - var animationCache = object.animationCache.animations[this.data.name]; - var blending = object.animationCache.blending; - - // loop through pos/rot/scl - - for ( var t = 0; t < 3; t ++ ) { - - // get keys - - var type = this.keyTypes[ t ]; - var prevKey = animationCache.prevKey[ type ]; - var nextKey = animationCache.nextKey[ type ]; - - if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) || - ( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) { - - prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - nextKey = this.getNextKeyWith( type, h, 1 ); - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - - } - - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; - - } - - var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - - var prevXYZ = prevKey[ type ]; - var nextXYZ = nextKey[ type ]; - - if ( scale < 0 ) scale = 0; - if ( scale > 1 ) scale = 1; - - // interpolate - - if ( type === "pos" ) { - - if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - - newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - // blend - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - object.position.lerp( newVector, proportionalWeight ); - blending.positionWeight += this.weight; - - } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; - points[ 1 ] = prevXYZ; - points[ 2 ] = nextXYZ; - points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; - - scale = scale * 0.33 + 0.33; - - var currentPoint = interpolateCatmullRom( points, scale ); - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - blending.positionWeight += this.weight; - - // blend - - var vector = object.position; - - vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight; - vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight; - vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - - target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); - target.sub( vector ); - target.y = 0; - target.normalize(); - - var angle = Math.atan2( target.x, target.z ); - object.rotation.set( 0, angle, 0 ); - - } - - } - - } else if ( type === "rot" ) { - - THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale ); - - // Avoid paying the cost of an additional slerp if we don't have to - if ( blending.quaternionWeight === 0 ) { - - object.quaternion.copy(newQuat); - blending.quaternionWeight = this.weight; - - } else { - - var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); - THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight ); - blending.quaternionWeight += this.weight; - - } - - } else if ( type === "scl" ) { - - newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); - object.scale.lerp( newVector, proportionalWeight ); - blending.scaleWeight += this.weight; - - } - - } - - } - - return true; - - }; - - } )(), - - getNextKeyWith: function ( type, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - key = key < keys.length - 1 ? key : keys.length - 1; - - } else { - - key = key % keys.length; - - } - - for ( ; key < keys.length; key ++ ) { - - if ( keys[ key ][ type ] !== undefined ) { - - return keys[ key ]; - - } - - } - - return this.data.hierarchy[ h ].keys[ 0 ]; - - }, - - getPrevKeyWith: function ( type, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - key = key > 0 ? key : 0; - - } else { - - key = key >= 0 ? key : key + keys.length; - - } - - - for ( ; key >= 0; key -- ) { - - if ( keys[ key ][ type ] !== undefined ) { - - return keys[ key ]; - - } - - } - - return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; - - } - -}; - -// File:src/extras/animation/KeyFrameAnimation.js - -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author khang duong - * @author erik kitson - */ - -THREE.KeyFrameAnimation = function ( data ) { - - this.root = data.node; - this.data = THREE.AnimationHandler.init( data ); - this.hierarchy = THREE.AnimationHandler.parse( this.root ); - this.currentTime = 0; - this.timeScale = 0.001; - this.isPlaying = false; - this.isPaused = true; - this.loop = true; - - // initialize to first keyframes - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - obj = this.hierarchy[h]; - - if ( keys.length && sids ) { - - for ( var s = 0; s < sids.length; s ++ ) { - - var sid = sids[ s ], - next = this.getNextKeyWith( sid, h, 0 ); - - if ( next ) { - - next.apply( sid ); - - } - - } - - obj.matrixAutoUpdate = false; - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; - - } - - } - -}; - -THREE.KeyFrameAnimation.prototype = { - - constructor: THREE.KeyFrameAnimation, - - play: function ( startTime ) { - - this.currentTime = startTime !== undefined ? startTime : 0; - - if ( this.isPlaying === false ) { - - this.isPlaying = true; - - // reset key cache - - var h, hl = this.hierarchy.length, - object, - node; - - for ( h = 0; h < hl; h ++ ) { - - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; - - if ( node.animationCache === undefined ) { - - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object.matrix; - - } - - var keys = this.data.hierarchy[h].keys; - - if (keys.length) { - - node.animationCache.prevKey = keys[ 0 ]; - node.animationCache.nextKey = keys[ 1 ]; - - this.startTime = Math.min( keys[0].time, this.startTime ); - this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); - - } - - } - - this.update( 0 ); - - } - - this.isPaused = false; - - THREE.AnimationHandler.play( this ); - - }, - - stop: function () { - - this.isPlaying = false; - this.isPaused = false; - - THREE.AnimationHandler.stop( this ); - - // reset JIT matrix and remove cache - - for ( var h = 0; h < this.data.hierarchy.length; h ++ ) { - - var obj = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; - - if ( node.animationCache !== undefined ) { - - var original = node.animationCache.originalMatrix; - - original.copy( obj.matrix ); - obj.matrix = original; - - delete node.animationCache; - - } - - } - - }, - - update: function ( delta ) { - - if ( this.isPlaying === false ) return; - - this.currentTime += delta * this.timeScale; - - // - - var duration = this.data.length; - - if ( this.loop === true && this.currentTime > duration ) { - - this.currentTime %= duration; - - } - - this.currentTime = Math.min( this.currentTime, duration ); - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; - - var keys = node.keys, - animationCache = node.animationCache; - - - if ( keys.length ) { - - var prevKey = animationCache.prevKey; - var nextKey = animationCache.nextKey; - - if ( nextKey.time <= this.currentTime ) { - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; - - } - - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; - - } - - if ( nextKey.time >= this.currentTime ) { - - prevKey.interpolate( nextKey, this.currentTime ); - - } else { - - prevKey.interpolate( nextKey, nextKey.time ); - - } - - this.data.hierarchy[ h ].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; - - } - - } - - }, - - getNextKeyWith: function ( sid, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - key = key % keys.length; - - for ( ; key < keys.length; key ++ ) { - - if ( keys[ key ].hasTarget( sid ) ) { - - return keys[ key ]; - - } - - } - - return keys[ 0 ]; - - }, - - getPrevKeyWith: function ( sid, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - key = key >= 0 ? key : key + keys.length; - - for ( ; key >= 0; key -- ) { - - if ( keys[ key ].hasTarget( sid ) ) { - - return keys[ key ]; - - } - - } - - return keys[ keys.length - 1 ]; - - } - -}; - -// File:src/extras/animation/MorphAnimation.js - -/** - * @author mrdoob / http://mrdoob.com - * @author willy-vvu / http://willy-vvu.github.io - */ - -THREE.MorphAnimation = function ( mesh ) { - - this.mesh = mesh; - this.frames = mesh.morphTargetInfluences.length; - this.currentTime = 0; - this.duration = 1000; - this.loop = true; - this.lastFrame = 0; - this.currentFrame = 0; - - this.isPlaying = false; - -}; - -THREE.MorphAnimation.prototype = { - - constructor: THREE.MorphAnimation, - - play: function () { - - this.isPlaying = true; - - }, - - pause: function () { - - this.isPlaying = false; - - }, - - update: function ( delta ) { - - if ( this.isPlaying === false ) return; - - this.currentTime += delta; - - if ( this.loop === true && this.currentTime > this.duration ) { - - this.currentTime %= this.duration; - - } - - this.currentTime = Math.min( this.currentTime, this.duration ); - - var interpolation = this.duration / this.frames; - var frame = Math.floor( this.currentTime / interpolation ); - - var influences = this.mesh.morphTargetInfluences; - - if ( frame != this.currentFrame ) { - - influences[ this.lastFrame ] = 0; - influences[ this.currentFrame ] = 1; - influences[ frame ] = 0; - - this.lastFrame = this.currentFrame; - this.currentFrame = frame; - - } - - influences[ frame ] = ( this.currentTime % interpolation ) / interpolation; - influences[ this.lastFrame ] = 1 - influences[ frame ]; - - } - -}; - -// File:src/extras/geometries/BoxGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as - */ - -THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - THREE.Geometry.call( this ); - - this.type = 'BoxGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - this.widthSegments = widthSegments || 1; - this.heightSegments = heightSegments || 1; - this.depthSegments = depthSegments || 1; - - var scope = this; - - var width_half = width / 2; - var height_half = height / 2; - var depth_half = depth / 2; - - buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px - buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx - buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py - buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny - buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz - buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz - - function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { - - var w, ix, iy, - gridX = scope.widthSegments, - gridY = scope.heightSegments, - width_half = width / 2, - height_half = height / 2, - offset = scope.vertices.length; - - if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { - - w = 'z'; - - } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { - - w = 'y'; - gridY = scope.depthSegments; - - } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { - - w = 'x'; - gridX = scope.depthSegments; - - } - - var gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY, - normal = new THREE.Vector3(); - - normal[ w ] = depth > 0 ? 1 : - 1; - - for ( iy = 0; iy < gridY1; iy ++ ) { - - for ( ix = 0; ix < gridX1; ix ++ ) { - - var vector = new THREE.Vector3(); - vector[ u ] = ( ix * segment_width - width_half ) * udir; - vector[ v ] = ( iy * segment_height - height_half ) * vdir; - vector[ w ] = depth; - - scope.vertices.push( vector ); - - } - - } - - 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; - - var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); - - var face = new THREE.Face3( a + offset, b + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; - - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - face = new THREE.Face3( b + offset, c + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; - - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - - } - - } - - this.mergeVertices(); - -}; - -THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; - -// File:src/extras/geometries/CircleGeometry.js - -/** - * @author hughes - */ - -THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - - this.type = 'CircleGeometry'; - - 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; - - var i, uvs = [], - center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); - - this.vertices.push(center); - uvs.push( centerUV ); - - for ( i = 0; i <= segments; i ++ ) { - - var vertex = new THREE.Vector3(); - var segment = thetaStart + i / segments * thetaLength; - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); - - } - - var n = new THREE.Vector3( 0, 0, 1 ); - - for ( i = 1; i <= segments; i ++ ) { - - this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); - - } - - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; - -// File:src/extras/geometries/CubeGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - - -THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); - return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); - - }; - -// File:src/extras/geometries/CylinderGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - - this.type = 'CylinderGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - radiusTop = radiusTop !== undefined ? radiusTop : 20; - radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; - height = height !== undefined ? height : 100; - - radialSegments = radialSegments || 8; - heightSegments = heightSegments || 1; - - openEnded = openEnded !== undefined ? openEnded : false; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; - - var heightHalf = height / 2; - - var x, y, vertices = [], uvs = []; - - for ( y = 0; y <= heightSegments; y ++ ) { - - var verticesRow = []; - var uvsRow = []; - - var v = y / heightSegments; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( x = 0; x <= radialSegments; x ++ ) { - - var u = x / radialSegments; - - var vertex = new THREE.Vector3(); - vertex.x = radius * Math.sin( u * thetaLength + thetaStart ); - vertex.y = - v * height + heightHalf; - vertex.z = radius * Math.cos( u * thetaLength + thetaStart ); - - this.vertices.push( vertex ); - - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - - } - - vertices.push( verticesRow ); - uvs.push( uvsRow ); - - } - - var tanTheta = ( radiusBottom - radiusTop ) / height; - var na, nb; - - for ( x = 0; x < radialSegments; x ++ ) { - - if ( radiusTop !== 0 ) { - - na = this.vertices[ vertices[ 0 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - - } else { - - na = this.vertices[ vertices[ 1 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); - - } - - na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); - nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); - - for ( y = 0; y < heightSegments; y ++ ) { - - var v1 = vertices[ y ][ x ]; - var v2 = vertices[ y + 1 ][ x ]; - var v3 = vertices[ y + 1 ][ x + 1 ]; - var v4 = vertices[ y ][ x + 1 ]; - - var n1 = na.clone(); - var n2 = na.clone(); - var n3 = nb.clone(); - var n4 = nb.clone(); - - var uv1 = uvs[ y ][ x ].clone(); - var uv2 = uvs[ y + 1 ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); - var uv4 = uvs[ y ][ x + 1 ].clone(); - - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - - } - - } - - // top cap - - if ( openEnded === false && radiusTop > 0 ) { - - this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); - - for ( x = 0; x < radialSegments; x ++ ) { - - var v1 = vertices[ 0 ][ x ]; - var v2 = vertices[ 0 ][ x + 1 ]; - var v3 = this.vertices.length - 1; - - var n1 = new THREE.Vector3( 0, 1, 0 ); - var n2 = new THREE.Vector3( 0, 1, 0 ); - var n3 = new THREE.Vector3( 0, 1, 0 ); - - var uv1 = uvs[ 0 ][ x ].clone(); - var uv2 = uvs[ 0 ][ x + 1 ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 0 ); - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } - - } - - // bottom cap - - if ( openEnded === false && radiusBottom > 0 ) { - - this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); - - for ( x = 0; x < radialSegments; x ++ ) { - - var v1 = vertices[ heightSegments ][ x + 1 ]; - var v2 = vertices[ heightSegments ][ x ]; - var v3 = this.vertices.length - 1; - - var n1 = new THREE.Vector3( 0, - 1, 0 ); - var n2 = new THREE.Vector3( 0, - 1, 0 ); - var n3 = new THREE.Vector3( 0, - 1, 0 ); - - var uv1 = uvs[ heightSegments ][ x + 1 ].clone(); - var uv2 = uvs[ heightSegments ][ x ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 1 ); - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } - - } - - this.computeFaceNormals(); - -}; - -THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry; - -// File:src/extras/geometries/ExtrudeGeometry.js - -/** - * @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 segements 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: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) - * frames: // containing arrays of tangents, normals, binormals - * - * material: // material index for front and back faces - * extrudeMaterial: // material index for extrusion and beveled faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ - -THREE.ExtrudeGeometry = function ( shapes, options ) { - - if ( typeof( shapes ) === "undefined" ) { - shapes = []; - return; - } - - THREE.Geometry.call( this ); - - this.type = 'ExtrudeGeometry'; - - shapes = shapes instanceof Array ? 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 ) ); - -}; - -THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; - -THREE.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 ); - } -}; - -THREE.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; - - var material = options.material; - var extrudeMaterial = options.extrudeMaterial; - - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.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 - - // Reuse TNB from TubeGeomtry for now. - // TODO1 - have a .isClosed in spline? - - splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new THREE.Vector3(); - normal = new THREE.Vector3(); - position2 = new THREE.Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - - } - - // Variables initalization - - 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 = ! THREE.Shape.Utils.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 ( THREE.Shape.Utils.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 = THREE.Shape.Utils.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 ) THREE.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 ) { - - var EPSILON = 0.0000000001; - - // computes for inPt the corresponding point inPt' on a new contour - // shiftet 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 colinear edges - var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear - - // 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 THREE.Vector2( v_trans_x, v_trans_y ); - } else { - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - } - - } else { // handle special case of colinear edges - - var direction_eq = false; // assumes: opposite - if ( v_prev_x > EPSILON ) { - if ( v_next_x > EPSILON ) { direction_eq = true; } - } else { - if ( v_prev_x < - EPSILON ) { - if ( v_next_x < - 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 THREE.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 * ( 1 - t ); - - //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ) ; // curved - //bs = bevelSize * t ; // linear - - // 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 * ( 1 - t ); - //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); - bs = bevelSize * Math.sin ( t * Math.PI / 2 ) ; - - // contract shape - - for ( i = 0, 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 THREE.Vector3( x, y, z ) ); - - } - - function f3( a, b, c ) { - - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - - // normal, color, material - scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - - 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 THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); - scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); - - 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 ] ] ); - - } - -}; - -THREE.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 THREE.Vector2( a.x, a.y ), - new THREE.Vector2( b.x, b.y ), - new THREE.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 THREE.Vector2( a.x, 1 - a.z ), - new THREE.Vector2( b.x, 1 - b.z ), - new THREE.Vector2( c.x, 1 - c.z ), - new THREE.Vector2( d.x, 1 - d.z ) - ]; - } else { - return [ - new THREE.Vector2( a.y, 1 - a.z ), - new THREE.Vector2( b.y, 1 - b.z ), - new THREE.Vector2( c.y, 1 - c.z ), - new THREE.Vector2( d.y, 1 - d.z ) - ]; - } - } -}; - -// File:src/extras/geometries/ShapeGeometry.js - -/** - * @author jonobr1 / http://jonobr1.com - * - * Creates a one-sided polygonal geometry from a path shape. Similar to - * ExtrudeGeometry. - * - * parameters = { - * - * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. - * - * material: // material index for front and back faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ - -THREE.ShapeGeometry = function ( shapes, options ) { - - THREE.Geometry.call( this ); - - this.type = 'ShapeGeometry'; - - if ( shapes instanceof Array === false ) shapes = [ shapes ]; - - this.addShapeList( shapes, options ); - - this.computeFaceNormals(); - -}; - -THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry; - -/** - * Add an array of shapes to THREE.ShapeGeometry. - */ -THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { - - for ( var i = 0, l = shapes.length; i < l; i ++ ) { - - this.addShape( shapes[ i ], options ); - - } - - return this; - -}; - -/** - * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. - */ -THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { - - if ( options === undefined ) options = {}; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - - var material = options.material; - var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; - - // - - var i, l, hole; - - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints( curveSegments ); - - var vertices = shapePoints.shape; - var holes = shapePoints.holes; - - var reverse = ! THREE.Shape.Utils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe... - - for ( i = 0, l = holes.length; i < l; i ++ ) { - - hole = holes[ i ]; - - if ( THREE.Shape.Utils.isClockWise( hole ) ) { - - holes[ i ] = hole.reverse(); - - } - - } - - reverse = false; - - } - - var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); - - // Vertices - - var contour = vertices; - - for ( i = 0, l = holes.length; i < l; i ++ ) { - - hole = holes[ i ]; - vertices = vertices.concat( hole ); - - } - - // - - var vert, vlen = vertices.length; - var face, flen = faces.length; - - for ( i = 0; i < vlen; i ++ ) { - - vert = vertices[ i ]; - - this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); - - } - - for ( i = 0; i < flen; i ++ ) { - - face = faces[ i ]; - - var a = face[ 0 ] + shapesOffset; - var b = face[ 1 ] + shapesOffset; - var c = face[ 2 ] + shapesOffset; - - this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) ); - - } - -}; - -// File:src/extras/geometries/LatheGeometry.js - -/** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://exocortex.com - */ - -// 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 2*PI) range of the lathed section -// 2*pi is a closed lathe, less than 2PI is a portion. - -THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { - - THREE.Geometry.call( this ); - - this.type = 'LatheGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - segments = segments || 12; - phiStart = phiStart || 0; - phiLength = phiLength || 2 * Math.PI; - - var inversePointLength = 1.0 / ( points.length - 1 ); - var inverseSegments = 1.0 / segments; - - for ( var i = 0, il = segments; i <= il; i ++ ) { - - var phi = phiStart + i * inverseSegments * phiLength; - - var c = Math.cos( phi ), - s = Math.sin( phi ); - - for ( var j = 0, jl = points.length; j < jl; j ++ ) { - - var pt = points[ j ]; - - var vertex = new THREE.Vector3(); - - vertex.x = c * pt.x - s * pt.y; - vertex.y = s * pt.x + c * pt.y; - vertex.z = pt.z; - - this.vertices.push( vertex ); - - } - - } - - var np = points.length; - - for ( var i = 0, il = segments; i < il; i ++ ) { - - for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { - - var base = j + np * i; - var a = base; - var b = base + np; - var c = base + 1 + np; - var d = base + 1; - - var u0 = i * inverseSegments; - var v0 = j * inversePointLength; - var u1 = u0 + inverseSegments; - var v1 = v0 + inversePointLength; - - this.faces.push( new THREE.Face3( a, b, d ) ); - - this.faceVertexUvs[ 0 ].push( [ - - new THREE.Vector2( u0, v0 ), - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u0, v1 ) - - ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - - this.faceVertexUvs[ 0 ].push( [ - - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u0, v1 ) - - ] ); - - - } - - } - - this.mergeVertices(); - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry; - -// File:src/extras/geometries/PlaneGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { - - console.info( 'THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.' ); - - THREE.Geometry.call( this ); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - -}; - -THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; - -// File:src/extras/geometries/PlaneBufferGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) { - - THREE.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 = widthSegments || 1; - var gridY = heightSegments || 1; - - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; - - var segment_width = width / gridX; - var segment_height = height / gridY; - - var vertices = new Float32Array( gridX1 * gridY1 * 3 ); - var normals = new Float32Array( gridX1 * gridY1 * 3 ); - var uvs = new Float32Array( gridX1 * gridY1 * 2 ); - - var offset = 0; - var offset2 = 0; - - for ( var iy = 0; iy < gridY1; iy ++ ) { - - var y = iy * segment_height - height_half; - - for ( var ix = 0; ix < gridX1; ix ++ ) { - - var x = ix * segment_width - width_half; - - vertices[ offset ] = x; - vertices[ offset + 1 ] = - y; - - normals[ offset + 2 ] = 1; - - uvs[ offset2 ] = ix / gridX; - uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); - - offset += 3; - offset2 += 2; - - } - - } - - offset = 0; - - var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); - - for ( var iy = 0; iy < gridY; iy ++ ) { - - for ( var 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; - - indices[ offset ] = a; - indices[ offset + 1 ] = b; - indices[ offset + 2 ] = d; - - indices[ offset + 3 ] = b; - indices[ offset + 4 ] = c; - indices[ offset + 5 ] = d; - - offset += 6; - - } - - } - - this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); - this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - -}; - -THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); -THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; - -// File:src/extras/geometries/RingGeometry.js - -/** - * @author Kaleb Murphy - */ - -THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - - this.type = 'RingGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - innerRadius = innerRadius || 0; - 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 ) : 8; - - var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - - for ( i = 0; i < phiSegments + 1; i ++ ) { // concentric circles inside ring - - for ( o = 0; o < thetaSegments + 1; o ++ ) { // number of segments per circle - - var vertex = new THREE.Vector3(); - var segment = thetaStart + o / thetaSegments * thetaLength; - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); - } - - radius += radiusStep; - - } - - var n = new THREE.Vector3( 0, 0, 1 ); - - for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring - - var thetaSegment = i * (thetaSegments + 1); - - for ( o = 0; o < thetaSegments ; o ++ ) { // number of segments per circle - - var segment = o + thetaSegment; - - var v1 = segment; - var v2 = segment + thetaSegments + 1; - var v3 = segment + thetaSegments + 2; - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - - v1 = segment; - v2 = segment + thetaSegments + 2; - v3 = segment + 1; - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - - } - } - - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; - - -// File:src/extras/geometries/SphereGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - - this.type = 'SphereGeometry'; - - 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 x, y, vertices = [], uvs = []; - - for ( y = 0; y <= heightSegments; y ++ ) { - - var verticesRow = []; - var uvsRow = []; - - for ( x = 0; x <= widthSegments; x ++ ) { - - var u = x / widthSegments; - var v = y / heightSegments; - - var vertex = new THREE.Vector3(); - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - this.vertices.push( vertex ); - - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - - } - - vertices.push( verticesRow ); - uvs.push( uvsRow ); - - } - - for ( y = 0; y < heightSegments; y ++ ) { - - for ( x = 0; x < widthSegments; x ++ ) { - - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = vertices[ y + 1 ][ x ]; - var v4 = vertices[ y + 1 ][ x + 1 ]; - - var n1 = this.vertices[ v1 ].clone().normalize(); - var n2 = this.vertices[ v2 ].clone().normalize(); - var n3 = this.vertices[ v3 ].clone().normalize(); - var n4 = this.vertices[ v4 ].clone().normalize(); - - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x ].clone(); - var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); - - if ( Math.abs( this.vertices[ v1 ].y ) === radius ) { - - uv1.x = ( uv1.x + uv2.x ) / 2; - this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); - - } else if ( Math.abs( this.vertices[ v3 ].y ) === radius ) { - - uv3.x = ( uv3.x + uv4.x ) / 2; - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } else { - - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - - } - - } - - } - - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; - -// File:src/extras/geometries/TextGeometry.js - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For creating 3D text geometry in three.js - * - * Text = 3D Text - * - * parameters = { - * size: , // size of the text - * height: , // thickness to extrude text - * curveSegments: , // number of points on the curves - * - * font: , // font name - * weight: , // font weight (normal, bold) - * style: , // font style (normal, italics) - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into text bevel goes - * bevelSize: , // how far from text outline is bevel - * } - * - */ - -/* Usage Examples - - // TextGeometry wrapper - - var text3d = new TextGeometry( text, options ); - - // Complete manner - - var textShapes = THREE.FontUtils.generateShapes( text, options ); - var text3d = new ExtrudeGeometry( textShapes, options ); - -*/ - - -THREE.TextGeometry = function ( text, parameters ) { - - parameters = parameters || {}; - - var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - - // 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; - - THREE.ExtrudeGeometry.call( this, textShapes, parameters ); - - this.type = 'TextGeometry'; - -}; - -THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); -THREE.TextGeometry.prototype.constructor = THREE.TextGeometry; - -// File:src/extras/geometries/TorusGeometry.js - -/** - * @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 - */ - -THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { - - THREE.Geometry.call( this ); - - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 8; - tubularSegments = tubularSegments || 6; - arc = arc || Math.PI * 2; - - var center = new THREE.Vector3(), uvs = [], normals = []; - - for ( var j = 0; j <= radialSegments; j ++ ) { - - for ( var i = 0; i <= tubularSegments; i ++ ) { - - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; - - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - - var vertex = new THREE.Vector3(); - 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 ); - - this.vertices.push( vertex ); - - uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); - normals.push( vertex.clone().sub( center ).normalize() ); - - } - - } - - for ( var j = 1; j <= radialSegments; j ++ ) { - - for ( var i = 1; i <= tubularSegments; i ++ ) { - - 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; - - var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); - - face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); - - } - - } - - this.computeFaceNormals(); - -}; - -THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; - -// File:src/extras/geometries/TorusKnotGeometry.js - -/** - * @author oosmoxiecode - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 - */ - -THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { - - THREE.Geometry.call( this ); - - this.type = 'TorusKnotGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - p: p, - q: q, - heightScale: heightScale - }; - - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 64; - tubularSegments = tubularSegments || 8; - p = p || 2; - q = q || 3; - heightScale = heightScale || 1; - - var grid = new Array( radialSegments ); - var tang = new THREE.Vector3(); - var n = new THREE.Vector3(); - var bitan = new THREE.Vector3(); - - for ( var i = 0; i < radialSegments; ++ i ) { - - grid[ i ] = new Array( tubularSegments ); - var u = i / radialSegments * 2 * p * Math.PI; - var p1 = getPos( u, q, p, radius, heightScale ); - var p2 = getPos( u + 0.01, q, p, radius, heightScale ); - tang.subVectors( p2, p1 ); - n.addVectors( p2, p1 ); - - bitan.crossVectors( tang, n ); - n.crossVectors( bitan, tang ); - bitan.normalize(); - n.normalize(); - - for ( var j = 0; j < tubularSegments; ++ j ) { - - var v = j / tubularSegments * 2 * Math.PI; - var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - var cy = tube * Math.sin( v ); - - var pos = new THREE.Vector3(); - pos.x = p1.x + cx * n.x + cy * bitan.x; - pos.y = p1.y + cx * n.y + cy * bitan.y; - pos.z = p1.z + cx * n.z + cy * bitan.z; - - grid[ i ][ j ] = this.vertices.push( pos ) - 1; - - } - - } - - for ( var i = 0; i < radialSegments; ++ i ) { - - for ( var j = 0; j < tubularSegments; ++ j ) { - - var ip = ( i + 1 ) % radialSegments; - var jp = ( j + 1 ) % tubularSegments; - - var a = grid[ i ][ j ]; - var b = grid[ ip ][ j ]; - var c = grid[ ip ][ jp ]; - var d = grid[ i ][ jp ]; - - var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); - var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); - var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); - var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); - - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - } - - this.computeFaceNormals(); - this.computeVertexNormals(); - - function getPos( u, in_q, in_p, radius, heightScale ) { - - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = in_q / in_p * u; - var cs = Math.cos( quOverP ); - - var tx = radius * ( 2 + cs ) * 0.5 * cu; - var ty = radius * ( 2 + cs ) * su * 0.5; - var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; - - return new THREE.Vector3( tx, ty, tz ); - - } - -}; - -THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; - -// File:src/extras/geometries/TubeGeometry.js - -/** - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * @author jonobr1 / https://github.com/jonobr1 - * - * Modified from the TorusKnotGeometry by @oosmoxiecode - * - * Creates a tube which extrudes along a 3d spline - * - * Uses parallel transport frames as described in - * http://www.cs.indiana.edu/pub/techreports/TR425.pdf - */ - -THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, taper ) { - - THREE.Geometry.call( this ); - - this.type = 'TubeGeometry'; - - this.parameters = { - path: path, - segments: segments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - segments = segments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; - taper = taper || THREE.TubeGeometry.NoTaper; - - var grid = []; - - var scope = this, - - tangent, - normal, - binormal, - - numpoints = segments + 1, - - u, v, r, - - cx, cy, - pos, pos2 = new THREE.Vector3(), - i, j, - ip, jp, - a, b, c, d, - uva, uvb, uvc, uvd; - - var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), - tangents = frames.tangents, - normals = frames.normals, - binormals = frames.binormals; - - // proxy internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; - - function vert( x, y, z ) { - - return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; - - } - - // consruct the grid - - for ( i = 0; i < numpoints; i ++ ) { - - grid[ i ] = []; - - u = i / ( numpoints - 1 ); - - pos = path.getPointAt( u ); - - tangent = tangents[ i ]; - normal = normals[ i ]; - binormal = binormals[ i ]; - - r = radius * taper( u ); - - for ( j = 0; j < radialSegments; j ++ ) { - - v = j / radialSegments * 2 * Math.PI; - - cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - cy = r * Math.sin( v ); - - pos2.copy( pos ); - pos2.x += cx * normal.x + cy * binormal.x; - pos2.y += cx * normal.y + cy * binormal.y; - pos2.z += cx * normal.z + cy * binormal.z; - - grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); - - } - } - - - // construct the mesh - - for ( i = 0; i < segments; i ++ ) { - - for ( j = 0; j < radialSegments; j ++ ) { - - ip = ( closed ) ? (i + 1) % segments : i + 1; - jp = (j + 1) % radialSegments; - - a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** - b = grid[ ip ][ j ]; - c = grid[ ip ][ jp ]; - d = grid[ i ][ jp ]; - - uva = new THREE.Vector2( i / segments, j / radialSegments ); - uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); - uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); - uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); - - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - } - - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; - -THREE.TubeGeometry.NoTaper = function ( u ) { - - return 1; - -}; - -THREE.TubeGeometry.SinusoidalTaper = function ( u ) { - - return Math.sin( Math.PI * u ); - -}; - -// For computing of Frenet frames, exposing the tangents, normals and binormals the spline -THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { - - var normal = new THREE.Vector3(), - - tangents = [], - normals = [], - binormals = [], - - vec = new THREE.Vector3(), - mat = new THREE.Matrix4(), - - numpoints = segments + 1, - theta, - epsilon = 0.0001, - smallest, - - tx, ty, tz, - i, u; - - - // expose internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; - - // compute the tangent vectors for each segment on the path - - for ( i = 0; i < numpoints; i ++ ) { - - u = i / ( numpoints - 1 ); - - tangents[ i ] = path.getTangentAt( u ); - tangents[ i ].normalize(); - - } - - initialNormal3(); - - /* - function initialNormal1(lastBinormal) { - // fixed start binormal. Has dangers of 0 vectors - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); - normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - } - - function initialNormal2() { - - // This uses the Frenet-Serret formula for deriving binormal - var t2 = path.getTangentAt( epsilon ); - - normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); - binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); - - normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - - } - */ - - function initialNormal3() { - // select an initial normal vector perpenicular to the first tangent vector, - // and in the direction of the smallest tangent xyz component - - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - smallest = Number.MAX_VALUE; - tx = Math.abs( tangents[ 0 ].x ); - ty = Math.abs( tangents[ 0 ].y ); - tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= smallest ) { - smallest = tx; - normal.set( 1, 0, 0 ); - } - - if ( ty <= smallest ) { - smallest = ty; - normal.set( 0, 1, 0 ); - } - - if ( tz <= smallest ) { - 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 path - - for ( i = 1; i < numpoints; i ++ ) { - - normals[ i ] = normals[ i - 1 ].clone(); - - binormals[ i ] = binormals[ i - 1 ].clone(); - - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - - if ( vec.length() > epsilon ) { - - vec.normalize(); - - theta = Math.acos( THREE.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 ) { - - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) ); - theta /= ( numpoints - 1 ); - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { - - theta = - theta; - - } - - for ( i = 1; i < numpoints; i ++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } -}; - -// File:src/extras/geometries/PolyhedronGeometry.js - -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { - - THREE.Geometry.call( this ); - - this.type = 'PolyhedronGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - radius = radius || 1; - detail = detail || 0; - - var that = this; - - for ( var i = 0, l = vertices.length; i < l; i += 3 ) { - - prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - - } - - var p = this.vertices; - - var faces = []; - - for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { - - var v1 = p[ indices[ i ] ]; - var v2 = p[ indices[ i + 1 ] ]; - var v3 = p[ indices[ i + 2 ] ]; - - faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - - } - - var centroid = new THREE.Vector3(); - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - subdivide( faces[ i ], detail ); - - } - - - // Handle case when face straddles the seam - - for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { - - var uvs = this.faceVertexUvs[ 0 ][ i ]; - - var x0 = uvs[ 0 ].x; - var x1 = uvs[ 1 ].x; - var x2 = uvs[ 2 ].x; - - var max = Math.max( x0, Math.max( x1, x2 ) ); - var min = Math.min( x0, Math.min( x1, x2 ) ); - - if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary - - if ( x0 < 0.2 ) uvs[ 0 ].x += 1; - if ( x1 < 0.2 ) uvs[ 1 ].x += 1; - if ( x2 < 0.2 ) uvs[ 2 ].x += 1; - - } - - } - - - // Apply radius - - for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { - - this.vertices[ i ].multiplyScalar( radius ); - - } - - - // Merge vertices - - this.mergeVertices(); - - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - - - // Project vector onto sphere's surface - - function prepare( vector ) { - - var vertex = vector.normalize().clone(); - vertex.index = that.vertices.push( vertex ) - 1; - - // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. - - var u = azimuth( vector ) / 2 / Math.PI + 0.5; - var v = inclination( vector ) / Math.PI + 0.5; - vertex.uv = new THREE.Vector2( u, 1 - v ); - - return vertex; - - } - - - // Approximate a curved face with recursively sub-divided triangles. - - function make( v1, v2, v3 ) { - - var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - that.faces.push( face ); - - centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - - var azi = azimuth( centroid ); - - that.faceVertexUvs[ 0 ].push( [ - correctUV( v1.uv, v1, azi ), - correctUV( v2.uv, v2, azi ), - correctUV( v3.uv, v3, azi ) - ] ); - - } - - - // Analytically subdivide a face to the required detail level. - - function subdivide( face, detail ) { - - var cols = Math.pow(2, detail); - var a = prepare( that.vertices[ face.a ] ); - var b = prepare( that.vertices[ face.b ] ); - var c = prepare( that.vertices[ face.c ] ); - var v = []; - - // Construct all of the vertices for this subdivision. - - for ( var i = 0 ; i <= cols; i ++ ) { - - v[ i ] = []; - - var aj = prepare( a.clone().lerp( c, i / cols ) ); - var bj = prepare( b.clone().lerp( c, i / cols ) ); - var rows = cols - i; - - for ( var j = 0; j <= rows; j ++) { - - if ( j == 0 && i == cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); - - } - - } - - } - - // Construct all of the faces. - - for ( var i = 0; i < cols ; i ++ ) { - - for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { - - var k = Math.floor( j / 2 ); - - if ( j % 2 == 0 ) { - - make( - v[ i ][ k + 1], - v[ i + 1 ][ k ], - v[ i ][ k ] - ); - - } else { - - make( - v[ i ][ k + 1 ], - v[ i + 1][ k + 1], - v[ i + 1 ][ k ] - ); - - } - - } - - } - - } - - - // 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 ) ) ); - - } - - - // Texture fixing helper. Spheres have some odd behaviours. - - function correctUV( uv, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); - return uv.clone(); - - } - - -}; - -THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry; - -// File:src/extras/geometries/DodecahedronGeometry.js - -/** - * @author Abe Pazos / https://hamoid.com - */ - -THREE.DodecahedronGeometry = function ( radius, detail ) { - - this.parameters = { - radius: radius, - detail: 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 - ]; - - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - -}; - -THREE.DodecahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry; - -// File:src/extras/geometries/IcosahedronGeometry.js - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.IcosahedronGeometry = function ( 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 - ]; - - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'IcosahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; -}; - -THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry; - -// File:src/extras/geometries/OctahedronGeometry.js - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.OctahedronGeometry = function ( radius, detail ) { - - this.parameters = { - radius: radius, - detail: 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 - ]; - - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'OctahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; -}; - -THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry; - -// File:src/extras/geometries/TetrahedronGeometry.js - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.TetrahedronGeometry = function ( 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 - ]; - - THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'TetrahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - -}; - -THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; - -// File:src/extras/geometries/ParametricGeometry.js - -/** - * @author zz85 / https://github.com/zz85 - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - * - * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); - * - */ - -THREE.ParametricGeometry = function ( func, slices, stacks ) { - - THREE.Geometry.call( this ); - - this.type = 'ParametricGeometry'; - - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; - - var verts = this.vertices; - var faces = this.faces; - var uvs = this.faceVertexUvs[ 0 ]; - - var i, j, p; - var u, v; - - var sliceCount = slices + 1; - - for ( i = 0; i <= stacks; i ++ ) { - - v = i / stacks; - - for ( j = 0; j <= slices; j ++ ) { - - u = j / slices; - - p = func( u, v ); - verts.push( p ); - - } - } - - var a, b, c, d; - var uva, uvb, uvc, uvd; - - for ( i = 0; i < stacks; i ++ ) { - - for ( j = 0; j < slices; j ++ ) { - - a = i * sliceCount + j; - b = i * sliceCount + j + 1; - c = (i + 1) * sliceCount + j + 1; - d = (i + 1) * sliceCount + j; - - uva = new THREE.Vector2( j / slices, i / stacks ); - uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); - uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); - uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); - - faces.push( new THREE.Face3( a, b, d ) ); - uvs.push( [ uva, uvb, uvd ] ); - - faces.push( new THREE.Face3( b, c, d ) ); - uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - - } - - // console.log(this); - - // magic bullet - // var diff = this.mergeVertices(); - // console.log('removed ', diff, ' vertices by merging'); - - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); -THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; - -// File:src/extras/helpers/AxisHelper.js - -/** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.AxisHelper = function ( size ) { - - size = size || 1; - - var vertices = new Float32Array( [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ] ); - - var colors = new Float32Array( [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ] ); - - var geometry = new THREE.BufferGeometry(); - geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - -}; - -THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; - -// File:src/extras/helpers/ArrowHelper.js - -/** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 - * @author bhouston / http://exocortex.com - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * color - color in hex value - * headLength - Number - * headWidth - Number - */ - -THREE.ArrowHelper = ( function () { - - var lineGeometry = new THREE.Geometry(); - lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); - - var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); - coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); - - return function ( dir, origin, length, color, headLength, headWidth ) { - - // dir is assumed to be normalized - - THREE.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; - - this.position.copy( origin ); - - this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - - } - -}() ); - -THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); -THREE.ArrowHelper.prototype.constructor = THREE.ArrowHelper; - -THREE.ArrowHelper.prototype.setDirection = ( function () { - - var axis = new THREE.Vector3(); - var radians; - - return function ( 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 ); - - } - - }; - -}() ); - -THREE.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, length - headLength, 1 ); - this.line.updateMatrix(); - - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); - -}; - -THREE.ArrowHelper.prototype.setColor = function ( color ) { - - this.line.material.color.set( color ); - this.cone.material.color.set( color ); - -}; - -// File:src/extras/helpers/BoxHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BoxHelper = function ( object ) { - - var geometry = new THREE.BufferGeometry(); - geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 72 ), 3 ) ); - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); - - if ( object !== undefined ) { - - this.update( object ); - - } - -}; - -THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.BoxHelper.prototype.constructor = THREE.BoxHelper; - -THREE.BoxHelper.prototype.update = function ( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - var min = geometry.boundingBox.min; - var max = geometry.boundingBox.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 vertices = this.geometry.attributes.position.array; - - vertices[ 0 ] = max.x; vertices[ 1 ] = max.y; vertices[ 2 ] = max.z; - vertices[ 3 ] = min.x; vertices[ 4 ] = max.y; vertices[ 5 ] = max.z; - - vertices[ 6 ] = min.x; vertices[ 7 ] = max.y; vertices[ 8 ] = max.z; - vertices[ 9 ] = min.x; vertices[ 10 ] = min.y; vertices[ 11 ] = max.z; - - vertices[ 12 ] = min.x; vertices[ 13 ] = min.y; vertices[ 14 ] = max.z; - vertices[ 15 ] = max.x; vertices[ 16 ] = min.y; vertices[ 17 ] = max.z; - - vertices[ 18 ] = max.x; vertices[ 19 ] = min.y; vertices[ 20 ] = max.z; - vertices[ 21 ] = max.x; vertices[ 22 ] = max.y; vertices[ 23 ] = max.z; - - // - - vertices[ 24 ] = max.x; vertices[ 25 ] = max.y; vertices[ 26 ] = min.z; - vertices[ 27 ] = min.x; vertices[ 28 ] = max.y; vertices[ 29 ] = min.z; - - vertices[ 30 ] = min.x; vertices[ 31 ] = max.y; vertices[ 32 ] = min.z; - vertices[ 33 ] = min.x; vertices[ 34 ] = min.y; vertices[ 35 ] = min.z; - - vertices[ 36 ] = min.x; vertices[ 37 ] = min.y; vertices[ 38 ] = min.z; - vertices[ 39 ] = max.x; vertices[ 40 ] = min.y; vertices[ 41 ] = min.z; - - vertices[ 42 ] = max.x; vertices[ 43 ] = min.y; vertices[ 44 ] = min.z; - vertices[ 45 ] = max.x; vertices[ 46 ] = max.y; vertices[ 47 ] = min.z; - - // - - vertices[ 48 ] = max.x; vertices[ 49 ] = max.y; vertices[ 50 ] = max.z; - vertices[ 51 ] = max.x; vertices[ 52 ] = max.y; vertices[ 53 ] = min.z; - - vertices[ 54 ] = min.x; vertices[ 55 ] = max.y; vertices[ 56 ] = max.z; - vertices[ 57 ] = min.x; vertices[ 58 ] = max.y; vertices[ 59 ] = min.z; - - vertices[ 60 ] = min.x; vertices[ 61 ] = min.y; vertices[ 62 ] = max.z; - vertices[ 63 ] = min.x; vertices[ 64 ] = min.y; vertices[ 65 ] = min.z; - - vertices[ 66 ] = max.x; vertices[ 67 ] = min.y; vertices[ 68 ] = max.z; - vertices[ 69 ] = max.x; vertices[ 70 ] = min.y; vertices[ 71 ] = min.z; - - this.geometry.attributes.position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - -}; - -// File:src/extras/helpers/BoundingBoxHelper.js - -/** - * @author WestLangley / http://github.com/WestLangley - */ - -// a helper to show the world-axis-aligned bounding box for an object - -THREE.BoundingBoxHelper = function ( object, hex ) { - - var color = ( hex !== undefined ) ? hex : 0x888888; - - this.object = object; - - this.box = new THREE.Box3(); - - THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); - -}; - -THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); -THREE.BoundingBoxHelper.prototype.constructor = THREE.BoundingBoxHelper; - -THREE.BoundingBoxHelper.prototype.update = function () { - - this.box.setFromObject( this.object ); - - this.box.size( this.scale ); - - this.box.center( this.position ); - -}; - -// File:src/extras/helpers/CameraHelper.js - -/** - * @author alteredq / http://alteredqualia.com/ - * - * - 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 - */ - -THREE.CameraHelper = function ( camera ) { - - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); - - var pointMap = {}; - - // colors - - var hexFrustum = 0xffaa00; - var hexCone = 0xff0000; - var hexUp = 0x00aaff; - var hexTarget = 0xffffff; - var hexCross = 0x333333; - - // near - - addLine( "n1", "n2", hexFrustum ); - addLine( "n2", "n4", hexFrustum ); - addLine( "n4", "n3", hexFrustum ); - addLine( "n3", "n1", hexFrustum ); - - // far - - addLine( "f1", "f2", hexFrustum ); - addLine( "f2", "f4", hexFrustum ); - addLine( "f4", "f3", hexFrustum ); - addLine( "f3", "f1", hexFrustum ); - - // sides - - addLine( "n1", "f1", hexFrustum ); - addLine( "n2", "f2", hexFrustum ); - addLine( "n3", "f3", hexFrustum ); - addLine( "n4", "f4", hexFrustum ); - - // cone - - addLine( "p", "n1", hexCone ); - addLine( "p", "n2", hexCone ); - addLine( "p", "n3", hexCone ); - addLine( "p", "n4", hexCone ); - - // up - - addLine( "u1", "u2", hexUp ); - addLine( "u2", "u3", hexUp ); - addLine( "u3", "u1", hexUp ); - - // target - - addLine( "c", "t", hexTarget ); - addLine( "p", "c", hexCross ); - - // cross - - addLine( "cn1", "cn2", hexCross ); - addLine( "cn3", "cn4", hexCross ); - - addLine( "cf1", "cf2", hexCross ); - addLine( "cf3", "cf4", hexCross ); - - function addLine( a, b, hex ) { - - addPoint( a, hex ); - addPoint( b, hex ); - - } - - function addPoint( id, hex ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.colors.push( new THREE.Color( hex ) ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( geometry.vertices.length - 1 ); - - } - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - - this.camera = camera; - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - -}; - -THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.CameraHelper.prototype.constructor = THREE.CameraHelper; - -THREE.CameraHelper.prototype.update = function () { - - var geometry, pointMap; - - var vector = new THREE.Vector3(); - var camera = new THREE.Camera(); - - var setPoint = function ( point, x, y, z ) { - - vector.set( x, y, z ).unproject( camera ); - - var points = pointMap[ point ]; - - if ( points !== undefined ) { - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - geometry.vertices[ points[ i ] ].copy( vector ); - - } - - } - - }; - - return function () { - - 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.verticesNeedUpdate = true; - - }; - -}(); - -// File:src/extras/helpers/DirectionalLightHelper.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.DirectionalLightHelper = function ( light, size ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - size = size || 1; - - var geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3( - size, size, 0 ), - new THREE.Vector3( size, size, 0 ), - new THREE.Vector3( size, - size, 0 ), - new THREE.Vector3( - size, - size, 0 ), - new THREE.Vector3( - size, size, 0 ) - ); - - var material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.lightPlane = new THREE.Line( geometry, material ); - this.add( this.lightPlane ); - - geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3(), - new THREE.Vector3() - ); - - material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.targetLine = new THREE.Line( geometry, material ); - this.add( this.targetLine ); - - this.update(); - -}; - -THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); -THREE.DirectionalLightHelper.prototype.constructor = THREE.DirectionalLightHelper; - -THREE.DirectionalLightHelper.prototype.dispose = function () { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); -}; - -THREE.DirectionalLightHelper.prototype.update = function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var v3 = new THREE.Vector3(); - - return function () { - - v1.setFromMatrixPosition( this.light.matrixWorld ); - v2.setFromMatrixPosition( this.light.target.matrixWorld ); - v3.subVectors( v2, v1 ); - - this.lightPlane.lookAt( v3 ); - this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.targetLine.geometry.vertices[ 1 ].copy( v3 ); - this.targetLine.geometry.verticesNeedUpdate = true; - this.targetLine.material.color.copy( this.lightPlane.material.color ); - - }; - -}(); - -// File:src/extras/helpers/EdgesHelper.js - -/** - * @author WestLangley / http://github.com/WestLangley - * @param object THREE.Mesh whose geometry will be used - * @param hex line color - * @param thresholdAngle the minimim angle (in degrees), - * between the face normals of adjacent faces, - * that is required to render an edge. A value of 10 means - * an edge is only rendered if the angle is at least 10 degrees. - */ - -THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { - - var color = ( hex !== undefined ) ? hex : 0xffffff; - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - - var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); - - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; - - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); - - var geometry2; - - if ( object.geometry instanceof THREE.BufferGeometry ) { - - geometry2 = new THREE.Geometry(); - geometry2.fromBufferGeometry( object.geometry ); - - } else { - - geometry2 = object.geometry.clone(); - - } - - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); - - var vertices = geometry2.vertices; - var faces = geometry2.faces; - var numEdges = 0; - - 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 ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; - numEdges ++; - - } else { - - hash[ key ].face2 = i; - - } - - } - - } - - var coords = new Float32Array( numEdges * 2 * 3 ); - - var index = 0; - - for ( var key in hash ) { - - var h = hash[ key ]; - - if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { - - var vertex = vertices[ h.vert1 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; - - vertex = vertices[ h.vert2 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; - - } - - } - - geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - -}; - -THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; - -// File:src/extras/helpers/FaceNormalsHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xffff00; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var faces = this.object.geometry.faces; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.normalMatrix = new THREE.Matrix3(); - - this.update(); - -}; - -THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper; - -THREE.FaceNormalsHelper.prototype.update = function () { - - var vertices = this.geometry.vertices; - - var object = this.object; - var objectVertices = object.geometry.vertices; - var objectFaces = object.geometry.faces; - var objectWorldMatrix = object.matrixWorld; - - object.updateMatrixWorld( true ); - - this.normalMatrix.getNormalMatrix( objectWorldMatrix ); - - for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) { - - var face = objectFaces[ i ]; - - vertices[ i2 ].copy( objectVertices[ face.a ] ) - .add( objectVertices[ face.b ] ) - .add( objectVertices[ face.c ] ) - .divideScalar( 3 ) - .applyMatrix4( objectWorldMatrix ); - - vertices[ i2 + 1 ].copy( face.normal ) - .applyMatrix3( this.normalMatrix ) - .normalize() - .multiplyScalar( this.size ) - .add( vertices[ i2 ] ); - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - -}; - - -// File:src/extras/helpers/GridHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.GridHelper = function ( size, step ) { - - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - - this.color1 = new THREE.Color( 0x444444 ); - this.color2 = new THREE.Color( 0x888888 ); - - for ( var i = - size; i <= size; i += step ) { - - geometry.vertices.push( - new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), - new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) - ); - - var color = i === 0 ? this.color1 : this.color2; - - geometry.colors.push( color, color, color, color ); - - } - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - -}; - -THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.GridHelper.prototype.constructor = THREE.GridHelper; - -THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { - - this.color1.set( colorCenterLine ); - this.color2.set( colorGrid ); - - this.geometry.colorsNeedUpdate = true; - -} - -// File:src/extras/helpers/HemisphereLightHelper.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.HemisphereLightHelper = function ( light, sphereSize ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.colors = [ new THREE.Color(), new THREE.Color() ]; - - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - - for ( var i = 0, il = 8; i < il; i ++ ) { - - geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; - - } - - var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); - - this.lightSphere = new THREE.Mesh( geometry, material ); - this.add( this.lightSphere ); - - this.update(); - -}; - -THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); -THREE.HemisphereLightHelper.prototype.constructor = THREE.HemisphereLightHelper; - -THREE.HemisphereLightHelper.prototype.dispose = function () { - this.lightSphere.geometry.dispose(); - this.lightSphere.material.dispose(); -}; - -THREE.HemisphereLightHelper.prototype.update = function () { - - var vector = new THREE.Vector3(); - - return function () { - - this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); - - this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - this.lightSphere.geometry.colorsNeedUpdate = true; - - } - -}(); - -// File:src/extras/helpers/PointLightHelper.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.PointLightHelper = function ( light, sphereSize ) { - - this.light = light; - this.light.updateMatrixWorld(); - - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - THREE.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 ); - */ - -}; - -THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); -THREE.PointLightHelper.prototype.constructor = THREE.PointLightHelper; - -THREE.PointLightHelper.prototype.dispose = function () { - - this.geometry.dispose(); - this.material.dispose(); -}; - -THREE.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 ); - - } - */ - -}; - -// File:src/extras/helpers/SkeletonHelper.js - -/** - * @author Sean Griffin / http://twitter.com/sgrif - * @author Michael Guerrero / http://realitymeltdown.com - * @author mrdoob / http://mrdoob.com/ - * @author ikerr / http://verold.com - */ - -THREE.SkeletonHelper = function ( object ) { - - this.bones = this.getBoneList( object ); - - var geometry = new THREE.Geometry(); - - for ( var i = 0; i < this.bones.length; i ++ ) { - - var bone = this.bones[ i ]; - - if ( bone.parent instanceof THREE.Bone ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - geometry.colors.push( new THREE.Color( 0, 0, 1 ) ); - geometry.colors.push( new THREE.Color( 0, 1, 0 ) ); - - } - - } - - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } ); - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - - this.root = object; - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - - this.update(); - -}; - - -THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper; - -THREE.SkeletonHelper.prototype.getBoneList = function( object ) { - - var boneList = []; - - if ( object instanceof THREE.Bone ) { - - boneList.push( object ); - - } - - for ( var i = 0; i < object.children.length; i ++ ) { - - boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); - - } - - return boneList; - -}; - -THREE.SkeletonHelper.prototype.update = function () { - - var geometry = this.geometry; - - var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld ); - - var boneMatrix = new THREE.Matrix4(); - - var j = 0; - - for ( var i = 0; i < this.bones.length; i ++ ) { - - var bone = this.bones[ i ]; - - if ( bone.parent instanceof THREE.Bone ) { - - boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); - geometry.vertices[ j ].setFromMatrixPosition( boneMatrix ); - - boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); - geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix ); - - j += 2; - - } - - } - - geometry.verticesNeedUpdate = true; - - geometry.computeBoundingSphere(); - -}; - -// File:src/extras/helpers/SpotLightHelper.js - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.SpotLightHelper = function ( light ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); - - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - - this.cone = new THREE.Mesh( geometry, material ); - this.add( this.cone ); - - this.update(); - -}; - -THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); -THREE.SpotLightHelper.prototype.constructor = THREE.SpotLightHelper; - -THREE.SpotLightHelper.prototype.dispose = function () { - this.cone.geometry.dispose(); - this.cone.material.dispose(); -}; - -THREE.SpotLightHelper.prototype.update = function () { - - var vector = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); - - return function () { - - var coneLength = this.light.distance ? this.light.distance : 10000; - 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 ); - - }; - -}(); - -// File:src/extras/helpers/VertexNormalsHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.VertexNormalsHelper = function ( 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 geometry = new THREE.Geometry(); - - var faces = object.geometry.faces; - - 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 ++ ) { - - geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.normalMatrix = new THREE.Matrix3(); - - this.update(); - -}; - -THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper; - -THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function( object ) { - - var keys = [ 'a', 'b', 'c', 'd' ]; - - this.object.updateMatrixWorld( true ); - - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - - var vertices = this.geometry.vertices; - - var verts = this.object.geometry.vertices; - - var faces = this.object.geometry.faces; - - var worldMatrix = this.object.matrixWorld; - - 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 vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; - - var normal = face.vertexNormals[ j ]; - - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - - v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); - - v1.add( vertices[ idx ] ); - idx = idx + 1; - - vertices[ idx ].copy( v1 ); - idx = idx + 1; - - } - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - - } - -}()); - -// File:src/extras/helpers/VertexTangentsHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0x0000ff; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var faces = object.geometry.faces; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.update(); - -}; - -THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.VertexTangentsHelper.prototype.constructor = THREE.VertexTangentsHelper; - -THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function( object ) { - - var keys = [ 'a', 'b', 'c', 'd' ]; - - this.object.updateMatrixWorld( true ); - - var vertices = this.geometry.vertices; - - var verts = this.object.geometry.vertices; - - var faces = this.object.geometry.faces; - - var worldMatrix = this.object.matrixWorld; - - var idx = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; - - var tangent = face.vertexTangents[ j ]; - - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - - v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); - - v1.add( vertices[ idx ] ); - idx = idx + 1; - - vertices[ idx ].copy( v1 ); - idx = idx + 1; - - } - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - - } - -}()); - -// File:src/extras/helpers/WireframeHelper.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.WireframeHelper = function ( object, hex ) { - - var color = ( hex !== undefined ) ? hex : 0xffffff; - - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; - - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); - - if ( object.geometry instanceof THREE.Geometry ) { - - var vertices = object.geometry.vertices; - var faces = object.geometry.faces; - var numEdges = 0; - - // allocate maximal size - var edges = new Uint32Array( 6 * faces.length ); - - 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 ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; - - } - - } - - } - - var coords = new Float32Array( numEdges * 2 * 3 ); - - for ( var i = 0, l = numEdges; i < l; i ++ ) { - - for ( var j = 0; j < 2; j ++ ) { - - var vertex = vertices[ edges [ 2 * i + j] ]; - - var index = 6 * i + 3 * j; - coords[ index + 0 ] = vertex.x; - coords[ index + 1 ] = vertex.y; - coords[ index + 2 ] = vertex.z; - - } - - } - - geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - - } else if ( object.geometry instanceof THREE.BufferGeometry ) { - - if ( object.geometry.attributes.index !== undefined ) { // Indexed BufferGeometry - - var vertices = object.geometry.attributes.position.array; - var indices = object.geometry.attributes.index.array; - var drawcalls = object.geometry.drawcalls; - var numEdges = 0; - - if ( drawcalls.length === 0 ) { - - drawcalls = [ { count : indices.length, index : 0, start : 0 } ]; - - } - - // allocate maximal size - var edges = new Uint32Array( 2 * indices.length ); - - for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) { - - var start = drawcalls[ o ].start; - var count = drawcalls[ o ].count; - var index = drawcalls[ o ].index; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - for ( var j = 0; j < 3; j ++ ) { - - edge[ 0 ] = index + indices[ i + j ]; - edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; - edge.sort( sortFunction ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; - - } - - } - - } - - } - - var coords = new Float32Array( numEdges * 2 * 3 ); - - for ( var i = 0, l = numEdges; i < l; i ++ ) { - - for ( var j = 0; j < 2; j ++ ) { - - var index = 6 * i + 3 * j; - var index2 = 3 * edges[ 2 * i + j]; - coords[ index + 0 ] = vertices[ index2 ]; - coords[ index + 1 ] = vertices[ index2 + 1 ]; - coords[ index + 2 ] = vertices[ index2 + 2 ]; - - } - - } - - geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - - } else { // non-indexed BufferGeometry - - var vertices = object.geometry.attributes.position.array; - var numEdges = vertices.length / 3; - var numTris = numEdges / 3; - - var coords = new Float32Array( numEdges * 2 * 3 ); - - for ( var i = 0, l = numTris; i < l; i ++ ) { - - for ( var j = 0; j < 3; j ++ ) { - - var index = 18 * i + 6 * j; - - var index1 = 9 * i + 3 * j; - coords[ index + 0 ] = vertices[ index1 ]; - coords[ index + 1 ] = vertices[ index1 + 1 ]; - coords[ index + 2 ] = vertices[ index1 + 2 ]; - - var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); - coords[ index + 3 ] = vertices[ index2 ]; - coords[ index + 4 ] = vertices[ index2 + 1 ]; - coords[ index + 5 ] = vertices[ index2 + 2 ]; - - } - - } - - geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - -}; - -THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); -THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; - -// File:src/extras/objects/ImmediateRenderObject.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ImmediateRenderObject = function () { - - THREE.Object3D.call( this ); - - this.render = function ( renderCallback ) {}; - -}; - -THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); -THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; - -// File:src/extras/objects/MorphBlendMesh.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphBlendMesh = function( geometry, material ) { - - THREE.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 ); - -}; - -THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); -THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; - -THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { - - var animation = { - - startFrame: start, - endFrame: 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 ); - -}; - -THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { - - var pattern = /([a-z]+)_?(\d+)/; - - 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; - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.direction = 1; - animation.directionBackwards = false; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.direction = - 1; - animation.directionBackwards = true; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.fps = fps; - animation.duration = ( animation.end - animation.start ) / animation.fps; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.duration = duration; - animation.fps = ( animation.end - animation.start ) / animation.duration; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.weight = weight; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.time = time; - - } - -}; - -THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { - - var time = 0; - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - time = animation.time; - - } - - return time; - -}; - -THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { - - var duration = - 1; - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - duration = animation.duration; - - } - - return duration; - -}; - -THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.time = 0; - animation.active = true; - - } else { - - THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); - - } - -}; - -THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.active = false; - - } - -}; - -THREE.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.startFrame + THREE.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; - - this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; - this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; - - } - -}; - - - -global.THREE = THREE; - - From 863062a208289d5afcf010f107b9f3b8fb0fe936 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 18 Jul 2015 09:21:54 -0400 Subject: [PATCH 41/43] engine shuts down on unload again --- scripts/engine.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/engine.js b/scripts/engine.js index a2837ad..d373889 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -40,8 +40,9 @@ elation.require(deps, function() { this.init = function() { this.systems = new elation.engine.systems(this); // shutdown cleanly if the user leaves the page - // TODO - // elation.events.add(window, "unload", elation.bind(this, this.stop)); + var target = null; + if (ENV_IS_BROWSER) target = window + elation.events.add(target, "unload", elation.bind(this, this.stop)); } this.start = function() { this.started = this.running = true; @@ -69,7 +70,6 @@ elation.require(deps, function() { // fire engine_frame event, which kicks off processing in any active systems //console.log("=========="); elation.events.fire({type: "engine_frame", element: this, data: evdata}); - // console.log('did a frame', this.systems.world.children.vrcade); this.lastupdate = ts; } From 1a7fd78baa8f373406a42b56a2e17352fd49ddc1 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 18 Jul 2015 09:29:49 -0400 Subject: [PATCH 42/43] add connect() function to client system, add initNetwork to shooter_client --- scripts/systems/client.js | 15 ++++++++++----- scripts/things/shooter_client.js | 11 ++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index 0bb62b1..9819e80 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -12,16 +12,21 @@ elation.extend("engine.systems.client", function(args) { this.system_attach = function(ev) { console.log('INIT: networking client'); this.world = this.engine.systems.world; - this.connection = new elation.engine.systems.client.connection({ - transport: 'websocket', - host: 'dev.brandonhinshaw.us', - port: '9001' - }); + // this.connection = new elation.engine.systems.client.connection({ + // transport: 'websocket', + // host: 'dev.brandonhinshaw.us', + // port: '9001' + // }); elation.events.add(this.connection.socket, 'new_message', elation.bind(this, this.onNewMessage)); elation.events.add(this.world, 'world_thing_add', elation.bind(this, this.onNewThing)); // elation.events.add(this.world, 'world_thing_remove', elation.bind(this, this.onThingRemove)); }; + this.connect = function(args) { + if (this.connection) return; + this.connection = new elation.engine.systems.client.connection(args); + } + this.onNewThing = function(ev) { var thing = ev.data.thing; if (thing.hasTag('local_sync')) { diff --git a/scripts/things/shooter_client.js b/scripts/things/shooter_client.js index 3888461..1522970 100644 --- a/scripts/things/shooter_client.js +++ b/scripts/things/shooter_client.js @@ -18,9 +18,18 @@ elation.require(_reqs, function() { // this.init = function() { // this.name = this.args.name || 'default'; // } - + this.initNetwork = function() { + // virtual - override this to create your connection, e.g. + // + // this.engine.systems.client.connect({ + // transport: 'websocket', + // host: 'dev.brandonhinshaw.us', + // port: '9001' + // }) + } this.postinit = function() { console.log('engine:', this.engine); + this.initNetwork(); elation.events.add(this.engine.systems.client, 'world_data', elation.bind(this, this.loadWorld)); elation.events.add(this.engine.systems.client, 'id_token', elation.bind(this, this.setIdToken)); elation.events.add(this.engine.systems.client, 'thing_added', elation.bind(this, this.createRemoteObject)); From 9fcc86abd0f140cd296db87fed9a05f27be95522 Mon Sep 17 00:00:00 2001 From: bioid Date: Sat, 18 Jul 2015 09:42:15 -0400 Subject: [PATCH 43/43] servers and clients must now be started by the game, which will supply the address/port/transport --- scripts/systems/client.js | 11 +++------- scripts/systems/server.js | 36 ++++++++++++++++++++------------ scripts/things/shooter_server.js | 5 +++++ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/scripts/systems/client.js b/scripts/systems/client.js index 9819e80..f06bcd8 100644 --- a/scripts/systems/client.js +++ b/scripts/systems/client.js @@ -12,19 +12,14 @@ elation.extend("engine.systems.client", function(args) { this.system_attach = function(ev) { console.log('INIT: networking client'); this.world = this.engine.systems.world; - // this.connection = new elation.engine.systems.client.connection({ - // transport: 'websocket', - // host: 'dev.brandonhinshaw.us', - // port: '9001' - // }); - elation.events.add(this.connection.socket, 'new_message', elation.bind(this, this.onNewMessage)); - elation.events.add(this.world, 'world_thing_add', elation.bind(this, this.onNewThing)); - // elation.events.add(this.world, 'world_thing_remove', elation.bind(this, this.onThingRemove)); }; this.connect = function(args) { if (this.connection) return; this.connection = new elation.engine.systems.client.connection(args); + console.log(this.connection); + elation.events.add(this.connection.socket, 'new_message', elation.bind(this, this.onNewMessage)); + elation.events.add(this.world, 'world_thing_add', elation.bind(this, this.onNewThing)); } this.onNewThing = function(ev) { diff --git a/scripts/systems/server.js b/scripts/systems/server.js index 7c37260..ff5921b 100644 --- a/scripts/systems/server.js +++ b/scripts/systems/server.js @@ -10,14 +10,18 @@ elation.extend("engine.systems.server", function(args) { this.system_attach = function(ev) { console.log('INIT: networking server'); this.world = this.engine.systems.world; - this.server = new elation.engine.systems.server.websocket; - this.adminServer = new elation.engine.systems.server.adminserver; + // this.adminServer = new elation.engine.systems.server.adminserver; + }; + + this.start = function(args) { + this.server = new elation.engine.systems.server.websocket; + this.server.start(args.port); var events = [ [this.server, 'client_disconnected', this.onClientDisconnect], [this.server, 'client_connected', this.onClientConnect], [this.world, 'world_thing_add', this.onThingAdd], - [this.adminServer, 'admin_client_connected', this.onAdminClientConnect], + // [this.adminServer, 'admin_client_connected', this.onAdminClientConnect], [this.world, 'world_thing_remove', this.onThingRemove], // [this.world, 'thing_change', this.onThingChange] ]; @@ -255,17 +259,23 @@ elation.extend("engine.systems.server.client", function(args) { // FIXME - servers should take args for port/etc elation.extend("engine.systems.server.websocket", function() { - var wsServer = require('ws').Server, - wss = new wsServer({ port: 9001 }); - console.log('websocket server running on 9001') - wss.on('connection', function(ws) { - console.log('game server websocket conn'); - var id = Date.now(); - elation.events.fire({element: this, type: 'client_connected', data: {id: id, channel: ws}}); - ws.on('close', function() { - elation.events.fire({element: this, type: 'client_disconnected', data: {id: id}}); + var wsServer = require('ws').Server; + + this.start = function(port) { + if (wss) return; + + var wss = new wsServer({ port: port }); + console.log('websocket server running on', port); + + wss.on('connection', function(ws) { + console.log('game server websocket conn'); + var id = Date.now(); + elation.events.fire({element: this, type: 'client_connected', data: {id: id, channel: ws}}); + ws.on('close', function() { + elation.events.fire({element: this, type: 'client_disconnected', data: {id: id}}); + }.bind(this)); }.bind(this)); - }.bind(this)); + } }) diff --git a/scripts/things/shooter_server.js b/scripts/things/shooter_server.js index ecb1689..0eb8537 100644 --- a/scripts/things/shooter_server.js +++ b/scripts/things/shooter_server.js @@ -13,9 +13,14 @@ var _reqs = [ elation.component.add('engine.things.shooter_server', function() { this.players = {}; + this.initNetwork = function(args) { + this.server.start({ port: 9001 }); + }; + this.postinit = function() { // network events this.server = this.engine.systems.server; + this.initNetwork(); elation.events.add(this.server, 'add_player', elation.bind(this, this.spawnRemotePlayer)); elation.events.add(this.server, 'remote_thing_change', elation.bind(this, this.remoteThingChange)); elation.events.add(this.server, 'add_thing', elation.bind(this, this.spawnNewThing));