From 73af227fb36668180fb7cb9cd4cd7745aea1157f Mon Sep 17 00:00:00 2001 From: Expo on server Date: Sat, 29 Apr 2023 22:46:14 +0100 Subject: [PATCH] remove unused copy of CaveView in troggle and updated cave.html template for caveview2 --- media/jslib/CaveView installation.mhtml | 164 - media/jslib/CaveView/css/caveview.css | 403 - media/jslib/CaveView/images/disc.png | Bin 1399 -> 0 bytes media/jslib/CaveView/images/ic_explore.png | Bin 471 -> 0 bytes media/jslib/CaveView/images/ic_help.png | Bin 476 -> 0 bytes media/jslib/CaveView/images/ic_info.png | Bin 340 -> 0 bytes media/jslib/CaveView/images/ic_location.png | Bin 1151 -> 0 bytes media/jslib/CaveView/images/ic_remove.png | Bin 325 -> 0 bytes media/jslib/CaveView/images/ic_route.png | Bin 317 -> 0 bytes media/jslib/CaveView/images/ic_settings.png | Bin 460 -> 0 bytes media/jslib/CaveView/images/ic_terrain.png | Bin 231 -> 0 bytes media/jslib/CaveView/js/CaveView-min.js | 1 - media/jslib/CaveView/js/CaveView.js | 55946 ---------------- media/jslib/CaveView/js/workers/caveWorker.js | 23173 ------- .../CaveView/js/workers/webTileWorker-min.js | 1 - .../CaveView/js/workers/webTileWorker.js | 10005 --- media/jslib/CaveView/lib/BGS.js | 35 - media/jslib/CaveView/lib/BingProvider.js | 129 - media/jslib/CaveView/lib/Detector.js | 78 - media/jslib/CaveView/lib/NLSProvider.js | 25 - media/jslib/CaveView/lib/OSMProvider.js | 22 - media/jslib/CaveView/lib/proj4-src.js | 5917 -- media/jslib/CaveView/lib/proj4.js | 3 - ...eases · aardgoose-CaveView.js · GitHub.url | 2 - media/jslib/demo 3d cave viewer.url | 2 - templates/cave.html | 12 +- 26 files changed, 6 insertions(+), 95912 deletions(-) delete mode 100644 media/jslib/CaveView installation.mhtml delete mode 100644 media/jslib/CaveView/css/caveview.css delete mode 100644 media/jslib/CaveView/images/disc.png delete mode 100644 media/jslib/CaveView/images/ic_explore.png delete mode 100644 media/jslib/CaveView/images/ic_help.png delete mode 100644 media/jslib/CaveView/images/ic_info.png delete mode 100644 media/jslib/CaveView/images/ic_location.png delete mode 100644 media/jslib/CaveView/images/ic_remove.png delete mode 100644 media/jslib/CaveView/images/ic_route.png delete mode 100644 media/jslib/CaveView/images/ic_settings.png delete mode 100644 media/jslib/CaveView/images/ic_terrain.png delete mode 100644 media/jslib/CaveView/js/CaveView-min.js delete mode 100644 media/jslib/CaveView/js/CaveView.js delete mode 100644 media/jslib/CaveView/js/workers/caveWorker.js delete mode 100644 media/jslib/CaveView/js/workers/webTileWorker-min.js delete mode 100644 media/jslib/CaveView/js/workers/webTileWorker.js delete mode 100644 media/jslib/CaveView/lib/BGS.js delete mode 100644 media/jslib/CaveView/lib/BingProvider.js delete mode 100644 media/jslib/CaveView/lib/Detector.js delete mode 100644 media/jslib/CaveView/lib/NLSProvider.js delete mode 100644 media/jslib/CaveView/lib/OSMProvider.js delete mode 100644 media/jslib/CaveView/lib/proj4-src.js delete mode 100644 media/jslib/CaveView/lib/proj4.js delete mode 100644 media/jslib/Releases · aardgoose-CaveView.js · GitHub.url delete mode 100644 media/jslib/demo 3d cave viewer.url diff --git a/media/jslib/CaveView installation.mhtml b/media/jslib/CaveView installation.mhtml deleted file mode 100644 index 495e87b..0000000 --- a/media/jslib/CaveView installation.mhtml +++ /dev/null @@ -1,164 +0,0 @@ -From: -Snapshot-Content-Location: https://aardgoose.github.io/CaveView.js/installation.html -Subject: CaveView installation -Date: Sun, 24 Oct 2021 15:46:19 -0000 -MIME-Version: 1.0 -Content-Type: multipart/related; - type="text/html"; - boundary="----MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----" - - -------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ---- -Content-Type: text/html -Content-ID: -Content-Transfer-Encoding: quoted-printable -Content-Location: https://aardgoose.github.io/CaveView.js/installation.html - - - CaveView installation -=09 - - - -

Cave View - installation instructions - V2 API

-

Install CaveView files

-

A zip archive containing the required files for the latest release are = -here.

-

There is no need to build the JavaScript application from source files = -unless you would like to modify the application.

-

Unzip the archive in a convenient location on your web server

-

Using in a web page

- -

CaveView requires two files to be included in the page. Replace the plac= -eholder %path% with the path to the unzipped files on the server in the fol= -lowing examples.

- -

caveview.css

-

The side panel interface and on screen indicators are styled with cavevi= -ew.css. Include this in the head section of the page.

- -
	<link type=3D"text/css" href=3D"%path%/CaveView/css/caveview.css" =
-rel=3D"stylesheet" />
- -

CaveView.js

- -

The CaveView application is provided in one javascript file. Include thi= -s in the body section of the page. NOTE: The filen= -ame has changed for the V2 API.

- -
	<script type=3D"text/javascript" src=3D"%path%/CaveView/js/CaveVie=
-w2.js" ></script>
- -

Add a container element

- -

Add an empty block element to the page, with a suitable id attribute. This contains the application, and be sized as required. For= - example a div element:

- -
<div id=3D'% element-id %' ></div>
- -

Create a script to run the application

- -

The application can be loaded using javascript, typically using an load = -event handler. Replace the placeholder %...% elements with values appropria= -te for your site.

-
<script type=3D"text/javascript" >
-
-	function onLoad () {
-
-		// display the user interface - and a blank canvas
-
-		// the configuration object specifies the location of CaveView, surveys a=
-nd terrain files
-
-		var viewer =3D new CV2.CaveViewer( '% element-id %', {
-			home: '% location of the unzipped CaveView directory on the survey %',
-			surveyDirectory: '% location of the survey files on the server %',
-			terrainDirectory: '% location of the terrain files on the server %'
-		} );
-
-		// if using the full user interface (UI)
-
-		var ui =3D new CV2.CaveViewUI( viewer );
-
-		// load a single survey to display
-
-		ui.loadCave( '% survey filename %' );
-
-		// or without the user interface
-
-		viewer.loadCave( '% survey filename %' );
-
-	}
-
-</script>
-
- -

alternatively provide a list of surveys to display, by replacing the loa= -dCave() function call with loadCaveList() :

- -
	ui.loadCaveList( [ '% survey filename 1 %', '% survey filename 2 %', =
-'% survey filename 3 %' ] );
-
- -

This can be automatically executed on page load by including a page load= - handler in the page body tag:

-
<body onload=3D"onload();" >
- -

CaveView should now display when the page is viewed.

-

The example files included demonstrate using multiple viewers on a page, -changing the default view settings and altering the appearance of the viewe= -r.

- -

Removal

- -

To remove the viewer from a page and reclaim memory used promptly:

-
	ui.dispose();
-	ui =3D null;
-	viewer =3D null;
-
-

Or if not using the UI, just the viewer:

-
	viewer.dispose();
-	viewer =3D null;
-
- - - -------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ---- -Content-Type: text/css -Content-Transfer-Encoding: quoted-printable -Content-Location: https://aardgoose.github.io/CaveView.js/doc.css - -@charset "utf-8"; - -h1, h2 { margin: 0px 16px 1em; } - -h3, h4, h5, p, pre, dl { margin-left: 32px; margin-right: 32px; } - -h2 { border-bottom: 2px solid gray; } - -h3 { color: navy; } - -h4 { margin-top: 2em; background-color: rgb(238, 238, 238); padding: 3px 2p= -x 1px; } - -* { font-family: sans-serif; } - -pre { font-family: monospace; font-weight: bold; background-color: rgb(238,= - 238, 238); padding: 8px; } - -dd > span { display: inline-block; padding: 0px 2px; margin-right: 5px; bac= -kground: rgb(238, 238, 238); } - -dd > span::before { content: "["; } - -dd > span::after { content: "]"; } - -dt { margin-bottom: 0.5em; font-weight: bold; color: rgb(102, 102, 102); pa= -dding-left: 16px; } - -dd { margin-bottom: 1em; } -------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ------ diff --git a/media/jslib/CaveView/css/caveview.css b/media/jslib/CaveView/css/caveview.css deleted file mode 100644 index 675d941..0000000 --- a/media/jslib/CaveView/css/caveview.css +++ /dev/null @@ -1,403 +0,0 @@ -body { - margin: 0; - padding: 0; - font-family: 'Source Sans Pro Regular','Helvetica Neue',Helvetica,Arial,sans-serif; -} - -div.cv-panel { - position: absolute; - top: 0; - left: 0; - z-index: 100; - background-color: rgba(50,50,50,0.5); - color: yellowgreen; - border: 1px solid black; - border-radius: 5px; -} - -div.cv-compass, div.cv-ahi { - position: absolute; - bottom: 95px; - right: 5px; - margin: 0; - padding-top: 2px; - /* border: 1px solid white; */ - text-align: center; - width: 78px; - height: 19px; - z-index: 50; - background-color: rgba(50,50,50,0.5); - background-color: black; - color: white; -} - -div.cv-ahi { - right: 95px; -} - -div.scale-legend { - position: absolute; - color: white; - background-color: black; - bottom: 30px; -} - -div.linear-scale { - position: absolute; - color: white; - background-color: black; - right: 30px; - width: 40px; - padding: 2px 0; - text-align: right; - border: 1px solid black; - font-size: 14px; -} - -div.linear-scale-caption { - position: absolute; - color: white; - background-color: black; - right: 5px; - width: 65px; - padding: 2px 0 5px 0; - text-align: left; - border: 1px solid black; - font-size: 14px; -} - -#min-div { - border-bottom: 1px solid white; -} - -#max-div { - border-top: 1px solid white; -} - -#angle-legend { - position: absolute; - width: 80px; - right: 5px; - bottom: 180px; - color: white; - background-color: black; - font-size: 14px; - text-align: center; -} - -#scene { - width: 100%; - height: 700px; - position: relative; -} - -#progress-bar { - position: absolute; - top: 55%; - height: 20px; - border: 1px solid white; - z-index: 100; -} - -#status-text { - position: absolute; - top: 50%; - height: 20px; - padding-left: 4px; - background-color: black; - color: white; - z-index: 100; -} - -#frame div.page ul { - list-style-type: none; - margin: 8px 0 0 0; - padding: 0; - width: 200px; - height: 100%; - cursor: default; - font-size: 12px; - overflow-y: auto; - overflow-x: hidden; -} - -#frame div.page li { - position: relative; - margin-left: 16px; - border-bottom: 1px solid #444444; -} - -#frame div.page li.selected { - color: #1ab4e5; -} - -#frame div.page li:hover { - color: yellow; -} - -#frame div.page div#ui-path { - font-size: 12px; - border-top: 1px solid grey; - border-bottom: 1px solid grey; - margin-top: 8px; - padding: 2px 0 2px 12px; -} - -#frame div.page div#ui-path span { - color: #1ab4e5; -} - -#frame div.page div.slide { - position: absolute; - top: 64px; - left: 0px; - height: auto; - margin-top:0; - bottom: 44px; - background-color: #222222; - transition: transform 0.25s ease-in; -} - -#frame div.slide-out { - border-right: 1px grey solid; - transform: translateX(-100%); -} - -#frame div.page div.descend-tree { - position: absolute; - top: 0px; - right: 0px; - margin: 0; - color: #1ab4e5; - z-index: 110; -} - -#frame { - position: absolute; - top: 0px; - left: 0px; - width: 240px; - height: 100%; - background-color: transparent; - transform: translateX(-200px); - transition: transform 0.25s ease-in; -} - -#frame.onscreen { - transform: none; - transition: transform 0.25s ease-out; -} - -#frame a.download { - border: 1px solid green; - display: block; - width: 180px; - box-sizing: border-box; - margin-top: 6px; - margin-bottom: 4px; - margin-left: 8px; - border: none; - border-bottom: 4px solid #1ab4e5; - color: #dddddd; - background-color: black; - padding-bottom: 4px; - box-shadow: 1px 1px 8px 0px #888888; - outline: none; - text-decoration: none; - text-align: center; -} - -#frame a.download:hover { - color: white; -} - -#frame a.download:active { - color: #dddddd; - border-bottom: 4px solid #0c536a; - box-shadow: none; - box-shadow: inset 1px 1px 8px 0px #888888; -} -#frame .tab { - position: absolute; - right: 0px; - width: 40px; - height: 40px; - box-sizing: border-box; - background-color: #444444; - border-left: 1px solid black; - background-position: center; - border-top: 1px solid black; -} - -#frame #close { - position: absolute; - right: 40px; - bottom: 0px; - width: 40px; - height: 40px; - box-sizing: border-box; - z-index: 150; - background-image: url(../images/ic_remove.png); - background-position: center; -} - -#icon_settings { - background-image: url(../images/ic_settings.png); -} - -#icon_terrain { - background-image: url(../images/ic_terrain.png); -} - -#icon_explore { - background-image: url(../images/ic_explore.png); -} - -#icon_info { - background-image: url(../images/ic_info.png); -} - -#icon_route { - background-image: url(../images/ic_route.png); -} - -#icon_help { - background-image: url(../images/ic_help.png); -} - -#frame div.toptab { - background-color: #222222; - border-left: none; - border-right: 1px solid grey; - border-top: 1px solid grey; -} - -#frame div.page { - position: absolute; - top: 0px; - bottom: 40px; - left: 0px; - width: 200px; - height: 100%; - color: white; - background-color: #222222; - padding: 0 4px; - box-sizing: border-box; - cursor: default; - padding-bottom: 40px; -} - -#frame div.page div.header { - margin: 16px 0px 8px 0px; - font-weight: bold; - height: 16px; - box-sizing: border-box; - padding-left: 2px; -} - -#frame div.page div.control { - margin: 2px 0 2px 0; - padding-top: 2px; -} - -#frame div.page label { - display: block; - border-top: 1px solid grey; - padding: 2px 0 2px 8px; - font-size: 12px; -} - -#frame div.page select { - display: block; - width: 180px; - box-sizing: border-box; - padding-top: 2px; - margin: 2px 0 4px 8px; -} - -#frame div.page select:empty { - background-color: #888888; -} - -#frame div.page button { - display: block; - width: 180px; - box-sizing: border-box; - margin-top: 4px; - margin-bottom: 4px; - margin-left: 8px; - border: none; - border-bottom: 4px solid #1ab4e5; - color: #dddddd; - background-color: black; - padding-bottom: 4px; - box-shadow: 1px 1px 8px 0px #888888; - outline: none; -} - -#frame div.page button:hover { - color: white; -} - -#frame div.page button:active { - color: #dddddd; - border-bottom: 4px solid #0c536a; - box-shadow: none; - box-shadow: inset 1px 1px 8px 0px #888888; -} - -#frame div.page input[type="text"] { - display: block; - width: 180px; - box-sizing: border-box; - margin-top: 2px; - margin-left: 8px; -} - -#frame div.page input[type="checkbox"] { - position: absolute; - right: 0px; -} - -#frame div.page input[type="range"] { - display: block; - width: 180px; - margin-left: 8px; -} - -#frame dt, #frame dd { - font-size: 12px; -} - -#frame dt { - clear: both; - float: left; - padding-left: 16px; -} - -#frame dd { - margin-left: 40px; -} - -#frame p { - font-size: 12px; - line-height: 18px; -} - -div.station-info { - position: absolute; - border: 1px solid white; - background-color: #222222; - color: white; - padding: 4px; - z-index: 200; -} - - -.overlay-branding { - color: white; - margin: 4px; - position: absolute; - right: 0; - top: 0; -} \ No newline at end of file diff --git a/media/jslib/CaveView/images/disc.png b/media/jslib/CaveView/images/disc.png deleted file mode 100644 index 92572c6221f356e3541815873e48b8b8373a19a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1399 zcmV--1&I2IP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipe@ z3<40qNoMT;0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000Ee zNklQSQbJ?t+H#?ZrC6yRFy?n`2lSB z0c`jIM2Zk7WtU%2C4`rdK(2&bY#uQo#3m;AHHI;sM;E<=CaxO;F;}{>G&Ax!_ulW` z?_3M6Z%mbE+ExF=at%P{5(Ko%65=iiY&d6f1^`Rn=me%zc+JdkmjrGA&$*jj<#HmC z*pEh|uU@`<8J(Y>j{-O$F90YK5zXWuC18Lz0+hgB5CTMWZkS5{WibSMp1jqYJ9>mCk=+lGgSe;ynh{N*~}7tvTOa5x;i z$K!EtZEcA(-_>4>AG$qP~JQZ zKLE^Tv!|(4>V3Vzi^Zb8ySrQULSjr0l%u1gLL!lPdlLjAk%$D~+%yUG$_yx}R4NmX z$6wt50c~wgv|>=g%YcB5-_stUi7EG?mNcjsT>IgrN<}P2f#Lf*8s94-&D4;Wi?G>4-O8><#L(t?d|nDolfg@Q@^mV zP@I^Uh^5o%Z2)lqI{=b&7RqJt+}zym z-rnBd1RMjfPiMfWzgkU{nq`>_KpVp_9bT{Zn?NAYIWRDAKM)AGySloX{C>aH0Nvc& zlp~SI+4}l=etCKM-J3UWQn_62HGl-A{WS^HLWM&9UsY_7a00juz{_!5yW8#Va5|ly z=H})WK@gfWP2*KnwdC{p^FpB@Wipv;Hk(ZYI0A4;{uaRdYT&i@0*;hR6J7vJ#N{duc{=ba2Y1xoOy{m`W$SL zWOLYMQs21Xk4H%+R>*SC7GwIwECHq^nP`#bfi((>pg~kqCOV{9R}9m<5!IFnm!x|N z5;n)wsptze;<_>skhG-`$9y_ch;cmPe3=M{a~M;II-d>|Vw)siCS2ln^@R#Y95NwM zo?mT8yHpELdEV*A)e2 z!{U@YniMn)RU8I+W>xuMQ^O;T%N`Ytf)YzKY175Wr%Rg#ixl<$d;pa;{TV*h3C;ij N002ovPDHLkV1kh;%>w`c diff --git a/media/jslib/CaveView/images/ic_help.png b/media/jslib/CaveView/images/ic_help.png deleted file mode 100644 index 5664f9532e7894e749472cd81b678d7a988eba19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 476 zcmV<20VDp2P)FS}u8eRGnR8$o7*^pdpI`;)Zh3C*_?imPqNz#SSTLSv(_UTP{{f$uStd zlCmrp4Mto>!JK>;E@M+6nhc1^F&J`Uj+oatTErMx7-H5HN0)I%7KU*hrI4{tD92#P z34NrdG%|LXMTeTEp~Zknj#$@hXtKqKn1W5_brIBAp+k=$B_%_8Y_rUquAaa1Br%** SC%+K@0000 z{qOx%>h;7s8wx56Jw1ks6KiI1kPi+#aH&PJ2*rG2kW`aBhfKK;qJpW6`6g6X0Tp+Kkgf)>vOxu@%56}U z3@UAqNxoWRgL?0avf0r66UZcknozT!fd*!ul0iosv`z*shZSj)K!&$r+jJ6WH*Wue zIy#Vd=B|yDMb~5N+mUhA&86jk4aR&ik^dv-u+xZ`Kd)*La`$@UnBd-%E5pt?DFHTP mMNUaWM@K`+k>x0Uub?07ICz#IlqDzt00001!7jA6Q7EXSwGH*7Z8U{e(@E+y&HP-ac8X4q!qR2P{ zG^VHok{IG=;>bw`Q&9m)H1jqt@+M97l`yrtH=Itd5q+>d*za+KkF7>M|q|Jl| z%oMKsJ(AeOLdCddInFNHm$bf_-5h7OqV+tzj#GgowvewNe1~q#Qa|_Bh@qQzD-f62 z?5e`;6;wa6sUDT5_D=!a0^JVdry^@Gy;{L<&Cg;ZaJu-ic?oqA3SlBBEJ z=GPrdO@VPe;*|#2qee+mR{PAkvWaq`5zV8iO~Lk1{@mgegs-(rsafD+^+3B;Vp2#= zfq&dGqqfu(Xs?$U6?9hfo>?}i!K>SlngWYVS9R8lQ5!4^lcmM`WckW>lJ`?{!Vi4T zLv~-`jraPEC(}qRki;)O=Nt6_L)Jn`#S3V+7zgS&A<`+$`H#C(nSmGlQeJ23+LRlZ z^!1%!P0|Tq4HG`!DOT5AhUSV!{f8cHNfwY8X{(jk9W+t)7H+ZTY$9<)WM|bkMFkzO zK(Dx}fFxeEnD$3z;vOr>oZ}AXu>4N0_&j;;jsyQB5Ye|fB_^%>VX=(FBgh6q^Aj`? zD>XwjbJAkCh>5HJ1A*M`S309w0ZDZ6yM?|+e@q)9sUpLjiJsZ;B$or&Jq}((@DM4< zD7{pPV9Ni~YaM4LdCzGbA%tOn1=$?mu)QkgF^*V%?~m@sU{!Jw`Rq%A92fow=Awj_CRxlil8(z3j`t?{&?gl9U`nLxUmb$bzw-WXg^^HYyS#SIruOMnU{sGUN*vQii(bf-7f5<+z(4 zPW`j-CAKGJyhVj2L3V_&?bh!eB&u2!Wl1P=DN2Jy2Pw*fMVS=I#I7XDa}{e#DQd*a zL_J1{SX=*-=w+YwvSA;CMSCe)1dC?vBT@xv3?n@YS2o>HBMNWLjft%vvA1Z|SGDvH z$F=qIKRau_`Oxo?liO}o&F`#=CnH|D-n9|io?aO?)}$2Km^lYBN@{9KGWN_m^?L^% Xd7WpbAcdEK00000NkvXXu0mjf-6)F4 diff --git a/media/jslib/CaveView/images/ic_route.png b/media/jslib/CaveView/images/ic_route.png deleted file mode 100644 index b7631d7d76fb46081b1bbc0f38e99436e572ec69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 317 zcmV-D0mA-?P)#Y|WVl#6e|~YC{#k-kvSPbO9!pG0^Hd&8s4H%R#Cqora46uzg+{#+v(63)D~4ER_8?c P00000NkvXXu0mjftW}8f diff --git a/media/jslib/CaveView/images/ic_settings.png b/media/jslib/CaveView/images/ic_settings.png deleted file mode 100644 index 97ded33b5558a0efbd7812296a52325b4170076e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 460 zcmV;-0W=4>kIV21T<&3Kg>clSSXlU}7 zNsTbZb7CDT8exhj%*e(#KY#)6xy}u?uzckjH(4PAzEPEh1-w0q?BPAtVVvU+$MuUd zim^-?Z*&k19JY)eT?W{4>I$)hC8bSG`$%Zf$FisplYAzY(o}#3ePW-OP>dHiLTyE8 z5z6Vv#(lhunj$1*cz0EVJ9s@A*ucB3BFy1+WndHUmWuEIZ$P35H8Q+=vQXg_LqaV@ zm?z|TsTk9IA=am%09Qzftuv(%OIZ4}NVJa{^Q2f76=H@QTgC>PWY~7OsDpS*8Lt)N zEWbIfpG@m8p5YBC;_%wCP~|(2vdmRx>0#;8WR`dQ1-2NIjXDoGtr048h%M+pCV0dp z9SxU>omUy0Vn}G0s>)%9(6-8A4Tr6%Lb0000nSm`JeTGQtPZ5Gn#uqMfnn?bYmEtaXiR@ghw#NvB zEylErjI^a=JRJZXzHCrrE|%%YLWz#dE`{elTYPn7Rw*KI`Kj?4gvdaX zHL^%0`=66V^3^O-;(wXCD$kdtvYSt0&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}function r(t,e,r,n){this._x=t||0,this._y=e||0,this._z=r||0,this._w=void 0!==n?n:1}function n(t,e,r){this.x=t||0,this.y=e||0,this.z=r||0}function i(t){if(void 0!==t){var e;for(e in t)Bs.set(e,t[e])}}function a(t,e){return Bs.has(t)?Bs.get(t):e}function o(t,e){return t.split(".").shift()+"."+e}function s(){}function c(t,e,r){return void 0===e&&void 0===r?this.set(t):this.setRGB(t,e,r)}function l(){}function h(t,e){this.x=t||0,this.y=e||0}function u(t,e,r,n,i,a,o,s,c,l){Object.defineProperty(this,"id",{value:Wl++}),this.uuid=Ko.generateUUID(),this.name="",this.image=void 0!==t?t:u.DEFAULT_IMAGE,this.mipmaps=[],this.mapping=void 0!==e?e:u.DEFAULT_MAPPING,this.wrapS=void 0!==r?r:Zc,this.wrapT=void 0!==n?n:Zc,this.magFilter=void 0!==i?i:tl,this.minFilter=void 0!==a?a:rl,this.anisotropy=void 0!==c?c:1,this.format=void 0!==o?o:vl,this.type=void 0!==s?s:nl,this.offset=new h(0,0),this.repeat=new h(1,1),this.generateMipmaps=!0,this.premultiplyAlpha=!1,this.flipY=!0,this.unpackAlignment=4,this.encoding=void 0!==l?l:Ul,this.version=0,this.onUpdate=null}function d(t,e,r,n,i,a,o,s,c,l,h,d){u.call(this,null,a,o,s,c,l,n,i,h,d),this.image={data:t,width:e,height:r},this.magFilter=void 0!==c?c:Qc,this.minFilter=void 0!==l?l:Qc,this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}function p(t){for(var e=t.length,r=new Uint8Array(3*e),n=0;n0)return t;var i=e*r,a=Jl[i];if(void 0===a&&(a=new Float32Array(i),Jl[i]=a),0!==e){n.toArray(a,0);for(var o=1,s=0;o!==e;++o)s+=r,t[o].toArray(a,s)}return a}function M(t,e){var r=Ql[e];void 0===r&&(r=new Int32Array(e),Ql[e]=r);for(var n=0;n!==e;++n)r[n]=t.allocTextureUnit();return r}function E(t,e){t.uniform1f(this.addr,e)}function S(t,e){t.uniform1i(this.addr,e)}function T(t,e){void 0===e.x?t.uniform2fv(this.addr,e):t.uniform2f(this.addr,e.x,e.y)}function A(t,e){void 0!==e.x?t.uniform3f(this.addr,e.x,e.y,e.z):void 0!==e.r?t.uniform3f(this.addr,e.r,e.g,e.b):t.uniform3fv(this.addr,e)}function L(t,e){void 0===e.x?t.uniform4fv(this.addr,e):t.uniform4f(this.addr,e.x,e.y,e.z,e.w)}function C(t,e){t.uniformMatrix2fv(this.addr,!1,e.elements||e)}function R(t,e){void 0===e.elements?t.uniformMatrix3fv(this.addr,!1,e):($l.set(e.elements),t.uniformMatrix3fv(this.addr,!1,$l))}function P(t,e){void 0===e.elements?t.uniformMatrix4fv(this.addr,!1,e):(Kl.set(e.elements),t.uniformMatrix4fv(this.addr,!1,Kl))}function I(t,e,r){var n=r.allocTextureUnit();t.uniform1i(this.addr,n),r.setTexture2D(e||ql,n)}function O(t,e,r){var n=r.allocTextureUnit();t.uniform1i(this.addr,n),r.setTextureCube(e||Zl,n)}function N(t,e){t.uniform2iv(this.addr,e)}function D(t,e){t.uniform3iv(this.addr,e)}function U(t,e){t.uniform4iv(this.addr,e)}function z(t){switch(t){case 5126:return E;case 35664:return T;case 35665:return A;case 35666:return L;case 35674:return C;case 35675:return R;case 35676:return P;case 35678:case 36198:return I;case 35680:return O;case 5124:case 35670:return S;case 35667:case 35671:return N;case 35668:case 35672:return D;case 35669:case 35673:return U}}function B(t,e){t.uniform1fv(this.addr,e)}function F(t,e){t.uniform1iv(this.addr,e)}function k(t,e){t.uniform2fv(this.addr,_(e,this.size,2))}function G(t,e){t.uniform3fv(this.addr,_(e,this.size,3))}function V(t,e){t.uniform4fv(this.addr,_(e,this.size,4))}function H(t,e){t.uniformMatrix2fv(this.addr,!1,_(e,this.size,4))}function j(t,e){t.uniformMatrix3fv(this.addr,!1,_(e,this.size,9))}function W(t,e){t.uniformMatrix4fv(this.addr,!1,_(e,this.size,16))}function X(t,e,r){var n=e.length,i=M(r,n);t.uniform1iv(this.addr,i);for(var a=0;a!==n;++a)r.setTexture2D(e[a]||ql,i[a])}function Y(t,e,r){var n=e.length,i=M(r,n);t.uniform1iv(this.addr,i);for(var a=0;a!==n;++a)r.setTextureCube(e[a]||Zl,i[a])}function q(t){switch(t){case 5126:return B;case 35664:return k;case 35665:return G;case 35666:return V;case 35674:return H;case 35675:return j;case 35676:return W;case 35678:return X;case 35680:return Y;case 5124:case 35670:return F;case 35667:case 35671:return N;case 35668:case 35672:return D;case 35669:case 35673:return U}}function Z(t,e,r){this.id=t,this.addr=r,this.setValue=z(e.type)}function J(t,e,r){this.id=t,this.addr=r,this.size=e.size,this.setValue=q(e.type)}function Q(t){this.id=t,w.call(this)}function K(t,e){t.seq.push(e),t.map[e.id]=e}function $(t,e,r){var n=t.name,i=n.length;for(th.lastIndex=0;;){var a=th.exec(n),o=th.lastIndex,s=a[1],c="]"===a[2],l=a[3];if(c&&(s|=0),void 0===l||"["===l&&o+2===i){K(r,void 0===l?new Z(s,t,e):new J(s,t,e));break}var h=r.map[s];void 0===h&&K(r,h=new Q(s)),r=h}}function tt(t,e,r){w.call(this),this.renderer=r;for(var n=t.getProgramParameter(e,t.ACTIVE_UNIFORMS),i=0;i.001&&P.scale>.001&&(M.x=P.x,M.y=P.y,M.z=P.z,w=P.size*P.scale/g.w,_.x=w*y,_.y=w,f.uniform3f(u.screenPosition,M.x,M.y,M.z),f.uniform2f(u.scale,_.x,_.y),f.uniform1f(u.rotation,P.rotation),f.uniform1f(u.opacity,P.opacity),f.uniform3f(u.color,P.color.r,P.color.g,P.color.b),m.setBlending(P.blending,P.blendEquation,P.blendSrc,P.blendDst),t.setTexture2D(P.texture,1),f.drawElements(f.TRIANGLES,6,f.UNSIGNED_SHORT,0))}}}m.enable(f.CULL_FACE),m.enable(f.DEPTH_TEST),m.buffers.depth.setMask(!0),t.resetGLState()}}}function nt(t,e){function i(){var t=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),e=new Uint16Array([0,1,2,0,2,3]);s=f.createBuffer(),c=f.createBuffer(),f.bindBuffer(f.ARRAY_BUFFER,s),f.bufferData(f.ARRAY_BUFFER,t,f.STATIC_DRAW),f.bindBuffer(f.ELEMENT_ARRAY_BUFFER,c),f.bufferData(f.ELEMENT_ARRAY_BUFFER,e,f.STATIC_DRAW),l=a(),h={position:f.getAttribLocation(l,"position"),uv:f.getAttribLocation(l,"uv")},d={uvOffset:f.getUniformLocation(l,"uvOffset"),uvScale:f.getUniformLocation(l,"uvScale"),rotation:f.getUniformLocation(l,"rotation"),scale:f.getUniformLocation(l,"scale"),color:f.getUniformLocation(l,"color"),map:f.getUniformLocation(l,"map"),opacity:f.getUniformLocation(l,"opacity"),modelViewMatrix:f.getUniformLocation(l,"modelViewMatrix"),projectionMatrix:f.getUniformLocation(l,"projectionMatrix"),fogType:f.getUniformLocation(l,"fogType"),fogDensity:f.getUniformLocation(l,"fogDensity"),fogNear:f.getUniformLocation(l,"fogNear"),fogFar:f.getUniformLocation(l,"fogFar"),fogColor:f.getUniformLocation(l,"fogColor"),alphaTest:f.getUniformLocation(l,"alphaTest")};var r=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");r.width=8,r.height=8;var n=r.getContext("2d");n.fillStyle="white",n.fillRect(0,0,8,8),(p=new u(r)).needsUpdate=!0}function a(){var e=f.createProgram(),r=f.createShader(f.VERTEX_SHADER),n=f.createShader(f.FRAGMENT_SHADER);return f.shaderSource(r,["precision "+t.getPrecision()+" float;","#define SHADER_NAME SpriteMaterial","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")),f.shaderSource(n,["precision "+t.getPrecision()+" float;","#define SHADER_NAME SpriteMaterial","uniform vec3 color;","uniform sampler2D map;","uniform float opacity;","uniform int fogType;","uniform vec3 fogColor;","uniform float fogDensity;","uniform float fogNear;","uniform float fogFar;","uniform float alphaTest;","varying vec2 vUV;","void main() {","vec4 texture = texture2D( map, vUV );","if ( texture.a < alphaTest ) discard;","gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );","if ( fogType > 0 ) {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float fogFactor = 0.0;","if ( fogType == 1 ) {","fogFactor = smoothstep( fogNear, fogFar, depth );","} else {","const float LOG2 = 1.442695;","fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","}","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}","}"].join("\n")),f.compileShader(r),f.compileShader(n),f.attachShader(e,r),f.attachShader(e,n),f.linkProgram(e),e}function o(t,e){return t.renderOrder!==e.renderOrder?t.renderOrder-e.renderOrder:t.z!==e.z?e.z-t.z:e.id-t.id}var s,c,l,h,d,p,f=t.context,m=t.state,g=new n,v=new r,y=new n;this.render=function(r,n){if(0!==e.length){void 0===l&&i(),f.useProgram(l),m.initAttributes(),m.enableAttribute(h.position),m.enableAttribute(h.uv),m.disableUnusedAttributes(),m.disable(f.CULL_FACE),m.enable(f.BLEND),f.bindBuffer(f.ARRAY_BUFFER,s),f.vertexAttribPointer(h.position,2,f.FLOAT,!1,16,0),f.vertexAttribPointer(h.uv,2,f.FLOAT,!1,16,8),f.bindBuffer(f.ELEMENT_ARRAY_BUFFER,c),f.uniformMatrix4fv(d.projectionMatrix,!1,n.projectionMatrix.elements),m.activeTexture(f.TEXTURE0),f.uniform1i(d.map,0);var a=0,u=0,x=r.fog;x?(f.uniform3f(d.fogColor,x.color.r,x.color.g,x.color.b),x.isFog?(f.uniform1f(d.fogNear,x.near),f.uniform1f(d.fogFar,x.far),f.uniform1i(d.fogType,1),a=1,u=1):x.isFogExp2&&(f.uniform1f(d.fogDensity,x.density),f.uniform1i(d.fogType,2),a=2,u=2)):(f.uniform1i(d.fogType,0),a=0,u=0);for(var b=0,w=e.length;b0&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}function ht(t,e){this.normal=void 0!==t?t:new n(1,0,0),this.constant=void 0!==e?e:0}function ut(t,e,r,n,i,a){this.planes=[void 0!==t?t:new ht,void 0!==e?e:new ht,void 0!==r?r:new ht,void 0!==n?n:new ht,void 0!==i?i:new ht,void 0!==a?a:new ht]}function dt(t,r,i,a){function o(e,r,n,i){var a=e.geometry,o=null,s=M,c=e.customDepthMaterial;if(n&&(s=E,c=e.customDistanceMaterial),c)o=c;else{var l=!1;r.morphTargets&&(a&&a.isBufferGeometry?l=a.morphAttributes&&a.morphAttributes.position&&a.morphAttributes.position.length>0:a&&a.isGeometry&&(l=a.morphTargets&&a.morphTargets.length>0)),e.isSkinnedMesh&&!1===r.skinning&&console.warn("THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:",e);var h=e.isSkinnedMesh&&r.skinning,u=0;l&&(u|=b),h&&(u|=w),o=s[u]}if(t.localClippingEnabled&&!0===r.clipShadows&&0!==r.clippingPlanes.length){var d=o.uuid,p=r.uuid,f=S[d];void 0===f&&(f={},S[d]=f);var m=f[p];void 0===m&&(m=o.clone(),f[p]=m),o=m}o.visible=r.visible,o.wireframe=r.wireframe;var g=r.side;return z.renderSingleSided&&g==Qs&&(g=Zs),z.renderReverseSided&&(g===Zs?g=Js:g===Js&&(g=Zs)),o.side=g,o.clipShadows=r.clipShadows,o.clippingPlanes=r.clippingPlanes,o.wireframeLinewidth=r.wireframeLinewidth,o.linewidth=r.linewidth,n&&void 0!==o.uniforms.lightPos&&o.uniforms.lightPos.value.copy(i),o}function s(e,r,n,a){if(!1!==e.visible){if(e.layers.test(r.layers)&&(e.isMesh||e.isLine||e.isPoints)&&e.castShadow&&(!e.frustumCulled||u.intersectsObject(e))){e.modelViewMatrix.multiplyMatrices(n.matrixWorldInverse,e.matrixWorld);var c=i.update(e),l=e.material;if(Array.isArray(l))for(var h=c.groups,d=0,p=h.length;de&&(e=t[r]);return e}function Ct(){Object.defineProperty(this,"id",{value:wt()}),this.uuid=Ko.generateUUID(),this.name="",this.type="BufferGeometry",this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0}}function Rt(t,e,r,n,i,a){_t.call(this),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:r,widthSegments:n,heightSegments:i,depthSegments:a},this.fromBufferGeometry(new Pt(t,e,r,n,i,a)),this.mergeVertices()}function Pt(t,e,r,i,a,o){function s(t,e,r,i,a,o,s,m,g,v,y){var x,b,w=o/g,_=s/v,M=o/2,E=s/2,S=m/2,T=g+1,A=v+1,L=0,C=0,R=new n;for(b=0;b0?1:-1,u.push(R.x,R.y,R.z),d.push(x/g),d.push(1-b/v),L+=1}}for(b=0;b65535?St:Et)(i,1),e.update(n,t.ELEMENT_ARRAY_BUFFER),c[r.id]=n,n}var s={},c={};return{get:i,update:a,getWireframeAttribute:o}}function Yt(){var t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];var r;switch(e.type){case"DirectionalLight":r={direction:new n,color:new c,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new h};break;case"SpotLight":r={position:new n,direction:new n,color:new c,distance:0,coneCos:0,penumbraCos:0,decay:0,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new h};break;case"PointLight":r={position:new n,color:new c,distance:0,decay:0,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new h};break;case"HemisphereLight":r={direction:new n,skyColor:new c,groundColor:new c};break;case"RectAreaLight":r={color:new c,position:new n,halfWidth:new n,halfHeight:new n}}return t[e.id]=r,r}}}function qt(t,e,r){function n(t){var n=r.frame,i=t.geometry,o=e.get(t,i);return a[o.id]!==n&&(i.isGeometry&&o.updateFromObject(t),e.update(o),a[o.id]=n),o}function i(){a={}}var a={};return{update:n,clear:i}}function Zt(t){for(var e=t.split("\n"),r=0;r");return oe(r)}return t.replace(/^[ \t]*#include +<([\w\d.]+)>/gm,e)}function se(t){function e(t,e,r,n){for(var i="",a=parseInt(e);a0?t.gammaFactor:1,v=ee(o,i,t.extensions),y=re(s),x=a.createProgram();r.isRawShaderMaterial?(f=[y,"\n"].filter(ie).join("\n"),m=[v,y,"\n"].filter(ie).join("\n")):(f=["precision "+i.precision+" float;","precision "+i.precision+" int;","#define SHADER_NAME "+n.name,y,i.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+g,"#define MAX_BONES "+i.maxBones,i.useFog&&i.fog?"#define USE_FOG":"",i.useFog&&i.fogExp?"#define FOG_EXP2":"",i.map?"#define USE_MAP":"",i.envMap?"#define USE_ENVMAP":"",i.envMap?"#define "+d:"",i.lightMap?"#define USE_LIGHTMAP":"",i.aoMap?"#define USE_AOMAP":"",i.emissiveMap?"#define USE_EMISSIVEMAP":"",i.bumpMap?"#define USE_BUMPMAP":"",i.normalMap?"#define USE_NORMALMAP":"",i.displacementMap&&i.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",i.specularMap?"#define USE_SPECULARMAP":"",i.roughnessMap?"#define USE_ROUGHNESSMAP":"",i.metalnessMap?"#define USE_METALNESSMAP":"",i.alphaMap?"#define USE_ALPHAMAP":"",i.vertexColors?"#define USE_COLOR":"",i.flatShading?"#define FLAT_SHADED":"",i.skinning?"#define USE_SKINNING":"",i.useVertexTexture?"#define BONE_TEXTURE":"",i.morphTargets?"#define USE_MORPHTARGETS":"",i.morphNormals&&!1===i.flatShading?"#define USE_MORPHNORMALS":"",i.doubleSided?"#define DOUBLE_SIDED":"",i.flipSided?"#define FLIP_SIDED":"","#define NUM_CLIPPING_PLANES "+i.numClippingPlanes,i.shadowMapEnabled?"#define USE_SHADOWMAP":"",i.shadowMapEnabled?"#define "+h:"",i.sizeAttenuation?"#define USE_SIZEATTENUATION":"",i.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",i.logarithmicDepthBuffer&&t.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(ie).join("\n"),m=[v,"precision "+i.precision+" float;","precision "+i.precision+" int;","#define SHADER_NAME "+n.name,y,i.alphaTest?"#define ALPHATEST "+i.alphaTest:"","#define GAMMA_FACTOR "+g,i.useFog&&i.fog?"#define USE_FOG":"",i.useFog&&i.fogExp?"#define FOG_EXP2":"",i.map?"#define USE_MAP":"",i.envMap?"#define USE_ENVMAP":"",i.envMap?"#define "+u:"",i.envMap?"#define "+d:"",i.envMap?"#define "+p:"",i.lightMap?"#define USE_LIGHTMAP":"",i.aoMap?"#define USE_AOMAP":"",i.emissiveMap?"#define USE_EMISSIVEMAP":"",i.bumpMap?"#define USE_BUMPMAP":"",i.normalMap?"#define USE_NORMALMAP":"",i.specularMap?"#define USE_SPECULARMAP":"",i.roughnessMap?"#define USE_ROUGHNESSMAP":"",i.metalnessMap?"#define USE_METALNESSMAP":"",i.alphaMap?"#define USE_ALPHAMAP":"",i.vertexColors?"#define USE_COLOR":"",i.gradientMap?"#define USE_GRADIENTMAP":"",i.flatShading?"#define FLAT_SHADED":"",i.doubleSided?"#define DOUBLE_SIDED":"",i.flipSided?"#define FLIP_SIDED":"","#define NUM_CLIPPING_PLANES "+i.numClippingPlanes,"#define UNION_CLIPPING_PLANES "+(i.numClippingPlanes-i.numClipIntersection),i.shadowMapEnabled?"#define USE_SHADOWMAP":"",i.shadowMapEnabled?"#define "+h:"",i.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",i.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",i.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",i.logarithmicDepthBuffer&&t.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"",i.envMap&&t.extensions.get("EXT_shader_texture_lod")?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;",i.toneMapping!==Uc?"#define TONE_MAPPING":"",i.toneMapping!==Uc?nh.tonemapping_pars_fragment:"",i.toneMapping!==Uc?te("toneMapping",i.toneMapping):"",i.dithering?"#define DITHERING":"",i.outputEncoding||i.mapEncoding||i.envMapEncoding||i.emissiveMapEncoding?nh.encodings_pars_fragment:"",i.mapEncoding?Kt("mapTexelToLinear",i.mapEncoding):"",i.envMapEncoding?Kt("envMapTexelToLinear",i.envMapEncoding):"",i.emissiveMapEncoding?Kt("emissiveMapTexelToLinear",i.emissiveMapEncoding):"",i.outputEncoding?$t("linearToOutputTexel",i.outputEncoding):"",i.depthPacking?"#define DEPTH_PACKING "+r.depthPacking:"","\n"].filter(ie).join("\n")),c=ae(c=oe(c),i),l=ae(l=oe(l),i),r.isShaderMaterial||(c=se(c),l=se(l));var b=f+c,w=m+l,_=Jt(a,a.VERTEX_SHADER,b),M=Jt(a,a.FRAGMENT_SHADER,w);a.attachShader(x,_),a.attachShader(x,M),void 0!==r.index0AttributeName?a.bindAttribLocation(x,0,r.index0AttributeName):!0===i.morphTargets&&a.bindAttribLocation(x,0,"position"),a.linkProgram(x);var E=a.getProgramInfoLog(x),S=a.getShaderInfoLog(_),T=a.getShaderInfoLog(M),A=!0,L=!0;!1===a.getProgramParameter(x,a.LINK_STATUS)?(A=!1,console.error("THREE.WebGLProgram: shader error: ",a.getError(),"gl.VALIDATE_STATUS",a.getProgramParameter(x,a.VALIDATE_STATUS),"gl.getProgramInfoLog",E,S,T)):""!==E?console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",E):""!==S&&""!==T||(L=!1),L&&(this.diagnostics={runnable:A,material:r,programLog:E,vertexShader:{log:S,prefix:f},fragmentShader:{log:T,prefix:m}}),a.deleteShader(_),a.deleteShader(M);var C;this.getUniforms=function(){return void 0===C&&(C=new tt(a,x,t)),C};var R;return this.getAttributes=function(){return void 0===R&&(R=ne(a,x)),R},this.destroy=function(){a.deleteProgram(x),this.program=void 0},Object.defineProperties(this,{uniforms:{get:function(){return console.warn("THREE.WebGLProgram: .uniforms is now .getUniforms()."),this.getUniforms()}},attributes:{get:function(){return console.warn("THREE.WebGLProgram: .attributes is now .getAttributes()."),this.getAttributes()}}}),this.id=ch++,this.code=e,this.usedTimes=1,this.program=x,this.vertexShader=_,this.fragmentShader=M,this}function le(t,e){function r(t){var r=t.skeleton.bones;if(e.floatVertexTextures)return 1024;var n=e.maxVertexUniforms,i=Math.floor((n-20)/4),a=Math.min(i,r.length);return a0,maxBones:d,useVertexTexture:e.floatVertexTextures,morphTargets:i.morphTargets,morphNormals:i.morphNormals,maxMorphTargets:t.maxMorphTargets,maxMorphNormals:t.maxMorphNormals,numDirLights:o.directional.length,numPointLights:o.point.length,numSpotLights:o.spot.length,numRectAreaLights:o.rectArea.length,numHemiLights:o.hemi.length,numClippingPlanes:c,numClipIntersection:l,dithering:i.dithering,shadowMapEnabled:t.shadowMap.enabled&&h.receiveShadow&&o.shadows.length>0,shadowMapType:t.shadowMap.type,toneMapping:t.toneMapping,physicallyCorrectLights:t.physicallyCorrectLights,premultipliedAlpha:i.premultipliedAlpha,alphaTest:i.alphaTest,doubleSided:i.side===Qs,flipSided:i.side===Js,depthPacking:void 0!==i.depthPacking&&i.depthPacking}},this.getProgramCode=function(e,r){var n=[];if(r.shaderID?n.push(r.shaderID):(n.push(e.fragmentShader),n.push(e.vertexShader)),void 0!==e.defines)for(var i in e.defines)n.push(i),n.push(e.defines[i]);for(var a=0;ae||t.height>e){var r=e/Math.max(t.width,t.height),n=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");return n.width=Math.floor(t.width*r),n.height=Math.floor(t.height*r),n.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,n.width,n.height),console.warn("THREE.WebGLRenderer: image is too big ("+t.width+"x"+t.height+"). Resized to "+n.width+"x"+n.height,t),n}return t}function c(t){return Ko.isPowerOfTwo(t.width)&&Ko.isPowerOfTwo(t.height)}function l(t){if(t instanceof HTMLImageElement||t instanceof HTMLCanvasElement){var e=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");return e.width=Ko.nearestPowerOfTwo(t.width),e.height=Ko.nearestPowerOfTwo(t.height),e.getContext("2d").drawImage(t,0,0,e.width,e.height),console.warn("THREE.WebGLRenderer: image is not power of two ("+t.width+"x"+t.height+"). Resized to "+e.width+"x"+e.height,t),e}return t}function h(t){return t.wrapS!==Zc||t.wrapT!==Zc||t.minFilter!==Qc&&t.minFilter!==tl}function u(t,e){return t.generateMipmaps&&e&&t.minFilter!==Qc&&t.minFilter!==tl}function d(e){return e===Qc||e===Kc||e===$c?t.NEAREST:t.LINEAR}function p(t){var e=t.target;e.removeEventListener("dispose",p),m(e),o.textures--}function f(t){var e=t.target;e.removeEventListener("dispose",f),g(e),o.textures--}function m(e){var r=n.get(e);if(e.image&&r.__image__webglTextureCube)t.deleteTexture(r.__image__webglTextureCube);else{if(void 0===r.__webglInit)return;t.deleteTexture(r.__webglTexture)}n.remove(e)}function g(e){var r=n.get(e),i=n.get(e.texture);if(e){if(void 0!==i.__webglTexture&&t.deleteTexture(i.__webglTexture),e.depthTexture&&e.depthTexture.dispose(),e.isWebGLRenderTargetCube)for(var a=0;a<6;a++)t.deleteFramebuffer(r.__webglFramebuffer[a]),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer[a]);else t.deleteFramebuffer(r.__webglFramebuffer),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer);n.remove(e.texture),n.remove(e)}}function v(e,i){var a=n.get(e);if(e.version>0&&a.__version!==e.version){var o=e.image;if(void 0===o)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined",e);else{if(!1!==o.complete)return void w(a,e,i);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete",e)}}r.activeTexture(t.TEXTURE0+i),r.bindTexture(t.TEXTURE_2D,a.__webglTexture)}function y(e,l){var h=n.get(e);if(6===e.image.length)if(e.version>0&&h.__version!==e.version){h.__image__webglTextureCube||(e.addEventListener("dispose",p),h.__image__webglTextureCube=t.createTexture(),o.textures++),r.activeTexture(t.TEXTURE0+l),r.bindTexture(t.TEXTURE_CUBE_MAP,h.__image__webglTextureCube),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,e.flipY);for(var d=e&&e.isCompressedTexture,f=e.image[0]&&e.image[0].isDataTexture,m=[],g=0;g<6;g++)m[g]=d||f?f?e.image[g].image:e.image[g]:s(e.image[g],i.maxCubemapSize);var v=c(m[0]),y=a(e.format),x=a(e.type);b(t.TEXTURE_CUBE_MAP,e,v);for(g=0;g<6;g++)if(d)for(var w,_=m[g].mipmaps,M=0,E=_.length;M-1?r.compressedTexImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+g,M,y,w.width,w.height,0,w.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()"):r.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+g,M,y,w.width,w.height,0,y,x,w.data);else f?r.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+g,0,y,m[g].width,m[g].height,0,y,x,m[g].data):r.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X+g,0,y,y,x,m[g]);u(e,v)&&t.generateMipmap(t.TEXTURE_CUBE_MAP),h.__version=e.version,e.onUpdate&&e.onUpdate(e)}else r.activeTexture(t.TEXTURE0+l),r.bindTexture(t.TEXTURE_CUBE_MAP,h.__image__webglTextureCube)}function x(e,i){r.activeTexture(t.TEXTURE0+i),r.bindTexture(t.TEXTURE_CUBE_MAP,n.get(e).__webglTexture)}function b(r,o,s){var c;if(s?(t.texParameteri(r,t.TEXTURE_WRAP_S,a(o.wrapS)),t.texParameteri(r,t.TEXTURE_WRAP_T,a(o.wrapT)),t.texParameteri(r,t.TEXTURE_MAG_FILTER,a(o.magFilter)),t.texParameteri(r,t.TEXTURE_MIN_FILTER,a(o.minFilter))):(t.texParameteri(r,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(r,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),o.wrapS===Zc&&o.wrapT===Zc||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.",o),t.texParameteri(r,t.TEXTURE_MAG_FILTER,d(o.magFilter)),t.texParameteri(r,t.TEXTURE_MIN_FILTER,d(o.minFilter)),o.minFilter!==Qc&&o.minFilter!==tl&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.",o)),c=e.get("EXT_texture_filter_anisotropic")){if(o.type===ll&&null===e.get("OES_texture_float_linear"))return;if(o.type===hl&&null===e.get("OES_texture_half_float_linear"))return;(o.anisotropy>1||n.get(o).__currentAnisotropy)&&(t.texParameterf(r,c.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(o.anisotropy,i.getMaxAnisotropy())),n.get(o).__currentAnisotropy=o.anisotropy)}}function w(e,n,d){void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",p),e.__webglTexture=t.createTexture(),o.textures++),r.activeTexture(t.TEXTURE0+d),r.bindTexture(t.TEXTURE_2D,e.__webglTexture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,n.flipY),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),t.pixelStorei(t.UNPACK_ALIGNMENT,n.unpackAlignment);var f=s(n.image,i.maxTextureSize);h(n)&&!1===c(f)&&(f=l(f));var m=c(f),g=a(n.format),v=a(n.type);b(t.TEXTURE_2D,n,m);var y,x=n.mipmaps;if(n.isDepthTexture){var w=t.DEPTH_COMPONENT;if(n.type===ll){if(!L)throw new Error("Float Depth Texture only supported in WebGL2.0");w=t.DEPTH_COMPONENT32F}else L&&(w=t.DEPTH_COMPONENT16);n.format===bl&&w===t.DEPTH_COMPONENT&&n.type!==ol&&n.type!==cl&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),n.type=ol,v=a(n.type)),n.format===wl&&(w=t.DEPTH_STENCIL,n.type!==fl&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),n.type=fl,v=a(n.type))),r.texImage2D(t.TEXTURE_2D,0,w,f.width,f.height,0,g,v,null)}else if(n.isDataTexture)if(x.length>0&&m){for(var _=0,M=x.length;_-1?r.compressedTexImage2D(t.TEXTURE_2D,_,g,y.width,y.height,0,y.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):r.texImage2D(t.TEXTURE_2D,_,g,y.width,y.height,0,g,v,y.data);else if(x.length>0&&m){for(var _=0,M=x.length;_=1,nt=null,it={},at=new y,ot=new y,st={};return st[t.TEXTURE_2D]=o(t.TEXTURE_2D,t.TEXTURE_2D,1),st[t.TEXTURE_CUBE_MAP]=o(t.TEXTURE_CUBE_MAP,t.TEXTURE_CUBE_MAP_POSITIVE_X,6),{buffers:{color:P,depth:I,stencil:O},init:s,initAttributes:c,enableAttribute:l,enableAttributeAndDivisor:h,disableUnusedAttributes:u,enable:d,disable:p,getCompressedTextureFormats:f,setBlending:m,setMaterial:g,setFlipSided:v,setCullFace:x,setLineWidth:b,setPolygonOffset:w,getScissorTest:_,setScissorTest:M,activeTexture:E,bindTexture:S,compressedTexImage2D:T,texImage2D:A,scissor:L,viewport:C,reset:R}}function pe(t,e,r){function n(){if(void 0!==a)return a;var r=e.get("EXT_texture_filter_anisotropic");return a=null!==r?t.getParameter(r.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0}function i(e){if("highp"===e){if(t.getShaderPrecisionFormat(t.VERTEX_SHADER,t.HIGH_FLOAT).precision>0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.HIGH_FLOAT).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(t.VERTEX_SHADER,t.MEDIUM_FLOAT).precision>0&&t.getShaderPrecisionFormat(t.FRAGMENT_SHADER,t.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}var a,o=void 0!==r.precision?r.precision:"highp",s=i(o);s!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",s,"instead."),o=s);var c=!0===r.logarithmicDepthBuffer&&!!e.get("EXT_frag_depth"),l=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS),h=t.getParameter(t.MAX_VERTEX_TEXTURE_IMAGE_UNITS),u=t.getParameter(t.MAX_TEXTURE_SIZE),d=t.getParameter(t.MAX_CUBE_MAP_TEXTURE_SIZE),p=t.getParameter(t.MAX_VERTEX_ATTRIBS),f=t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS),m=t.getParameter(t.MAX_VARYING_VECTORS),g=t.getParameter(t.MAX_FRAGMENT_UNIFORM_VECTORS),v=h>0,y=!!e.get("OES_texture_float");return{getMaxAnisotropy:n,getMaxPrecision:i,precision:o,logarithmicDepthBuffer:c,maxTextures:l,maxVertexTextures:h,maxTextureSize:u,maxCubemapSize:d,maxAttributes:p,maxVertexUniforms:f,maxVaryings:m,maxFragmentUniforms:g,vertexTextures:v,floatFragmentTextures:y,floatVertexTextures:v&&y}}function fe(t){xt.call(this),this.cameras=t||[]}function me(t){function r(){if(i.isPresenting){var e=i.getEyeParameters("left"),r=e.renderWidth,a=e.renderHeight;p=t.getPixelRatio(),d=t.getSize(),t.setDrawingBufferSize(2*r,a,1)}else n.enabled&&t.setDrawingBufferSize(d.width,d.height,p)}var n=this,i=null,a=null;"VRFrameData"in window&&(a=new window.VRFrameData);var o=new e,s=new e,c=new e,l=new xt;l.bounds=new y(0,0,.5,1),l.layers.enable(1);var h=new xt;h.bounds=new y(.5,0,.5,1),h.layers.enable(2);var u=new fe([l,h]);u.layers.enable(1),u.layers.enable(2);var d,p;window.addEventListener("vrdisplaypresentchange",r,!1),this.enabled=!1,this.standing=!1,this.getDevice=function(){return i},this.setDevice=function(t){void 0!==t&&(i=t)},this.getCamera=function(t){if(null===i)return t;i.depthNear=t.near,i.depthFar=t.far,i.getFrameData(a);var e=a.pose;null!==e.position?t.position.fromArray(e.position):t.position.set(0,0,0),null!==e.orientation&&t.quaternion.fromArray(e.orientation),t.updateMatrixWorld();var r=i.stageParameters;if(this.standing&&r&&(s.fromArray(r.sittingToStandingTransform),c.getInverse(s),t.matrixWorld.multiply(s),t.matrixWorldInverse.multiply(c)),!1===i.isPresenting)return t;u.matrixWorld.copy(t.matrixWorld),u.matrixWorldInverse.copy(t.matrixWorldInverse),l.matrixWorldInverse.fromArray(a.leftViewMatrix),h.matrixWorldInverse.fromArray(a.rightViewMatrix),this.standing&&r&&(l.matrixWorldInverse.multiply(c),h.matrixWorldInverse.multiply(c));var n=t.parent;null!==n&&(o.getInverse(n.matrixWorld),l.matrixWorldInverse.multiply(o),h.matrixWorldInverse.multiply(o)),l.matrixWorld.getInverse(l.matrixWorldInverse),h.matrixWorld.getInverse(h.matrixWorldInverse),l.projectionMatrix.fromArray(a.leftProjectionMatrix),h.projectionMatrix.fromArray(a.rightProjectionMatrix),u.projectionMatrix.copy(l.projectionMatrix);var d=i.getLayers();if(d.length){var p=d[0];null!==p.leftBounds&&4===p.leftBounds.length&&l.bounds.fromArray(p.leftBounds),null!==p.rightBounds&&4===p.rightBounds.length&&h.bounds.fromArray(p.rightBounds)}return u},this.getStandingMatrix=function(){return s},this.submitFrame=function(){i&&i.isPresenting&&i.submitFrame()}}function ge(t){var e={};return{get:function(r){if(void 0!==e[r])return e[r];var n;switch(r){case"WEBGL_depth_texture":n=t.getExtension("WEBGL_depth_texture")||t.getExtension("MOZ_WEBGL_depth_texture")||t.getExtension("WEBKIT_WEBGL_depth_texture");break;case"EXT_texture_filter_anisotropic":n=t.getExtension("EXT_texture_filter_anisotropic")||t.getExtension("MOZ_EXT_texture_filter_anisotropic")||t.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case"WEBGL_compressed_texture_s3tc":n=t.getExtension("WEBGL_compressed_texture_s3tc")||t.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||t.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");break;case"WEBGL_compressed_texture_pvrtc":n=t.getExtension("WEBGL_compressed_texture_pvrtc")||t.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;case"WEBGL_compressed_texture_etc1":n=t.getExtension("WEBGL_compressed_texture_etc1");break;default:n=t.getExtension(r)}return null===n&&console.warn("THREE.WebGLRenderer: "+r+" extension not supported."),e[r]=n,n}}}function ve(){function t(){l.value!==n&&(l.value=n,l.needsUpdate=i>0),r.numPlanes=i,r.numIntersection=0}function e(t,e,n,i){var a=null!==t?t.length:0,o=null;if(0!==a){if(o=l.value,!0!==i||null===o){var h=n+4*a,u=e.matrixWorldInverse;c.getNormalMatrix(u),(null===o||o.length=0){var l=i[s];if(void 0!==l){var h=l.normalized,u=l.itemSize,d=Bt.get(l),p=d.buffer,f=d.type,m=d.bytesPerElement;if(l.isInterleavedBufferAttribute){var g=l.data,v=g.stride,y=l.offset;g&&g.isInstancedInterleavedBuffer?(Dt.enableAttributeAndDivisor(c,g.meshPerAttribute),void 0===r.maxInstancedCount&&(r.maxInstancedCount=g.meshPerAttribute*g.count)):Dt.enableAttribute(c),Pt.bindBuffer(Pt.ARRAY_BUFFER,p),Pt.vertexAttribPointer(c,u,f,h,v*m,(n*v+y)*m)}else l.isInstancedBufferAttribute?(Dt.enableAttributeAndDivisor(c,l.meshPerAttribute),void 0===r.maxInstancedCount&&(r.maxInstancedCount=l.meshPerAttribute*l.count)):Dt.enableAttribute(c),Pt.bindBuffer(Pt.ARRAY_BUFFER,p),Pt.vertexAttribPointer(c,u,f,h,0,n*u*m)}else if(void 0!==o){var x=o[s];if(void 0!==x)switch(x.length){case 2:Pt.vertexAttrib2fv(c,x);break;case 3:Pt.vertexAttrib3fv(c,x);break;case 4:Pt.vertexAttrib4fv(c,x);break;default:Pt.vertexAttrib1fv(c,x)}}}}Dt.disableUnusedAttributes()}function f(t,e,r){if(t.visible){if(t.layers.test(e.layers))if(t.isLight)j.push(t);else if(t.isSprite)t.frustumCulled&&!xt.intersectsSprite(t)||Y.push(t);else if(t.isLensFlare)q.push(t);else if(t.isImmediateRenderObject)r&&Et.setFromMatrixPosition(t.matrixWorld).applyMatrix4(Mt),W.push(t,null,t.material,Et.z,null);else if((t.isMesh||t.isLine||t.isPoints)&&(t.isSkinnedMesh&&t.skeleton.update(),!t.frustumCulled||xt.intersectsObject(t))){r&&Et.setFromMatrixPosition(t.matrixWorld).applyMatrix4(Mt);var n=Gt.update(t),i=t.material;if(Array.isArray(i))for(var a=n.groups,o=0,s=a.length;o=0&&t.numSupportedMorphTargets++}if(t.morphNormals){t.numSupportedMorphNormals=0;for(var d=0;d=0&&t.numSupportedMorphNormals++}var p=n.shader.uniforms;(t.isShaderMaterial||t.isRawShaderMaterial)&&!0!==t.clipping||(n.numClippingPlanes=bt.numPlanes,n.numIntersection=bt.numIntersection,p.clippingPlanes=bt.uniform),n.fog=e,n.lightsHash=At.hash,t.lights&&(p.ambientLightColor.value=At.ambient,p.directionalLights.value=At.directional,p.spotLights.value=At.spot,p.rectAreaLights.value=At.rectArea,p.pointLights.value=At.point,p.hemisphereLights.value=At.hemi,p.directionalShadowMap.value=At.directionalShadowMap,p.directionalShadowMatrix.value=At.directionalShadowMatrix,p.spotShadowMap.value=At.spotShadowMap,p.spotShadowMatrix.value=At.spotShadowMatrix,p.pointShadowMap.value=At.pointShadowMap,p.pointShadowMatrix.value=At.pointShadowMatrix);var f=n.program.getUniforms(),m=tt.seqWithValue(f.seq,p);n.uniformsList=m}function x(t,e,r,n){lt=0;var i=Ut.get(r);if(wt&&(_t||t!==it)){var a=t===it&&r.id===$;bt.setState(r.clippingPlanes,r.clipIntersection,r.clipShadows,t,i,a)}!1===r.needsUpdate&&(void 0===i.program?r.needsUpdate=!0:r.fog&&i.fog!==e?r.needsUpdate=!0:r.lights&&i.lightsHash!==At.hash?r.needsUpdate=!0:void 0===i.numClippingPlanes||i.numClippingPlanes===bt.numPlanes&&i.numIntersection===bt.numIntersection||(r.needsUpdate=!0)),r.needsUpdate&&(v(r,e,n),r.needsUpdate=!1);var o=!1,s=!1,c=!1,l=i.program,h=l.getUniforms(),u=i.shader.uniforms;if(l.id!==J&&(Pt.useProgram(l.program),J=l.id,o=!0,s=!0,c=!0),r.id!==$&&($=r.id,s=!0),o||t!==it){if(h.setValue(Pt,"projectionMatrix",t.projectionMatrix),Nt.logarithmicDepthBuffer&&h.setValue(Pt,"logDepthBufFC",2/(Math.log(t.far+1)/Math.LN2)),it!==(at||t)&&(it=at||t,s=!0,c=!0),r.isShaderMaterial||r.isMeshPhongMaterial||r.isMeshStandardMaterial||r.envMap){var p=h.map.cameraPosition;void 0!==p&&p.setValue(Pt,Et.setFromMatrixPosition(t.matrixWorld))}(r.isMeshPhongMaterial||r.isMeshLambertMaterial||r.isMeshBasicMaterial||r.isMeshStandardMaterial||r.isShaderMaterial||r.skinning)&&h.setValue(Pt,"viewMatrix",t.matrixWorldInverse)}if(r.skinning){h.setOptional(Pt,n,"bindMatrix"),h.setOptional(Pt,n,"bindMatrixInverse");var f=n.skeleton;if(f){var m=f.bones;if(Nt.floatVertexTextures){if(void 0===f.boneTexture){var g=Math.sqrt(4*m.length);g=Ko.nextPowerOfTwo(Math.ceil(g)),g=Math.max(g,4);var y=new Float32Array(g*g*4);y.set(f.boneMatrices);var x=new d(y,g,g,vl,ll);f.boneMatrices=y,f.boneTexture=x,f.boneTextureSize=g}h.setValue(Pt,"boneTexture",f.boneTexture),h.setValue(Pt,"boneTextureSize",f.boneTextureSize)}else h.setOptional(Pt,f,"boneMatrices")}}return s&&(h.setValue(Pt,"toneMappingExposure",Z.toneMappingExposure),h.setValue(Pt,"toneMappingWhitePoint",Z.toneMappingWhitePoint),r.lights&&P(u,c),e&&r.fog&&E(u,e),(r.isMeshBasicMaterial||r.isMeshLambertMaterial||r.isMeshPhongMaterial||r.isMeshStandardMaterial||r.isMeshNormalMaterial||r.isMeshDepthMaterial)&&b(u,r),r.isLineBasicMaterial?w(u,r):r.isLineDashedMaterial?(w(u,r),_(u,r)):r.isPointsMaterial?M(u,r):r.isMeshLambertMaterial?S(u,r):r.isMeshToonMaterial?A(u,r):r.isMeshPhongMaterial?T(u,r):r.isMeshPhysicalMaterial?C(u,r):r.isMeshStandardMaterial?L(u,r):r.isMeshDepthMaterial?r.displacementMap&&(u.displacementMap.value=r.displacementMap,u.displacementScale.value=r.displacementScale,u.displacementBias.value=r.displacementBias):r.isMeshNormalMaterial&&R(u,r),void 0!==u.ltcMat&&(u.ltcMat.value=eh.LTC_MAT_TEXTURE),void 0!==u.ltcMag&&(u.ltcMag.value=eh.LTC_MAG_TEXTURE),tt.upload(Pt,i.uniformsList,u,Z)),h.setValue(Pt,"modelViewMatrix",n.modelViewMatrix),h.setValue(Pt,"normalMatrix",n.normalMatrix),h.setValue(Pt,"modelMatrix",n.matrixWorld),l}function b(t,e){t.opacity.value=e.opacity,t.diffuse.value=e.color,e.emissive&&t.emissive.value.copy(e.emissive).multiplyScalar(e.emissiveIntensity),t.map.value=e.map,t.specularMap.value=e.specularMap,t.alphaMap.value=e.alphaMap,e.lightMap&&(t.lightMap.value=e.lightMap,t.lightMapIntensity.value=e.lightMapIntensity),e.aoMap&&(t.aoMap.value=e.aoMap,t.aoMapIntensity.value=e.aoMapIntensity);var r;if(e.map?r=e.map:e.specularMap?r=e.specularMap:e.displacementMap?r=e.displacementMap:e.normalMap?r=e.normalMap:e.bumpMap?r=e.bumpMap:e.roughnessMap?r=e.roughnessMap:e.metalnessMap?r=e.metalnessMap:e.alphaMap?r=e.alphaMap:e.emissiveMap&&(r=e.emissiveMap),void 0!==r){r.isWebGLRenderTarget&&(r=r.texture);var n=r.offset,i=r.repeat;t.offsetRepeat.value.set(n.x,n.y,i.x,i.y)}t.envMap.value=e.envMap,t.flipEnvMap.value=e.envMap&&e.envMap.isCubeTexture?-1:1,t.reflectivity.value=e.reflectivity,t.refractionRatio.value=e.refractionRatio}function w(t,e){t.diffuse.value=e.color,t.opacity.value=e.opacity}function _(t,e){t.dashSize.value=e.dashSize,t.totalSize.value=e.dashSize+e.gapSize,t.scale.value=e.scale}function M(t,e){if(t.diffuse.value=e.color,t.opacity.value=e.opacity,t.size.value=e.size*mt,t.scale.value=.5*ft,t.map.value=e.map,null!==e.map){var r=e.map.offset,n=e.map.repeat;t.offsetRepeat.value.set(r.x,r.y,n.x,n.y)}}function E(t,e){t.fogColor.value=e.color,e.isFog?(t.fogNear.value=e.near,t.fogFar.value=e.far):e.isFogExp2&&(t.fogDensity.value=e.density)}function S(t,e){e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap)}function T(t,e){t.specular.value=e.specular,t.shininess.value=Math.max(e.shininess,1e-4),e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap),e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale),e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale)),e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}function A(t,e){T(t,e),e.gradientMap&&(t.gradientMap.value=e.gradientMap)}function L(t,e){t.roughness.value=e.roughness,t.metalness.value=e.metalness,e.roughnessMap&&(t.roughnessMap.value=e.roughnessMap),e.metalnessMap&&(t.metalnessMap.value=e.metalnessMap),e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap),e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale),e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale)),e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias),e.envMap&&(t.envMapIntensity.value=e.envMapIntensity)}function C(t,e){t.clearCoat.value=e.clearCoat,t.clearCoatRoughness.value=e.clearCoatRoughness,L(t,e)}function R(t,e){e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale),e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale)),e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}function P(t,e){t.ambientLightColor.needsUpdate=e,t.directionalLights.needsUpdate=e,t.pointLights.needsUpdate=e,t.spotLights.needsUpdate=e,t.rectAreaLights.needsUpdate=e,t.hemisphereLights.needsUpdate=e}function I(t){for(var e=0,r=0,n=t.length;r=Nt.maxTextures&&console.warn("THREE.WebGLRenderer: Trying to use "+t+" texture units while this GPU supports only "+Nt.maxTextures),lt+=1,t}function D(t){var e;if(t===qc)return Pt.REPEAT;if(t===Zc)return Pt.CLAMP_TO_EDGE;if(t===Jc)return Pt.MIRRORED_REPEAT;if(t===Qc)return Pt.NEAREST;if(t===Kc)return Pt.NEAREST_MIPMAP_NEAREST;if(t===$c)return Pt.NEAREST_MIPMAP_LINEAR;if(t===tl)return Pt.LINEAR;if(t===el)return Pt.LINEAR_MIPMAP_NEAREST;if(t===rl)return Pt.LINEAR_MIPMAP_LINEAR;if(t===nl)return Pt.UNSIGNED_BYTE;if(t===ul)return Pt.UNSIGNED_SHORT_4_4_4_4;if(t===dl)return Pt.UNSIGNED_SHORT_5_5_5_1;if(t===pl)return Pt.UNSIGNED_SHORT_5_6_5;if(t===il)return Pt.BYTE;if(t===al)return Pt.SHORT;if(t===ol)return Pt.UNSIGNED_SHORT;if(t===sl)return Pt.INT;if(t===cl)return Pt.UNSIGNED_INT;if(t===ll)return Pt.FLOAT;if(t===hl&&null!==(e=Ot.get("OES_texture_half_float")))return e.HALF_FLOAT_OES;if(t===ml)return Pt.ALPHA;if(t===gl)return Pt.RGB;if(t===vl)return Pt.RGBA;if(t===yl)return Pt.LUMINANCE;if(t===xl)return Pt.LUMINANCE_ALPHA;if(t===bl)return Pt.DEPTH_COMPONENT;if(t===wl)return Pt.DEPTH_STENCIL;if(t===lc)return Pt.FUNC_ADD;if(t===hc)return Pt.FUNC_SUBTRACT;if(t===uc)return Pt.FUNC_REVERSE_SUBTRACT;if(t===fc)return Pt.ZERO;if(t===mc)return Pt.ONE;if(t===gc)return Pt.SRC_COLOR;if(t===vc)return Pt.ONE_MINUS_SRC_COLOR;if(t===yc)return Pt.SRC_ALPHA;if(t===xc)return Pt.ONE_MINUS_SRC_ALPHA;if(t===bc)return Pt.DST_ALPHA;if(t===wc)return Pt.ONE_MINUS_DST_ALPHA;if(t===_c)return Pt.DST_COLOR;if(t===Mc)return Pt.ONE_MINUS_DST_COLOR;if(t===Ec)return Pt.SRC_ALPHA_SATURATE;if((t===_l||t===Ml||t===El||t===Sl)&&null!==(e=Ot.get("WEBGL_compressed_texture_s3tc"))){if(t===_l)return e.COMPRESSED_RGB_S3TC_DXT1_EXT;if(t===Ml)return e.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(t===El)return e.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(t===Sl)return e.COMPRESSED_RGBA_S3TC_DXT5_EXT}if((t===Tl||t===Al||t===Ll||t===Cl)&&null!==(e=Ot.get("WEBGL_compressed_texture_pvrtc"))){if(t===Tl)return e.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(t===Al)return e.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(t===Ll)return e.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(t===Cl)return e.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}if(t===Rl&&null!==(e=Ot.get("WEBGL_compressed_texture_etc1")))return e.COMPRESSED_RGB_ETC1_WEBGL;if((t===dc||t===pc)&&null!==(e=Ot.get("EXT_blend_minmax"))){if(t===dc)return e.MIN_EXT;if(t===pc)return e.MAX_EXT}return t===fl&&null!==(e=Ot.get("WEBGL_depth_texture"))?e.UNSIGNED_INT_24_8_WEBGL:0}console.log("THREE.WebGLRenderer",Gs);var U=void 0!==(t=t||{}).canvas?t.canvas:document.createElementNS("http://www.w3.org/1999/xhtml","canvas"),z=void 0!==t.context?t.context:null,B=void 0!==t.alpha&&t.alpha,F=void 0===t.depth||t.depth,k=void 0===t.stencil||t.stencil,G=void 0!==t.antialias&&t.antialias,V=void 0===t.premultipliedAlpha||t.premultipliedAlpha,H=void 0!==t.preserveDrawingBuffer&&t.preserveDrawingBuffer,j=[],W=null,X=new Float32Array(8),Y=[],q=[];this.domElement=U,this.context=null,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.gammaFactor=2,this.gammaInput=!1,this.gammaOutput=!1,this.physicallyCorrectLights=!1,this.toneMapping=zc,this.toneMappingExposure=1,this.toneMappingWhitePoint=1,this.maxMorphTargets=8,this.maxMorphNormals=4;var Z=this,J=null,Q=null,K=null,$=-1,et="",it=null,at=null,ot=new y,st=null,ct=new y,lt=0,ht=U.width,ft=U.height,mt=1,gt=new y(0,0,ht,ft),vt=!1,yt=new y(0,0,ht,ft),xt=new ut,bt=new ve,wt=!1,_t=!1,Mt=new e,Et=new n,St=new e,Tt=new e,At={hash:"",ambient:[0,0,0],directional:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[],point:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],shadows:[]},Lt={geometries:0,textures:0},Rt={frame:0,calls:0,vertices:0,faces:0,points:0};this.info={render:Rt,memory:Lt,programs:null};var Pt;try{var It={alpha:B,depth:F,stencil:k,antialias:G,premultipliedAlpha:V,preserveDrawingBuffer:H};if(null===(Pt=z||U.getContext("webgl",It)||U.getContext("experimental-webgl",It)))throw null!==U.getContext("webgl")?"Error creating WebGL context with your selected attributes.":"Error creating WebGL context.";void 0===Pt.getShaderPrecisionFormat&&(Pt.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}}),U.addEventListener("webglcontextlost",o,!1)}catch(t){console.error("THREE.WebGLRenderer: "+t)}var Ot=new ge(Pt);Ot.get("WEBGL_depth_texture"),Ot.get("OES_texture_float"),Ot.get("OES_texture_float_linear"),Ot.get("OES_texture_half_float"),Ot.get("OES_texture_half_float_linear"),Ot.get("OES_standard_derivatives"),Ot.get("ANGLE_instanced_arrays"),Ot.get("OES_element_index_uint")&&(Ct.MaxIndex=4294967296);var Nt=new pe(Pt,Ot,t),Dt=new de(Pt,Ot,D),Ut=new ue,zt=new he(Pt,Ot,Dt,Ut,Nt,D,Lt),Bt=new pt(Pt),kt=new Xt(Pt,Bt,Lt),Gt=new qt(Pt,kt,Rt),Vt=new le(this,Nt),Zt=new Yt,Jt=new Ht,Qt=new Ft(this,Dt,Gt,V),Kt=new me(this);this.info.programs=Vt.programs;var $t=new Wt(Pt,Ot,Rt),te=new jt(Pt,Ot,Rt);i(),this.context=Pt,this.capabilities=Nt,this.extensions=Ot,this.properties=Ut,this.renderLists=Jt,this.state=Dt,this.vr=Kt;var ee=new dt(this,At,Gt,Nt);this.shadowMap=ee;var re=new nt(this,Y),ne=new rt(this,q);this.getContext=function(){return Pt},this.getContextAttributes=function(){return Pt.getContextAttributes()},this.forceContextLoss=function(){var t=Ot.get("WEBGL_lose_context");t&&t.loseContext()},this.getMaxAnisotropy=function(){return Nt.getMaxAnisotropy()},this.getPrecision=function(){return Nt.precision},this.getPixelRatio=function(){return mt},this.setPixelRatio=function(t){void 0!==t&&(mt=t,this.setSize(ht,ft,!1))},this.getSize=function(){return{width:ht,height:ft}},this.setSize=function(t,e,r){var n=Kt.getDevice();if(n&&n.isPresenting)return void console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");ht=t,ft=e,U.width=t*mt,U.height=e*mt,!1!==r&&(U.style.width=t+"px",U.style.height=e+"px"),this.setViewport(0,0,t,e)},this.getDrawingBufferSize=function(){return{width:ht*mt,height:ft*mt}},this.setDrawingBufferSize=function(t,e,r){ht=t,ft=e,mt=r,U.width=t*r,U.height=e*r,this.setViewport(0,0,t,e)},this.setViewport=function(t,e,r,n){yt.set(t,ft-e-n,r,n),Dt.viewport(ct.copy(yt).multiplyScalar(mt))},this.setScissor=function(t,e,r,n){gt.set(t,ft-e-n,r,n),Dt.scissor(ot.copy(gt).multiplyScalar(mt))},this.setScissorTest=function(t){Dt.setScissorTest(vt=t)},this.getClearColor=Qt.getClearColor,this.setClearColor=Qt.setClearColor,this.getClearAlpha=Qt.getClearAlpha,this.setClearAlpha=Qt.setClearAlpha,this.clear=function(t,e,r){var n=0;(void 0===t||t)&&(n|=Pt.COLOR_BUFFER_BIT),(void 0===e||e)&&(n|=Pt.DEPTH_BUFFER_BIT),(void 0===r||r)&&(n|=Pt.STENCIL_BUFFER_BIT),Pt.clear(n)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.clearTarget=function(t,e,r,n){this.setRenderTarget(t),this.clear(e,r,n)},this.resetGLState=a,this.dispose=function(){U.removeEventListener("webglcontextlost",o,!1),Jt.dispose()},this.renderBufferImmediate=function(t,e,r){Dt.initAttributes();var n=Ut.get(t);t.hasPositions&&!n.position&&(n.position=Pt.createBuffer()),t.hasNormals&&!n.normal&&(n.normal=Pt.createBuffer()),t.hasUvs&&!n.uv&&(n.uv=Pt.createBuffer()),t.hasColors&&!n.color&&(n.color=Pt.createBuffer());var i=e.getAttributes();if(t.hasPositions&&(Pt.bindBuffer(Pt.ARRAY_BUFFER,n.position),Pt.bufferData(Pt.ARRAY_BUFFER,t.positionArray,Pt.DYNAMIC_DRAW),Dt.enableAttribute(i.position),Pt.vertexAttribPointer(i.position,3,Pt.FLOAT,!1,0,0)),t.hasNormals){if(Pt.bindBuffer(Pt.ARRAY_BUFFER,n.normal),!r.isMeshPhongMaterial&&!r.isMeshStandardMaterial&&!r.isMeshNormalMaterial&&r.shading===Ks)for(var a=0,o=3*t.count;a8&&(d.length=8);for(var g=n.morphAttributes,f=0,m=d.length;f0&&E.renderInstances(n,R,I):E.render(R,I)}},this.compile=function(t,e){j=[],t.traverse(function(t){t.isLight&&j.push(t)}),O(j,e),t.traverse(function(e){if(e.material)if(Array.isArray(e.material))for(var r=0;r=0&&e<=t.width-n&&r>=0&&r<=t.height-i&&Pt.readPixels(e,r,n,i,D(l),D(h),a):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.")}finally{s&&Pt.bindFramebuffer(Pt.FRAMEBUFFER,K)}}}}function xe(t,e){this.name="",this.color=new c(t),this.density=void 0!==e?e:25e-5}function be(t,e,r){this.name="",this.color=new c(t),this.near=void 0!==e?e:1,this.far=void 0!==r?r:1e3}function we(){gt.call(this),this.type="Scene",this.background=null,this.fog=null,this.overrideMaterial=null,this.autoUpdate=!0}function _e(t,e,r,i,a){gt.call(this),this.lensFlares=[],this.positionScreen=new n,this.customUpdateCallback=void 0,void 0!==t&&this.add(t,e,r,i,a)}function Me(t){it.call(this),this.type="SpriteMaterial",this.color=new c(16777215),this.map=null,this.rotation=0,this.fog=!1,this.lights=!1,this.setValues(t)}function Ee(t){gt.call(this),this.type="Sprite",this.material=void 0!==t?t:new Me}function Se(){gt.call(this),this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function Te(t,r){if(t=t||[],this.bones=t.slice(0),this.boneMatrices=new Float32Array(16*this.bones.length),void 0===r)this.calculateInverses();else if(this.bones.length===r.length)this.boneInverses=r.slice(0);else{console.warn("THREE.Skeleton boneInverses is the wrong length."),this.boneInverses=[];for(var n=0,i=this.bones.length;n=0?(d=t(v-1e-5,g,d),p.subVectors(u,d)):(d=t(v+1e-5,g,d),p.subVectors(d,u)),g-1e-5>=0?(d=t(v,g-1e-5,d),f.subVectors(u,d)):(d=t(v,g+1e-5,d),f.subVectors(d,u)),h.crossVectors(p,f).normalize(),c.push(h.x,h.y,h.z),l.push(v,g)}}for(i=0;i.9&&a<.1&&(e<.2&&(m[t+0]+=1),r<.2&&(m[t+2]+=1),n<.2&&(m[t+4]+=1))}}function s(t){f.push(t.x,t.y,t.z)}function c(e,r){var n=3*e;r.x=t[n+0],r.y=t[n+1],r.z=t[n+2]}function l(){for(var t=new n,e=new n,r=new n,i=new n,a=new h,o=new h,s=new h,c=0,l=0;c0)&&m.push(_,M,S),(l!==r-1||h0&&l(!0),e>0&&l(!1)),this.setIndex(d),this.addAttribute("position",new Tt(p,3)),this.addAttribute("normal",new Tt(f,3)),this.addAttribute("uv",new Tt(m,2))}function yr(t,e,r,n,i,a,o){gr.call(this,0,t,e,r,n,i,a,o),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:r,heightSegments:n,openEnded:i,thetaStart:a,thetaLength:o}}function xr(t,e,r,n,i,a,o){vr.call(this,0,t,e,r,n,i,a,o),this.type="ConeBufferGeometry",this.parameters={radius:t,height:e,radialSegments:r,heightSegments:n,openEnded:i,thetaStart:a,thetaLength:o}}function br(t,e,r,n){_t.call(this),this.type="CircleGeometry",this.parameters={radius:t,segments:e,thetaStart:r,thetaLength:n},this.fromBufferGeometry(new wr(t,e,r,n)),this.mergeVertices()}function wr(t,e,r,i){Ct.call(this),this.type="CircleBufferGeometry",this.parameters={radius:t,segments:e,thetaStart:r,thetaLength:i},t=t||50,e=void 0!==e?Math.max(3,e):8,r=void 0!==r?r:0,i=void 0!==i?i:2*Math.PI;var a,o,s=[],c=[],l=[],u=[],d=new n,p=new h;for(c.push(0,0,0),l.push(0,0,1),u.push(.5,.5),o=0,a=3;o<=e;o++,a+=3){var f=r+o/e*i;d.x=t*Math.cos(f),d.y=t*Math.sin(f),c.push(d.x,d.y,d.z),l.push(0,0,1),p.x=(c[a]/t+1)/2,p.y=(c[a+1]/t+1)/2,u.push(p.x,p.y)}for(a=1;a<=e;a++)s.push(a,a+1,0);this.setIndex(s),this.addAttribute("position",new Tt(c,3)),this.addAttribute("normal",new Tt(l,3)),this.addAttribute("uv",new Tt(u,2))}function _r(t){at.call(this,{uniforms:rh.merge([eh.lights,{opacity:{value:1}}]),vertexShader:nh.shadow_vert,fragmentShader:nh.shadow_frag}),this.lights=!0,this.transparent=!0,Object.defineProperties(this,{opacity:{enumerable:!0,get:function(){return this.uniforms.opacity.value},set:function(t){this.uniforms.opacity.value=t}}}),this.setValues(t)}function Mr(t){at.call(this,t),this.type="RawShaderMaterial"}function Er(t){it.call(this),this.defines={STANDARD:""},this.type="MeshStandardMaterial",this.color=new c(16777215),this.roughness=.5,this.metalness=.5,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new c(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalScale=new h(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.roughnessMap=null,this.metalnessMap=null,this.alphaMap=null,this.envMap=null,this.envMapIntensity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(t)}function Sr(t){Er.call(this),this.defines={PHYSICAL:""},this.type="MeshPhysicalMaterial",this.reflectivity=.5,this.clearCoat=0,this.clearCoatRoughness=0,this.setValues(t)}function Tr(t){it.call(this),this.type="MeshPhongMaterial",this.color=new c(16777215),this.specular=new c(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new c(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalScale=new h(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=Oc,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(t)}function Ar(t){Tr.call(this),this.defines={TOON:""},this.type="MeshToonMaterial",this.gradientMap=null,this.setValues(t)}function Lr(t){it.call(this),this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalScale=new h(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.lights=!1,this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(t)}function Cr(t){it.call(this),this.type="MeshLambertMaterial",this.color=new c(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new c(0),this.emissiveIntensity=1,this.emissiveMap=null,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=Oc,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.skinning=!1,this.morphTargets=!1,this.morphNormals=!1,this.setValues(t)}function Rr(t){it.call(this),this.type="LineDashedMaterial",this.color=new c(16777215),this.linewidth=1,this.scale=1,this.dashSize=3,this.gapSize=1,this.lights=!1,this.setValues(t)}function Pr(t,e,r){var n=this,i=!1,a=0,o=0;this.onStart=void 0,this.onLoad=t,this.onProgress=e,this.onError=r,this.itemStart=function(t){o++,!1===i&&void 0!==n.onStart&&n.onStart(t,a,o),i=!0},this.itemEnd=function(t){a++,void 0!==n.onProgress&&n.onProgress(t,a,o),a===o&&(i=!1,void 0!==n.onLoad&&n.onLoad())},this.itemError=function(t){void 0!==n.onError&&n.onError(t)}}function Ir(t){this.manager=void 0!==t?t:ph}function Or(t){this.manager=void 0!==t?t:ph,this._parser=null}function Nr(t){this.manager=void 0!==t?t:ph,this._parser=null}function Dr(t){this.manager=void 0!==t?t:ph}function Ur(t){this.manager=void 0!==t?t:ph}function zr(t){this.manager=void 0!==t?t:ph}function Br(t,e){gt.call(this),this.type="Light",this.color=new c(t),this.intensity=void 0!==e?e:1,this.receiveShadow=void 0}function Fr(t,e,r){Br.call(this,t,r),this.type="HemisphereLight",this.castShadow=void 0,this.position.copy(gt.DefaultUp),this.updateMatrix(),this.groundColor=new c(e)}function kr(t){this.camera=t,this.bias=0,this.radius=1,this.mapSize=new h(512,512),this.map=null,this.matrix=new e}function Gr(){kr.call(this,new xt(50,1,.5,500))}function Vr(t,e,r,n,i,a){Br.call(this,t,e),this.type="SpotLight",this.position.copy(gt.DefaultUp),this.updateMatrix(),this.target=new gt,Object.defineProperty(this,"power",{get:function(){return this.intensity*Math.PI},set:function(t){this.intensity=t/Math.PI}}),this.distance=void 0!==r?r:0,this.angle=void 0!==n?n:Math.PI/3,this.penumbra=void 0!==i?i:0,this.decay=void 0!==a?a:1,this.shadow=new Gr}function Hr(t,e,r,n){Br.call(this,t,e),this.type="PointLight",Object.defineProperty(this,"power",{get:function(){return 4*this.intensity*Math.PI},set:function(t){this.intensity=t/(4*Math.PI)}}),this.distance=void 0!==r?r:0,this.decay=void 0!==n?n:1,this.shadow=new kr(new xt(90,1,.5,500))}function jr(){kr.call(this,new yt(-5,5,5,-5,.5,500))}function Wr(t,e){Br.call(this,t,e),this.type="DirectionalLight",this.position.copy(gt.DefaultUp),this.updateMatrix(),this.target=new gt,this.shadow=new jr}function Xr(t,e){Br.call(this,t,e),this.type="AmbientLight",this.castShadow=void 0}function Yr(t,e,r,n){Br.call(this,t,e),this.type="RectAreaLight",this.position.set(0,1,0),this.updateMatrix(),this.width=void 0!==r?r:10,this.height=void 0!==n?n:10}function qr(t,e,r,n){this.parameterPositions=t,this._cachedIndex=0,this.resultBuffer=void 0!==n?n:new e.constructor(r),this.sampleValues=e,this.valueSize=r}function Zr(t,e,r,n){qr.call(this,t,e,r,n),this._weightPrev=-0,this._offsetPrev=-0,this._weightNext=-0,this._offsetNext=-0}function Jr(t,e,r,n){qr.call(this,t,e,r,n)}function Qr(t,e,r,n){qr.call(this,t,e,r,n)}function Kr(t,e,r,n){if(void 0===t)throw new Error("track name is undefined");if(void 0===e||0===e.length)throw new Error("no keyframes in track named "+t);this.name=t,this.times=fh.convertArray(e,this.TimeBufferType),this.values=fh.convertArray(r,this.ValueBufferType),this.setInterpolation(n||this.DefaultInterpolation),this.validate(),this.optimize()}function $r(t,e,r,n){Kr.call(this,t,e,r,n)}function tn(t,e,r,n){qr.call(this,t,e,r,n)}function en(t,e,r,n){Kr.call(this,t,e,r,n)}function rn(t,e,r,n){Kr.call(this,t,e,r,n)}function nn(t,e,r,n){Kr.call(this,t,e,r,n)}function an(t,e,r){Kr.call(this,t,e,r)}function on(t,e,r,n){Kr.call(this,t,e,r,n)}function sn(t,e,r,n){Kr.apply(this,arguments)}function cn(t,e,r){this.name=t,this.tracks=r,this.duration=void 0!==e?e:-1,this.uuid=Ko.generateUUID(),this.duration<0&&this.resetDuration(),this.optimize()}function ln(t){this.manager=void 0!==t?t:ph,this.textures={}}function hn(t){this.manager=void 0!==t?t:ph}function un(){this.onLoadStart=function(){},this.onLoadProgress=function(){},this.onLoadComplete=function(){}}function dn(t){"boolean"==typeof t&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."),t=void 0),this.manager=void 0!==t?t:ph,this.withCredentials=!1}function pn(t){this.manager=void 0!==t?t:ph,this.texturePath=""}function fn(t,e,r,n,i){var a=.5*(n-e),o=.5*(i-r),s=t*t;return(2*r-2*n+a+o)*(t*s)+(-3*r+3*n-2*a-o)*s+a*t+r}function mn(t,e){var r=1-t;return r*r*e}function gn(t,e){return 2*(1-t)*t*e}function vn(t,e){return t*t*e}function yn(t,e,r,n){return mn(t,e)+gn(t,r)+vn(t,n)}function xn(t,e){var r=1-t;return r*r*r*e}function bn(t,e){var r=1-t;return 3*r*r*t*e}function wn(t,e){return 3*(1-t)*t*t*e}function _n(t,e){return t*t*t*e}function Mn(t,e,r,n,i){return xn(t,e)+bn(t,r)+wn(t,n)+_n(t,i)}function En(){this.arcLengthDivisions=200}function Sn(t,e){En.call(this),this.v1=t,this.v2=e}function Tn(){En.call(this),this.curves=[],this.autoClose=!1}function An(t,e,r,n,i,a,o,s){En.call(this),this.aX=t,this.aY=e,this.xRadius=r,this.yRadius=n,this.aStartAngle=i,this.aEndAngle=a,this.aClockwise=o,this.aRotation=s||0}function Ln(t){En.call(this),this.points=void 0===t?[]:t}function Cn(t,e,r,n){En.call(this),this.v0=t,this.v1=e,this.v2=r,this.v3=n}function Rn(t,e,r){En.call(this),this.v0=t,this.v1=e,this.v2=r}function Pn(t){Tn.call(this),this.currentPoint=new h,t&&this.fromPoints(t)}function In(){Pn.apply(this,arguments),this.holes=[]}function On(){this.subPaths=[],this.currentPath=null}function Nn(t){this.data=t}function Dn(t){this.manager=void 0!==t?t:ph}function Un(t){this.manager=void 0!==t?t:ph}function zn(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new xt,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new xt,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1}function Bn(){gt.call(this),this.type="AudioListener",this.context=_h.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null}function Fn(t){gt.call(this),this.type="Audio",this.context=t.context,this.gain=this.context.createGain(),this.gain.connect(t.getInput()),this.autoplay=!1,this.buffer=null,this.loop=!1,this.startTime=0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.sourceType="empty",this.filters=[]}function kn(t){Fn.call(this,t),this.panner=this.context.createPanner(),this.panner.connect(this.gain)}function Gn(t,e){this.analyser=t.context.createAnalyser(),this.analyser.fftSize=void 0!==e?e:2048,this.data=new Uint8Array(this.analyser.frequencyBinCount),t.getOutput().connect(this.analyser)}function Vn(t,e,r){this.binding=t,this.valueSize=r;var n,i=Float64Array;switch(e){case"quaternion":n=this._slerp;break;case"string":case"bool":i=Array,n=this._select;break;default:n=this._lerp}this.buffer=new i(4*r),this._mixBufferRegion=n,this.cumulativeWeight=0,this.useCount=0,this.referenceCount=0}function Hn(t,e,r){var n=r||jn.parseTrackName(e);this._targetGroup=t,this._bindings=t.subscribe_(e,n)}function jn(t,e,r){this.path=e,this.parsedPath=r||jn.parseTrackName(e),this.node=jn.findNode(t,this.parsedPath.nodeName)||t,this.rootNode=t}function Wn(t){this.uuid=Ko.generateUUID(),this._objects=Array.prototype.slice.call(arguments),this.nCachedObjects_=0;var e={};this._indicesByUUID=e;for(var r=0,n=arguments.length;r!==n;++r)e[arguments[r].uuid]=r;this._paths=[],this._parsedPaths=[],this._bindings=[],this._bindingsIndicesByPath={};var i=this;this.stats={objects:{get total(){return i._objects.length},get inUse(){return this.total-i.nCachedObjects_}},get bindingsPerObject(){return i._bindings.length}}}function Xn(t,e,r){this._mixer=t,this._clip=e,this._localRoot=r||null;for(var n=e.tracks,i=n.length,a=new Array(i),o={endingStart:Il,endingEnd:Il},s=0;s!==i;++s){var c=n[s].createInterpolant(null);a[s]=c,c.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(i),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=Pl,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}function Yn(t){this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}function qn(t){"string"==typeof t&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),t=arguments[1]),this.value=t}function Zn(){Ct.call(this),this.type="InstancedBufferGeometry",this.maxInstancedCount=void 0}function Jn(t,e,r,n){this.uuid=Ko.generateUUID(),this.data=t,this.itemSize=e,this.offset=r,this.normalized=!0===n}function Qn(t,e){this.uuid=Ko.generateUUID(),this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.dynamic=!1,this.updateRange={offset:0,count:-1},this.onUploadCallback=function(){},this.version=0}function Kn(t,e,r){Qn.call(this,t,e),this.meshPerAttribute=r||1}function $n(t,e,r){Mt.call(this,t,e),this.meshPerAttribute=r||1}function ti(t,e,r,n){this.ray=new Dt(t,e),this.near=r||0,this.far=n||1/0,this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}},Object.defineProperties(this.params,{PointCloud:{get:function(){return console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points."),this.Points}}})}function ei(t,e){return t.distance-e.distance}function ri(t,e,r,n){if(!1!==t.visible&&(t.raycast(e,r),!0===n))for(var i=t.children,a=0,o=i.length;a256)return void console.error("too many glyphs for atlas");var o;n.textAlign="left",n.font="20px "+t,n.fillStyle="#ffffff";for(var s,c,l=0;lf&&(f=l);var L=T*x+A*b+M,C=T*w+A*_+E;for(this.boundingBox=new st(new n(M,E,p),new n(L,C,f)),i=0;i20;)(n=i.split(".")).shift(),i=n.join("."),a=!0;a&&(i="..."+i),this.addLine(i),this.addLine("x: "+e.x+" m").addLine("y: "+e.y+" m").addLine("z: "+e.z+" m"),null!==r&&this.addLine("depth from surface: "+Math.round(r)+" m")}function Oa(){this.array=null}function Na(t,e,r,n,i){return this.x=t,this.y=e,this.zoom=r,this.tileSet=n,this.clip=i,this.canZoom=!0,this.evicted=!1,this.replaced=!1,this.evictionCount=1,this.resurrectionPending=!1,this.childrenLoading=0,this.childErrors=0,this.boundingBox=null,this.worldBoundingBox=null,Bt.call(this,new Ct,Dh.getSurfaceMaterial()),this.onBeforeRender=mu.onBeforeRender,this.onAfterRender=mu.onAfterRender,this}function Da(t,e,r){function n(t){s.tileSets=JSON.parse(t),e()}function i(){e()}Ta.call(this),this.name="WebTerrain",this.type="CV.WebTerrain";var o=t.limits;this.limits=new et(new h(o.min.x,o.min.y),new h(o.max.x,o.max.y)),this.offsets=t.offsets,this.onLoaded=r,this.childrenLoading=0,this.childErrors=0,this.terrainLoaded=!1,this.material=null,this.initialZoom=null,this.currentZoom=null,this.currentLimits=null,this.dying=!1,this.overlaysLoading=0,this.debug=!0,this.workerPool=new Ca("webTileWorker.js"),void 0!==Qh&&(this.progressDial=Qh.getProgressDial());var s=this;(new Ir).setResponseType("text").load(a("terrainDirectory","")+"/tileSets.json",n,function(){},i)}function Ua(t,e){this.provider=t,this.container=e;var r=t.getAttribution();r&&(r.classList.add("overlay-branding"),this.attribution=r),this.materialCache={}}function za(t,e){function i(){return 2*Math.PI/60/60*U.autoRotateSpeed}function a(){return Math.pow(.95,U.zoomSpeed)}function o(t){j.theta-=t}function s(t){j.phi-=t}function c(t){U.object instanceof xt?W/=t:U.object instanceof yt?(U.object.zoom=Math.max(U.minZoom,Math.min(U.maxZoom,U.object.zoom*t)),U.object.updateProjectionMatrix(),Y=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),U.enableZoom=!1)}function l(t){U.object instanceof xt?W*=t:U.object instanceof yt?(U.object.zoom=Math.max(U.minZoom,Math.min(U.maxZoom,U.object.zoom/t)),U.object.updateProjectionMatrix(),Y=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),U.enableZoom=!1)}function u(t){q.set(t.clientX,t.clientY)}function d(t){tt.set(t.clientX,t.clientY)}function p(t){Q.set(t.clientX,t.clientY)}function f(t){Z.set(t.clientX,t.clientY),J.subVectors(Z,q);var e=U.domElement===document?U.domElement.body:U.domElement;o(2*Math.PI*J.x/e.clientWidth*U.rotateSpeed),s(2*Math.PI*J.y/e.clientHeight*U.rotateSpeed),q.copy(Z),U.update()}function m(t){et.set(t.clientX,t.clientY),rt.subVectors(et,tt),rt.y>0?c(a()):rt.y<0&&l(a()),tt.copy(et),U.update()}function g(t){K.set(t.clientX,t.clientY),$.subVectors(K,Q),at($.x,$.y),Q.copy(K),U.update()}function v(t){}function y(t){t.deltaY<0?l(a()):t.deltaY>0&&c(a()),U.update()}function x(t){switch(t.keyCode){case U.keys.UP:at(0,U.keyPanSpeed),U.update();break;case U.keys.BOTTOM:at(0,-U.keyPanSpeed),U.update();break;case U.keys.LEFT:at(U.keyPanSpeed,0),U.update();break;case U.keys.RIGHT:at(-U.keyPanSpeed,0),U.update()}}function b(t){q.set(t.touches[0].pageX,t.touches[0].pageY)}function w(t){var e=t.touches[0].pageX-t.touches[1].pageX,r=t.touches[0].pageY-t.touches[1].pageY,n=Math.sqrt(e*e+r*r);tt.set(0,n)}function _(t){Q.set(t.touches[0].pageX,t.touches[0].pageY)}function M(t){Z.set(t.touches[0].pageX,t.touches[0].pageY),J.subVectors(Z,q);var e=U.domElement===document?U.domElement.body:U.domElement;o(2*Math.PI*J.x/e.clientWidth*U.rotateSpeed),s(2*Math.PI*J.y/e.clientHeight*U.rotateSpeed),q.copy(Z),U.update()}function E(t){var e=t.touches[0].pageX-t.touches[1].pageX,r=t.touches[0].pageY-t.touches[1].pageY,n=Math.sqrt(e*e+r*r);et.set(0,n),rt.subVectors(et,tt),rt.y>0?l(a()):rt.y<0&&c(a()),tt.copy(et),U.update()}function S(t){K.set(t.touches[0].pageX,t.touches[0].pageY),$.subVectors(K,Q),at($.x,$.y),Q.copy(K),U.update()}function T(t){}function A(t){if(!1!==U.enabled){if(t.preventDefault(),t.button===U.mouseButtons.ORBIT){if(!1===U.enableRotate)return;u(t),G=k.ROTATE}else if(t.button===U.mouseButtons.ZOOM){if(!1===U.enableZoom)return;d(t),G=k.DOLLY}else if(t.button===U.mouseButtons.PAN){if(!1===U.enablePan)return;p(t),G=k.PAN}G!==k.NONE&&(document.addEventListener("mousemove",L,!1),document.addEventListener("mouseup",C,!1),U.dispatchEvent(B))}}function L(t){if(!1!==U.enabled)if(t.preventDefault(),G===k.ROTATE){if(!1===U.enableRotate)return;f(t)}else if(G===k.DOLLY){if(!1===U.enableZoom)return;m(t)}else if(G===k.PAN){if(!1===U.enablePan)return;g(t)}}function C(t){!1!==U.enabled&&(v(t),document.removeEventListener("mousemove",L,!1),document.removeEventListener("mouseup",C,!1),U.dispatchEvent(F),G=k.NONE)}function R(t){!1===U.enabled||!1===U.enableZoom||G!==k.NONE&&G!==k.ROTATE||(t.preventDefault(),t.stopPropagation(),y(t),U.dispatchEvent(B),U.dispatchEvent(F))}function P(t){!1!==U.enabled&&!1!==U.enableKeys&&!1!==U.enablePan&&x(t)}function I(t){if(!1!==U.enabled){switch(t.touches.length){case 1:if(!1===U.enableRotate)return;b(t),G=k.TOUCH_ROTATE;break;case 2:if(!1===U.enableZoom)return;w(t),G=k.TOUCH_DOLLY;break;case 3:if(!1===U.enablePan)return;_(t),G=k.TOUCH_PAN;break;default:G=k.NONE}G!==k.NONE&&U.dispatchEvent(B)}}function O(t){if(!1!==U.enabled)switch(t.preventDefault(),t.stopPropagation(),t.touches.length){case 1:if(!1===U.enableRotate)return;if(G!==k.TOUCH_ROTATE)return;M(t);break;case 2:if(!1===U.enableZoom)return;if(G!==k.TOUCH_DOLLY)return;E(t);break;case 3:if(!1===U.enablePan)return;if(G!==k.TOUCH_PAN)return;S(t);break;default:G=k.NONE}}function N(t){!1!==U.enabled&&(T(t),U.dispatchEvent(F),G=k.NONE)}function D(t){t.preventDefault()}this.object=t,this.domElement=void 0!==e?e:document,this.enabled=!0,this.target=new n,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.25,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.keyPanSpeed=7,this.autoRotate=!1,this.autoRotateSpeed=2,this.enableKeys=!0,this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40},this.mouseButtons={ORBIT:Vs.LEFT,ZOOM:Vs.MIDDLE,PAN:Vs.RIGHT},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this.getPolarAngle=function(){return H.phi},this.getAzimuthalAngle=function(){return H.theta},this.reset=function(){U.target.copy(U.target0),U.object.position.copy(U.position0),U.object.zoom=U.zoom0,U.object.updateProjectionMatrix(),U.dispatchEvent(z),U.update(),G=k.NONE},this.update=function(){var e=new n,a=(new r).setFromUnitVectors(t.up,new n(0,1,0)),s=a.clone().inverse(),c=new n,l=new r;return function(){var t=U.object.position;return e.copy(t).sub(U.target),e.applyQuaternion(a),H.setFromVector3(e),U.autoRotate&&G===k.NONE&&o(i()),H.theta+=j.theta,H.phi+=j.phi,H.theta=Math.max(U.minAzimuthAngle,Math.min(U.maxAzimuthAngle,H.theta)),H.phi=Math.max(U.minPolarAngle,Math.min(U.maxPolarAngle,H.phi)),H.makeSafe(),H.radius*=W,H.radius=Math.max(U.minDistance,Math.min(U.maxDistance,H.radius)),U.target.add(X),e.setFromSpherical(H),e.applyQuaternion(s),t.copy(U.target).add(e),U.object.lookAt(U.target),!0===U.enableDamping?(j.theta*=1-U.dampingFactor,j.phi*=1-U.dampingFactor):j.set(0,0,0),W=1,X.set(0,0,0),!!(Y||c.distanceToSquared(U.object.position)>V||8*(1-l.dot(U.object.quaternion))>V)&&(U.dispatchEvent(z),c.copy(U.object.position),l.copy(U.object.quaternion),Y=!1,!0)}}(),this.dispose=function(){U.domElement.removeEventListener("contextmenu",D,!1),U.domElement.removeEventListener("mousedown",A,!1),U.domElement.removeEventListener("wheel",R,!1),U.domElement.removeEventListener("touchstart",I,!1),U.domElement.removeEventListener("touchend",N,!1),U.domElement.removeEventListener("touchmove",O,!1),document.removeEventListener("mousemove",L,!1),document.removeEventListener("mouseup",C,!1),window.removeEventListener("keydown",P,!1)};var U=this,z={type:"change"},B={type:"start"},F={type:"end"},k={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY:4,TOUCH_PAN:5},G=k.NONE,V=1e-6,H=new ii,j=new ii,W=1,X=new n,Y=!1,q=new h,Z=new h,J=new h,Q=new h,K=new h,$=new h,tt=new h,et=new h,rt=new h,nt=function(){var t=new n;return function(e,r){t.setFromMatrixColumn(r,0),t.multiplyScalar(-e),X.add(t)}}(),it=function(){var t=new n;return function(e,r){t.setFromMatrixColumn(r,1),t.multiplyScalar(e),X.add(t)}}(),at=function(){var t=new n;return function(e,r){var n=U.domElement===document?U.domElement.body:U.domElement;if(U.object instanceof xt){var i=U.object.position;t.copy(i).sub(U.target);var a=t.length();a*=Math.tan(U.object.fov/2*Math.PI/180),nt(2*e*a/n.clientHeight,U.object.matrix),it(2*r*a/n.clientHeight,U.object.matrix)}else U.object instanceof yt?(nt(e*(U.object.right-U.object.left)/U.object.zoom/n.clientWidth,U.object.matrix),it(r*(U.object.top-U.object.bottom)/U.object.zoom/n.clientHeight,U.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),U.enablePan=!1)}}();U.domElement.addEventListener("contextmenu",D,!1),U.domElement.addEventListener("mousedown",A,!1),U.domElement.addEventListener("wheel",R,!1),U.domElement.addEventListener("touchstart",I,!1),U.domElement.addEventListener("touchend",N,!1),U.domElement.addEventListener("touchmove",O,!1),window.addEventListener("keydown",P,!1),this.update()}function Ba(t,e){function r(t,e){Object.defineProperty(ed,e,{writeable:!0,get:function(){return qa(t)},set:function(r){Ya(t,r),this.dispatchEvent({type:"change",name:e})}})}function n(t,e){r(t,e),e="has"+e.substr(0,1).toUpperCase()+e.substr(1),Object.defineProperty(ed,e,{get:function(){return Pu.hasFeature(t)}})}function a(t,e,r){t(isNaN(r)?r:Number(r)),ed.dispatchEvent({type:"change",name:e})}function o(t){switch(Wu=t?us:hs){case hs:Xu=Pu.pointTargets;break;case us:Xu=Pu.legTargets;break;default:console.warn("invalid mouse mode")}}console.log("CaveView v"+$o),(Eu=document.getElementById(t))||alert("No container DOM object ["+t+"] available"),i(e);var s=Eu.clientWidth,c=Eu.clientHeight;(Su=new ye({antialias:!0})).setSize(s,c),Su.setPixelRatio(window.devicePixelRatio),Su.setClearColor(0),Su.autoClear=!1,(Tu=new yt(-s/2,s/2,c/2,-c/2,1,4e3)).rotateOnAxis(zs,Math.PI/2),Xa(Tu),Xa(Au=new xt(75,s/c,1,16e3)),Lu=Au,Hu.add(Au),Hu.add(Tu),(Ru=new Wr(16777215)).position.copy(ku),Hu.add(Ru),Hu.add(new Fr(16777215,65535,.3)),Cu=new ti,Su.clear(),Eu.appendChild(Su.domElement),Bu=new za(Lu,Su.domElement),Fu=new na(Bu,rd,mo),Bu.addEventListener("change",function(){Fu.prepare(null,null),Fu.start(80)}),Bu.enableDamping=!0,window.addEventListener("resize",io),Object.defineProperties(ed,{container:{value:Eu},terrain:{writeable:!0,get:function(){return qa(Cs)},set:function(t){co(t)}},terrainShading:{writeable:!0,get:function(){return Uu},set:function(t){a(Ja,"terrainShading",t)}},hasTerrain:{get:function(){return!!Yu}},terrainDatumShift:{writeable:!0,get:function(){return!!Yu.activeDatumShift},set:function(t){Ha(t)}},terrainOverlays:{get:function(){return Yu.isTiled?Object.keys(Ju):Yu.hasOverlay?[!0]:[]}},terrainOverlay:{writeable:!0,get:function(){return Qu},set:function(t){a($a,"terrainOverlay",t)}},terrainOpacity:{writeable:!0,get:function(){return Yu.getOpacity()},set:function(t){Va(t)}},shadingMode:{writeable:!0,get:function(){return Du},set:function(t){a(Qa,"shadingMode",t)}},surfaceShading:{writeable:!0,get:function(){return Zu},set:function(t){a(Ka,"surfaceShading",t)}},cameraType:{writeable:!0,get:function(){return zu},set:function(t){a(Wa,"cameraType",t)}},view:{writeable:!0,get:function(){return is},set:function(t){a(Za,"view",t)}},cursorHeight:{writeable:!0,get:function(){return Nu},set:function(t){Ga(t)}},initCursorHeight:{writeable:!0,get:function(){return Nu},set:function(t){Nu=t}},maxHeight:{get:function(){return Iu.max.z}},minHeight:{get:function(){return Iu.min.z}},maxLegLength:{get:function(){return qu.maxLegLength}},minLegLength:{get:function(){return qu.minLegLength}},section:{writeable:!0,get:function(){return Ku},set:function(t){a(no,"section",t)}},highlight:{writeable:!0,set:function(t){a(ro,"highlight",t)}},routeEdit:{writeable:!0,get:function(){return Wu===us},set:function(t){o(t),this.dispatchEvent({type:"change",name:"routeEdit"})}},setPOI:{writeable:!0,get:function(){return!0},set:function(t){a(vo,"setPOI",t)}},developerInfo:{writeable:!0,get:function(){return!0},set:function(t){}},HUD:{writeable:!0,get:function(){return Qh.getVisibility()},set:function(t){Qh.setVisibility(t)}},cut:{writeable:!0,get:function(){return!0},set:function(){eo()}},zScale:{writeable:!0,get:function(){return Ou},set:function(t){Fa(t)}},autoRotate:{writeable:!0,get:function(){return Bu.autoRotate},set:function(t){ka(!!t)}},autoRotateSpeed:{writeable:!0,get:function(){return Bu.autoRotateSpeed/11},set:function(t){Bu.autoRotateSpeed=11*t}}}),r(Ts,"box"),n(Ls,"entrances"),n(Rs,"stations"),n(Ps,"traces"),n(Os,"scraps"),n(Is,"walls"),n(Es,"splays"),n(Ss,"surfaceLegs"),n(Ns,"stationLabels"),Dh.initCache(ed),Qh.init(t,Su)}function Fa(t){var r=Math.pow(2,4*(Ou-.5)),n=Math.pow(2,4*(t-.5));Pu.applyMatrix((new e).makeScale(1,1,n/r)),Ou=t,rd()}function ka(t){Bu.autoRotate=t,t?(Fu.prepare(null,null),Fu.start(2952e3)):Fu.stop()}function Ga(t){Nu=t,ed.dispatchEvent({type:"cursorChange",name:"cursorHeight"}),rd()}function Va(t){Yu.setOpacity(t),ed.dispatchEvent({type:"change",name:"terrainOpacity"}),rd()}function Ha(t){Yu.applyDatumShift(t),ed.dispatchEvent({type:"change",name:"terrainDatumShift"}),rd()}function ja(){if(null!==Yu&&Yu.isLoaded()){var t=Eu.clientWidth,e=Eu.clientHeight,r=Iu.getSize(),n=t/r.x,i=e/r.y;n0}function Za(t,e){var r=new n,i=e||240;switch(t){case as:r.set(0,0,ns);break;case os:r.set(0,ns,0);break;case ss:r.set(0,-ns,0);break;case cs:r.set(ns,0,0);break;case ls:r.set(-ns,0,0);break;default:return void console.warn("invalid view mode specified: ",t)}r.add($u),Fu.cancel(),Fu.prepare(r,$u),Fu.start(i)}function Ja(t){Yu.setShadingMode(t,rd)&&(Uu=t),rd()}function Qa(t){(null!==Yu||t!==bs&&t!==_s)&&(Pu.setShadingMode(t)&&(Du=t),rd())}function Ka(t){Pu.setLegShading(Ss,t)&&(Zu=t),rd()}function $a(t){Uu===ys&&(Qu=t,Yu.setOverlay(Ju[t],rd))}function to(t,e){Ju[t]=new Ua(e,Eu),1===Object.keys(Ju).length&&(Qu=t)}function eo(){if(0!==Ku){Pu.remove(Yu),Pu.cutSection(Ku);var t=Pu;ao(),so(t)}}function ro(t){Pu.highlightSelection(t),rd()}function no(t){var e=Pu.selectSection(t);if(Qa(Du),Ku=t,0!==t){if(void 0===e.p){if(void 0===e.boundingBox)return;var r=e.boundingBox.clone();Fu.prepare(null,r.applyMatrix4(Pu.matrixWorld))}else Fu.prepare(null,Pu.getWorldPosition(e.p));rd()}}function io(){var t=Eu.clientWidth,e=Eu.clientHeight;Su.setSize(t,e),void 0!==Tu&&(Tu.left=-t/2,Tu.right=t/2,Tu.top=e/2,Tu.bottom=-e/2,Tu.updateProjectionMatrix(),Au.aspect=t/e,Au.updateProjectionMatrix(),rd())}function ao(){Vu=!1,Su.clear(),Qh.setVisibility(!1),Pu&&(Pu.remove(Yu),Hu.remove(Pu)),Bu.enabled=!1,Pu=null,Yu=null,Ku=0,Wu=hs,Xu=[],Du=ds,Zu=gs,Uu=xs,ho(),Dh.flushCache(),Eu.removeEventListener("mousedown",fo),Xa(Au),Xa(Tu),ed.cameraType=rs,Za(as,1),rd()}function oo(t){if(!t)return void alert("failed loading cave information");so(new Ra(t))}function so(t){function e(){Yu.hasCoverage()?(Ja(Uu),Yu.tileArea(Pu.limits),Yu.setDefaultOverlay(Ju[Qu]),Pu.add(Yu)):Yu=null,ed.dispatchEvent({type:"newCave",name:"newCave"})}function r(){rd(),lo(),null===Yu.depthTexture&&ja()}function n(){Qa(Du),rd()}var i=!1;qu=(Pu=t).getFeature(Ms).stats,yo(Pu),Yu=Pu.terrain,Hu.up=zs,Hu.add(Pu),Vu=!0,no(0),Xu=Pu.pointTargets,Ka(Zu),null===Yu?(Yu=new Da(Pu,e,r,rd),i=!0):(Pu.add(Yu),Ja(Uu),ja()),Hu.matrixAutoUpdate=!1,Eu.addEventListener("mousedown",fo,!1),Qh.setVisibility(!0),i||ed.dispatchEvent({type:"newCave",name:"newCave"}),Bu.object=Lu,Bu.enabled=!0,Pu.getRoutes().addEventListener("changed",n),Za(as,1),rd()}function co(t){Yu.isLoaded()&&(t?lo():ho(),Yu.setVisibility(t),Ya(Cs,t),ed.dispatchEvent({type:"change",name:"terrain"}))}function lo(){uo(),Bu.addEventListener("end",uo)}function ho(){Bu&&(Bu.removeEventListener("end",uo),po())}function uo(){td=performance.now()}function po(){td=0}function fo(t){function e(){Qa(Du),rd()}var r,i;ju.x=t.clientX/Eu.clientWidth*2-1,ju.y=-t.clientY/Eu.clientHeight*2+1,Cu.setFromCamera(ju,Lu);for(var a=Cu.intersectObjects(Xu,!1),o=0,s=a.length;oGu&&(po(),Yu.zoomCheck(Lu)&&setTimeout(go,5*Gu))}function vo(){Fu.start(200)}function yo(t){var e=Eu.clientWidth,r=Eu.clientHeight,i=Pu.scaleFactor;Iu=Pu.limits,Ou=.5;var a=Iu.getSize();Nu=0;var o=Math.min(e/a.x,r/a.y),s=o*i,c=new n(o,o,s);t.scale.copy(c),t.position.copy(Pu.modelLimits.getCenter().multiply(c).negate()),Qh.setScale(s),t.setScale(s)}function xo(){return qu}function bo(){return Bu}function wo(){return Pu.getMetadataURL()}function _o(){return Pu.getRoutes()}function Mo(){return Pu.surveyTree}function Eo(t,e){function r(t){t.target.parentElement.classList.remove("onscreen")}var n=document.createElement("div"),i=document.createElement("div"),a=Eo.frame;if(i.classList.add("page"),n.id=t,n.classList.add("tab"),n.style.top=40*Eo.position+++"px",n.addEventListener("click",this.tabHandleClick),void 0!==e&&n.addEventListener("click",e),null===a){(a=document.createElement("div")).id="frame",a.style.display="block",Eo.frame=a;var o=document.createElement("div");o.id="close",o.addEventListener("click",r),a.appendChild(o)}a.appendChild(n),a.appendChild(i),Eo.pages.push({tab:n,page:i}),this.page=i,this.slide=void 0}function So(t){var e=(t.clientWidth-300)/2,r=document.createElement("div");r.id="status-text",r.style.width="300px",r.style.left=e+"px";var n=document.createElement("progress");n.id="progress-bar",n.style.width="300px",n.style.left=e+"px",n.setAttribute("max","100"),this.container=t,this.progressBar=n,this.statusText=r}function To(t){this.fileName=t,this.groups=[],this.surface=[],this.xGroups=[],this.surveyTree=new ia,this.sourceCRS=null,this.targetCRS="EPSG:3857",this.projection=null}function Ao(t){this.fileName=t,this.scraps=[],this.faults=[],this.lineSegments=[],this.xGroups=[],this.surveyTree=new ia("",0),this.terrain={},this.hasTerrain=!1}function Lo(t){this.fileName=t,this.groups=[],this.surface=[],this.xGroups=[],this.surveyTree=new ia,this.sourceCRS=null,this.targetCRS="EPSG:3857",this.projection=null}function Co(t){this.filename=t,this.box=new st}function Ro(t,e){t||alert("No callback specified"),this.callback=t,this.progress=e,this.dataResponse=null,this.metadataResponse=null,this.taskCount=0}function Po(t,e){if(!(sd=document.getElementById(t)))return void alert("No container DOM object ["+t+"] available");ld=new So(sd),ed.init(t,e),id=new Ro(Zo,qo),document.addEventListener("keydown",Qo),sd.addEventListener("drop",Vo),sd.addEventListener("dragover",Go),Object.defineProperty(pd,"file",{get:function(){return cd},set:function(t){Xo(t),cd=t}}),ed.addEventListener("change",Eo.handleChange),ed.addEventListener("change",Oo),ed.addEventListener("newCave",Jo)}function Io(t,e){for(var r,n=e?"block":"none",i=0,a=t.length;i2?(n.style.color="yellow",n.textContent="◼ "):0===t.hitCount?(n.style.color="red",n.textContent="◻ "):(n.style.color="red",n.textContent="◼ ");if(e.appendChild(n),e.appendChild(r),t.children.length>0){var a=document.createElement("div");a.classList.add("descend-tree"),a.id="ssv"+t.id,a.textContent="►",e.appendChild(a)}o.appendChild(e)}}function a(t,e){return u(t.name,e.name)}for(var o,l,h,d=hu.getSurveyColourMap(ad,ed.section);l=c.firstChild;)c.removeChild(l);null===t.parent?c.textContent=""===t.name?"[model]":t.name:((h=document.createElement("span")).textContent=" ◄",s.addListener(h,"click",i),c.appendChild(h),c.appendChild(document.createTextNode(" "+t.name))),o=document.createElement("ul");var p=t.children;return p.sorted||(p.sort(a),p.sorted=!0),t.forEachChild(e),od=t,s.addListener(o,"mouseover",n),s.addListener(o,"mouseleave",r),o}function r(t){t.stopPropagation(),ed.highlight=0}function n(t){t.stopPropagation();var e=t.target;if("LI"===e.nodeName){var r=Number(e.id.split("v")[1]);return r!==h&&(ed.highlight=ed.section!==r?r:0,h=r),!1}}function i(t){t.stopPropagation(),null!==od.parent&&s.replaceSlide(e(od.parent),--l,o)}function a(){ed.section=od.id}function o(t){var r=t.target,n=Number(r.id.split("v")[1]);switch(t.stopPropagation(),r.nodeName){case"LI":ed.section=ed.section!==n?n:0,ed.setPOI=!0;break;case"DIV":n&&s.replaceSlide(e(od.findById(n)),++l,o)}}var s,c=document.createElement("div"),l=0,h=0,u=new Intl.Collator("en-GB",{numeric:!0}).compare;if(od=ad,fd){(s=new Eo("icon_explore")).addHeader("Selection"),c.id="ui-path",s.addListener(c,"click",a),s.appendChild(c),s.addSlide(e(od),l,o);sd.clientHeight;s.addListener(ed,"change",t)}}function Do(){function t(){hd.addRoute(i()),n=a.addSelect("Current Route",hd.getRouteNames(),hd,"setRoute",n)}function e(){hd.saveCurrent()}function r(){ed.shadingMode=ws,!hd.setRoute&&s.length>0&&(hd.setRoute=s[0])}var n,i,a=new Eo("icon_route",r),s=hd.getRouteNames();a.addHeader("Routes"),a.addCheckbox("Edit Routes",ed,"routeEdit"),n=a.addSelect("Current Route",s,hd,"setRoute"),gd.push(a.addButton("Save",e)),gd.push(a.addTextBox("New Route","---",function(t){i=t})),gd.push(a.addButton("Add",t)),gd.push(a.addDownloadButton("Download",ed.getMetadata,o(cd,"json"))),Io(gd,!1),a.addListener(hd,"changed",Eo.handleChange)}function Uo(){function t(t,r){var n=document.createElement("dt"),i=document.createElement("dd");n.textContent=t,i.textContent=r,e.appendChild(n),e.appendChild(i)}var e,r=new Eo("icon_help");r.addHeader("Help - key commands"),r.addHeader("Shading"),e=document.createElement("dl"),t("1","height"),t("2","leg angle"),t("3","leg length"),t("4","height cursor "),t("5","single colour"),t("6","survey section"),t("7","route"),t("8","depth from surface"),t("9","depth cursor"),t("[","move depth cursor up"),t("]","move depth cursor down"),dd.length>0&&t("n","next cave"),r.appendChild(e),r.addHeader("View"),e=document.createElement("dl"),t("O","orthogonal view"),t("P","perspective view"),t("R","reset to plan view"),t(".","center view on last feature selected"),r.appendChild(e),r.addHeader("Visibility"),e=document.createElement("dl"),t("C","scraps on/off [lox only]"),t("J","station labels on/off"),t("L","labels on/off"),t("Q","splay legs on/off"),t("S","surface legs on/off"),t("T","terrain on/off"),t("W","LRUD walls on/off"),t("Z","stations on/off"),t("","-"),t("<","Decrease terrain opacity"),t(">","Increase terrain opacity"),r.appendChild(e),r.addHeader("Selection"),e=document.createElement("dl"),t("V","Remove all except selected section"),r.appendChild(e)}function zo(){var t=new Eo("icon_info");t.addHeader("Information"),t.addText("CaveView v"+$o+" - a work in progress 3d cave viewer for Survex (.3d) and Therion (.lox) models."),t.addText("Requires a browser supporting WebGL (IE 11+ and most other recent browsers), no plugins required. Created using the THREE.js 3D library and chroma,js colour handling library.")}function Bo(){var t=Object.assign({},yd);ed.hasTerrain&&(t.depth=bs,t["depth cursor"]=_s);var e=new Eo("icon_settings");e.addHeader("Survey"),dd.length>0&&e.addSelect("File",dd,pd,"file"),e.addHeader("View"),e.addSelect("Camera Type",_d,ed,"cameraType"),e.addSelect("View",wd,ed,"view"),e.addRange("Vertical scaling",ed,"zScale"),e.addCheckbox("Auto Rotate",ed,"autoRotate"),e.addRange("Rotation Speed",ed,"autoRotateSpeed"),e.addHeader("Shading"),e.addSelect("Underground Legs",t,ed,"shadingMode"),e.addHeader("Visibility"),ed.hasEntrances&&e.addCheckbox("Entrances",ed,"entrances"),ed.hasStations&&e.addCheckbox("Stations",ed,"stations"),ed.hasStationLabels&&e.addCheckbox("Station Labels",ed,"stationLabels"),ed.hasSplays&&e.addCheckbox("Splay Legs",ed,"splays"),ed.hasWalls&&e.addCheckbox("Walls (LRUD)",ed,"walls"),ed.hasScraps&&e.addCheckbox("Scraps",ed,"scraps"),ed.hasTraces&&e.addCheckbox("Dye Traces",ed,"traces"),e.addCheckbox("Indicators",ed,"HUD"),e.addCheckbox("Bounding Box",ed,"box")}function Fo(){vd=null,md=[];var t=new Eo("icon_terrain");if(t.addHeader("Surface Features"),ed.hasSurfaceLegs&&(t.addCheckbox("Surface Legs",ed,"surfaceLegs"),t.addSelect("Leg Shading",xd,ed,"surfaceShading")),ed.hasTerrain){t.addHeader("Terrain"),t.addCheckbox("Terrain",ed,"terrain");var e=ed.terrainOverlays,r=Object.assign({},bd);e.length>0&&(r["map overlay"]=ys),md.push(t.addSelect("Shading",r,ed,"terrainShading")),e.length>1&&(vd=t.addSelect("Overlay",e,ed,"terrainOverlay"),md.push(vd)),md.push(t.addRange("Terrain opacity",ed,"terrainOpacity")),md.push(t.addCheckbox("Vertical datum shift",ed,"terrainDatumShift")),Io(md,!1)}}function ko(){Eo.reset(),Bo(),Fo(),No(),Do(),zo(),Uo(),sd.appendChild(Eo.frame)}function Go(t){t.preventDefault(),t.dataTransfer.dropEffect="copy"}function Vo(t){var e=t.dataTransfer;t.preventDefault(),1===e.files.length&&Yo(e.files[0])}function Ho(){fd&&(fd=!1,Eo.clear(),ad=null)}function jo(t){dd=t,Wo()}function Wo(){if(0===dd.length)return!1;++ud>=dd.length&&(ud=0),pd.file=dd[ud]}function Xo(t){cd=t,Ho(),ed.clearView(),ld.Start("Loading file "+cd+" ..."),id.loadURL(cd)}function Yo(t){Ho(),ed.clearView(),ld.Start("Loading file "+t.name+" ..."),id.loadFile(t)}function qo(t){ld.Update(t)}function Zo(t){function e(){ld.End(),ld.Start("Rendering..."),setTimeout(r,100)}function r(){ed.loadCave(nd),ld.End()}nd=t,setTimeout(e,100)}function Jo(){ed.shadingMode=ds,ad=ed.getSurveyTree(),hd=ed.getRoutes(),fd=!0,nd=null,ko()}function Qo(t){if(fd)switch(t.keyCode){case 49:ed.shadingMode=ds;break;case 50:ed.shadingMode=fs;break;case 51:ed.shadingMode=ps;break;case 52:ed.shadingMode=ms;break;case 53:ed.shadingMode=gs;break;case 54:ed.shadingMode=vs;break;case 55:ed.shadingMode=ws;break;case 56:ed.shadingMode=bs;break;case 57:ed.shadingMode=_s;break;case 67:ed.hasScraps&&(ed.scraps=!ed.scraps);break;case 68:ed.hasTraces&&(ed.traces=!ed.traces);break;case 73:ed.developerInfo=!0;break;case 74:ed.hasStationLabels&&(ed.stationLabels=!ed.stationLabels);break;case 76:ed.hasEntrances&&(ed.entrances=!ed.entrances);break;case 78:Wo();break;case 79:ed.cameraType=es;break;case 80:ed.cameraType=rs;break;case 81:ed.hasSplays&&(ed.splays=!ed.splays);break;case 82:ed.view=as;break;case 83:ed.hasSurfaceLegs&&(ed.surfaceLegs=!ed.surfaceLegs);break;case 84:ed.hasTerrain&&(ed.terrain=!ed.terrain);break;case 86:Ho(),ed.cut=!0;break;case 87:ed.hasWalls&&(ed.walls=!ed.walls);break;case 88:ed.setPOI=!0;break;case 90:ed.stations=!ed.stations;break;case 107:case 219:ed.cursorHeight++;break;case 109:case 221:ed.cursorHeight--;break;case 188:ed.hasTerrain&&(ed.terrainOpacity=Math.max(ed.terrainOpacity-.05,0));break;case 190:ed.hasTerrain&&(ed.terrainOpacity=Math.min(ed.terrainOpacity+.05,1))}}void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52)),void 0===Number.isInteger&&(Number.isInteger=function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t}),void 0===Math.sign&&(Math.sign=function(t){return t<0?-1:t>0?1:+t}),void 0===Function.prototype.name&&Object.defineProperty(Function.prototype,"name",{get:function(){return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]}}),void 0===Object.assign&&function(){Object.assign=function(t){if(void 0===t||null===t)throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(t),r=1;r>=4,r[i]=e[19===i?3&t|8:t]);return r.join("")}}(),clamp:function(t,e,r){return Math.max(e,Math.min(r,t))},euclideanModulo:function(t,e){return(t%e+e)%e},mapLinear:function(t,e,r,n,i){return n+(t-e)*(i-n)/(r-e)},lerp:function(t,e,r){return(1-r)*t+r*e},smoothstep:function(t,e,r){return t<=e?0:t>=r?1:(t=(t-e)/(r-e))*t*(3-2*t)},smootherstep:function(t,e,r){return t<=e?0:t>=r?1:(t=(t-e)/(r-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},degToRad:function(t){return t*Ko.DEG2RAD},radToDeg:function(t){return t*Ko.RAD2DEG},isPowerOfTwo:function(t){return 0==(t&t-1)&&0!==t},nearestPowerOfTwo:function(t){return Math.pow(2,Math.round(Math.log(t)/Math.LN2))},nextPowerOfTwo:function(t){return t--,t|=t>>1,t|=t>>2,t|=t>>4,t|=t>>8,t|=t>>16,++t}};Object.assign(e.prototype,{isMatrix4:!0,set:function(t,e,r,n,i,a,o,s,c,l,h,u,d,p,f,m){var g=this.elements;return g[0]=t,g[4]=e,g[8]=r,g[12]=n,g[1]=i,g[5]=a,g[9]=o,g[13]=s,g[2]=c,g[6]=l,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=f,g[15]=m,this},identity:function(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this},clone:function(){return(new e).fromArray(this.elements)},copy:function(t){var e=this.elements,r=t.elements;return e[0]=r[0],e[1]=r[1],e[2]=r[2],e[3]=r[3],e[4]=r[4],e[5]=r[5],e[6]=r[6],e[7]=r[7],e[8]=r[8],e[9]=r[9],e[10]=r[10],e[11]=r[11],e[12]=r[12],e[13]=r[13],e[14]=r[14],e[15]=r[15],this},copyPosition:function(t){var e=this.elements,r=t.elements;return e[12]=r[12],e[13]=r[13],e[14]=r[14],this},extractBasis:function(t,e,r){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),r.setFromMatrixColumn(this,2),this},makeBasis:function(t,e,r){return this.set(t.x,e.x,r.x,0,t.y,e.y,r.y,0,t.z,e.z,r.z,0,0,0,0,1),this},extractRotation:function(){var t=new n;return function(e){var r=this.elements,n=e.elements,i=1/t.setFromMatrixColumn(e,0).length(),a=1/t.setFromMatrixColumn(e,1).length(),o=1/t.setFromMatrixColumn(e,2).length();return r[0]=n[0]*i,r[1]=n[1]*i,r[2]=n[2]*i,r[4]=n[4]*a,r[5]=n[5]*a,r[6]=n[6]*a,r[8]=n[8]*o,r[9]=n[9]*o,r[10]=n[10]*o,this}}(),makeRotationFromEuler:function(t){t&&t.isEuler||console.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var e=this.elements,r=t.x,n=t.y,i=t.z,a=Math.cos(r),o=Math.sin(r),s=Math.cos(n),c=Math.sin(n),l=Math.cos(i),h=Math.sin(i);if("XYZ"===t.order){var u=a*l,d=a*h,p=o*l,f=o*h;e[0]=s*l,e[4]=-s*h,e[8]=c,e[1]=d+p*c,e[5]=u-f*c,e[9]=-o*s,e[2]=f-u*c,e[6]=p+d*c,e[10]=a*s}else if("YXZ"===t.order){var m=s*l,g=s*h,v=c*l,y=c*h;e[0]=m+y*o,e[4]=v*o-g,e[8]=a*c,e[1]=a*h,e[5]=a*l,e[9]=-o,e[2]=g*o-v,e[6]=y+m*o,e[10]=a*s}else if("ZXY"===t.order){var m=s*l,g=s*h,v=c*l,y=c*h;e[0]=m-y*o,e[4]=-a*h,e[8]=v+g*o,e[1]=g+v*o,e[5]=a*l,e[9]=y-m*o,e[2]=-a*c,e[6]=o,e[10]=a*s}else if("ZYX"===t.order){var u=a*l,d=a*h,p=o*l,f=o*h;e[0]=s*l,e[4]=p*c-d,e[8]=u*c+f,e[1]=s*h,e[5]=f*c+u,e[9]=d*c-p,e[2]=-c,e[6]=o*s,e[10]=a*s}else if("YZX"===t.order){var x=a*s,b=a*c,w=o*s,_=o*c;e[0]=s*l,e[4]=_-x*h,e[8]=w*h+b,e[1]=h,e[5]=a*l,e[9]=-o*l,e[2]=-c*l,e[6]=b*h+w,e[10]=x-_*h}else if("XZY"===t.order){var x=a*s,b=a*c,w=o*s,_=o*c;e[0]=s*l,e[4]=-h,e[8]=c*l,e[1]=x*h+_,e[5]=a*l,e[9]=b*h-w,e[2]=w*h-b,e[6]=o*l,e[10]=_*h+x}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this},makeRotationFromQuaternion:function(t){var e=this.elements,r=t._x,n=t._y,i=t._z,a=t._w,o=r+r,s=n+n,c=i+i,l=r*o,h=r*s,u=r*c,d=n*s,p=n*c,f=i*c,m=a*o,g=a*s,v=a*c;return e[0]=1-(d+f),e[4]=h-v,e[8]=u+g,e[1]=h+v,e[5]=1-(l+f),e[9]=p-m,e[2]=u-g,e[6]=p+m,e[10]=1-(l+d),e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this},lookAt:function(){var t=new n,e=new n,r=new n;return function(n,i,a){var o=this.elements;return r.subVectors(n,i),0===r.lengthSq()&&(r.z=1),r.normalize(),t.crossVectors(a,r),0===t.lengthSq()&&(1===Math.abs(a.z)?r.x+=1e-4:r.z+=1e-4,r.normalize(),t.crossVectors(a,r)),t.normalize(),e.crossVectors(r,t),o[0]=t.x,o[4]=e.x,o[8]=r.x,o[1]=t.y,o[5]=e.y,o[9]=r.y,o[2]=t.z,o[6]=e.z,o[10]=r.z,this}}(),multiply:function(t,e){return void 0!==e?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(t,e)):this.multiplyMatrices(this,t)},premultiply:function(t){return this.multiplyMatrices(t,this)},multiplyMatrices:function(t,e){var r=t.elements,n=e.elements,i=this.elements,a=r[0],o=r[4],s=r[8],c=r[12],l=r[1],h=r[5],u=r[9],d=r[13],p=r[2],f=r[6],m=r[10],g=r[14],v=r[3],y=r[7],x=r[11],b=r[15],w=n[0],_=n[4],M=n[8],E=n[12],S=n[1],T=n[5],A=n[9],L=n[13],C=n[2],R=n[6],P=n[10],I=n[14],O=n[3],N=n[7],D=n[11],U=n[15];return i[0]=a*w+o*S+s*C+c*O,i[4]=a*_+o*T+s*R+c*N,i[8]=a*M+o*A+s*P+c*D,i[12]=a*E+o*L+s*I+c*U,i[1]=l*w+h*S+u*C+d*O,i[5]=l*_+h*T+u*R+d*N,i[9]=l*M+h*A+u*P+d*D,i[13]=l*E+h*L+u*I+d*U,i[2]=p*w+f*S+m*C+g*O,i[6]=p*_+f*T+m*R+g*N,i[10]=p*M+f*A+m*P+g*D,i[14]=p*E+f*L+m*I+g*U,i[3]=v*w+y*S+x*C+b*O,i[7]=v*_+y*T+x*R+b*N,i[11]=v*M+y*A+x*P+b*D,i[15]=v*E+y*L+x*I+b*U,this},multiplyScalar:function(t){var e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this},applyToBufferAttribute:function(){var t=new n;return function(e){for(var r=0,n=e.count;r=0?1:-1,y=1-g*g;if(y>Number.EPSILON){var x=Math.sqrt(y),b=Math.atan2(x,g*v);m=Math.sin(m*b)/x,o=Math.sin(o*b)/x}var w=o*v;if(s=s*m+u*w,c=c*m+d*w,l=l*m+p*w,h=h*m+f*w,m===1-o){var _=1/Math.sqrt(s*s+c*c+l*l+h*h);s*=_,c*=_,l*=_,h*=_}}t[e]=s,t[e+1]=c,t[e+2]=l,t[e+3]=h}}),Object.defineProperties(r.prototype,{x:{get:function(){return this._x},set:function(t){this._x=t,this.onChangeCallback()}},y:{get:function(){return this._y},set:function(t){this._y=t,this.onChangeCallback()}},z:{get:function(){return this._z},set:function(t){this._z=t,this.onChangeCallback()}},w:{get:function(){return this._w},set:function(t){this._w=t,this.onChangeCallback()}}}),Object.assign(r.prototype,{set:function(t,e,r,n){return this._x=t,this._y=e,this._z=r,this._w=n,this.onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this.onChangeCallback(),this},setFromEuler:function(t,e){if(!t||!t.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var r=t._x,n=t._y,i=t._z,a=t.order,o=Math.cos,s=Math.sin,c=o(r/2),l=o(n/2),h=o(i/2),u=s(r/2),d=s(n/2),p=s(i/2);return"XYZ"===a?(this._x=u*l*h+c*d*p,this._y=c*d*h-u*l*p,this._z=c*l*p+u*d*h,this._w=c*l*h-u*d*p):"YXZ"===a?(this._x=u*l*h+c*d*p,this._y=c*d*h-u*l*p,this._z=c*l*p-u*d*h,this._w=c*l*h+u*d*p):"ZXY"===a?(this._x=u*l*h-c*d*p,this._y=c*d*h+u*l*p,this._z=c*l*p+u*d*h,this._w=c*l*h-u*d*p):"ZYX"===a?(this._x=u*l*h-c*d*p,this._y=c*d*h+u*l*p,this._z=c*l*p-u*d*h,this._w=c*l*h+u*d*p):"YZX"===a?(this._x=u*l*h+c*d*p,this._y=c*d*h+u*l*p,this._z=c*l*p-u*d*h,this._w=c*l*h-u*d*p):"XZY"===a&&(this._x=u*l*h-c*d*p,this._y=c*d*h-u*l*p,this._z=c*l*p+u*d*h,this._w=c*l*h+u*d*p),!1!==e&&this.onChangeCallback(),this},setFromAxisAngle:function(t,e){var r=e/2,n=Math.sin(r);return this._x=t.x*n,this._y=t.y*n,this._z=t.z*n,this._w=Math.cos(r),this.onChangeCallback(),this},setFromRotationMatrix:function(t){var e,r=t.elements,n=r[0],i=r[4],a=r[8],o=r[1],s=r[5],c=r[9],l=r[2],h=r[6],u=r[10],d=n+s+u;return d>0?(e=.5/Math.sqrt(d+1),this._w=.25/e,this._x=(h-c)*e,this._y=(a-l)*e,this._z=(o-i)*e):n>s&&n>u?(e=2*Math.sqrt(1+n-s-u),this._w=(h-c)/e,this._x=.25*e,this._y=(i+o)/e,this._z=(a+l)/e):s>u?(e=2*Math.sqrt(1+s-n-u),this._w=(a-l)/e,this._x=(i+o)/e,this._y=.25*e,this._z=(c+h)/e):(e=2*Math.sqrt(1+u-n-s),this._w=(o-i)/e,this._x=(a+l)/e,this._y=(c+h)/e,this._z=.25*e),this.onChangeCallback(),this},setFromUnitVectors:function(){var t,e=new n;return function(r,i){return void 0===e&&(e=new n),t=r.dot(i)+1,t<1e-6?(t=0,Math.abs(r.x)>Math.abs(r.z)?e.set(-r.y,r.x,0):e.set(0,-r.z,r.y)):e.crossVectors(r,i),this._x=e.x,this._y=e.y,this._z=e.z,this._w=t,this.normalize()}}(),inverse:function(){return this.conjugate().normalize()},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this.onChangeCallback(),this},dot:function(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._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 t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this.onChangeCallback(),this},multiply:function(t,e){return void 0!==e?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(t,e)):this.multiplyQuaternions(this,t)},premultiply:function(t){return this.multiplyQuaternions(t,this)},multiplyQuaternions:function(t,e){var r=t._x,n=t._y,i=t._z,a=t._w,o=e._x,s=e._y,c=e._z,l=e._w;return this._x=r*l+a*o+n*c-i*s,this._y=n*l+a*s+i*o-r*c,this._z=i*l+a*c+r*s-n*o,this._w=a*l-r*o-n*s-i*c,this.onChangeCallback(),this},slerp:function(t,e){if(0===e)return this;if(1===e)return this.copy(t);var r=this._x,n=this._y,i=this._z,a=this._w,o=a*t._w+r*t._x+n*t._y+i*t._z;if(o<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,o=-o):this.copy(t),o>=1)return this._w=a,this._x=r,this._y=n,this._z=i,this;var s=Math.sqrt(1-o*o);if(Math.abs(s)<.001)return this._w=.5*(a+this._w),this._x=.5*(r+this._x),this._y=.5*(n+this._y),this._z=.5*(i+this._z),this;var c=Math.atan2(s,o),l=Math.sin((1-e)*c)/s,h=Math.sin(e*c)/s;return this._w=a*l+this._w*h,this._x=r*l+this._x*h,this._y=n*l+this._y*h,this._z=i*l+this._z*h,this.onChangeCallback(),this},equals:function(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w},fromArray:function(t,e){return void 0===e&&(e=0),this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this.onChangeCallback(),this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t},onChange:function(t){return this.onChangeCallback=t,this},onChangeCallback:function(){}}),Object.assign(n.prototype,{isVector3:!0,set:function(t,e,r){return this.x=t,this.y=e,this.z=r,this},setScalar:function(t){return this.x=t,this.y=t,this.z=t,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setZ:function(t){return this.z=t,this},setComponent:function(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this},getComponent:function(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(t){return this.x=t.x,this.y=t.y,this.z=t.z,this},add:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this)},addScalar:function(t){return this.x+=t,this.y+=t,this.z+=t,this},addVectors:function(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this},addScaledVector:function(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this},sub:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this)},subScalar:function(t){return this.x-=t,this.y-=t,this.z-=t,this},subVectors:function(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this},multiply:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(t,e)):(this.x*=t.x,this.y*=t.y,this.z*=t.z,this)},multiplyScalar:function(t){return this.x*=t,this.y*=t,this.z*=t,this},multiplyVectors:function(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this},applyEuler:function(){var t=new r;return function(e){return e&&e.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(t.setFromEuler(e))}}(),applyAxisAngle:function(){var t=new r;return function(e,r){return this.applyQuaternion(t.setFromAxisAngle(e,r))}}(),applyMatrix3:function(t){var e=this.x,r=this.y,n=this.z,i=t.elements;return this.x=i[0]*e+i[3]*r+i[6]*n,this.y=i[1]*e+i[4]*r+i[7]*n,this.z=i[2]*e+i[5]*r+i[8]*n,this},applyMatrix4:function(t){var e=this.x,r=this.y,n=this.z,i=t.elements,a=1/(i[3]*e+i[7]*r+i[11]*n+i[15]);return this.x=(i[0]*e+i[4]*r+i[8]*n+i[12])*a,this.y=(i[1]*e+i[5]*r+i[9]*n+i[13])*a,this.z=(i[2]*e+i[6]*r+i[10]*n+i[14])*a,this},applyQuaternion:function(t){var e=this.x,r=this.y,n=this.z,i=t.x,a=t.y,o=t.z,s=t.w,c=s*e+a*n-o*r,l=s*r+o*e-i*n,h=s*n+i*r-a*e,u=-i*e-a*r-o*n;return this.x=c*s+u*-i+l*-o-h*-a,this.y=l*s+u*-a+h*-i-c*-o,this.z=h*s+u*-o+c*-a-l*-i,this},project:function(){var t=new e;return function(e){return t.multiplyMatrices(e.projectionMatrix,t.getInverse(e.matrixWorld)),this.applyMatrix4(t)}}(),unproject:function(){var t=new e;return function(e){return t.multiplyMatrices(e.matrixWorld,t.getInverse(e.projectionMatrix)),this.applyMatrix4(t)}}(),transformDirection:function(t){var e=this.x,r=this.y,n=this.z,i=t.elements;return this.x=i[0]*e+i[4]*r+i[8]*n,this.y=i[1]*e+i[5]*r+i[9]*n,this.z=i[2]*e+i[6]*r+i[10]*n,this.normalize()},divide:function(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this},divideScalar:function(t){return this.multiplyScalar(1/t)},min:function(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this},max:function(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this},clamp:function(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this},clampScalar:function(){var t=new n,e=new n;return function(r,n){return t.set(r,r,r),e.set(n,n,n),this.clamp(t,e)}}(),clampLength:function(t,e){var r=this.length();return this.divideScalar(r||1).multiplyScalar(Math.max(t,Math.min(e,r)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return 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},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this},dot:function(t){return this.x*t.x+this.y*t.y+this.z*t.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()||1)},setLength:function(t){return this.normalize().multiplyScalar(t)},lerp:function(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this},lerpVectors:function(t,e,r){return this.subVectors(e,t).multiplyScalar(r).add(t)},cross:function(t,e){if(void 0!==e)return console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(t,e);var r=this.x,n=this.y,i=this.z;return this.x=n*t.z-i*t.y,this.y=i*t.x-r*t.z,this.z=r*t.y-n*t.x,this},crossVectors:function(t,e){var r=t.x,n=t.y,i=t.z,a=e.x,o=e.y,s=e.z;return this.x=n*s-i*o,this.y=i*a-r*s,this.z=r*o-n*a,this},projectOnVector:function(t){var e=t.dot(this)/t.lengthSq();return this.copy(t).multiplyScalar(e)},projectOnPlane:function(){var t=new n;return function(e){return t.copy(this).projectOnVector(e),this.sub(t)}}(),reflect:function(){var t=new n;return function(e){return this.sub(t.copy(e).multiplyScalar(2*this.dot(e)))}}(),angleTo:function(t){var e=this.dot(t)/Math.sqrt(this.lengthSq()*t.lengthSq());return Math.acos(Ko.clamp(e,-1,1))},distanceTo:function(t){return Math.sqrt(this.distanceToSquared(t))},distanceToSquared:function(t){var e=this.x-t.x,r=this.y-t.y,n=this.z-t.z;return e*e+r*r+n*n},distanceToManhattan:function(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)},setFromSpherical:function(t){var e=Math.sin(t.phi)*t.radius;return this.x=e*Math.sin(t.theta),this.y=Math.cos(t.phi)*t.radius,this.z=e*Math.cos(t.theta),this},setFromCylindrical:function(t){return this.x=t.radius*Math.sin(t.theta),this.y=t.y,this.z=t.radius*Math.cos(t.theta),this},setFromMatrixPosition:function(t){var e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this},setFromMatrixScale:function(t){var e=this.setFromMatrixColumn(t,0).length(),r=this.setFromMatrixColumn(t,1).length(),n=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=r,this.z=n,this},setFromMatrixColumn:function(t,e){return this.fromArray(t.elements,4*e)},equals:function(t){return t.x===this.x&&t.y===this.y&&t.z===this.z},fromArray:function(t,e){return void 0===e&&(e=0),this.x=t[e],this.y=t[e+1],this.z=t[e+2],this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t},fromBufferAttribute:function(t,e,r){return void 0!==r&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}});var $o="1.2.2",ts=1,es=1,rs=2,ns=600,is=0,as=1,os=2,ss=3,cs=4,ls=5,hs=0,us=1,ds=1,ps=2,fs=3,ms=4,gs=5,vs=6,ys=7,xs=8,bs=9,ws=10,_s=11,Ms=1,Es=2,Ss=3,Ts=4,As=5,Ls=6,Cs=7,Rs=8,Ps=9,Is=10,Os=11,Ns=12,Ds=0,Us=1,zs=new n(0,0,1),Bs=new Map;String.prototype.padStart||(String.prototype.padStart=function(t,e){return t>>=0,e=String(e||" "),this.length>t?String(this):((t-=this.length)>e.length&&(e+=e.repeat(t/e.length)),e.slice(0,t)+String(this))}),String.prototype.repeat||(String.prototype.repeat=function(t){if(null==this)throw new TypeError("can't convert "+this+" to object");var e=""+this;if((t=+t)!=t&&(t=0),t<0)throw new RangeError("repeat count must be non-negative");if(t==1/0)throw new RangeError("repeat count must be less than infinity");if(t=Math.floor(t),0==e.length||0==t)return"";if(e.length*t>=1<<28)throw new RangeError("repeat count must not overflow maximum string size");for(var r="";1==(1&t)&&(r+=e),0!=(t>>>=1);)e+=e;return r}),s.stdWidth=40,s.stdMargin=5,s.prototype.removeDomObjects=function(){for(var t,e=0,r=this.domObjects.length;e>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,this},setRGB:function(t,e,r){return this.r=t,this.g=e,this.b=r,this},setHSL:function(){function t(t,e,r){return r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+6*(e-t)*(2/3-r):t}return function(e,r,n){if(e=Ko.euclideanModulo(e,1),r=Ko.clamp(r,0,1),n=Ko.clamp(n,0,1),0===r)this.r=this.g=this.b=n;else{var i=n<=.5?n*(1+r):n+r-n*r,a=2*n-i;this.r=t(a,i,e+1/3),this.g=t(a,i,e),this.b=t(a,i,e-1/3)}return this}}(),setStyle:function(t){function e(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}var r;if(r=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(t)){var n,i=r[1],a=r[2];switch(i){case"rgb":case"rgba":if(n=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(255,parseInt(n[1],10))/255,this.g=Math.min(255,parseInt(n[2],10))/255,this.b=Math.min(255,parseInt(n[3],10))/255,e(n[5]),this;if(n=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a))return this.r=Math.min(100,parseInt(n[1],10))/100,this.g=Math.min(100,parseInt(n[2],10))/100,this.b=Math.min(100,parseInt(n[3],10))/100,e(n[5]),this;break;case"hsl":case"hsla":if(n=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(a)){var o=parseFloat(n[1])/360,s=parseInt(n[2],10)/100,c=parseInt(n[3],10)/100;return e(n[5]),this.setHSL(o,s,c)}}}else if(r=/^\#([A-Fa-f0-9]+)$/.exec(t)){var l=(h=r[1]).length;if(3===l)return this.r=parseInt(h.charAt(0)+h.charAt(0),16)/255,this.g=parseInt(h.charAt(1)+h.charAt(1),16)/255,this.b=parseInt(h.charAt(2)+h.charAt(2),16)/255,this;if(6===l)return this.r=parseInt(h.charAt(0)+h.charAt(1),16)/255,this.g=parseInt(h.charAt(2)+h.charAt(3),16)/255,this.b=parseInt(h.charAt(4)+h.charAt(5),16)/255,this}if(t&&t.length>0){var h=Fs[t];void 0!==h?this.setHex(h):console.warn("THREE.Color: Unknown color "+t)}return this},clone:function(){return new this.constructor(this.r,this.g,this.b)},copy:function(t){return this.r=t.r,this.g=t.g,this.b=t.b,this},copyGammaToLinear:function(t,e){return void 0===e&&(e=2),this.r=Math.pow(t.r,e),this.g=Math.pow(t.g,e),this.b=Math.pow(t.b,e),this},copyLinearToGamma:function(t,e){void 0===e&&(e=2);var r=e>0?1/e:1;return this.r=Math.pow(t.r,r),this.g=Math.pow(t.g,r),this.b=Math.pow(t.b,r),this},convertGammaToLinear:function(){var t=this.r,e=this.g,r=this.b;return this.r=t*t,this.g=e*e,this.b=r*r,this},convertLinearToGamma:function(){return this.r=Math.sqrt(this.r),this.g=Math.sqrt(this.g),this.b=Math.sqrt(this.b),this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(t){var e,r,n=t||{h:0,s:0,l:0},i=this.r,a=this.g,o=this.b,s=Math.max(i,a,o),c=Math.min(i,a,o),l=(c+s)/2;if(c===s)e=0,r=0;else{var h=s-c;switch(r=l<=.5?h/(s+c):h/(2-s-c),s){case i:e=(a-o)/h+(a2048||e.height>2048?e.toDataURL("image/jpeg",.6):e.toDataURL("image/png")}(r)}),e.image=r.uuid}return t.textures[this.uuid]=e,e},dispose:function(){this.dispatchEvent({type:"dispose"})},transformUv:function(t){if(300===this.mapping){if(t.multiply(this.repeat),t.add(this.offset),t.x<0||t.x>1)switch(this.wrapS){case qc:t.x=t.x-Math.floor(t.x);break;case Zc:t.x=t.x<0?0:1;break;case Jc:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case qc:t.y=t.y-Math.floor(t.y);break;case Zc:t.y=t.y<0?0:1;break;case Jc:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}this.flipY&&(t.y=1-t.y)}}}),d.prototype=Object.create(u.prototype),d.prototype.constructor=d,d.prototype.isDataTexture=!0;var Xl={colors:[],texture:[]},Yl={getTexture:g,getColors:v,red:new c(16711680),yellow:new c(16776960),green:new c(65280),white:new c(16777215),grey:new c(4473924),lightGrey:new c(8947848),hudBlue:new c(1077133),hudRed:new c(8397056)};Object.assign(y.prototype,{isVector4:!0,set:function(t,e,r,n){return this.x=t,this.y=e,this.z=r,this.w=n,this},setScalar:function(t){return this.x=t,this.y=t,this.z=t,this.w=t,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setZ:function(t){return this.z=t,this},setW:function(t){return this.w=t,this},setComponent:function(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this},getComponent:function(t){switch(t){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: "+t)}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this},add:function(t,e){return void 0!==e?(console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this)},addScalar:function(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this},addVectors:function(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this},addScaledVector:function(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this},sub:function(t,e){return void 0!==e?(console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this)},subScalar:function(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this},subVectors:function(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this},multiplyScalar:function(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this},applyMatrix4:function(t){var e=this.x,r=this.y,n=this.z,i=this.w,a=t.elements;return this.x=a[0]*e+a[4]*r+a[8]*n+a[12]*i,this.y=a[1]*e+a[5]*r+a[9]*n+a[13]*i,this.z=a[2]*e+a[6]*r+a[10]*n+a[14]*i,this.w=a[3]*e+a[7]*r+a[11]*n+a[15]*i,this},divideScalar:function(t){return this.multiplyScalar(1/t)},setAxisAngleFromQuaternion:function(t){this.w=2*Math.acos(t.w);var e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this},setAxisAngleFromRotationMatrix:function(t){var e,r,n,i,a=t.elements,o=a[0],s=a[4],c=a[8],l=a[1],h=a[5],u=a[9],d=a[2],p=a[6],f=a[10];if(Math.abs(s-l)<.01&&Math.abs(c-d)<.01&&Math.abs(u-p)<.01){if(Math.abs(s+l)<.1&&Math.abs(c+d)<.1&&Math.abs(u+p)<.1&&Math.abs(o+h+f-3)<.1)return this.set(1,0,0,0),this;e=Math.PI;var m=(o+1)/2,g=(h+1)/2,v=(f+1)/2,y=(s+l)/4,x=(c+d)/4,b=(u+p)/4;return m>g&&m>v?m<.01?(r=0,n=.707106781,i=.707106781):(n=y/(r=Math.sqrt(m)),i=x/r):g>v?g<.01?(r=.707106781,n=0,i=.707106781):(r=y/(n=Math.sqrt(g)),i=b/n):v<.01?(r=.707106781,n=.707106781,i=0):(r=x/(i=Math.sqrt(v)),n=b/i),this.set(r,n,i,e),this}var w=Math.sqrt((p-u)*(p-u)+(c-d)*(c-d)+(l-s)*(l-s));return Math.abs(w)<.001&&(w=1),this.x=(p-u)/w,this.y=(c-d)/w,this.z=(l-s)/w,this.w=Math.acos((o+h+f-1)/2),this},min:function(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this.w=Math.min(this.w,t.w),this},max:function(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this.w=Math.max(this.w,t.w),this},clamp:function(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this.w=Math.max(t.w,Math.min(e.w,this.w)),this},clampScalar:function(){var t,e;return function(r,n){return void 0===t&&(t=new y,e=new y),t.set(r,r,r,r),e.set(n,n,n,n),this.clamp(t,e)}}(),clampLength:function(t,e){var r=this.length();return this.divideScalar(r||1).multiplyScalar(Math.max(t,Math.min(e,r)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this},ceil:function(){return 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},round:function(){return 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},roundToZero:function(){return 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},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this},dot:function(t){return this.x*t.x+this.y*t.y+this.z*t.z+this.w*t.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()||1)},setLength:function(t){return this.normalize().multiplyScalar(t)},lerp:function(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this.w+=(t.w-this.w)*e,this},lerpVectors:function(t,e,r){return this.subVectors(e,t).multiplyScalar(r).add(t)},equals:function(t){return t.x===this.x&&t.y===this.y&&t.z===this.z&&t.w===this.w},fromArray:function(t,e){return void 0===e&&(e=0),this.x=t[e],this.y=t[e+1],this.z=t[e+2],this.w=t[e+3],this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t[e+3]=this.w,t},fromBufferAttribute:function(t,e,r){return void 0!==r&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this.w=t.getW(e),this}}),Object.assign(x.prototype,l.prototype,{isWebGLRenderTarget:!0,setSize:function(t,e){this.width===t&&this.height===e||(this.width=t,this.height=e,this.dispose()),this.viewport.set(0,0,t,e),this.scissor.set(0,0,t,e)},clone:function(){return(new this.constructor).copy(this)},copy:function(t){return this.width=t.width,this.height=t.height,this.viewport.copy(t.viewport),this.texture=t.texture.clone(),this.depthBuffer=t.depthBuffer,this.stencilBuffer=t.stencilBuffer,this.depthTexture=t.depthTexture,this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),b.prototype=Object.create(u.prototype),b.prototype.constructor=b,b.prototype.isCubeTexture=!0,Object.defineProperty(b.prototype,"images",{get:function(){return this.image},set:function(t){this.image=t}});var ql=new u,Zl=new b,Jl=[],Ql=[],Kl=new Float32Array(16),$l=new Float32Array(9);Q.prototype.setValue=function(t,e){for(var r=this.seq,n=0,i=r.length;n!==i;++n){var a=r[n];a.setValue(t,e[a.id])}};var th=/([\w\d_]+)(\])?(\[|\.)?/g;tt.prototype.setValue=function(t,e,r){var n=this.map[e];void 0!==n&&n.setValue(t,r,this.renderer)},tt.prototype.setOptional=function(t,e,r){var n=e[r];void 0!==n&&this.setValue(t,r,n)},tt.upload=function(t,e,r,n){for(var i=0,a=e.length;i!==a;++i){var o=e[i],s=r[o.id];!1!==s.needsUpdate&&o.setValue(t,s.value,n)}},tt.seqWithValue=function(t,e){for(var r=[],n=0,i=t.length;n!==i;++n){var a=t[n];a.id in e&&r.push(a)}return r};var eh={common:{diffuse:{value:new c(15658734)},opacity:{value:1},map:{value:null},offsetRepeat:{value:new y(0,0,1,1)},specularMap:{value:null},alphaMap:{value:null},envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new h(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new c(16777215)}},lights:{ambientLightColor:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new c(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},offsetRepeat:{value:new y(0,0,1,1)}}},rh={merge:function(t){for(var e={},r=0;r 0.0 ) {\r\n\r\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\r\n\r\n\t\t// based upon Frostbite 3 Moving to Physically-based Rendering\r\n\t\t// page 32, equation 26: E[window1]\r\n\t\t// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\n\t\t// this is intended to be used on spot and point lights who are represented as luminous intensity\r\n\t\t// but who must be converted to luminous irradiance for surface lighting calculation\r\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\r\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\r\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\r\n\r\n#else\r\n\r\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\r\n\r\n#endif\r\n\r\n\t}\r\n\r\n\treturn 1.0;\r\n\r\n}\r\n\r\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\r\n\r\n\treturn RECIPROCAL_PI * diffuseColor;\r\n\r\n} // validated\r\n\r\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\r\n\r\n\t// Original approximation by Christophe Schlick \'94\r\n\t// float fresnel = pow( 1.0 - dotLH, 5.0 );\r\n\r\n\t// Optimized variant (presented by Epic at SIGGRAPH \'13)\r\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\r\n\r\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\r\n\r\n} // validated\r\n\r\n// Microfacet Models for Refraction through Rough Surfaces - equation (34)\r\n// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html\r\n// alpha is "roughness squared" in Disney’s reparameterization\r\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\r\n\r\n\t// geometry term = G(l)⋅G(v) / 4(n⋅l)(n⋅v)\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\r\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\r\n\r\n\treturn 1.0 / ( gl * gv );\r\n\r\n} // validated\r\n\r\n// Moving Frostbite to Physically Based Rendering 2.0 - page 12, listing 2\r\n// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\t// dotNL and dotNV are explicitly swapped. This is not a mistake.\r\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\r\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\r\n\r\n\treturn 0.5 / max( gv + gl, EPSILON );\r\n}\r\n\r\n// Microfacet Models for Refraction through Rough Surfaces - equation (33)\r\n// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html\r\n// alpha is "roughness squared" in Disney’s reparameterization\r\nfloat D_GGX( const in float alpha, const in float dotNH ) {\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; // avoid alpha = 0 with dotNH = 1\r\n\r\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\r\n\r\n}\r\n\r\n// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility\r\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\r\n\r\n\tfloat alpha = pow2( roughness ); // UE4\'s roughness\r\n\r\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\r\n\r\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\r\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\r\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\r\n\r\n\tvec3 F = F_Schlick( specularColor, dotLH );\r\n\r\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\r\n\r\n\tfloat D = D_GGX( alpha, dotNH );\r\n\r\n\treturn F * ( G * D );\r\n\r\n} // validated\r\n\r\n// Rect Area Light\r\n\r\n// Area light computation code adapted from:\r\n// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines\r\n// By: Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt\r\n// https://drive.google.com/file/d/0BzvWIdpUpRx_d09ndGVjNVJzZjA/view\r\n// https://eheitzresearch.wordpress.com/415-2/\r\n// http://blog.selfshadow.com/sandbox/ltc.html\r\n\r\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\r\n\r\n\tconst float LUT_SIZE = 64.0;\r\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\r\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\r\n\r\n\tfloat theta = acos( dot( N, V ) );\r\n\r\n\t// Parameterization of texture:\r\n\t// sqrt(roughness) -> [0,1]\r\n\t// theta -> [0, PI/2]\r\n\tvec2 uv = vec2(\r\n\t\tsqrt( saturate( roughness ) ),\r\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\r\n\r\n\t// Ensure we don\'t have nonlinearities at the look-up table\'s edges\r\n\t// see: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter24.html\r\n\t// "Shader Analysis" section\r\n\tuv = uv * LUT_SCALE + LUT_BIAS;\r\n\r\n\treturn uv;\r\n\r\n}\r\n\r\n// Real-Time Area Lighting: a Journey from Research to Production\r\n// By: Stephen Hill & Eric Heitz\r\n// http://advances.realtimerendering.com/s2016/s2016_ltc_rnd.pdf\r\n// An approximation for the form factor of a clipped rectangle.\r\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\r\n\r\n\tfloat l = length( f );\r\n\r\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\r\n\r\n}\r\n\r\n// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines\r\n// also Real-Time Area Lighting: a Journey from Research to Production\r\n// http://advances.realtimerendering.com/s2016/s2016_ltc_rnd.pdf\r\n// Normalization by 2*PI is incorporated in this function itself.\r\n// theta/sin(theta) is approximated by rational polynomial\r\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\r\n\r\n\tfloat x = dot( v1, v2 );\r\n\r\n\tfloat y = abs( x );\r\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\r\n\tfloat b = 3.45068 + (4.18814 + y) * y;\r\n\tfloat v = a / b;\r\n\r\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\r\n\r\n\treturn cross( v1, v2 ) * theta_sintheta;\r\n\r\n}\r\n\r\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\r\n\r\n\t// bail if point is on back side of plane of light\r\n\t// assumes ccw winding order of light vertices\r\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\r\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\r\n\tvec3 lightNormal = cross( v1, v2 );\r\n\r\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\r\n\r\n\t// construct orthonormal basis around N\r\n\tvec3 T1, T2;\r\n\tT1 = normalize( V - N * dot( V, N ) );\r\n\tT2 = - cross( N, T1 ); // negated from paper; possibly due to a different assumed handedness of world coordinate system\r\n\r\n\t// compute transform\r\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\r\n\r\n\t// transform rect\r\n\tvec3 coords[ 4 ];\r\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\r\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\r\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\r\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\r\n\r\n\t// project rect onto sphere\r\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\r\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\r\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\r\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\r\n\r\n\t// calculate vector form factor\r\n\tvec3 vectorFormFactor = vec3( 0.0 );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\r\n\r\n\t// adjust for horizon clipping\r\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\r\n\r\n\treturn result;\r\n\r\n}\r\n\r\n// End Rect Area Light\r\n\r\n// ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile\r\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\r\n\r\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\r\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\r\n\r\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\r\n\r\n\tvec4 r = roughness * c0 + c1;\r\n\r\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\r\n\r\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\r\n\r\n\treturn specularColor * AB.x + AB.y;\r\n\r\n} // validated\r\n\r\n\r\nfloat G_BlinnPhong_Implicit( ) {\r\n\r\n\t// geometry term is (n dot l)(n dot v) / 4(n dot l)(n dot v)\r\n\treturn 0.25;\r\n\r\n}\r\n\r\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\r\n\r\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\r\n\r\n}\r\n\r\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\r\n\r\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\r\n\r\n\t//float dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\r\n\t//float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\r\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\r\n\r\n\tvec3 F = F_Schlick( specularColor, dotLH );\r\n\r\n\tfloat G = G_BlinnPhong_Implicit( );\r\n\r\n\tfloat D = D_BlinnPhong( shininess, dotNH );\r\n\r\n\treturn F * ( G * D );\r\n\r\n} // validated\r\n\r\n// source: http://simonstechblog.blogspot.ca/2011/12/microfacet-brdf.html\r\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\r\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\r\n}\r\n\r\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\r\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\r\n}\r\n',bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\r\n\r\n\tuniform sampler2D bumpMap;\r\n\tuniform float bumpScale;\r\n\r\n\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\r\n\t// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\r\n\r\n\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\r\n\r\n\tvec2 dHdxy_fwd() {\r\n\r\n\t\tvec2 dSTdx = dFdx( vUv );\r\n\t\tvec2 dSTdy = dFdy( vUv );\r\n\r\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\r\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\r\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\r\n\r\n\t\treturn vec2( dBx, dBy );\r\n\r\n\t}\r\n\r\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\r\n\r\n\t\t// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988\r\n\r\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\r\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\r\n\t\tvec3 vN = surf_norm;\t\t// normalized\r\n\r\n\t\tvec3 R1 = cross( vSigmaY, vN );\r\n\t\tvec3 R2 = cross( vN, vSigmaX );\r\n\r\n\t\tfloat fDet = dot( vSigmaX, R1 );\r\n\r\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\r\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\r\n\r\n\t}\r\n\r\n#endif\r\n",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\r\n\r\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\r\n\r\n\t\tvec4 plane = clippingPlanes[ i ];\r\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\r\n\r\n\t}\r\n\t\t\r\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\r\n\r\n\t\tbool clipped = true;\r\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\r\n\t\t\tvec4 plane = clippingPlanes[ i ];\r\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\r\n\t\t}\r\n\r\n\t\tif ( clipped ) discard;\r\n\t\r\n\t#endif\r\n\r\n#endif\r\n",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\r\n\r\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\t\tvarying vec3 vViewPosition;\r\n\t#endif\r\n\r\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\r\n\r\n#endif\r\n",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\tvarying vec3 vViewPosition;\r\n#endif\r\n",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\tvViewPosition = - mvPosition.xyz;\r\n#endif\r\n\r\n",color_fragment:"#ifdef USE_COLOR\r\n\r\n\tdiffuseColor.rgb *= vColor;\r\n\r\n#endif",color_pars_fragment:"#ifdef USE_COLOR\r\n\r\n\tvarying vec3 vColor;\r\n\r\n#endif\r\n",color_pars_vertex:"#ifdef USE_COLOR\r\n\r\n\tvarying vec3 vColor;\r\n\r\n#endif",color_vertex:"#ifdef USE_COLOR\r\n\r\n\tvColor.xyz = color.xyz;\r\n\r\n#endif",common:"#define PI 3.14159265359\r\n#define PI2 6.28318530718\r\n#define PI_HALF 1.5707963267949\r\n#define RECIPROCAL_PI 0.31830988618\r\n#define RECIPROCAL_PI2 0.15915494\r\n#define LOG2 1.442695\r\n#define EPSILON 1e-6\r\n\r\n#define saturate(a) clamp( a, 0.0, 1.0 )\r\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\r\n\r\nfloat pow2( const in float x ) { return x*x; }\r\nfloat pow3( const in float x ) { return x*x*x; }\r\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\r\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\r\n// expects values in the range of [0,1]x[0,1], returns values in the [0,1] range.\r\n// do not collapse into a single function per: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/\r\nhighp float rand( const in vec2 uv ) {\r\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\r\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\r\n\treturn fract(sin(sn) * c);\r\n}\r\n\r\nstruct IncidentLight {\r\n\tvec3 color;\r\n\tvec3 direction;\r\n\tbool visible;\r\n};\r\n\r\nstruct ReflectedLight {\r\n\tvec3 directDiffuse;\r\n\tvec3 directSpecular;\r\n\tvec3 indirectDiffuse;\r\n\tvec3 indirectSpecular;\r\n};\r\n\r\nstruct GeometricContext {\r\n\tvec3 position;\r\n\tvec3 normal;\r\n\tvec3 viewDir;\r\n};\r\n\r\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\r\n\r\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\r\n\r\n}\r\n\r\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\r\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\r\n\r\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\r\n\r\n}\r\n\r\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\r\n\r\n\treturn - distance * planeNormal + point;\r\n\r\n}\r\n\r\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\r\n\r\n}\r\n\r\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\r\n\r\n}\r\n\r\nmat3 transpose( const in mat3 v ) {\r\n\r\n\tmat3 tmp;\r\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\r\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\r\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\r\n\r\n\treturn tmp;\r\n\r\n}\r\n",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\r\n\r\n#define cubeUV_textureSize (1024.0)\r\n\r\nint getFaceFromDirection(vec3 direction) {\r\n\tvec3 absDirection = abs(direction);\r\n\tint face = -1;\r\n\tif( absDirection.x > absDirection.z ) {\r\n\t\tif(absDirection.x > absDirection.y )\r\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\r\n\t\telse\r\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\r\n\t}\r\n\telse {\r\n\t\tif(absDirection.z > absDirection.y )\r\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\r\n\t\telse\r\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\r\n\t}\r\n\treturn face;\r\n}\r\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\r\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\r\n\r\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\r\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\r\n\tfloat dxRoughness = dFdx(roughness);\r\n\tfloat dyRoughness = dFdy(roughness);\r\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\r\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\r\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\r\n\t// Clamp the value to the max mip level counts. hard coded to 6 mips\r\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\r\n\tfloat mipLevel = 0.5 * log2(d);\r\n\treturn vec2(floor(mipLevel), fract(mipLevel));\r\n}\r\n\r\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\r\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\r\n\r\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\r\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\r\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\r\n\r\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\r\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\r\n\t// float powScale = exp2(roughnessLevel + mipLevel);\r\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\r\n\t// float scale = 1.0 / exp2(roughnessLevel + 2.0 + mipLevel);\r\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\r\n\t// float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);\r\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\r\n\r\n\tbool bRes = mipLevel == 0.0;\r\n\tscale = bRes && (scale < a) ? a : scale;\r\n\r\n\tvec3 r;\r\n\tvec2 offset;\r\n\tint face = getFaceFromDirection(direction);\r\n\r\n\tfloat rcpPowScale = 1.0 / powScale;\r\n\r\n\tif( face == 0) {\r\n\t\tr = vec3(direction.x, -direction.z, direction.y);\r\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 1) {\r\n\t\tr = vec3(direction.y, direction.x, direction.z);\r\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 2) {\r\n\t\tr = vec3(direction.z, direction.x, direction.y);\r\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 3) {\r\n\t\tr = vec3(direction.x, direction.z, direction.y);\r\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\telse if( face == 4) {\r\n\t\tr = vec3(direction.y, direction.x, -direction.z);\r\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\telse {\r\n\t\tr = vec3(direction.z, -direction.x, direction.y);\r\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\tr = normalize(r);\r\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\r\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\r\n\tvec2 base = offset + vec2( texelOffset );\r\n\treturn base + s * ( scale - 2.0 * texelOffset );\r\n}\r\n\r\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\r\n\r\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\r\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\r\n\tfloat r1 = floor(roughnessVal);\r\n\tfloat r2 = r1 + 1.0;\r\n\tfloat t = fract(roughnessVal);\r\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\r\n\tfloat s = mipInfo.y;\r\n\tfloat level0 = mipInfo.x;\r\n\tfloat level1 = level0 + 1.0;\r\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\r\n\r\n\t// round to nearest mipmap if we are not interpolating.\r\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\r\n\r\n\t// Tri linear interpolation.\r\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\r\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\r\n\r\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\r\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\r\n\r\n\tvec4 result = mix(color10, color20, t);\r\n\r\n\treturn vec4(result.rgb, 1.0);\r\n}\r\n\r\n#endif\r\n",defaultnormal_vertex:"vec3 transformedNormal = normalMatrix * objectNormal;\r\n\r\n#ifdef FLIP_SIDED\r\n\r\n\ttransformedNormal = - transformedNormal;\r\n\r\n#endif\r\n",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\r\n\r\n\tuniform sampler2D displacementMap;\r\n\tuniform float displacementScale;\r\n\tuniform float displacementBias;\r\n\r\n#endif\r\n",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\r\n\r\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\r\n\r\n#endif\r\n",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\r\n\r\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\r\n\r\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\r\n\r\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\r\n\r\n#endif\r\n",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\r\n\r\n\tuniform sampler2D emissiveMap;\r\n\r\n#endif\r\n",encodings_fragment:" gl_FragColor = linearToOutputTexel( gl_FragColor );\r\n",encodings_pars_fragment:"// For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/\r\n\r\nvec4 LinearToLinear( in vec4 value ) {\r\n\treturn value;\r\n}\r\n\r\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\r\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\r\n}\r\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\r\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\r\n}\r\n\r\nvec4 sRGBToLinear( in vec4 value ) {\r\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\r\n}\r\nvec4 LinearTosRGB( in vec4 value ) {\r\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\r\n}\r\n\r\nvec4 RGBEToLinear( in vec4 value ) {\r\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\r\n}\r\nvec4 LinearToRGBE( in vec4 value ) {\r\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\r\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\r\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\r\n// return vec4( value.brg, ( 3.0 + 128.0 ) / 256.0 );\r\n}\r\n\r\n// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html\r\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\r\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\r\n}\r\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\r\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\r\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\r\n\tM = ceil( M * 255.0 ) / 255.0;\r\n\treturn vec4( value.rgb / ( M * maxRange ), M );\r\n}\r\n\r\n// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html\r\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\r\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\r\n}\r\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\r\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\r\n\tfloat D = max( maxRange / maxRGB, 1.0 );\r\n\tD = min( floor( D ) / 255.0, 1.0 );\r\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\r\n}\r\n\r\n// LogLuv reference: http://graphicrants.blogspot.ca/2009/04/rgbm-color-encoding.html\r\n\r\n// M matrix, for encoding\r\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\r\nvec4 LinearToLogLuv( in vec4 value ) {\r\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\r\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\r\n\tvec4 vResult;\r\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\r\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\r\n\tvResult.w = fract(Le);\r\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\r\n\treturn vResult;\r\n}\r\n\r\n// Inverse M matrix, for decoding\r\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\r\nvec4 LogLuvToLinear( in vec4 value ) {\r\n\tfloat Le = value.z * 255.0 + value.w;\r\n\tvec3 Xp_Y_XYZp;\r\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\r\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\r\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\r\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\r\n\treturn vec4( max(vRGB, 0.0), 1.0 );\r\n}\r\n",envmap_fragment:"#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\r\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\r\n\r\n\t\t// Transforming Normal Vectors with the Inverse Transformation\r\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t#else\r\n\r\n\t\tvec3 reflectVec = vReflect;\r\n\r\n\t#endif\r\n\r\n\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\r\n\r\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\r\n\r\n\t\tvec2 sampleUV;\r\n\t\tsampleUV.y = asin( flipNormal * reflectVec.y ) * RECIPROCAL_PI + 0.5;\r\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\r\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\r\n\r\n\t#elif defined( ENVMAP_TYPE_SPHERE )\r\n\r\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\r\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\r\n\r\n\t#else\r\n\r\n\t\tvec4 envColor = vec4( 0.0 );\r\n\r\n\t#endif\r\n\r\n\tenvColor = envMapTexelToLinear( envColor );\r\n\r\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\r\n\r\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\r\n\r\n\t#elif defined( ENVMAP_BLENDING_MIX )\r\n\r\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\r\n\r\n\t#elif defined( ENVMAP_BLENDING_ADD )\r\n\r\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\r\n\r\n\t#endif\r\n\r\n#endif\r\n",envmap_pars_fragment:"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\r\n\tuniform float reflectivity;\r\n\tuniform float envMapIntensity;\r\n#endif\r\n\r\n#ifdef USE_ENVMAP\r\n\r\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\r\n\t\tvarying vec3 vWorldPosition;\r\n\t#endif\r\n\r\n\t#ifdef ENVMAP_TYPE_CUBE\r\n\t\tuniform samplerCube envMap;\r\n\t#else\r\n\t\tuniform sampler2D envMap;\r\n\t#endif\r\n\tuniform float flipEnvMap;\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\r\n\t\tuniform float refractionRatio;\r\n\t#else\r\n\t\tvarying vec3 vReflect;\r\n\t#endif\r\n\r\n#endif\r\n",envmap_pars_vertex:"#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\t\tvarying vec3 vWorldPosition;\r\n\r\n\t#else\r\n\r\n\t\tvarying vec3 vReflect;\r\n\t\tuniform float refractionRatio;\r\n\r\n\t#endif\r\n\r\n#endif\r\n",envmap_vertex:"#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\r\n\t\tvWorldPosition = worldPosition.xyz;\r\n\r\n\t#else\r\n\r\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\r\n\r\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t#endif\r\n\r\n#endif\r\n",fog_vertex:"\r\n#ifdef USE_FOG\r\nfogDepth = -mvPosition.z;\r\n#endif",fog_pars_vertex:"#ifdef USE_FOG\r\n\r\n varying float fogDepth;\r\n\r\n#endif\r\n",fog_fragment:"#ifdef USE_FOG\r\n\r\n\t#ifdef FOG_EXP2\r\n\r\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\r\n\r\n\t#else\r\n\r\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\r\n\r\n\t#endif\r\n\r\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\r\n\r\n#endif\r\n",fog_pars_fragment:"#ifdef USE_FOG\r\n\r\n\tuniform vec3 fogColor;\r\n\tvarying float fogDepth;\r\n\r\n\t#ifdef FOG_EXP2\r\n\r\n\t\tuniform float fogDensity;\r\n\r\n\t#else\r\n\r\n\t\tuniform float fogNear;\r\n\t\tuniform float fogFar;\r\n\r\n\t#endif\r\n\r\n#endif\r\n",gradientmap_pars_fragment:"#ifdef TOON\r\n\r\n\tuniform sampler2D gradientMap;\r\n\r\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\r\n\r\n\t\t// dotNL will be from -1.0 to 1.0\r\n\t\tfloat dotNL = dot( normal, lightDirection );\r\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\r\n\r\n\t\t#ifdef USE_GRADIENTMAP\r\n\r\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\r\n\r\n\t\t#else\r\n\r\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\r\n\r\n\t\t#endif\r\n\r\n\r\n\t}\r\n\r\n#endif\r\n",lightmap_fragment:"#ifdef USE_LIGHTMAP\r\n\r\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity; // factor of PI should not be present; included here to prevent breakage\r\n\r\n#endif\r\n",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\r\n\r\n\tuniform sampler2D lightMap;\r\n\tuniform float lightMapIntensity;\r\n\r\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\r\n\r\nGeometricContext geometry;\r\ngeometry.position = mvPosition.xyz;\r\ngeometry.normal = normalize( transformedNormal );\r\ngeometry.viewDir = normalize( -mvPosition.xyz );\r\n\r\nGeometricContext backGeometry;\r\nbackGeometry.position = geometry.position;\r\nbackGeometry.normal = -geometry.normal;\r\nbackGeometry.viewDir = geometry.viewDir;\r\n\r\nvLightFront = vec3( 0.0 );\r\n\r\n#ifdef DOUBLE_SIDED\r\n\tvLightBack = vec3( 0.0 );\r\n#endif\r\n\r\nIncidentLight directLight;\r\nfloat dotNL;\r\nvec3 directLightColor_Diffuse;\r\n\r\n#if NUM_POINT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n\r\n#if NUM_DIR_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if NUM_HEMI_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\r\n\r\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n",lights_pars:"uniform vec3 ambientLightColor;\r\n\r\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\r\n\r\n\tvec3 irradiance = ambientLightColor;\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI;\r\n\r\n\t#endif\r\n\r\n\treturn irradiance;\r\n\r\n}\r\n\r\n#if NUM_DIR_LIGHTS > 0\r\n\r\n\tstruct DirectionalLight {\r\n\t\tvec3 direction;\r\n\t\tvec3 color;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\r\n\r\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tdirectLight.color = directionalLight.color;\r\n\t\tdirectLight.direction = directionalLight.direction;\r\n\t\tdirectLight.visible = true;\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_POINT_LIGHTS > 0\r\n\r\n\tstruct PointLight {\r\n\t\tvec3 position;\r\n\t\tvec3 color;\r\n\t\tfloat distance;\r\n\t\tfloat decay;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\r\n\r\n\t// directLight is an out parameter as having it as a return value caused compiler errors on some devices\r\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tvec3 lVector = pointLight.position - geometry.position;\r\n\t\tdirectLight.direction = normalize( lVector );\r\n\r\n\t\tfloat lightDistance = length( lVector );\r\n\r\n\t\tdirectLight.color = pointLight.color;\r\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\r\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tstruct SpotLight {\r\n\t\tvec3 position;\r\n\t\tvec3 direction;\r\n\t\tvec3 color;\r\n\t\tfloat distance;\r\n\t\tfloat decay;\r\n\t\tfloat coneCos;\r\n\t\tfloat penumbraCos;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\r\n\r\n\t// directLight is an out parameter as having it as a return value caused compiler errors on some devices\r\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tvec3 lVector = spotLight.position - geometry.position;\r\n\t\tdirectLight.direction = normalize( lVector );\r\n\r\n\t\tfloat lightDistance = length( lVector );\r\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\r\n\r\n\t\tif ( angleCos > spotLight.coneCos ) {\r\n\r\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\r\n\r\n\t\t\tdirectLight.color = spotLight.color;\r\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\r\n\t\t\tdirectLight.visible = true;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tdirectLight.color = vec3( 0.0 );\r\n\t\t\tdirectLight.visible = false;\r\n\r\n\t\t}\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_RECT_AREA_LIGHTS > 0\r\n\r\n\tstruct RectAreaLight {\r\n\t\tvec3 color;\r\n\t\tvec3 position;\r\n\t\tvec3 halfWidth;\r\n\t\tvec3 halfHeight;\r\n\t};\r\n\r\n\t// Pre-computed values of LinearTransformedCosine approximation of BRDF\r\n\t// BRDF approximation Texture is 64x64\r\n\tuniform sampler2D ltcMat; // RGBA Float\r\n\tuniform sampler2D ltcMag; // Alpha Float (only has w component)\r\n\r\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\r\n\r\n#endif\r\n\r\n\r\n#if NUM_HEMI_LIGHTS > 0\r\n\r\n\tstruct HemisphereLight {\r\n\t\tvec3 direction;\r\n\t\tvec3 skyColor;\r\n\t\tvec3 groundColor;\r\n\t};\r\n\r\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\r\n\r\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\r\n\r\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\r\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\r\n\r\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\r\n\r\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\t\tirradiance *= PI;\r\n\r\n\t\t#endif\r\n\r\n\t\treturn irradiance;\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\r\n\r\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\r\n\r\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\r\n\r\n\t\t\t// TODO: replace with properly filtered cubemaps and access the irradiance LOD level, be it the last LOD level\r\n\t\t\t// of a specular cubemap, or just the default level of a specially created irradiance cubemap.\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\t// force the bias high to get the last LOD level as it is the most blurred.\r\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\r\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec4 envMapColor = vec4( 0.0 );\r\n\r\n\t\t#endif\r\n\r\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\r\n\r\n\t}\r\n\r\n\t// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html\r\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\r\n\r\n\t\t//float envMapWidth = pow( 2.0, maxMIPLevelScalar );\r\n\t\t//float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\r\n\r\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\r\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\r\n\r\n\t\t// clamp to allowable LOD ranges.\r\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\r\n\r\n\t}\r\n\r\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\r\n\r\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\r\n\r\n\t\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\r\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\r\n\r\n\t\t\tvec2 sampleUV;\r\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\r\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\r\n\r\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#endif\r\n\r\n\t\treturn envMapColor.rgb * envMapIntensity;\r\n\r\n\t}\r\n\r\n#endif\r\n",lights_phong_fragment:"BlinnPhongMaterial material;\r\nmaterial.diffuseColor = diffuseColor.rgb;\r\nmaterial.specularColor = specular;\r\nmaterial.specularShininess = shininess;\r\nmaterial.specularStrength = specularStrength;\r\n",lights_phong_pars_fragment:"varying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n\r\nstruct BlinnPhongMaterial {\r\n\r\n\tvec3\tdiffuseColor;\r\n\tvec3\tspecularColor;\r\n\tfloat\tspecularShininess;\r\n\tfloat\tspecularStrength;\r\n\r\n};\r\n\r\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t#ifdef TOON\r\n\r\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\r\n\r\n\t#else\r\n\r\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\r\n\t\tvec3 irradiance = dotNL * directLight.color;\r\n\r\n\t#endif\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI; // punctual light\r\n\r\n\t#endif\r\n\r\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\r\n\r\n}\r\n\r\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n}\r\n\r\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\r\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\r\n\r\n#define Material_LightProbeLOD( material )\t(0)\r\n",lights_physical_fragment:"PhysicalMaterial material;\r\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\r\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\r\n#ifdef STANDARD\r\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\r\n#else\r\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\r\n\tmaterial.clearCoat = saturate( clearCoat ); // Burley clearcoat model\r\n\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\r\n#endif\r\n",lights_physical_pars_fragment:"struct PhysicalMaterial {\r\n\r\n\tvec3\tdiffuseColor;\r\n\tfloat\tspecularRoughness;\r\n\tvec3\tspecularColor;\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat clearCoat;\r\n\t\tfloat clearCoatRoughness;\r\n\t#endif\r\n\r\n};\r\n\r\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\r\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\r\n\r\n// Clear coat directional hemishperical reflectance (this approximation should be improved)\r\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\r\n\r\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\r\n\r\n}\r\n\r\n#if NUM_RECT_AREA_LIGHTS > 0\r\n\r\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t\tvec3 normal = geometry.normal;\r\n\t\tvec3 viewDir = geometry.viewDir;\r\n\t\tvec3 position = geometry.position;\r\n\t\tvec3 lightPos = rectAreaLight.position;\r\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\r\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\r\n\t\tvec3 lightColor = rectAreaLight.color;\r\n\t\tfloat roughness = material.specularRoughness;\r\n\r\n\t\tvec3 rectCoords[ 4 ];\r\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight; // counterclockwise\r\n\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\r\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\r\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\r\n\r\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\r\n\r\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\r\n\r\n\t\tvec4 t = texture2D( ltcMat, uv );\r\n\r\n\t\tmat3 mInv = mat3(\r\n\t\t\tvec3( 1, 0, t.y ),\r\n\t\t\tvec3( 0, t.z, 0 ),\r\n\t\t\tvec3( t.w, 0, t.x )\r\n\t\t);\r\n\r\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); // no fresnel\r\n\r\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\r\n\r\n\tvec3 irradiance = dotNL * directLight.color;\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI; // punctual light\r\n\r\n\t#endif\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\r\n\t#else\r\n\t\tfloat clearCoatDHR = 0.0;\r\n\t#endif\r\n\r\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\r\n\r\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n\t#ifndef STANDARD\r\n\r\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\r\n\r\n\t#endif\r\n\r\n}\r\n\r\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n}\r\n\r\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\t\tfloat dotNL = dotNV;\r\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\r\n\t#else\r\n\t\tfloat clearCoatDHR = 0.0;\r\n\t#endif\r\n\r\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\r\n\r\n\t#ifndef STANDARD\r\n\r\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\r\n\r\n\t#endif\r\n\r\n}\r\n\r\n#define RE_Direct\t\t\t\tRE_Direct_Physical\r\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\r\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\r\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\r\n\r\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\r\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\r\n\r\n// ref: http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\r\n\r\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\r\n\r\n}\r\n",lights_template:"\r\n\r\nGeometricContext geometry;\r\n\r\ngeometry.position = - vViewPosition;\r\ngeometry.normal = normal;\r\ngeometry.viewDir = normalize( vViewPosition );\r\n\r\nIncidentLight directLight;\r\n\r\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tPointLight pointLight;\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tpointLight = pointLights[ i ];\r\n\r\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tSpotLight spotLight;\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tspotLight = spotLights[ i ];\r\n\r\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tDirectionalLight directionalLight;\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tdirectionalLight = directionalLights[ i ];\r\n\r\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\r\n\r\n\tRectAreaLight rectAreaLight;\r\n\r\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\r\n\r\n\t\trectAreaLight = rectAreaLights[ i ];\r\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if defined( RE_IndirectDiffuse )\r\n\r\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\r\n\r\n\t#ifdef USE_LIGHTMAP\r\n\r\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\r\n\r\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\t\tlightMapIrradiance *= PI; // factor of PI should not be present; included here to prevent breakage\r\n\r\n\t\t#endif\r\n\r\n\t\tirradiance += lightMapIrradiance;\r\n\r\n\t#endif\r\n\r\n\t#if ( NUM_HEMI_LIGHTS > 0 )\r\n\r\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\r\n\r\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\r\n\r\n\t\t}\r\n\r\n\t#endif\r\n\r\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t// TODO, replace 8 with the real maxMIPLevel\r\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\r\n\r\n\t#endif\r\n\r\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\r\n\r\n#endif\r\n\r\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\r\n\r\n\t// TODO, replace 8 with the real maxMIPLevel\r\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\r\n\r\n\t#ifndef STANDARD\r\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\r\n\t#else\r\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\r\n\t#endif\r\n\r\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\r\n\r\n#endif\r\n",logdepthbuf_fragment:"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\r\n\r\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\r\n\r\n#endif",logdepthbuf_pars_fragment:"#ifdef USE_LOGDEPTHBUF\r\n\r\n\tuniform float logDepthBufFC;\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvarying float vFragDepth;\r\n\r\n\t#endif\r\n\r\n#endif\r\n",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvarying float vFragDepth;\r\n\r\n\t#endif\r\n\r\n\tuniform float logDepthBufFC;\r\n\r\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\r\n\r\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvFragDepth = 1.0 + gl_Position.w;\r\n\r\n\t#else\r\n\r\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\r\n\r\n\t#endif\r\n\r\n#endif\r\n",map_fragment:"#ifdef USE_MAP\r\n\r\n\tvec4 texelColor = texture2D( map, vUv );\r\n\r\n\ttexelColor = mapTexelToLinear( texelColor );\r\n\tdiffuseColor *= texelColor;\r\n\r\n#endif\r\n",map_pars_fragment:"#ifdef USE_MAP\r\n\r\n\tuniform sampler2D map;\r\n\r\n#endif\r\n",map_particle_fragment:"#ifdef USE_MAP\r\n\r\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\r\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\r\n\r\n#endif\r\n",map_particle_pars_fragment:"#ifdef USE_MAP\r\n\r\n\tuniform vec4 offsetRepeat;\r\n\tuniform sampler2D map;\r\n\r\n#endif\r\n",metalnessmap_fragment:"float metalnessFactor = metalness;\r\n\r\n#ifdef USE_METALNESSMAP\r\n\r\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\r\n\r\n\t// reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\r\n\tmetalnessFactor *= texelMetalness.b;\r\n\r\n#endif\r\n",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\r\n\r\n\tuniform sampler2D metalnessMap;\r\n\r\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\r\n\r\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\r\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\r\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\r\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\r\n\r\n#endif\r\n",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\r\n\r\n\t#ifndef USE_MORPHNORMALS\r\n\r\n\tuniform float morphTargetInfluences[ 8 ];\r\n\r\n\t#else\r\n\r\n\tuniform float morphTargetInfluences[ 4 ];\r\n\r\n\t#endif\r\n\r\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\r\n\r\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\r\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\r\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\r\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\r\n\r\n\t#ifndef USE_MORPHNORMALS\r\n\r\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\r\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\r\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\r\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\r\n\r\n\t#endif\r\n\r\n#endif\r\n",normal_flip:"#ifdef DOUBLE_SIDED\r\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\r\n#else\r\n\tfloat flipNormal = 1.0;\r\n#endif\r\n",normal_fragment:"#ifdef FLAT_SHADED\r\n\r\n\t// Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ...\r\n\r\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\r\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\r\n\tvec3 normal = normalize( cross( fdx, fdy ) );\r\n\r\n#else\r\n\r\n\tvec3 normal = normalize( vNormal ) * flipNormal;\r\n\r\n#endif\r\n\r\n#ifdef USE_NORMALMAP\r\n\r\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\r\n\r\n#elif defined( USE_BUMPMAP )\r\n\r\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\r\n\r\n#endif\r\n",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\r\n\r\n\tuniform sampler2D normalMap;\r\n\tuniform vec2 normalScale;\r\n\r\n\t// Per-Pixel Tangent Space Normal Mapping\r\n\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\r\n\r\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\r\n\r\n\t\t// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988\r\n\r\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\r\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\r\n\t\tvec2 st0 = dFdx( vUv.st );\r\n\t\tvec2 st1 = dFdy( vUv.st );\r\n\r\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\r\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\r\n\t\tvec3 N = normalize( surf_norm );\r\n\r\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\r\n\t\tmapN.xy = normalScale * mapN.xy;\r\n\t\tmat3 tsn = mat3( S, T, N );\r\n\t\treturn normalize( tsn * mapN );\r\n\r\n\t}\r\n\r\n#endif\r\n",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\r\n\treturn normalize( normal ) * 0.5 + 0.5;\r\n}\r\n\r\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\r\n\treturn 1.0 - 2.0 * rgb.xyz;\r\n}\r\n\r\nconst float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)\r\nconst float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nconst float ShiftRight8 = 1. / 256.;\r\n\r\nvec4 packDepthToRGBA( const in float v ) {\r\n\tvec4 r = vec4( fract( v * PackFactors ), v );\r\n\tr.yzw -= r.xyz * ShiftRight8; // tidy overflow\r\n\treturn r * PackUpscale;\r\n}\r\n\r\nfloat unpackRGBAToDepth( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\n// NOTE: viewZ/eyeZ is < 0 when in front of the camera per OpenGL conventions\r\n\r\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\r\n\treturn ( viewZ + near ) / ( near - far );\r\n}\r\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\r\n\treturn linearClipZ * ( near - far ) - near;\r\n}\r\n\r\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\r\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\r\n}\r\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\r\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\r\n}\r\n",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\r\n\r\n\t// Get get normal blending with premultipled, use with CustomBlending, OneFactor, OneMinusSrcAlphaFactor, AddEquation.\r\n\tgl_FragColor.rgb *= gl_FragColor.a;\r\n\r\n#endif\r\n",project_vertex:"vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\r\n\r\ngl_Position = projectionMatrix * mvPosition;\r\n",dithering_fragment:"#if defined( DITHERING )\r\n\r\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\r\n\r\n#endif\r\n",dithering_pars_fragment:"#if defined( DITHERING )\r\n\r\n\t// based on https://www.shadertoy.com/view/MslGR8\r\n\tvec3 dithering( vec3 color ) {\r\n\t\t//Calculate grid position\r\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\r\n\r\n\t\t//Shift the individual colors differently, thus making it even harder to see the dithering pattern\r\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\r\n\r\n\t\t//modify shift acording to grid position.\r\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\r\n\r\n\t\t//shift the color by dither_shift\r\n\t\treturn color + dither_shift_RGB;\r\n\t}\r\n\r\n#endif\r\n",roughnessmap_fragment:"float roughnessFactor = roughness;\r\n\r\n#ifdef USE_ROUGHNESSMAP\r\n\r\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\r\n\r\n\t// reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\r\n\troughnessFactor *= texelRoughness.g;\r\n\r\n#endif\r\n",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\r\n\r\n\tuniform sampler2D roughnessMap;\r\n\r\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\r\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\r\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\r\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\r\n\r\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\r\n\r\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\r\n\r\n\t}\r\n\r\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\r\n\r\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\r\n\r\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\r\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\r\n\r\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\r\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\r\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\r\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\r\n\r\n\t\tvec2 f = fract( uv * size + 0.5 );\r\n\r\n\t\tfloat a = mix( lb, lt, f.y );\r\n\t\tfloat b = mix( rb, rt, f.y );\r\n\t\tfloat c = mix( a, b, f.x );\r\n\r\n\t\treturn c;\r\n\r\n\t}\r\n\r\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\r\n\r\n\t\tfloat shadow = 1.0;\r\n\r\n\t\tshadowCoord.xyz /= shadowCoord.w;\r\n\t\tshadowCoord.z += shadowBias;\r\n\r\n\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\r\n\t\t// if ( all( something, something ) ) using this instead\r\n\r\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\r\n\t\tbool inFrustum = all( inFrustumVec );\r\n\r\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\r\n\r\n\t\tbool frustumTest = all( frustumTestVec );\r\n\r\n\t\tif ( frustumTest ) {\r\n\r\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\r\n\r\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\r\n\r\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\r\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\r\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\r\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\r\n\r\n\t\t\tshadow = (\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\r\n\r\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\r\n\r\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\r\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\r\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\r\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\r\n\r\n\t\t\tshadow = (\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#else // no percentage-closer filtering:\r\n\r\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\r\n\r\n\t\t#endif\r\n\r\n\t\t}\r\n\r\n\t\treturn shadow;\r\n\r\n\t}\r\n\r\n\t// cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D\r\n\t// vector suitable for 2D texture mapping. This code uses the following layout for the\r\n\t// 2D texture:\r\n\t//\r\n\t// xzXZ\r\n\t// y Y\r\n\t//\r\n\t// Y - Positive y direction\r\n\t// y - Negative y direction\r\n\t// X - Positive x direction\r\n\t// x - Negative x direction\r\n\t// Z - Positive z direction\r\n\t// z - Negative z direction\r\n\t//\r\n\t// Source and test bed:\r\n\t// https://gist.github.com/tschw/da10c43c467ce8afd0c4\r\n\r\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\r\n\r\n\t\t// Number of texels to avoid at the edge of each square\r\n\r\n\t\tvec3 absV = abs( v );\r\n\r\n\t\t// Intersect unit cube\r\n\r\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\r\n\t\tabsV *= scaleToCube;\r\n\r\n\t\t// Apply scale to avoid seams\r\n\r\n\t\t// two texels less per square (one texel will do for NEAREST)\r\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\r\n\r\n\t\t// Unwrap\r\n\r\n\t\t// space: -1 ... 1 range for each square\r\n\t\t//\r\n\t\t// #X##\t\tdim := ( 4 , 2 )\r\n\t\t// # #\t\tcenter := ( 1 , 1 )\r\n\r\n\t\tvec2 planar = v.xy;\r\n\r\n\t\tfloat almostATexel = 1.5 * texelSizeY;\r\n\t\tfloat almostOne = 1.0 - almostATexel;\r\n\r\n\t\tif ( absV.z >= almostOne ) {\r\n\r\n\t\t\tif ( v.z > 0.0 )\r\n\t\t\t\tplanar.x = 4.0 - v.x;\r\n\r\n\t\t} else if ( absV.x >= almostOne ) {\r\n\r\n\t\t\tfloat signX = sign( v.x );\r\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\r\n\r\n\t\t} else if ( absV.y >= almostOne ) {\r\n\r\n\t\t\tfloat signY = sign( v.y );\r\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\r\n\t\t\tplanar.y = v.z * signY - 2.0;\r\n\r\n\t\t}\r\n\r\n\t\t// Transform to UV space\r\n\r\n\t\t// scale := 0.5 / dim\r\n\t\t// translate := ( center + 0.5 ) / dim\r\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\r\n\r\n\t}\r\n\r\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\r\n\r\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\r\n\r\n\t\t// for point lights, the uniform @vShadowCoord is re-purposed to hold\r\n\t\t// the distance from the light to the world-space position of the fragment.\r\n\t\tvec3 lightToPosition = shadowCoord.xyz;\r\n\r\n\t\t// bd3D = base direction 3D\r\n\t\tvec3 bd3D = normalize( lightToPosition );\r\n\t\t// dp = distance from light to fragment position\r\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\r\n\r\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\r\n\r\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\r\n\r\n\t\t\treturn (\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#else // no percentage-closer filtering\r\n\r\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\r\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\r\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\r\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\r\n\r\n#endif\r\n",shadowmap_vertex:"#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\r\n\r\n#endif\r\n",shadowmask_pars_fragment:"float getShadowMask() {\r\n\r\n\tfloat shadow = 1.0;\r\n\r\n\t#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\tDirectionalLight directionalLight;\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tdirectionalLight = directionalLights[ i ];\r\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tSpotLight spotLight;\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tspotLight = spotLights[ i ];\r\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\tPointLight pointLight;\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tpointLight = pointLights[ i ];\r\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\r\n\r\n\t#endif\r\n\r\n\treturn shadow;\r\n\r\n}\r\n",skinbase_vertex:"#ifdef USE_SKINNING\r\n\r\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\r\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\r\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\r\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\r\n\r\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\r\n\r\n\tuniform mat4 bindMatrix;\r\n\tuniform mat4 bindMatrixInverse;\r\n\r\n\t#ifdef BONE_TEXTURE\r\n\r\n\t\tuniform sampler2D boneTexture;\r\n\t\tuniform int boneTextureSize;\r\n\r\n\t\tmat4 getBoneMatrix( const in float i ) {\r\n\r\n\t\t\tfloat j = i * 4.0;\r\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\r\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\r\n\r\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\r\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\r\n\r\n\t\t\ty = dy * ( y + 0.5 );\r\n\r\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\r\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\r\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\r\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\r\n\r\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\r\n\r\n\t\t\treturn bone;\r\n\r\n\t\t}\r\n\r\n\t#else\r\n\r\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\r\n\r\n\t\tmat4 getBoneMatrix( const in float i ) {\r\n\r\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\r\n\t\t\treturn bone;\r\n\r\n\t\t}\r\n\r\n\t#endif\r\n\r\n#endif\r\n",skinning_vertex:"#ifdef USE_SKINNING\r\n\r\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\r\n\r\n\tvec4 skinned = vec4( 0.0 );\r\n\tskinned += boneMatX * skinVertex * skinWeight.x;\r\n\tskinned += boneMatY * skinVertex * skinWeight.y;\r\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\r\n\tskinned += boneMatW * skinVertex * skinWeight.w;\r\n\r\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\r\n\r\n#endif\r\n",skinnormal_vertex:"#ifdef USE_SKINNING\r\n\r\n\tmat4 skinMatrix = mat4( 0.0 );\r\n\tskinMatrix += skinWeight.x * boneMatX;\r\n\tskinMatrix += skinWeight.y * boneMatY;\r\n\tskinMatrix += skinWeight.z * boneMatZ;\r\n\tskinMatrix += skinWeight.w * boneMatW;\r\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\r\n\r\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\r\n\r\n#endif\r\n",specularmap_fragment:"float specularStrength;\r\n\r\n#ifdef USE_SPECULARMAP\r\n\r\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\r\n\tspecularStrength = texelSpecular.r;\r\n\r\n#else\r\n\r\n\tspecularStrength = 1.0;\r\n\r\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\r\n\r\n\tuniform sampler2D specularMap;\r\n\r\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\r\n\r\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\r\n\r\n#endif\r\n",tonemapping_pars_fragment:"#define saturate(a) clamp( a, 0.0, 1.0 )\r\n\r\nuniform float toneMappingExposure;\r\nuniform float toneMappingWhitePoint;\r\n\r\n// exposure only\r\nvec3 LinearToneMapping( vec3 color ) {\r\n\r\n\treturn toneMappingExposure * color;\r\n\r\n}\r\n\r\n// source: https://www.cs.utah.edu/~reinhard/cdrom/\r\nvec3 ReinhardToneMapping( vec3 color ) {\r\n\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\r\nvec3 Uncharted2ToneMapping( vec3 color ) {\r\n\r\n\t// John Hable's filmic operator from Uncharted 2 video game\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\nvec3 OptimizedCineonToneMapping( vec3 color ) {\r\n\r\n\t// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson\r\n\tcolor *= toneMappingExposure;\r\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\r\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\r\n\r\n}\r\n",uv_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvarying vec2 vUv;\r\n\r\n#endif",uv_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvarying vec2 vUv;\r\n\tuniform vec4 offsetRepeat;\r\n\r\n#endif\r\n",uv_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\r\n\r\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tvarying vec2 vUv2;\r\n\r\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tattribute vec2 uv2;\r\n\tvarying vec2 vUv2;\r\n\r\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tvUv2 = uv2;\r\n\r\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\r\n\r\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\r\n\r\n#endif\r\n",cube_frag:"uniform samplerCube tCube;\r\nuniform float tFlip;\r\nuniform float opacity;\r\n\r\nvarying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\r\n\tgl_FragColor.a *= opacity;\r\n\r\n}\r\n",cube_vert:"varying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tvWorldPosition = transformDirection( position, modelMatrix );\r\n\r\n\t#include \r\n\t#include \r\n\r\n}\r\n",depth_frag:"#if DEPTH_PACKING == 3200\r\n\r\n\tuniform float opacity;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( 1.0 );\r\n\r\n\t#if DEPTH_PACKING == 3200\r\n\r\n\t\tdiffuseColor.a = opacity;\r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\r\n\t#if DEPTH_PACKING == 3200\r\n\r\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\r\n\r\n\t#elif DEPTH_PACKING == 3201\r\n\r\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\r\n\r\n\t#endif\r\n\r\n}\r\n",depth_vert:"#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\t#include \r\n\r\n\t#ifdef USE_DISPLACEMENTMAP\r\n\r\n\t\t#include \r\n\t\t#include \r\n\t\t#include \r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",distanceRGBA_frag:"uniform vec3 lightPos;\r\nvarying vec4 vWorldPosition;\r\n\r\n#include \r\n#include \r\n#include \r\n\r\nvoid main () {\r\n\r\n\t#include \r\n\r\n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\r\n\r\n}\r\n",distanceRGBA_vert:"varying vec4 vWorldPosition;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvWorldPosition = worldPosition;\r\n\r\n}\r\n",equirect_frag:"uniform sampler2D tEquirect;\r\nuniform float tFlip;\r\n\r\nvarying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\t// \tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\r\n\tvec3 direction = normalize( vWorldPosition );\r\n\tvec2 sampleUV;\r\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\r\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\r\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\r\n\r\n}\r\n",equirect_vert:"varying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tvWorldPosition = transformDirection( position, modelMatrix );\r\n\r\n\t#include \r\n\t#include \r\n\r\n}\r\n",linedashed_frag:"uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\nuniform float dashSize;\r\nuniform float totalSize;\r\n\r\nvarying float vLineDistance;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\r\n\r\n\t\tdiscard;\r\n\r\n\t}\r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb; // simple shader\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",linedashed_vert:"uniform float scale;\r\nattribute float lineDistance;\r\n\r\nvarying float vLineDistance;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvLineDistance = scale * lineDistance;\r\n\r\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\r\n\tgl_Position = projectionMatrix * mvPosition;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshbasic_frag:"uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\r\n\t// accumulation (baked indirect lighting only)\r\n\t#ifdef USE_LIGHTMAP\r\n\r\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\r\n\r\n\t#else\r\n\r\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\r\n\r\n\t#endif\r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\r\n\r\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\r\n\r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshbasic_vert:"#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_ENVMAP\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshlambert_frag:"uniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform float opacity;\r\n\r\nvarying vec3 vLightFront;\r\n\r\n#ifdef DOUBLE_SIDED\r\n\r\n\tvarying vec3 vLightBack;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\r\n\r\n\t#include \r\n\r\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\r\n\r\n\t#ifdef DOUBLE_SIDED\r\n\r\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\r\n\r\n\t#else\r\n\r\n\t\treflectedLight.directDiffuse = vLightFront;\r\n\r\n\t#endif\r\n\r\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\r\n\r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshlambert_vert:"#define LAMBERT\r\n\r\nvarying vec3 vLightFront;\r\n\r\n#ifdef DOUBLE_SIDED\r\n\r\n\tvarying vec3 vLightBack;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshphong_frag:"#define PHONG\r\n\r\nuniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform vec3 specular;\r\nuniform float shininess;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\t#include \r\n\t#include \r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\r\n\r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshphong_vert:"#define PHONG\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshphysical_frag:"#define PHYSICAL\r\n\r\nuniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform float roughness;\r\nuniform float metalness;\r\nuniform float opacity;\r\n\r\n#ifndef STANDARD\r\n\tuniform float clearCoat;\r\n\tuniform float clearCoatRoughness;\r\n#endif\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\t#include \r\n\t#include \r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",meshphysical_vert:"#define PHYSICAL\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",normal_frag:"#define NORMAL\r\n\r\nuniform float opacity;\r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvarying vec3 vViewPosition;\r\n\r\n#endif\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\r\n\r\n}\r\n",normal_vert:"#define NORMAL\r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvarying vec3 vViewPosition;\r\n\r\n#endif\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n#endif\r\n\r\n}\r\n",points_frag:"uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",points_vert:"uniform float size;\r\nuniform float scale;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_SIZEATTENUATION\r\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\r\n\t#else\r\n\t\tgl_PointSize = size;\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",shadow_frag:"uniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\r\n\r\n}\r\n",shadow_vert:"#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"},ih={basic:{uniforms:rh.merge([eh.common,eh.aomap,eh.lightmap,eh.fog]),vertexShader:nh.meshbasic_vert,fragmentShader:nh.meshbasic_frag},lambert:{uniforms:rh.merge([eh.common,eh.aomap,eh.lightmap,eh.emissivemap,eh.fog,eh.lights,{emissive:{value:new c(0)}}]),vertexShader:nh.meshlambert_vert,fragmentShader:nh.meshlambert_frag},phong:{uniforms:rh.merge([eh.common,eh.aomap,eh.lightmap,eh.emissivemap,eh.bumpmap,eh.normalmap,eh.displacementmap,eh.gradientmap,eh.fog,eh.lights,{emissive:{value:new c(0)},specular:{value:new c(1118481)},shininess:{value:30}}]),vertexShader:nh.meshphong_vert,fragmentShader:nh.meshphong_frag},standard:{uniforms:rh.merge([eh.common,eh.aomap,eh.lightmap,eh.emissivemap,eh.bumpmap,eh.normalmap,eh.displacementmap,eh.roughnessmap,eh.metalnessmap,eh.fog,eh.lights,{emissive:{value:new c(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:nh.meshphysical_vert,fragmentShader:nh.meshphysical_frag},points:{uniforms:rh.merge([eh.points,eh.fog]),vertexShader:nh.points_vert,fragmentShader:nh.points_frag},dashed:{uniforms:rh.merge([eh.common,eh.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:nh.linedashed_vert,fragmentShader:nh.linedashed_frag},depth:{uniforms:rh.merge([eh.common,eh.displacementmap]),vertexShader:nh.depth_vert,fragmentShader:nh.depth_frag},normal:{uniforms:rh.merge([eh.common,eh.bumpmap,eh.normalmap,eh.displacementmap,{opacity:{value:1}}]),vertexShader:nh.normal_vert,fragmentShader:nh.normal_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:nh.cube_vert,fragmentShader:nh.cube_frag},equirect:{uniforms:{tEquirect:{value:null},tFlip:{value:-1}},vertexShader:nh.equirect_vert,fragmentShader:nh.equirect_frag},distanceRGBA:{uniforms:{lightPos:{value:new n}},vertexShader:nh.distanceRGBA_vert,fragmentShader:nh.distanceRGBA_frag}};ih.physical={uniforms:rh.merge([ih.standard.uniforms,{clearCoat:{value:0},clearCoatRoughness:{value:0}}]),vertexShader:nh.meshphysical_vert,fragmentShader:nh.meshphysical_frag},Object.assign(et.prototype,{set:function(t,e){return this.min.copy(t),this.max.copy(e),this},setFromPoints:function(t){this.makeEmpty();for(var e=0,r=t.length;ethis.max.x||t.ythis.max.y)},containsBox:function(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y},getParameter:function(t,e){return(e||new h).set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(t){return!(t.max.xthis.max.x||t.max.ythis.max.y)},clampPoint:function(t,e){return(e||new h).copy(t).clamp(this.min,this.max)},distanceToPoint:function(){var t=new h;return function(e){return t.copy(e).clamp(this.min,this.max).sub(e).length()}}(),intersect:function(t){return this.min.max(t.min),this.max.min(t.max),this},union:function(t){return this.min.min(t.min),this.max.max(t.max),this},translate:function(t){return this.min.add(t),this.max.add(t),this},equals:function(t){return t.min.equals(this.min)&&t.max.equals(this.max)}});var ah=0;Object.assign(it.prototype,l.prototype,{isMaterial:!0,onBeforeCompile:function(){},setValues:function(t){if(void 0!==t)for(var e in t){var r=t[e];if(void 0!==r){var n=this[e];void 0!==n?n&&n.isColor?n.set(r):n&&n.isVector3&&r&&r.isVector3?n.copy(r):this[e]="overdraw"===e?Number(r):r:console.warn("THREE."+this.type+": '"+e+"' is not a property of this material.")}else console.warn("THREE.Material: '"+e+"' parameter is undefined.")}},toJSON:function(t){function e(t){var e=[];for(var r in t){var n=t[r];delete n.metadata,e.push(n)}return e}var r=void 0===t;r&&(t={textures:{},images:{}});var n={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearCoat&&(n.clearCoat=this.clearCoat),void 0!==this.clearCoatRoughness&&(n.clearCoatRoughness=this.clearCoatRoughness),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,n.reflectivity=this.reflectivity),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.size&&(n.size=this.size),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==ic&&(n.blending=this.blending),this.shading!==$s&&(n.shading=this.shading),this.side!==Zs&&(n.side=this.side),this.vertexColors!==tc&&(n.vertexColors=this.vertexColors),this.opacity<1&&(n.opacity=this.opacity),!0===this.transparent&&(n.transparent=this.transparent),n.depthFunc=this.depthFunc,n.depthTest=this.depthTest,n.depthWrite=this.depthWrite,this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=this.premultipliedAlpha),!0===this.wireframe&&(n.wireframe=this.wireframe),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),n.skinning=this.skinning,n.morphTargets=this.morphTargets,n.dithering=this.dithering,r){var i=e(t.textures),a=e(t.images);i.length>0&&(n.textures=i),a.length>0&&(n.images=a)}return n},clone:function(){return(new this.constructor).copy(this)},copy:function(t){this.name=t.name,this.fog=t.fog,this.lights=t.lights,this.blending=t.blending,this.side=t.side,this.shading=t.shading,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.premultipliedAlpha=t.premultipliedAlpha,this.overdraw=t.overdraw,this.visible=t.visible,this.clipShadows=t.clipShadows,this.clipIntersection=t.clipIntersection;var e=t.clippingPlanes,r=null;if(null!==e){var n=e.length;r=new Array(n);for(var i=0;i!==n;++i)r[i]=e[i].clone()}return this.clippingPlanes=r,this},dispose:function(){this.dispatchEvent({type:"dispose"})}}),at.prototype=Object.create(it.prototype),at.prototype.constructor=at,at.prototype.isShaderMaterial=!0,at.prototype.copy=function(t){return it.prototype.copy.call(this,t),this.fragmentShader=t.fragmentShader,this.vertexShader=t.vertexShader,this.uniforms=rh.clone(t.uniforms),this.defines=t.defines,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.lights=t.lights,this.clipping=t.clipping,this.skinning=t.skinning,this.morphTargets=t.morphTargets,this.morphNormals=t.morphNormals,this.extensions=t.extensions,this},at.prototype.toJSON=function(t){var e=it.prototype.toJSON.call(this,t);return e.uniforms=this.uniforms,e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e},ot.prototype=Object.create(it.prototype),ot.prototype.constructor=ot,ot.prototype.isMeshDepthMaterial=!0,ot.prototype.copy=function(t){return it.prototype.copy.call(this,t),this.depthPacking=t.depthPacking,this.skinning=t.skinning,this.morphTargets=t.morphTargets,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this},Object.assign(st.prototype,{isBox3:!0,set:function(t,e){return this.min.copy(t),this.max.copy(e),this},setFromArray:function(t){for(var e=1/0,r=1/0,n=1/0,i=-1/0,a=-1/0,o=-1/0,s=0,c=t.length;si&&(i=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(e,r,n),this.max.set(i,a,o),this},setFromBufferAttribute:function(t){for(var e=1/0,r=1/0,n=1/0,i=-1/0,a=-1/0,o=-1/0,s=0,c=t.count;si&&(i=l),h>a&&(a=h),u>o&&(o=u)}return this.min.set(e,r,n),this.max.set(i,a,o),this},setFromPoints:function(t){this.makeEmpty();for(var e=0,r=t.length;ethis.max.x||t.ythis.max.y||t.zthis.max.z)},containsBox:function(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z},getParameter:function(t,e){return(e||new n).set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(t){return!(t.max.xthis.max.x||t.max.ythis.max.y||t.max.zthis.max.z)},intersectsSphere:function(){var t=new n;return function(e){return this.clampPoint(e.center,t),t.distanceToSquared(e.center)<=e.radius*e.radius}}(),intersectsPlane:function(t){var e,r;return t.normal.x>0?(e=t.normal.x*this.min.x,r=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,r=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,r+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,r+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,r+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,r+=t.normal.z*this.min.z),e<=t.constant&&r>=t.constant},clampPoint:function(t,e){return(e||new n).copy(t).clamp(this.min,this.max)},distanceToPoint:function(){var t=new n;return function(e){return t.copy(e).clamp(this.min,this.max).sub(e).length()}}(),getBoundingSphere:function(){var t=new n;return function(e){var r=e||new ct;return this.getCenter(r.center),r.radius=.5*this.getSize(t).length(),r}}(),intersect:function(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this},union:function(t){return this.min.min(t.min),this.max.max(t.max),this},applyMatrix4:function(){var t=[new n,new n,new n,new n,new n,new n,new n,new n];return function(e){return this.isEmpty()?this:(t[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),t[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),t[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),t[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),t[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),t[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),t[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),t[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(t),this)}}(),translate:function(t){return this.min.add(t),this.max.add(t),this},equals:function(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}),Object.assign(ct.prototype,{set:function(t,e){return this.center.copy(t),this.radius=e,this},setFromPoints:function(){var t=new st;return function(e,r){var n=this.center;void 0!==r?n.copy(r):t.setFromPoints(e).getCenter(n);for(var i=0,a=0,o=e.length;athis.radius*this.radius&&(i.sub(this.center).normalize(),i.multiplyScalar(this.radius).add(this.center)),i},getBoundingBox:function(t){var e=t||new st;return e.set(this.center,this.center),e.expandByScalar(this.radius),e},applyMatrix4:function(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this},translate:function(t){return this.center.add(t),this},equals:function(t){return t.center.equals(this.center)&&t.radius===this.radius}}),Object.assign(lt.prototype,{isMatrix3:!0,set:function(t,e,r,n,i,a,o,s,c){var l=this.elements;return l[0]=t,l[1]=n,l[2]=o,l[3]=e,l[4]=i,l[5]=s,l[6]=r,l[7]=a,l[8]=c,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(t){var e=this.elements,r=t.elements;return e[0]=r[0],e[1]=r[1],e[2]=r[2],e[3]=r[3],e[4]=r[4],e[5]=r[5],e[6]=r[6],e[7]=r[7],e[8]=r[8],this},setFromMatrix4:function(t){var e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this},applyToBufferAttribute:function(){var t=new n;return function(e){for(var r=0,n=e.count;r1))return i.copy(a).multiplyScalar(s).add(e.start)}else if(0===this.distanceToPoint(e.start))return i.copy(e.start)}}(),intersectsLine:function(t){var e=this.distanceToPoint(t.start),r=this.distanceToPoint(t.end);return e<0&&r>0||r<0&&e>0},intersectsBox:function(t){return t.intersectsPlane(this)},intersectsSphere:function(t){return t.intersectsPlane(this)},coplanarPoint:function(t){return(t||new n).copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var t=new n,e=new lt;return function(r,n){var i=this.coplanarPoint(t).applyMatrix4(r),a=n||e.getNormalMatrix(r),o=this.normal.applyMatrix3(a).normalize();return this.constant=-i.dot(o),this}}(),translate:function(t){return this.constant=this.constant-t.dot(this.normal),this},equals:function(t){return t.normal.equals(this.normal)&&t.constant===this.constant}}),Object.assign(ut.prototype,{set:function(t,e,r,n,i,a){var o=this.planes;return o[0].copy(t),o[1].copy(e),o[2].copy(r),o[3].copy(n),o[4].copy(i),o[5].copy(a),this},clone:function(){return(new this.constructor).copy(this)},copy:function(t){for(var e=this.planes,r=0;r<6;r++)e[r].copy(t.planes[r]);return this},setFromMatrix:function(t){var e=this.planes,r=t.elements,n=r[0],i=r[1],a=r[2],o=r[3],s=r[4],c=r[5],l=r[6],h=r[7],u=r[8],d=r[9],p=r[10],f=r[11],m=r[12],g=r[13],v=r[14],y=r[15];return e[0].setComponents(o-n,h-s,f-u,y-m).normalize(),e[1].setComponents(o+n,h+s,f+u,y+m).normalize(),e[2].setComponents(o+i,h+c,f+d,y+g).normalize(),e[3].setComponents(o-i,h-c,f-d,y-g).normalize(),e[4].setComponents(o-a,h-l,f-p,y-v).normalize(),e[5].setComponents(o+a,h+l,f+p,y+v).normalize(),this},intersectsObject:function(){var t=new ct;return function(e){var r=e.geometry;return null===r.boundingSphere&&r.computeBoundingSphere(),t.copy(r.boundingSphere).applyMatrix4(e.matrixWorld),this.intersectsSphere(t)}}(),intersectsSprite:function(){var t=new ct;return function(e){return t.center.set(0,0,0),t.radius=.7071067811865476,t.applyMatrix4(e.matrixWorld),this.intersectsSphere(t)}}(),intersectsSphere:function(t){for(var e=this.planes,r=t.center,n=-t.radius,i=0;i<6;i++)if(e[i].distanceToPoint(r)0?r.min.x:r.max.x,e.x=a.normal.x>0?r.max.x:r.min.x,t.y=a.normal.y>0?r.min.y:r.max.y,e.y=a.normal.y>0?r.max.y:r.min.y,t.z=a.normal.z>0?r.min.z:r.max.z,e.z=a.normal.z>0?r.max.z:r.min.z;var o=a.distanceToPoint(t),s=a.distanceToPoint(e);if(o<0&&s<0)return!1}return!0}}(),containsPoint:function(t){for(var e=this.planes,r=0;r<6;r++)if(e[r].distanceToPoint(t)<0)return!1;return!0}}),ft.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"],ft.DefaultOrder="XYZ",Object.defineProperties(ft.prototype,{x:{get:function(){return this._x},set:function(t){this._x=t,this.onChangeCallback()}},y:{get:function(){return this._y},set:function(t){this._y=t,this.onChangeCallback()}},z:{get:function(){return this._z},set:function(t){this._z=t,this.onChangeCallback()}},order:{get:function(){return this._order},set:function(t){this._order=t,this.onChangeCallback()}}}),Object.assign(ft.prototype,{isEuler:!0,set:function(t,e,r,n){return this._x=t,this._y=e,this._z=r,this._order=n||this._order,this.onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this.onChangeCallback(),this},setFromRotationMatrix:function(t,e,r){var n=Ko.clamp,i=t.elements,a=i[0],o=i[4],s=i[8],c=i[1],l=i[5],h=i[9],u=i[2],d=i[6],p=i[10];return e=e||this._order,"XYZ"===e?(this._y=Math.asin(n(s,-1,1)),Math.abs(s)<.99999?(this._x=Math.atan2(-h,p),this._z=Math.atan2(-o,a)):(this._x=Math.atan2(d,l),this._z=0)):"YXZ"===e?(this._x=Math.asin(-n(h,-1,1)),Math.abs(h)<.99999?(this._y=Math.atan2(s,p),this._z=Math.atan2(c,l)):(this._y=Math.atan2(-u,a),this._z=0)):"ZXY"===e?(this._x=Math.asin(n(d,-1,1)),Math.abs(d)<.99999?(this._y=Math.atan2(-u,p),this._z=Math.atan2(-o,l)):(this._y=0,this._z=Math.atan2(c,a))):"ZYX"===e?(this._y=Math.asin(-n(u,-1,1)),Math.abs(u)<.99999?(this._x=Math.atan2(d,p),this._z=Math.atan2(c,a)):(this._x=0,this._z=Math.atan2(-o,l))):"YZX"===e?(this._z=Math.asin(n(c,-1,1)),Math.abs(c)<.99999?(this._x=Math.atan2(-h,l),this._y=Math.atan2(-u,a)):(this._x=0,this._y=Math.atan2(s,p))):"XZY"===e?(this._z=Math.asin(-n(o,-1,1)),Math.abs(o)<.99999?(this._x=Math.atan2(d,l),this._y=Math.atan2(s,a)):(this._x=Math.atan2(-h,p),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+e),this._order=e,!1!==r&&this.onChangeCallback(),this},setFromQuaternion:function(){var t=new e;return function(e,r,n){return t.makeRotationFromQuaternion(e),this.setFromRotationMatrix(t,r,n)}}(),setFromVector3:function(t,e){return this.set(t.x,t.y,t.z,e||this._order)},reorder:function(){var t=new r;return function(e){return t.setFromEuler(this),this.setFromQuaternion(t,e)}}(),equals:function(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order},fromArray:function(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this.onChangeCallback(),this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t},toVector3:function(t){return t?t.set(this._x,this._y,this._z):new n(this._x,this._y,this._z)},onChange:function(t){return this.onChangeCallback=t,this},onChangeCallback:function(){}}),Object.assign(mt.prototype,{set:function(t){this.mask=1<1){for(var e=0;e1){for(var e=0;e0){a.children=[];for(s=0;s0&&(i.geometries=l),h.length>0&&(i.materials=h),u.length>0&&(i.textures=u),d.length>0&&(i.images=d)}return i.object=a,i},clone:function(t){return(new this.constructor).copy(this,t)},copy:function(t,e){if(void 0===e&&(e=!0),this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(var r=0;r0)for(g=0;g0&&(this.normalsNeedUpdate=!0)},computeFlatVertexNormals:function(){var t,e,r;for(this.computeFaceNormals(),t=0,e=this.faces.length;t0&&(this.normalsNeedUpdate=!0)},computeMorphNormals:function(){var t,e,r,i,a;for(r=0,i=this.faces.length;r0&&(t+=e[r].distanceTo(e[r-1])),this.lineDistances[r]=t},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new st),this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new ct),this.boundingSphere.setFromPoints(this.vertices)},merge:function(t,e,r){if(!t||!t.isGeometry)return void console.error("THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.",t);var n,i=this.vertices.length,a=this.vertices,o=t.vertices,s=this.faces,c=t.faces,l=this.faceVertexUvs[0],h=t.faceVertexUvs[0],u=this.colors,d=t.colors;void 0===r&&(r=0),void 0!==e&&(n=(new lt).getNormalMatrix(e));for(var p=0,f=o.length;p=0;r--){var f=d[r];for(this.faces.splice(f,1),o=0,s=this.faceVertexUvs.length;o0,b=v.vertexNormals.length>0,w=1!==v.color.r||1!==v.color.g||1!==v.color.b,_=v.vertexColors.length>0,M=0;if(M=t(M,0,0),M=t(M,1,!0),M=t(M,2,!1),M=t(M,3,y),M=t(M,4,x),M=t(M,5,b),M=t(M,6,w),M=t(M,7,_),h.push(M),h.push(v.a,v.b,v.c),h.push(v.materialIndex),y){var E=this.faceVertexUvs[0][c];h.push(n(E[0]),n(E[1]),n(E[2]))}if(x&&h.push(e(v.normal)),b){var S=v.vertexNormals;h.push(e(S[0]),e(S[1]),e(S[2]))}if(w&&h.push(r(v.color)),_){var T=v.vertexColors;h.push(r(T[0]),r(T[1]),r(T[2]))}}return i.data={},i.data.vertices=s,i.data.normals=u,p.length>0&&(i.data.colors=p),m.length>0&&(i.data.uvs=[m]),i.data.faces=h,i},clone:function(){return(new _t).copy(this)},copy:function(t){var e,r,n,i,a,o;this.vertices=[],this.colors=[],this.faces=[],this.faceVertexUvs=[[]],this.morphTargets=[],this.morphNormals=[],this.skinWeights=[],this.skinIndices=[],this.lineDistances=[],this.boundingBox=null,this.boundingSphere=null,this.name=t.name;var s=t.vertices;for(e=0,r=s.length;e0,o=i[1]&&i[1].length>0,s=t.morphTargets,c=s.length;if(c>0){e=[];for(v=0;v0){l=[];for(v=0;v65535?St:Et)(t,1):this.index=t},addAttribute:function(t,e){return e&&e.isBufferAttribute||e&&e.isInterleavedBufferAttribute?"index"===t?(console.warn("THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute."),void this.setIndex(e)):(this.attributes[t]=e,this):(console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),void this.addAttribute(t,new Mt(arguments[1],arguments[2])))},getAttribute:function(t){return this.attributes[t]},removeAttribute:function(t){return delete this.attributes[t],this},addGroup:function(t,e,r){this.groups.push({start:t,count:e,materialIndex:void 0!==r?r:0})},clearGroups:function(){this.groups=[]},setDrawRange:function(t,e){this.drawRange.start=t,this.drawRange.count=e},applyMatrix:function(t){var e=this.attributes.position;void 0!==e&&(t.applyToBufferAttribute(e),e.needsUpdate=!0);var r=this.attributes.normal;return void 0!==r&&((new lt).getNormalMatrix(t).applyToBufferAttribute(r),r.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},rotateX:function(){var t=new e;return function(e){return t.makeRotationX(e),this.applyMatrix(t),this}}(),rotateY:function(){var t=new e;return function(e){return t.makeRotationY(e),this.applyMatrix(t),this}}(),rotateZ:function(){var t=new e;return function(e){return t.makeRotationZ(e),this.applyMatrix(t),this}}(),translate:function(){var t=new e;return function(e,r,n){return t.makeTranslation(e,r,n),this.applyMatrix(t),this}}(),scale:function(){var t=new e;return function(e,r,n){return t.makeScale(e,r,n),this.applyMatrix(t),this}}(),lookAt:function(){var t=new gt;return function(e){t.lookAt(e),t.updateMatrix(),this.applyMatrix(t.matrix)}}(),center:function(){this.computeBoundingBox();var t=this.boundingBox.getCenter().negate();return this.translate(t.x,t.y,t.z),t},setFromObject:function(t){var e=t.geometry;if(t.isPoints||t.isLine){var r=new Tt(3*e.vertices.length,3),n=new Tt(3*e.colors.length,3);if(this.addAttribute("position",r.copyVector3sArray(e.vertices)),this.addAttribute("color",n.copyColorsArray(e.colors)),e.lineDistances&&e.lineDistances.length===e.vertices.length){var i=new Tt(e.lineDistances.length,1);this.addAttribute("lineDistance",i.copyArray(e.lineDistances))}null!==e.boundingSphere&&(this.boundingSphere=e.boundingSphere.clone()),null!==e.boundingBox&&(this.boundingBox=e.boundingBox.clone())}else t.isMesh&&e&&e.isGeometry&&this.fromGeometry(e);return this},updateFromObject:function(t){var e=t.geometry;if(t.isMesh){var r=e.__directGeometry;if(!0===e.elementsNeedUpdate&&(r=void 0,e.elementsNeedUpdate=!1),void 0===r)return this.fromGeometry(e);r.verticesNeedUpdate=e.verticesNeedUpdate,r.normalsNeedUpdate=e.normalsNeedUpdate,r.colorsNeedUpdate=e.colorsNeedUpdate,r.uvsNeedUpdate=e.uvsNeedUpdate,r.groupsNeedUpdate=e.groupsNeedUpdate,e.verticesNeedUpdate=!1,e.normalsNeedUpdate=!1,e.colorsNeedUpdate=!1,e.uvsNeedUpdate=!1,e.groupsNeedUpdate=!1,e=r}var n;return!0===e.verticesNeedUpdate&&(void 0!==(n=this.attributes.position)&&(n.copyVector3sArray(e.vertices),n.needsUpdate=!0),e.verticesNeedUpdate=!1),!0===e.normalsNeedUpdate&&(void 0!==(n=this.attributes.normal)&&(n.copyVector3sArray(e.normals),n.needsUpdate=!0),e.normalsNeedUpdate=!1),!0===e.colorsNeedUpdate&&(void 0!==(n=this.attributes.color)&&(n.copyColorsArray(e.colors),n.needsUpdate=!0),e.colorsNeedUpdate=!1),e.uvsNeedUpdate&&(void 0!==(n=this.attributes.uv)&&(n.copyVector2sArray(e.uvs),n.needsUpdate=!0),e.uvsNeedUpdate=!1),e.lineDistancesNeedUpdate&&(void 0!==(n=this.attributes.lineDistance)&&(n.copyArray(e.lineDistances),n.needsUpdate=!0),e.lineDistancesNeedUpdate=!1),e.groupsNeedUpdate&&(e.computeGroups(t.geometry),this.groups=e.groups,e.groupsNeedUpdate=!1),this},fromGeometry:function(t){return t.__directGeometry=(new At).fromGeometry(t),this.fromDirectGeometry(t.__directGeometry)},fromDirectGeometry:function(t){var e=new Float32Array(3*t.vertices.length);if(this.addAttribute("position",new Mt(e,3).copyVector3sArray(t.vertices)),t.normals.length>0){var r=new Float32Array(3*t.normals.length);this.addAttribute("normal",new Mt(r,3).copyVector3sArray(t.normals))}if(t.colors.length>0){var n=new Float32Array(3*t.colors.length);this.addAttribute("color",new Mt(n,3).copyColorsArray(t.colors))}if(t.uvs.length>0){var i=new Float32Array(2*t.uvs.length);this.addAttribute("uv",new Mt(i,2).copyVector2sArray(t.uvs))}if(t.uvs2.length>0){var a=new Float32Array(2*t.uvs2.length);this.addAttribute("uv2",new Mt(a,2).copyVector2sArray(t.uvs2))}if(t.indices.length>0){var o=new(Lt(t.indices)>65535?Uint32Array:Uint16Array)(3*t.indices.length);this.setIndex(new Mt(o,1).copyIndicesArray(t.indices))}this.groups=t.groups;for(var s in t.morphTargets){for(var c=[],l=t.morphTargets[s],h=0,u=l.length;h0){var f=new Tt(4*t.skinIndices.length,4);this.addAttribute("skinIndex",f.copyVector4sArray(t.skinIndices))}if(t.skinWeights.length>0){var m=new Tt(4*t.skinWeights.length,4);this.addAttribute("skinWeight",m.copyVector4sArray(t.skinWeights))}return null!==t.boundingSphere&&(this.boundingSphere=t.boundingSphere.clone()),null!==t.boundingBox&&(this.boundingBox=t.boundingBox.clone()),this},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new st);var t=this.attributes.position;void 0!==t?this.boundingBox.setFromBufferAttribute(t):this.boundingBox.makeEmpty(),(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.',this)},computeBoundingSphere:function(){var t=new st,e=new n;return function(){null===this.boundingSphere&&(this.boundingSphere=new ct);var r=this.attributes.position;if(r){var n=this.boundingSphere.center;t.setFromBufferAttribute(r),t.getCenter(n);for(var i=0,a=0,o=r.count;a0&&(t.data.groups=JSON.parse(JSON.stringify(s)));var c=this.boundingSphere;return null!==c&&(t.data.boundingSphere={center:c.center.toArray(),radius:c.radius}),t},clone:function(){return(new Ct).copy(this)},copy:function(t){var e,r,n;this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.name=t.name;var i=t.index;null!==i&&this.setIndex(i.clone());var a=t.attributes;for(e in a){var o=a[e];this.addAttribute(e,o.clone())}var s=t.morphAttributes;for(e in s){var c=[],l=s[e];for(r=0,n=l.length;r0)if(s=d*f-p,c=d*p-f,h=u*g,s>=0)if(c>=-h)if(c<=h){var v=1/g;l=(s*=v)*(s+d*(c*=v)+2*p)+c*(d*s+c+2*f)+m}else c=u,l=-(s=Math.max(0,-(d*c+p)))*s+c*(c+2*f)+m;else c=-u,l=-(s=Math.max(0,-(d*c+p)))*s+c*(c+2*f)+m;else c<=-h?l=-(s=Math.max(0,-(-d*u+p)))*s+(c=s>0?-u:Math.min(Math.max(-u,-f),u))*(c+2*f)+m:c<=h?(s=0,l=(c=Math.min(Math.max(-u,-f),u))*(c+2*f)+m):l=-(s=Math.max(0,-(d*u+p)))*s+(c=s>0?u:Math.min(Math.max(-u,-f),u))*(c+2*f)+m;else c=d>0?-u:u,l=-(s=Math.max(0,-(d*c+p)))*s+c*(c+2*f)+m;return a&&a.copy(this.direction).multiplyScalar(s).add(this.origin),o&&o.copy(e).multiplyScalar(c).add(t),l}}(),intersectSphere:function(){var t=new n;return function(e,r){t.subVectors(e.center,this.origin);var n=t.dot(this.direction),i=t.dot(t)-n*n,a=e.radius*e.radius;if(i>a)return null;var o=Math.sqrt(a-i),s=n-o,c=n+o;return s<0&&c<0?null:s<0?this.at(c,r):this.at(s,r)}}(),intersectsSphere:function(t){return this.distanceToPoint(t.center)<=t.radius},distanceToPlane:function(t){var e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;var r=-(this.origin.dot(t.normal)+t.constant)/e;return r>=0?r:null},intersectPlane:function(t,e){var r=this.distanceToPlane(t);return null===r?null:this.at(r,e)},intersectsPlane:function(t){var e=t.distanceToPoint(this.origin);return 0===e||t.normal.dot(this.direction)*e<0},intersectBox:function(t,e){var r,n,i,a,o,s,c=1/this.direction.x,l=1/this.direction.y,h=1/this.direction.z,u=this.origin;return c>=0?(r=(t.min.x-u.x)*c,n=(t.max.x-u.x)*c):(r=(t.max.x-u.x)*c,n=(t.min.x-u.x)*c),l>=0?(i=(t.min.y-u.y)*l,a=(t.max.y-u.y)*l):(i=(t.max.y-u.y)*l,a=(t.min.y-u.y)*l),r>a||i>n?null:((i>r||r!==r)&&(r=i),(a=0?(o=(t.min.z-u.z)*h,s=(t.max.z-u.z)*h):(o=(t.max.z-u.z)*h,s=(t.min.z-u.z)*h),r>s||o>n?null:((o>r||r!==r)&&(r=o),(s=0?r:n,e)))},intersectsBox:function(){var t=new n;return function(e){return null!==this.intersectBox(e,t)}}(),intersectTriangle:function(){var t=new n,e=new n,r=new n,i=new n;return function(n,a,o,s,c){e.subVectors(a,n),r.subVectors(o,n),i.crossVectors(e,r);var l,h=this.direction.dot(i);if(h>0){if(s)return null;l=1}else{if(!(h<0))return null;l=-1,h=-h}t.subVectors(this.origin,n);var u=l*this.direction.dot(r.crossVectors(t,r));if(u<0)return null;var d=l*this.direction.dot(e.cross(t));if(d<0)return null;if(u+d>h)return null;var p=-l*t.dot(i);return p<0?null:this.at(p/h,c)}}(),applyMatrix4:function(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this},equals:function(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}}),Object.assign(Ut.prototype,{set:function(t,e){return this.start.copy(t),this.end.copy(e),this},clone:function(){return(new this.constructor).copy(this)},copy:function(t){return this.start.copy(t.start),this.end.copy(t.end),this},getCenter:function(t){return(t||new n).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(t){return(t||new n).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(t,e){var r=e||new n;return this.delta(r).multiplyScalar(t).add(this.start)},closestPointToPointParameter:function(){var t=new n,e=new n;return function(r,n){t.subVectors(r,this.start),e.subVectors(this.end,this.start);var i=e.dot(e),a=e.dot(t)/i;return n&&(a=Ko.clamp(a,0,1)),a}}(),closestPointToPoint:function(t,e,r){var i=this.closestPointToPointParameter(t,e),a=r||new n;return this.delta(a).multiplyScalar(i).add(this.start)},applyMatrix4:function(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this},equals:function(t){return t.start.equals(this.start)&&t.end.equals(this.end)}}),Object.assign(zt,{normal:function(){var t=new n;return function(e,r,i,a){var o=a||new n;o.subVectors(i,r),t.subVectors(e,r),o.cross(t);var s=o.lengthSq();return s>0?o.multiplyScalar(1/Math.sqrt(s)):o.set(0,0,0)}}(),barycoordFromPoint:function(){var t=new n,e=new n,r=new n;return function(i,a,o,s,c){t.subVectors(s,a),e.subVectors(o,a),r.subVectors(i,a);var l=t.dot(t),h=t.dot(e),u=t.dot(r),d=e.dot(e),p=e.dot(r),f=l*d-h*h,m=c||new n;if(0===f)return m.set(-2,-1,-1);var g=1/f,v=(d*u-h*p)*g,y=(l*p-h*u)*g;return m.set(1-v-y,y,v)}}(),containsPoint:function(){var t=new n;return function(e,r,n,i){var a=zt.barycoordFromPoint(e,r,n,i,t);return a.x>=0&&a.y>=0&&a.x+a.y<=1}}()}),Object.assign(zt.prototype,{set:function(t,e,r){return this.a.copy(t),this.b.copy(e),this.c.copy(r),this},setFromPointsAndIndices:function(t,e,r,n){return this.a.copy(t[e]),this.b.copy(t[r]),this.c.copy(t[n]),this},clone:function(){return(new this.constructor).copy(this)},copy:function(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this},area:function(){var t=new n,e=new n;return function(){return t.subVectors(this.c,this.b),e.subVectors(this.a,this.b),.5*t.cross(e).length()}}(),midpoint:function(t){return(t||new n).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(t){return zt.normal(this.a,this.b,this.c,t)},plane:function(t){return(t||new ht).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(t,e){return zt.barycoordFromPoint(t,this.a,this.b,this.c,e)},containsPoint:function(t){return zt.containsPoint(t,this.a,this.b,this.c)},closestPointToPoint:function(){var t=new ht,e=[new Ut,new Ut,new Ut],r=new n,i=new n;return function(a,o){var s=o||new n,c=1/0;if(t.setFromCoplanarPoints(this.a,this.b,this.c),t.projectPoint(a,r),!0===this.containsPoint(r))s.copy(r);else{e[0].set(this.a,this.b),e[1].set(this.b,this.c),e[2].set(this.c,this.a);for(var l=0;l0){var o=i[a[0]];if(void 0!==o)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},t=0,e=o.length;t0)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},t=0,e=s.length;te.far?null:{distance:c,point:b.clone(),object:t}}function i(e,n,i,a,o,s,h,d){c.fromBufferAttribute(a,s),l.fromBufferAttribute(a,h),u.fromBufferAttribute(a,d);var p=r(e,n,i,c,l,u,x);return p&&(o&&(m.fromBufferAttribute(o,s),g.fromBufferAttribute(o,h),v.fromBufferAttribute(o,d),p.uv=t(x,c,l,u,m,g,v)),p.face=new bt(s,h,d,zt.normal(c,l,u)),p.faceIndex=s),p}var a=new e,o=new Dt,s=new ct,c=new n,l=new n,u=new n,d=new n,p=new n,f=new n,m=new h,g=new h,v=new h,y=new n,x=new n,b=new n;return function(e,n){var h=this.geometry,y=this.material,b=this.matrixWorld;if(void 0!==y&&(null===h.boundingSphere&&h.computeBoundingSphere(),s.copy(h.boundingSphere),s.applyMatrix4(b),!1!==e.ray.intersectsSphere(s)&&(a.getInverse(b),o.copy(e.ray).applyMatrix4(a),null===h.boundingBox||!1!==o.intersectsBox(h.boundingBox)))){var w;if(h.isBufferGeometry){var _,M,E,S,T,A=h.index,L=h.attributes.position,C=h.attributes.uv;if(null!==A)for(S=0,T=A.count;S0&&(O=z);for(var B=0,F=U.length;Ba)){var o=n.ray.origin.distanceTo(t);on.far||i.push({distance:o,point:t.clone(),face:null,object:this})}}}(),clone:function(){return new this.constructor(this.material).copy(this)}}),Se.prototype=Object.assign(Object.create(gt.prototype),{constructor:Se,copy:function(t){gt.prototype.copy.call(this,t,!1);for(var e=t.levels,r=0,n=e.length;r1){t.setFromMatrixPosition(r.matrixWorld),e.setFromMatrixPosition(this.matrixWorld);var i=t.distanceTo(e);n[0].object.visible=!0;for(var a=1,o=n.length;a=n[a].distance;a++)n[a-1].object.visible=!1,n[a].object.visible=!0;for(;as||(p.applyMatrix4(this.matrixWorld),(S=e.ray.origin.distanceTo(p))e.far||a.push({distance:S,point:d.clone().applyMatrix4(this.matrixWorld),index:y,face:null,faceIndex:null,object:this}))}else for(var y=0,x=g.length/3-1;ys||(p.applyMatrix4(this.matrixWorld),(S=e.ray.origin.distanceTo(p))e.far||a.push({distance:S,point:d.clone().applyMatrix4(this.matrixWorld),index:y,face:null,faceIndex:null,object:this}))}else if(c.isGeometry)for(var _=c.vertices,M=_.length,y=0;ys)){p.applyMatrix4(this.matrixWorld);var S=e.ray.origin.distanceTo(p);Se.far||a.push({distance:S,point:d.clone().applyMatrix4(this.matrixWorld),index:y,face:null,faceIndex:null,object:this})}}}}}(),clone:function(){return new this.constructor(this.geometry,this.material).copy(this)}}),Pe.prototype=Object.assign(Object.create(Re.prototype),{constructor:Pe,isLineSegments:!0}),Ie.prototype=Object.assign(Object.create(Re.prototype),{constructor:Ie,isLineLoop:!0}),Oe.prototype=Object.create(it.prototype),Oe.prototype.constructor=Oe,Oe.prototype.isPointsMaterial=!0,Oe.prototype.copy=function(t){return it.prototype.copy.call(this,t),this.color.copy(t.color),this.map=t.map,this.size=t.size,this.sizeAttenuation=t.sizeAttenuation,this},Ne.prototype=Object.assign(Object.create(gt.prototype),{constructor:Ne,isPoints:!0,raycast:function(){var t=new e,r=new Dt,i=new ct;return function(e,a){function o(t,n){var i=r.distanceSqToPoint(t);if(ie.far)return;a.push({distance:c,distanceToRay:Math.sqrt(i),point:o.clone(),index:n,face:null,object:s})}}var s=this,c=this.geometry,l=this.matrixWorld,h=e.params.Points.threshold;if(null===c.boundingSphere&&c.computeBoundingSphere(),i.copy(c.boundingSphere),i.applyMatrix4(l),i.radius+=h,!1!==e.ray.intersectsSphere(i)){t.getInverse(l),r.copy(e.ray).applyMatrix4(t);var u=h/((this.scale.x+this.scale.y+this.scale.z)/3),d=u*u,p=new n;if(c.isBufferGeometry){var f=c.index,m=c.attributes.position.array;if(null!==f)for(var g=f.array,v=0,y=g.length;v=-Number.EPSILON&&L>=-Number.EPSILON&&A>=-Number.EPSILON))return!1;return!0}return function(e,r){var n=e.length;if(n<3)return null;var i,a,o,s=[],c=[],l=[];if(lh.area(e)>0)for(a=0;a2;){if(u--<=0)return console.warn("THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()"),r?l:s;if(i=a,h<=i&&(i=0),a=i+1,h<=a&&(a=0),o=a+1,h<=o&&(o=0),t(e,i,a,o,h,c)){var d,p,f,m,g;for(d=c[i],p=c[a],f=c[o],s.push([e[d],e[p],e[f]]),l.push([c[i],c[a],c[o]]),m=a,g=a+1;g2&&t[e-1].equals(t[0])&&t.pop()}function n(t,e,r){return t.x!==e.x?t.xNumber.EPSILON){var f;if(d>0){if(p<0||p>d)return[];if((f=l*h-c*u)<0||f>d)return[]}else{if(p>0||p0||fS?[]:b===S?a?[]:[y]:w<=S?[y,x]:[y,M]}function a(t,e,r,n){var i=e.x-t.x,a=e.y-t.y,o=r.x-t.x,s=r.y-t.y,c=n.x-t.x,l=n.y-t.y,h=i*s-a*o,u=i*l-a*c;if(Math.abs(h)>Number.EPSILON){var d=c*s-l*o;return h>0?u>=0&&d>=0:u>=0||d>=0}return u>0}r(t),e.forEach(r);for(var o,s,c,l,h,u,d={},p=t.concat(),f=0,m=e.length;f0;){if(--w<0){console.log("Infinite Loop! Holes left:"+g.length+", Probably Hole outside Shape!");break}for(o=b;on&&(o=0);var s=a(m[t],m[i],m[o],r[e]);if(!s)return!1;var c=r.length-1,l=e-1;l<0&&(l=c);var h=e+1;return h>c&&(h=0),!!(s=a(r[e],r[l],r[h],m[t]))}(o,_)&&!function(t,e){var r,n;for(r=0;r0)return!0;return!1}(s,c)&&!function(t,r){var n,a,o,s;for(n=0;n0)return!0;return!1}(s,c)){n=_,g.splice(y,1),u=m.slice(0,o+1),d=m.slice(o),p=r.slice(n),f=r.slice(0,n+1),m=u.concat(p).concat(f).concat(d),b=o;break}if(n>=0)break;v[h]=!0}if(n>=0)break}}return m}(t,e),v=lh.triangulate(g,!1);for(o=0,s=v.length;oNumber.EPSILON){var p=Math.sqrt(u),f=Math.sqrt(c*c+l*l),m=e.x-s/p,g=e.y+o/p,v=((r.x-l/f-m)*l-(r.y+c/f-g)*c)/(o*l-s*c),y=(n=m+o*v-t.x)*n+(i=g+s*v-t.y)*i;if(y<=2)return new h(n,i);a=Math.sqrt(y/2)}else{var x=!1;o>Number.EPSILON?c>Number.EPSILON&&(x=!0):o<-Number.EPSILON?c<-Number.EPSILON&&(x=!0):Math.sign(s)===Math.sign(l)&&(x=!0),x?(n=-s,i=o,a=Math.sqrt(u)):(n=o,i=s,a=Math.sqrt(u/2))}return new h(n/a,i/a)}function a(t,e){var r,n;for(J=t.length;--J>=0;){r=J,(n=J-1)<0&&(n=t.length-1);var i=0,a=L+2*S;for(i=0;i=0;G--){for(H=G/S,j=M*Math.cos(H*Math.PI/2),V=E*Math.sin(H*Math.PI/2),J=0,Q=k.length;J0||0===t.search(/^data\:image\/jpeg/);a.format=r?gl:vl,a.needsUpdate=!0,void 0!==e&&e(a)},r,n),a},setCrossOrigin:function(t){return this.crossOrigin=t,this},setPath:function(t){return this.path=t,this}}),Br.prototype=Object.assign(Object.create(gt.prototype),{constructor:Br,isLight:!0,copy:function(t){return gt.prototype.copy.call(this,t),this.color.copy(t.color),this.intensity=t.intensity,this},toJSON:function(t){var e=gt.prototype.toJSON.call(this,t);return e.object.color=this.color.getHex(),e.object.intensity=this.intensity,void 0!==this.groundColor&&(e.object.groundColor=this.groundColor.getHex()),void 0!==this.distance&&(e.object.distance=this.distance),void 0!==this.angle&&(e.object.angle=this.angle),void 0!==this.decay&&(e.object.decay=this.decay),void 0!==this.penumbra&&(e.object.penumbra=this.penumbra),void 0!==this.shadow&&(e.object.shadow=this.shadow.toJSON()),e}}),Fr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Fr,isHemisphereLight:!0,copy:function(t){return Br.prototype.copy.call(this,t),this.groundColor.copy(t.groundColor),this}}),Object.assign(kr.prototype,{copy:function(t){return this.camera=t.camera.clone(),this.bias=t.bias,this.radius=t.radius,this.mapSize.copy(t.mapSize),this},clone:function(){return(new this.constructor).copy(this)},toJSON:function(){var t={};return 0!==this.bias&&(t.bias=this.bias),1!==this.radius&&(t.radius=this.radius),512===this.mapSize.x&&512===this.mapSize.y||(t.mapSize=this.mapSize.toArray()),t.camera=this.camera.toJSON(!1).object,delete t.camera.matrix,t}}),Gr.prototype=Object.assign(Object.create(kr.prototype),{constructor:Gr,isSpotLightShadow:!0,update:function(t){var e=this.camera,r=2*Ko.RAD2DEG*t.angle,n=this.mapSize.width/this.mapSize.height,i=t.distance||e.far;r===e.fov&&n===e.aspect&&i===e.far||(e.fov=r,e.aspect=n,e.far=i,e.updateProjectionMatrix())}}),Vr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Vr,isSpotLight:!0,copy:function(t){return Br.prototype.copy.call(this,t),this.distance=t.distance,this.angle=t.angle,this.penumbra=t.penumbra,this.decay=t.decay,this.target=t.target.clone(),this.shadow=t.shadow.clone(),this}}),Hr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Hr,isPointLight:!0,copy:function(t){return Br.prototype.copy.call(this,t),this.distance=t.distance,this.decay=t.decay,this.shadow=t.shadow.clone(),this}}),jr.prototype=Object.assign(Object.create(kr.prototype),{constructor:jr}),Wr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Wr,isDirectionalLight:!0,copy:function(t){return Br.prototype.copy.call(this,t),this.target=t.target.clone(),this.shadow=t.shadow.clone(),this}}),Xr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Xr,isAmbientLight:!0}),Yr.prototype=Object.assign(Object.create(Br.prototype),{constructor:Yr,isRectAreaLight:!0,copy:function(t){return Br.prototype.copy.call(this,t),this.width=t.width,this.height=t.height,this},toJSON:function(t){var e=Br.prototype.toJSON.call(this,t);return e.object.width=this.width,e.object.height=this.height,e}});var fh={arraySlice:function(t,e,r){return fh.isTypedArray(t)?new t.constructor(t.subarray(e,void 0!==r?r:t.length)):t.slice(e,r)},convertArray:function(t,e,r){return!t||!r&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)},isTypedArray:function(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)},getKeyframeOrder:function(t){function e(e,r){return t[e]-t[r]}for(var r=t.length,n=new Array(r),i=0;i!==r;++i)n[i]=i;return n.sort(e),n},sortedArray:function(t,e,r){for(var n=t.length,i=new t.constructor(n),a=0,o=0;o!==n;++a)for(var s=r[a]*e,c=0;c!==e;++c)i[o++]=t[s+c];return i},flattenJSON:function(t,e,r,n){for(var i=1,a=t[0];void 0!==a&&void 0===a[n];)a=t[i++];if(void 0!==a){var o=a[n];if(void 0!==o)if(Array.isArray(o))do{void 0!==(o=a[n])&&(e.push(a.time),r.push.apply(r,o)),a=t[i++]}while(void 0!==a);else if(void 0!==o.toArray)do{void 0!==(o=a[n])&&(e.push(a.time),o.toArray(r,r.length)),a=t[i++]}while(void 0!==a);else do{void 0!==(o=a[n])&&(e.push(a.time),r.push(o)),a=t[i++]}while(void 0!==a)}}};Object.assign(qr.prototype,{evaluate:function(t){var e=this.parameterPositions,r=this._cachedIndex,n=e[r],i=e[r-1];t:{e:{var a;r:{n:if(!(t=i)break t;var o=e[1];t=i)break e}a=r,r=0}}for(;r>>1;te;)--a;if(++a,0!==i||a!==n){i>=a&&(a=Math.max(a,1),i=a-1);var o=this.getValueSize();this.times=fh.arraySlice(r,i,a),this.values=fh.arraySlice(this.values,i*o,a*o)}return this},validate:function(){var t=!0,e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrackPrototype: Invalid value size in track.",this),t=!1);var r=this.times,n=this.values,i=r.length;0===i&&(console.error("THREE.KeyframeTrackPrototype: Track is empty.",this),t=!1);for(var a=null,o=0;o!==i;o++){var s=r[o];if("number"==typeof s&&isNaN(s)){console.error("THREE.KeyframeTrackPrototype: Time is not a valid number.",this,o,s),t=!1;break}if(null!==a&&a>s){console.error("THREE.KeyframeTrackPrototype: Out of order keys.",this,o,s,a),t=!1;break}a=s}if(void 0!==n&&fh.isTypedArray(n))for(var o=0,c=n.length;o!==c;++o){var l=n[o];if(isNaN(l)){console.error("THREE.KeyframeTrackPrototype: Value is not a valid number.",this,o,l),t=!1;break}}return t},optimize:function(){for(var t=this.times,e=this.values,r=this.getValueSize(),n=2302===this.getInterpolation(),i=1,a=t.length-1,o=1;o0){t[i]=t[a];for(var f=a*r,m=i*r,d=0;d!==r;++d)e[m+d]=e[f+d];++i}return i!==t.length&&(this.times=fh.arraySlice(t,0,i),this.values=fh.arraySlice(e,0,i*r)),this}},$r.prototype=Object.assign(Object.create(mh),{constructor:$r,ValueTypeName:"vector"}),tn.prototype=Object.assign(Object.create(qr.prototype),{constructor:tn,interpolate_:function(t,e,n,i){for(var a=this.resultBuffer,o=this.sampleValues,s=this.valueSize,c=t*s,l=(n-e)/(i-e),h=c+s;c!==h;c+=4)r.slerpFlat(a,0,o,c-s,o,c,l);return a}}),en.prototype=Object.assign(Object.create(mh),{constructor:en,ValueTypeName:"quaternion",DefaultInterpolation:2301,InterpolantFactoryMethodLinear:function(t){return new tn(this.times,this.values,this.getValueSize(),t)},InterpolantFactoryMethodSmooth:void 0}),rn.prototype=Object.assign(Object.create(mh),{constructor:rn,ValueTypeName:"number"}),nn.prototype=Object.assign(Object.create(mh),{constructor:nn,ValueTypeName:"string",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),an.prototype=Object.assign(Object.create(mh),{constructor:an,ValueTypeName:"bool",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0}),on.prototype=Object.assign(Object.create(mh),{constructor:on,ValueTypeName:"color"}),sn.prototype=mh,mh.constructor=sn,Object.assign(sn,{parse:function(t){if(void 0===t.type)throw new Error("track type undefined, can not parse");var e=sn._getTrackTypeForValueTypeName(t.type);if(void 0===t.times){var r=[],n=[];fh.flattenJSON(t.keys,r,n,"value"),t.times=r,t.values=n}return void 0!==e.parse?e.parse(t):new e(t.name,t.times,t.values,t.interpolation)},toJSON:function(t){var e,r=t.constructor;if(void 0!==r.toJSON)e=r.toJSON(t);else{e={name:t.name,times:fh.convertArray(t.times,Array),values:fh.convertArray(t.values,Array)};var n=t.getInterpolation();n!==t.DefaultInterpolation&&(e.interpolation=n)}return e.type=t.ValueTypeName,e},_getTrackTypeForValueTypeName:function(t){switch(t.toLowerCase()){case"scalar":case"double":case"float":case"number":case"integer":return rn;case"vector":case"vector2":case"vector3":case"vector4":return $r;case"color":return on;case"quaternion":return en;case"bool":case"boolean":return an;case"string":return nn}throw new Error("Unsupported typeName: "+t)}}),Object.assign(cn,{parse:function(t){for(var e=[],r=t.tracks,n=1/(t.fps||1),i=0,a=r.length;i!==a;++i)e.push(sn.parse(r[i]).scale(n));return new cn(t.name,t.duration,e)},toJSON:function(t){for(var e=[],r=t.tracks,n={name:t.name,duration:t.duration,tracks:e},i=0,a=r.length;i!==a;++i)e.push(sn.toJSON(r[i]));return n},CreateFromMorphTargetSequence:function(t,e,r,n){for(var i=e.length,a=[],o=0;o1){var c=n[h=s[1]];c||(n[h]=c=[]),c.push(o)}}var l=[];for(var h in n)l.push(cn.CreateFromMorphTargetSequence(h,n[h],e,r));return l},parseAnimation:function(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;for(var r=function(t,e,r,n,i){if(0!==r.length){var a=[],o=[];fh.flattenJSON(r,a,o,n),0!==a.length&&i.push(new t(e,a,o))}},n=[],i=t.name||"default",a=t.length||-1,o=t.fps||30,s=t.hierarchy||[],c=0;c1?t.skinWeights[n+1]:0,s=r>2?t.skinWeights[n+2]:0,c=r>3?t.skinWeights[n+3]:0;e.skinWeights.push(new y(a,o,s,c))}if(t.skinIndices)for(var n=0,i=t.skinIndices.length;n1?t.skinIndices[n+1]:0,u=r>2?t.skinIndices[n+2]:0,d=r>3?t.skinIndices[n+3]:0;e.skinIndices.push(new y(l,h,u,d))}e.bones=t.bones,e.bones&&e.bones.length>0&&(e.skinWeights.length!==e.skinIndices.length||e.skinIndices.length!==e.vertices.length)&&console.warn("When skinning, number of vertices ("+e.vertices.length+"), skinIndices ("+e.skinIndices.length+"), and skinWeights ("+e.skinWeights.length+") should match.")}function r(t,e){var r=t.scale;if(void 0!==t.morphTargets)for(var i=0,a=t.morphTargets.length;i0){console.warn('THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.');for(var u=e.faces,d=t.morphColors[0].colors,i=0,a=u.length;i0&&(e.animations=r)}return function(n,a){void 0!==n.data&&(n=n.data),void 0!==n.scale?n.scale=1/n.scale:n.scale=1;var o=new _t;return t(n,o),e(n,o),r(n,o),i(n,o),o.computeFaceNormals(),o.computeBoundingSphere(),void 0===n.materials||0===n.materials.length?{geometry:o}:{geometry:o,materials:un.prototype.initMaterials(n.materials,a,this.crossOrigin)}}}()}),Object.assign(pn.prototype,{load:function(t,e,r,n){""===this.texturePath&&(this.texturePath=t.substring(0,t.lastIndexOf("/")+1));var i=this;new Ir(i.manager).load(t,function(r){var a=null;try{a=JSON.parse(r)}catch(e){return void 0!==n&&n(e),void console.error("THREE:ObjectLoader: Can't parse "+t+".",e.message)}var o=a.metadata;if(void 0===o||void 0===o.type||"geometry"===o.type.toLowerCase())return void console.error("THREE.ObjectLoader: Can't load "+t+". Use THREE.JSONLoader instead.");i.parse(a,e)},r,n)},setTexturePath:function(t){this.texturePath=t},setCrossOrigin:function(t){this.crossOrigin=t},parse:function(t,e){var r=this.parseGeometries(t.geometries),n=this.parseImages(t.images,function(){void 0!==e&&e(o)}),i=this.parseTextures(t.textures,n),a=this.parseMaterials(t.materials,i),o=this.parseObject(t.object,r,a);return t.animations&&(o.animations=this.parseAnimations(t.animations)),void 0!==t.images&&0!==t.images.length||void 0!==e&&e(o),o},parseGeometries:function(t){var e={};if(void 0!==t)for(var r=new dn,n=new hn,i=0,a=t.length;i0){var i=new Dr(new Pr(e));i.setCrossOrigin(this.crossOrigin);for(var a=0,o=t.length;a0?new Le(s,l):new Bt(s,l);break;case"LOD":o=new Se;break;case"Line":o=new Re(i(e.geometry),a(e.material),e.mode);break;case"LineLoop":o=new Ie(i(e.geometry),a(e.material));break;case"LineSegments":o=new Pe(i(e.geometry),a(e.material));break;case"PointCloud":case"Points":o=new Ne(i(e.geometry),a(e.material));break;case"Sprite":o=new Ee(a(e.material));break;case"Group":o=new De;break;default:o=new gt}if(o.uuid=e.uuid,void 0!==e.name&&(o.name=e.name),void 0!==e.matrix?(t.fromArray(e.matrix),t.decompose(o.position,o.quaternion,o.scale)):(void 0!==e.position&&o.position.fromArray(e.position),void 0!==e.rotation&&o.rotation.fromArray(e.rotation),void 0!==e.quaternion&&o.quaternion.fromArray(e.quaternion),void 0!==e.scale&&o.scale.fromArray(e.scale)),void 0!==e.castShadow&&(o.castShadow=e.castShadow),void 0!==e.receiveShadow&&(o.receiveShadow=e.receiveShadow),e.shadow&&(void 0!==e.shadow.bias&&(o.shadow.bias=e.shadow.bias),void 0!==e.shadow.radius&&(o.shadow.radius=e.shadow.radius),void 0!==e.shadow.mapSize&&o.shadow.mapSize.fromArray(e.shadow.mapSize),void 0!==e.shadow.camera&&(o.shadow.camera=this.parseObject(e.shadow.camera))),void 0!==e.visible&&(o.visible=e.visible),void 0!==e.userData&&(o.userData=e.userData),void 0!==e.children)for(var h in e.children)o.add(this.parseObject(e.children[h],r,n));if("LOD"===e.type)for(var u=e.levels,d=0;d0)){c=i;break}c=i-1}if(i=c,n[i]===r)return i/(a-1);var l=n[i];return(i+(r-l)/(n[i+1]-l))/(a-1)},getTangent:function(t){var e=t-1e-4,r=t+1e-4;e<0&&(e=0),r>1&&(r=1);var n=this.getPoint(e);return this.getPoint(r).clone().sub(n).normalize()},getTangentAt:function(t){var e=this.getUtoTmapping(t);return this.getTangent(e)},computeFrenetFrames:function(t,r){var i,a,o,s=new n,c=[],l=[],h=[],u=new n,d=new e;for(i=0;i<=t;i++)a=i/t,c[i]=this.getTangentAt(a),c[i].normalize();l[0]=new n,h[0]=new n;var p=Number.MAX_VALUE,f=Math.abs(c[0].x),m=Math.abs(c[0].y),g=Math.abs(c[0].z);for(f<=p&&(p=f,s.set(1,0,0)),m<=p&&(p=m,s.set(0,1,0)),g<=p&&s.set(0,0,1),u.crossVectors(c[0],s).normalize(),l[0].crossVectors(c[0],u),h[0].crossVectors(c[0],l[0]),i=1;i<=t;i++)l[i]=l[i-1].clone(),h[i]=h[i-1].clone(),u.crossVectors(c[i-1],c[i]),u.length()>Number.EPSILON&&(u.normalize(),o=Math.acos(Ko.clamp(c[i-1].dot(c[i]),-1,1)),l[i].applyMatrix4(d.makeRotationAxis(u,o))),h[i].crossVectors(c[i],l[i]);if(!0===r)for(o=Math.acos(Ko.clamp(l[0].dot(l[t]),-1,1)),o/=t,c[0].dot(u.crossVectors(l[0],l[t]))>0&&(o=-o),i=1;i<=t;i++)l[i].applyMatrix4(d.makeRotationAxis(c[i],o*i)),h[i].crossVectors(c[i],l[i]);return{tangents:c,normals:l,binormals:h}}}),Sn.prototype=Object.create(En.prototype),Sn.prototype.constructor=Sn,Sn.prototype.isLineCurve=!0,Sn.prototype.getPoint=function(t){if(1===t)return this.v2.clone();var e=this.v2.clone().sub(this.v1);return e.multiplyScalar(t).add(this.v1),e},Sn.prototype.getPointAt=function(t){return this.getPoint(t)},Sn.prototype.getTangent=function(t){return this.v2.clone().sub(this.v1).normalize()},Tn.prototype=Object.assign(Object.create(En.prototype),{constructor:Tn,add:function(t){this.curves.push(t)},closePath:function(){var t=this.curves[0].getPoint(0),e=this.curves[this.curves.length-1].getPoint(1);t.equals(e)||this.curves.push(new Sn(e,t))},getPoint:function(t){for(var e=t*this.getLength(),r=this.getCurveLengths(),n=0;n=e){var i=r[n]-e,a=this.curves[n],o=a.getLength(),s=0===o?0:1-i/o;return a.getPointAt(s)}n++}return null},getLength:function(){var t=this.getCurveLengths();return t[t.length-1]},updateArcLengths:function(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var t=[],e=0,r=0,n=this.curves.length;r1&&!r[r.length-1].equals(r[0])&&r.push(r[0]),r},createPointsGeometry:function(t){var e=this.getPoints(t);return this.createGeometry(e)},createSpacedPointsGeometry:function(t){var e=this.getSpacedPoints(t);return this.createGeometry(e)},createGeometry:function(t){for(var e=new _t,r=0,i=t.length;re;)r-=e;re.length-2?e.length-1:n+1],c=e[n>e.length-3?e.length-1:n+2];return new h(fn(i,a.x,o.x,s.x,c.x),fn(i,a.y,o.y,s.y,c.y))},Cn.prototype=Object.create(En.prototype),Cn.prototype.constructor=Cn,Cn.prototype.getPoint=function(t){var e=this.v0,r=this.v1,n=this.v2,i=this.v3;return new h(Mn(t,e.x,r.x,n.x,i.x),Mn(t,e.y,r.y,n.y,i.y))},Rn.prototype=Object.create(En.prototype),Rn.prototype.constructor=Rn,Rn.prototype.getPoint=function(t){var e=this.v0,r=this.v1,n=this.v2;return new h(yn(t,e.x,r.x,n.x),yn(t,e.y,r.y,n.y))};var bh=Object.assign(Object.create(Tn.prototype),{fromPoints:function(t){this.moveTo(t[0].x,t[0].y);for(var e=1,r=t.length;e0){var l=c.getPoint(0);l.equals(this.currentPoint)||this.lineTo(l.x,l.y)}this.curves.push(c);var h=c.getPoint(1);this.currentPoint.copy(h)}});Pn.prototype=bh,bh.constructor=Pn,In.prototype=Object.assign(Object.create(bh),{constructor:In,getPointsHoles:function(t){for(var e=[],r=0,n=this.holes.length;r1){for(var v=!1,y=[],x=0,b=d.length;xNumber.EPSILON){if(l<0&&(o=e[a],c=-c,s=e[i],l=-l),t.ys.y)continue;if(t.y===o.y){if(t.x===o.x)return!0}else{var h=l*(t.x-o.x)-c*(t.y-o.y);if(0===h)return!0;if(h<0)continue;n=!n}}else{if(t.y!==o.y)continue;if(s.x<=t.x&&t.x<=o.x||o.x<=t.x&&t.x<=s.x)return!0}}return n})(M.p,d[S].p)&&(x!==S&&y.push({froms:x,tos:S,hole:_}),E?(E=!1,u[S].push(M)):v=!0);E&&u[x].push(M)}y.length>0&&(v||(p=u))}for(var T,m=0,A=d.length;m0){this.source.connect(this.filters[0]);for(var t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(var t=1,e=this.filters.length;t=.5)for(var a=0;a!==i;++a)t[e+a]=t[r+a]},_slerp:function(t,e,n,i){r.slerpFlat(t,e,t,e,t,n,i)},_lerp:function(t,e,r,n,i){for(var a=1-n,o=0;o!==i;++o){var s=e+o;t[s]=t[s]*a+t[r+o]*n}}}),Object.assign(Hn.prototype,{getValue:function(t,e){this.bind();var r=this._targetGroup.nCachedObjects_,n=this._bindings[r];void 0!==n&&n.getValue(t,e)},setValue:function(t,e){for(var r=this._bindings,n=this._targetGroup.nCachedObjects_,i=r.length;n!==i;++n)r[n].setValue(t,e)},bind:function(){for(var t=this._bindings,e=this._targetGroup.nCachedObjects_,r=t.length;e!==r;++e)t[e].bind()},unbind:function(){for(var t=this._bindings,e=this._targetGroup.nCachedObjects_,r=t.length;e!==r;++e)t[e].unbind()}}),Object.assign(jn,{Composite:Hn,create:function(t,e,r){return t&&t.isAnimationObjectGroup?new jn.Composite(t,e,r):new jn(t,e,r)},sanitizeNodeName:function(t){return t.replace(/\s/g,"_").replace(/[^\w-]/g,"")},parseTrackName:function(){var t=new RegExp("^"+/((?:[\w-]+[\/:])*)/.source+/([\w-\.]+)?/.source+/(?:\.([\w-]+)(?:\[(.+)\])?)?/.source+/\.([\w-]+)(?:\[(.+)\])?/.source+"$"),e=["material","materials","bones"];return function(r){var n=t.exec(r);if(!n)throw new Error("PropertyBinding: Cannot parse trackName: "+r);var i={nodeName:n[2],objectName:n[3],objectIndex:n[4],propertyName:n[5],propertyIndex:n[6]},a=i.nodeName&&i.nodeName.lastIndexOf(".");if(void 0!==a&&-1!==a){var o=i.nodeName.substring(a+1);-1!==e.indexOf(o)&&(i.nodeName=i.nodeName.substring(0,a),i.objectName=o)}if(null===i.propertyName||0===i.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+r);return i}}(),findNode:function(t,e){if(!e||""===e||"root"===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){var r=function(t){for(var r=0;r=r){var u=r++,d=e[u];n[d.uuid]=h,e[h]=d,n[l]=u,e[u]=c;for(var p=0,f=a;p!==f;++p){var m=i[p],g=m[u],v=m[h];m[h]=g,m[u]=v}}}this.nCachedObjects_=r},uncache:function(t){for(var e=this._objects,r=e.length,n=this.nCachedObjects_,i=this._indicesByUUID,a=this._bindings,o=a.length,s=0,c=arguments.length;s!==c;++s){var l=arguments[s].uuid,h=i[l];if(void 0!==h)if(delete i[l],h0)for(var c=this._interpolants,l=this._propertyBindings,h=0,u=c.length;h!==u;++h)c[h].evaluate(o),l[h].accumulate(n,s)},_updateWeight:function(t){var e=0;if(this.enabled){e=this.weight;var r=this._weightInterpolant;if(null!==r){var n=r.evaluate(t)[0];e*=n,t>r.parameterPositions[1]&&(this.stopFading(),0===n&&(this.enabled=!1))}}return this._effectiveWeight=e,e},_updateTimeScale:function(t){var e=0;if(!this.paused){e=this.timeScale;var r=this._timeScaleInterpolant;null!==r&&(e*=r.evaluate(t)[0],t>r.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e))}return this._effectiveTimeScale=e,e},_updateTime:function(t){var e=this.time+t;if(0===t)return e;var r=this._clip.duration,n=this.loop,i=this._loopCount;if(2200===n){-1===i&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(e>=r)e=r;else{if(!(e<0))break t;e=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{var a=2202===n;if(-1===i&&(t>=0?(i=0,this._setEndings(!0,0===this.repetitions,a)):this._setEndings(0===this.repetitions,!0,a)),e>=r||e<0){var o=Math.floor(e/r);e-=r*o,i+=Math.abs(o);var s=this.repetitions-i;if(s<0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,e=t>0?r:0,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(0===s){var c=t<0;this._setEndings(c,!c,a)}else this._setEndings(!1,!1,a);this._loopCount=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:o})}}if(a&&1==(1&i))return this.time=e,r-e}return this.time=e,e},_setEndings:function(t,e,r){var n=this._interpolantSettings;r?(n.endingStart=2401,n.endingEnd=2401):(n.endingStart=t?this.zeroSlopeAtStart?2401:Il:2402,n.endingEnd=e?this.zeroSlopeAtEnd?2401:Il:2402)},_scheduleFading:function(t,e,r){var n=this._mixer,i=n.time,a=this._weightInterpolant;null===a&&(a=n._lendControlInterpolant(),this._weightInterpolant=a);var o=a.parameterPositions,s=a.sampleValues;return o[0]=i,s[0]=e,o[1]=i+t,s[1]=r,this}}),Object.assign(Yn.prototype,l.prototype,{_bindAction:function(t,e){var r=t._localRoot||this._root,n=t._clip.tracks,i=n.length,a=t._propertyBindings,o=t._interpolants,s=r.uuid,c=this._bindingsByRootAndName,l=c[s];void 0===l&&(l={},c[s]=l);for(var h=0;h!==i;++h){var u=n[h],d=u.name,p=l[d];if(void 0!==p)a[h]=p;else{if(void 0!==(p=a[h])){null===p._cacheIndex&&(++p.referenceCount,this._addInactiveBinding(p,s,d));continue}var f=e&&e._propertyBindings[h].binding.parsedPath;++(p=new Vn(jn.create(r,d,f),u.ValueTypeName,u.getValueSize())).referenceCount,this._addInactiveBinding(p,s,d),a[h]=p}o[h].resultBuffer=p.buffer}},_activateAction:function(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){var e=(t._localRoot||this._root).uuid,r=t._clip.uuid,n=this._actionsByClip[r];this._bindAction(t,n&&n.knownActions[0]),this._addInactiveAction(t,r,e)}for(var i=t._propertyBindings,a=0,o=i.length;a!==o;++a){var s=i[a];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(t)}},_deactivateAction:function(t){if(this._isActiveAction(t)){for(var e=t._propertyBindings,r=0,n=e.length;r!==n;++r){var i=e[r];0==--i.useCount&&(i.restoreOriginalState(),this._takeBackBinding(i))}this._takeBackAction(t)}},_initMemoryManager:function(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;var t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}},_isActiveAction:function(t){var e=t._cacheIndex;return null!==e&&e0?0:(Math.floor(Math.abs(a)/e.length)+1)*e.length:0===o&&a===r-1&&(a=r-2,o=1);var s,c,l,h;if(this.closed||a>0?s=e[(a-1)%r]:(Mh.subVectors(e[0],e[1]).add(e[0]),s=Mh),c=e[a%r],l=e[(a+1)%r],this.closed||a+2=0&&(i=2*Math.PI-i),i!==this.lastRotation){var a=360-Math.round(Ko.radToDeg(i));this.txt.textContent=a.toString().padStart(3,"0")+"°",this.rotateOnAxis(r,i-this.lastRotation),this.lastRotation=i}}}}();var Ah={cursorVertexShader:"\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\t\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float height;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\theight = position.z;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n",cursorFragmentShader:"\r\nuniform float cursor;\r\nuniform float cursorWidth;\r\n\r\nuniform vec3 baseColor;\r\nuniform vec3 cursorColor;\r\n\r\nvarying float height;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n#else\r\n\r\n\tfloat light = 1.0;\r\n\r\n#endif\r\n\r\n\tfloat delta = abs( height - cursor );\r\n\tfloat ss = smoothstep( 0.0, cursorWidth, cursorWidth - delta );\r\n\r\n\r\n#ifdef SURFACE\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light;\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 );\r\n\r\n\t}\r\n\r\n#else\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light * vec4( vColor, 1.0 );\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 ) * vec4( vColor, 1.0 );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n}\r\n",depthMapVertexShader:"\r\nuniform float minZ;\r\nuniform float scaleZ;\r\n\r\nvarying float vHeight;\r\n\r\nvoid main() {\r\n\r\n\tvHeight = ( position.z - minZ ) * scaleZ;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n",depthMapFragmentShader:"\r\nconst float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\n\r\nconst float ShiftRight8 = 1. / 256.;\r\n\r\nvec4 packFloatToRGBA( const in float v ) {\r\n\r\n\tvec4 r = vec4( fract( v * PackFactors ), v );\r\n\r\n\tr.yzw -= r.xyz * ShiftRight8; // tidy overflow\r\n\r\n\treturn r * PackUpscale;\r\n\r\n}\r\n\r\nvarying float vHeight;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = packFloatToRGBA( vHeight );\r\n\r\n}\r\n",depthVertexShader:"const float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nfloat unpackRGBAToFloat( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\nuniform float minX;\r\nuniform float minY;\r\nuniform float minZ;\r\n\r\nuniform float scaleX;\r\nuniform float scaleY;\r\nuniform float rangeZ;\r\n\r\nuniform float depthScale;\r\n\r\nuniform sampler2D depthMap;\r\nuniform float datumShift;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float vDepth;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\t// get terrain height in model space\r\n\r\n\tvec2 terrainCoords = vec2( ( position.x - minX ) * scaleX, ( position.y - minY ) * scaleY );\r\n\tfloat terrainHeight = unpackRGBAToFloat( texture2D( depthMap, terrainCoords ) );\r\n\r\n\tterrainHeight = terrainHeight * rangeZ + minZ + datumShift;\r\n\r\n\t// depth below terrain for this vertex, scaled in 0.0 - 1.0 range\r\n\r\n\tvDepth = ( terrainHeight - position.z ) * depthScale;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n",depthFragmentShader:"\r\nuniform sampler2D cmap;\r\nvarying float vDepth;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( vDepth, 1.0 ) ) * light;\r\n\r\n#else\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( vDepth, 1.0 ) ) * vec4( vColor, 1.0 );\r\n\r\n#endif\r\n\r\n}\r\n",depthCursorVertexShader:"\r\nconst float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nfloat unpackRGBAToFloat( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\nuniform float minX;\r\nuniform float minY;\r\nuniform float minZ;\r\n\r\nuniform float scaleX;\r\nuniform float scaleY;\r\nuniform float rangeZ;\r\n\r\nuniform sampler2D depthMap;\r\nuniform float datumShift;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\t\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float vDepth;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\tvec2 terrainCoords = vec2( ( position.x - minX ) * scaleX, ( position.y - minY ) * scaleY );\r\n\tfloat terrainHeight = unpackRGBAToFloat( texture2D( depthMap, terrainCoords ) );\r\n\r\n\tvDepth = terrainHeight * rangeZ + datumShift + minZ - position.z;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n\r\n\r\n\r\n\r\n\r\n",depthCursorFragmentShader:"\r\nuniform float cursor;\r\nuniform float cursorWidth;\r\n\r\nuniform vec3 baseColor;\r\nuniform vec3 cursorColor;\r\n\r\nvarying float vDepth;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n\tfloat light;\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n#else\r\n\r\n\tlight = 1.0;\r\n\r\n#endif\r\n\r\n\tfloat delta = abs( vDepth - cursor );\r\n\tfloat ss = smoothstep( 0.0, cursorWidth, cursorWidth - delta );\r\n\r\n#ifdef SURFACE\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light;\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 );\r\n\r\n\t}\r\n\r\n#else\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light * vec4( vColor, 1.0 );\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 ) * vec4( vColor, 1.0 );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n}",extendedPointsVertexShader:"uniform float size;\r\nuniform float scale;\r\nuniform float pScale;\r\n\r\nattribute float pSize;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_SIZEATTENUATION\r\n\t\tgl_PointSize = pScale * pSize * ( scale / - mvPosition.z );\r\n\t#else\r\n\t\tgl_PointSize = pScale * pSize;\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",extendedPointsFragmentShader:"uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n",glyphVertexShader:"\r\n\r\n// glyph shader, each instance represents one glyph.\r\n\r\nuniform float cellScale;\r\nuniform mat2 rotate;\r\nuniform float scale;\r\n\r\nattribute vec2 instanceUvs;\r\nattribute float instanceOffsets;\r\nattribute float instanceWidths;\r\n\r\nvarying vec2 vUv;\r\nvarying vec3 vColor;\r\n\r\nvoid main() {\r\n\r\n\tvColor = color;\r\n\r\n\t// select glyph from atlas ( with proportional spacing ).\r\n\r\n\tvUv = instanceUvs + vec2( position.x * cellScale * instanceWidths, position.y * cellScale );\r\n\r\n\t// scale by glyph width ( vertices form unit square with (0,0) origin )\r\n\r\n\tvec2 newPosition = vec2( position.x * instanceWidths, position.y );\r\n\r\n\t// move to correct offset in string\r\n\r\n\tnewPosition.x += instanceOffsets;\r\n\r\n\t// rotate as required\r\n\r\n\tnewPosition = rotate * newPosition;\r\n\r\n\t// position of GlyphString object on screeno\r\n\r\n\tvec4 offset = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\r\n\r\n\t// scale glyphs\r\n\r\n\tnewPosition.xy *= 0.0625;\r\n\r\n\t// correct for aspect ratio\r\n\r\n\tnewPosition.x *= scale;\r\n\r\n\t// move to clip space\r\n\r\n\tnewPosition.xy *= offset.w;\r\n\r\n\tgl_Position = vec4( newPosition, 0.0, 0.0 ) + offset;\r\n\r\n}\r\n",glyphFragmentShader:"\r\nuniform sampler2D atlas;\r\n\r\nvarying vec2 vUv;\r\nvarying vec3 vColor;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = texture2D( atlas, vUv ) * vec4( vColor, 1.0 );\r\n\r\n}",heightVertexShader:"\r\nuniform sampler2D cmap;\r\n\r\nuniform float minZ;\r\nuniform float scaleZ;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float zMap;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\tzMap = ( position.z - minZ ) * scaleZ;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n",heightFragmentShader:"\r\nuniform sampler2D cmap;\r\n\r\nvarying float zMap;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( 1.0 - zMap, 1.0 ) ) * vec4( light, light, light, 1.0 );\r\n\r\n#else\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( 1.0 - zMap, 1.0 ) ) * vec4( vColor, 1.0 );\r\n\r\n#endif\r\n\r\n}\r\n",waterVertexShader:"\r\nattribute vec3 sinks;\r\n\r\nvarying vec3 vPosition;\r\nvarying vec3 vSink;\r\n\r\nvoid main() {\r\n\r\n\tvPosition = position;\r\n\tvSink = sinks;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n",waterFragmentShader:"\r\nuniform float offset;\r\n\r\nvarying vec3 vPosition;\r\nvarying vec3 vSink;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = vec4( 0.1, 0.1, sin( offset + distance( vPosition, vSink ) ) * 0.4 + 0.6, 0.0 );\r\n\r\n}\r\n"};xi.prototype=Object.create(at.prototype),xi.prototype.constructor=xi,xi.prototype.setCursor=function(t){var e=Math.max(Math.min(t,this.halfRange),-this.halfRange);return this.uniforms.cursor.value=e,e},xi.prototype.getCursor=function(){return this.uniforms.cursor.value},bi.prototype=Object.create(at.prototype),bi.prototype.constructor=bi,bi.prototype.setDatumShift=function(t){this.uniforms.datumShift.value=t},wi.prototype=Object.create(at.prototype),wi.prototype.constructor=wi,wi.prototype.setCursor=function(t){var e=Math.max(Math.min(t,this.max),0);return this.uniforms.cursor.value=e,e},wi.prototype.getCursor=function(){return this.uniforms.cursor.value},wi.prototype.setDatumShift=function(t){this.uniforms.datumShift.value=t},_i.prototype=Object.create(at.prototype),_i.prototype.constructor=_i,Mi.prototype=Object.create(at.prototype),Mi.prototype.constructor=Mi,Ei.prototype.constructor=Ei,Ei.prototype.getTexture=function(){return this.texture},Ei.prototype.getCellScale=function(){return this.cellScale},Ei.prototype.getGlyph=function(t){var e=this.map[t];return void 0===e&&(console.warn("unavailable glyph ["+t+"]",t.codePointAt()),e=this.map["☐"]),e};var Lh={},Ch={};Ch.getAtlas=function(t){var e=Lh[t];return void 0===e&&(e=new Ei(t),Lh[t]=e),e},Si.prototype=Object.create(at.prototype),Si.prototype.constructor=Si,Si.prototype.getAtlas=function(){return this.atlas};var Rh,Ph=new Map,Ih=[],Oh=[],Nh={},Dh={getHeightMaterial:Ci,getDepthMapMaterial:Ri,getDepthMaterial:Pi,getDepthCursorMaterial:Oi,getCursorMaterial:Ii,getSurfaceMaterial:Ni,getLineMaterial:Di,getGlyphMaterial:Ui,setTerrain:zi,initCache:Bi,flushCache:Fi};ki.prototype=Object.create(Bt.prototype),Object.assign(ki.prototype,s.prototype),ki.prototype.constructor=ki,ki.prototype.setRange=function(t,e,r){return this.maxDiv.textContent=Math.round(e)+"m",this.minDiv.textContent=Math.round(t)+"m",this.setCaption(r),this},ki.prototype.setCaption=function(t){return this.caption.textContent=t,this},ki.prototype.setMaterial=function(t){return this.material=t,this},Gi.prototype=Object.create(Bt.prototype),Object.assign(Gi.prototype,s.prototype),Gi.prototype.constructor=Gi,Gi.prototype.setRange=function(t,e,r){return this.maxDiv.textContent=Math.round(e)+"m",this.minDiv.textContent=Math.round(t)+"m",this.caption.textContent=r,this},Gi.prototype.setCursor=function(t){return this.cursor.position.setY(this.barHeight*t),this},Vi.prototype=Object.create(Bt.prototype),Object.assign(Vi.prototype,s.prototype),Vi.prototype.constructor=Vi,Vi.prototype.set=function(t){this.progress=t;for(var e=2*Math.floor(Math.min(100,Math.round(t))/2),r=this.geometry.faces,n=0;n=3?i*Math.pow(10,s-3)+"km":i*Math.pow(10,s)+"m",t*=Math.pow(10,s),this.currentLength!==i){if(!r[i]){var l=function(t){var e,r,i=t*a.hScale,o=new It(i,4,t),s=new It(i,4,10*t),c=new _t;c.vertices.push(new n(-i/2,0,1)),c.vertices.push(new n(i/2,0,1));var l=new Bt(o,new Nt({color:16777215,vertexColors:ec,side:Zs})),h=new Bt(s,new Nt({color:16777215,vertexColors:ec,side:Zs})),u=new Pe(c,new Ce({color:16711680}));for(e=0,r=o.faces.length;e0&&(r[this.currentLength].mesh.visible=!1),r[i].mesh.visible=this.visible,this.currentLength=i}r[i].mesh.scale.x=t;var h=this.legend;return h.style.display=this.visible?"block":"none",h.style.left=t*r[i].topRight-h.clientWidth+"px",h.textContent=e,this};var Uh,zh,Bh,Fh,kh,Gh,Vh,Hh,jh,Wh=0,Xh=null,Yh=null,qh=null,Zh=null,Jh=!0,Qh={init:ji,renderHUD:Qi,update:Ji,setVisibility:Wi,getVisibility:Xi,getProgressDial:Yi,setScale:qi};na.prototype.constructor=na,na.prototype.prepare=function(t,e){if(0===this.frameCount){if(this.skipNext=!1,e&&e.isBox3){var r,n=e.getSize(),i=this.controls.object;if(e=e.getCenter(),i.isPerspectiveCamera){var a=Math.tan(.5*Ko.DEG2RAD*i.getEffectiveFOV()),o=1.5*a*n.y/2+n.z,s=a*i.aspect*n.x/2+n.z;r=Math.max(o,s),this.targetZoom=1,0===r&&(r=100)}else{var c=(i.right-i.left)/n.x,l=(i.top-i.bottom)/n.y;this.targetZoom=Math.min(c,l),r=600}(t=e.clone()).z=t.z+r}this.cameraTarget=t,this.targetPOI=e,this.moveRequired=null!==this.cameraTarget||null!==this.targetPOI;var h=this.controls.target,u=this.controls.object.position;if(null!==t)if(t.equals(u))this.moveRequired=!1,null===e&&(this.skipNext=!0);else{null===e&&(e=h);var d=u.distanceTo(t),p=this.getControlPoint(h,u,t,d),f=this.getControlPoint(e,t,u,d);this.curve=new fi(u,p,f,t)}}},na.prototype.getControlPoint=function(t,e,r,i){for(var a=new n,o=new n,s=new n,c=0;0===c;)a.copy(e).sub(t),o.copy(r).sub(t),s.crossVectors(a,o),0===(c=s.length())&&t.addScalar(-1);var l=(new n).crossVectors(s,a).setLength(Math.min(i,a.length())/3),h=(new n).copy(l).add(a),u=(new n).copy(l).negate().add(a);return o.distanceTo(h)0},ia.prototype.constructor=ia,ia.prototype.traverse=function(t){var e=this.children;t(this);for(var r=0;r0;){r=!1;for(var n=0,i=e.children.length;n0;)n=new ia(t.shift(),null,this.root,r),r.children.push(n),r=n;return void 0!==e&&Object.assign(r,e),r},ia.prototype.getPath=function(t){var e=this,r=[];void 0===t&&(t=this.root);do{r.push(e.name),e=e.parent}while(e!==t);return r.reverse().join(".")},ia.prototype.getSubtreeIds=function(t,e){function r(t){e.add(t.id)}this.findById(t).traverse(r)},ia.prototype.getIdByPath=function(t){var e=this.getByPathArray(t);return 0===t.length?e.id:void 0},aa.prototype.type="Box3Helper",aa.prototype=Object.create(Pe.prototype),aa.prototype.constructor=aa,aa.prototype.update=function(t){if(this.box3=t,!t.isEmpty()){var e=t.min,r=t.max,n=this.geometry.attributes.position,i=n.array;i[0]=r.x,i[1]=r.y,i[2]=r.z,i[3]=e.x,i[4]=r.y,i[5]=r.z,i[6]=e.x,i[7]=e.y,i[8]=r.z,i[9]=r.x,i[10]=e.y,i[11]=r.z,i[12]=r.x,i[13]=r.y,i[14]=e.z,i[15]=e.x,i[16]=r.y,i[17]=e.z,i[18]=e.x,i[19]=e.y,i[20]=e.z,i[21]=r.x,i[22]=e.y,i[23]=e.z,n.needsUpdate=!0,this.geometry.computeBoundingSphere()}},aa.prototype.removed=function(){this.geometry&&this.geometry.dispose()},oa.indexAttribute=null,oa.positionAttribute=null,oa.prototype=Object.assign(Object.create(Zn.prototype),{constructor:oa}),sa.prototype=Object.assign(Object.create(Bt.prototype),{constructor:sa,isGlyphString:!0,getWidth:function(){return this.geometry.width}}),ca.prototype=Object.create(Ne.prototype),ca.prototype.constructor=ca;var Kh=new n,$h=new n,tu=new n,eu=new n,ru=new zt(Kh,$h,tu),nu=new zt(Kh,tu,eu),iu=[];ua.prototype.addNode=function(t,e){var r=0,n=t.position;if(this.markers.push(t),this.centroid.add(t.position),this.count++,0!=e--){var i=(this.xMin+this.xMax)/2,a=(this.yMin+this.yMax)/2;n.x>i&&(r+=1),n.y>a&&(r+=2);var o=this.nodes[r];if(void 0===o){switch(r){case 0:o=new ua(this.xMin,i,this.yMin,a);break;case 1:o=new ua(i,this.xMax,this.yMin,a);break;case 2:o=new ua(this.xMin,i,a,this.yMax);break;case 3:o=new ua(i,this.xMax,a,this.yMax)}this.nodes[r]=o}o.addNode(t,e)}},ua.prototype.check=function(t){for(var e,r=0;r<4;r++)if(void 0!==(e=this.nodes[r])){if(e.count<2){this.nodes[r]=void 0;continue}e.projectedArea(t)<.8?e.clusterMarkers(t):(e.showMarkers(),e.check(t))}},ua.prototype.showMarkers=function(){for(var t=this.markers,e=0,r=t.length;e2?(this.colors[e.stationVertexIndex]=this.junctionColor,this.pointSizes[e.stationVertexIndex]=4):e.hitCount>0&&(this.pointSizes[e.stationVertexIndex]=2))},fa.prototype.finalise=function(){var t=this.geometry,e=new Tt(3*this.vertices.length,3),r=new Tt(3*this.colors.length,3);t.addAttribute("pSize",new Tt(this.pointSizes,1)),t.addAttribute("position",e.copyVector3sArray(this.vertices)),t.addAttribute("color",r.copyColorsArray(this.colors)),this.pointSizes=null,this.vertices=null,this.colors=null},fa.prototype.setScale=function(t){this.material.uniforms.pScale.value=t,this.material.needsUpdate=!0};var au=new n;ma.prototype=Object.create(De.prototype),ma.prototype.constructor=ma,ma.prototype.addStation=function(t){var e;e=0===t.hitCount?this.splayLabelMaterial:t.hitCount<3?this.defaultLabelMaterial:this.junctionLabelMaterial;var r=new sa(t.name,e);r.layers.set(Ns),r.position.copy(t.p),r.hitCount=t.hitCount,r.visible=!1,this.add(r)},ma.prototype.update=function(t,e,r){var n=au.copy(t.position);t.isOrthographicCamera&&(n.sub(e),n.setLength(ns/t.zoom),n.add(e)),n.applyMatrix4(r);for(var i,a,o=t.layers.mask&1<2||o+20)return cu;cu=[];var n=0===(lu=e)?t.id:lu,i=t.findById(n),a=this.getSurveyColour(n);r(i);for(var o=i.children;1===o.length;)r(i=o[0]),o=i.children;for(var s=0,c=o.length;s0){var a=Math.sqrt(n/i-Math.pow(r/i,2));t.datumShift=r/i,console.log("Adjustmenting terrain height by ",t.datumShift,a)}null===this.terrain&&(this.terrain=t)},Ra.prototype.loadCave=function(t){var e=this;!function(t){function r(t){Object.assign(t,ia.prototype)}void 0===t.forEachChild&&(r(t),t.forEachChild(r,!0)),null===e.surveyTree?e.surveyTree=t:e.surveyTree.children.push(t)}(t.surveyTree),function(t){function r(t,r){var n=i[t];if(0!==n.vertices.length){var a=e.getFeature(t,xa);a.addLegs(n.vertices,n.colors,n.runs),e.addFeature(a,t,r+":g")}}var i=[];i[Ms]={vertices:[],colors:[],runs:[]},i[Ss]={vertices:[],colors:[],runs:[]},i[Es]={vertices:[],colors:[],runs:[]};var a,o,s,c,l=t.length;if(0===l)return null;for(var h,u,d=new n,p=0;pt.clientWidth||r+c.clientHeight>t.clientHeight?s():(c.style.left=e+"px",c.style.top=r+"px")}function s(){t.removeChild(c),t.removeEventListener("mousemove",o),t.removeEventListener("mouseup",s)}var c=this.div,l=new n;c.style.left=e+"px",c.style.top=r+"px",t.appendChild(c),t.addEventListener("mouseup",s),t.addEventListener("mousemove",o)},Pa.prototype.addLine=function(t){var e=document.createElement("div");return e.textContent=t,this.div.appendChild(e),this},Ia.prototype=Object.create(Pa.prototype),Ia.prototype.constructor=Ia;var vu=new n,yu=new n,xu=new n,bu=new n,wu=new zt(vu,yu,xu),_u=new zt(vu,xu,bu);Na.liveTiles=0,Na.prototype=Object.create(Bt.prototype),Na.prototype.constructor=Na,Na.prototype.type="Tile",Na.prototype.isTile=!0,Na.prototype.createFromBufferAttributes=function(t,e,r,i){var a,o,s=this.geometry;for(a in e)o=e[a],s.addAttribute(a,new Tt(o.array,o.itemSize));s.setIndex(new Et(t,1)),s.boundingBox=new st(new n(r.min.x,r.min.y,r.min.z),new n(r.max.x,r.max.y,r.max.z)),e=s.attributes;for(var c in e)e[c].onUpload(Oa);return this.geometry.index.onUpload(Oa),this.layers.set(Cs),this.material=i,this},Na.prototype.getWorldBoundingBox=function(){var t;return null===this.worldBoundingBox&&(this.updateMatrixWorld(),(t=this.getBoundingBox().clone()).applyMatrix4(this.matrixWorld),this.worldBoundingBox=t),this.worldBoundingBox},Na.prototype.getBoundingBox=function(){var t;if(null===this.boundingBox){(t=this.geometry.boundingBox.clone()).min.x+=5,t.min.y+=5,t.max.x-=5,t.max.y-=5,this.boundingBox=t}return this.boundingBox},Na.prototype.empty=function(){this.isMesh=!1,this.boundingBox||(console.warn("FIXUP :",this.x,this.y),this.getWorldBoundingBox()),this.geometry&&(this.geometry.dispose(),this.geometry=new Ct),--Na.liveTiles},Na.prototype.evict=function(){this.evictionCount++,this.evicted=!0,this.replaced=!1,this.empty()},Na.prototype.setReplaced=function(){this.evicted=!1,this.replaced=!0,this.empty()},Na.prototype.setPending=function(t){t&&null===this.parent&&t.add(this),this.parent.childrenLoading++,this.isMesh=!1,this.evicted=!1},Na.prototype.setFailed=function(){var t=this.parent;t.childErrors++,t.childrenLoading--,t.canZoom=!1,t.remove(this)},Na.prototype.setLoaded=function(t,e,r){function n(t){t.isMesh=!0,Na.liveTiles++,0==--a&&r()}var i=this.parent,a=0;if(0==--i.childrenLoading){if(0===i.childErrors){i.isTile&&i.setReplaced();for(var o=i.children,s=0,c=o.length;s=t.minX&&e.max_x<=t.maxX&&e.min_y>=t.minY&&e.max_y<=t.maxY)return t.directory=i+t.subdirectory,this.tileSet=t,!0;return!1},Da.prototype.getCoverage=function(t,e){var r={zoom:e},n=Mu,i=-Mu,a=Math.pow(2,e-1)/Mu;return r.min_x=Math.floor((t.min.x-i)*a),r.max_x=Math.floor((t.max.x-i)*a),r.max_y=Math.floor((n-t.min.y)*a),r.min_y=Math.floor((n-t.max.y)*a),r.count=(r.max_x-r.min_x+1)*(r.max_y-r.min_y+1),r},Da.prototype.pickCoverage=function(t){var e,r=this.tileSet,n=r.maxZoom+1;do{--n,e=this.getCoverage(t,n)}while(e.count>4&&n>r.minZoom);return e},Da.prototype.loadTile=function(t,e,r,n,i){function a(t){var e=t.data;return c.workerPool.putWorker(b),--c.tilesLoading,c.dying?void c.progressDial.end():"ok"!==e.status||0!==y.parent.childErrors?(y.setFailed(),void(c.progressDial&&c.progressDial.end())):(c.progressDial&&c.progressDial.add(c.progressInc),y.createFromBufferAttributes(e.index,e.attributes,e.boundingBox,c.material),c.progressDial&&c.progressDial.add(c.progressInc),y.setLoaded(c.activeOverlay,c.opacity,c.onLoaded)&&c.progressDial&&c.progressDial.end(),void(c.terrainLoaded=!0))}var o=this.tileSet,s=r>o.dtmMaxZoom?Math.pow(2,o.dtmMaxZoom-r):1;if(1===s||null!==this.activeOverlay||null===this.currentZoom){console.log("load: [ ",r+"/"+t+"/"+e,"]");var c=this,l=this.limits,h=Mu/Math.pow(2,r-1),u={top:0,bottom:0,left:0,right:0},d=h*t-Mu,p=d+h,f=Mu-h*e,m=f-h,g=o.divisions*s,v=h/g;++this.tilesLoading,f>l.max.y&&(u.top=Math.floor((f-l.max.y)/v)),ml.max.x&&(u.right=Math.floor((p-l.max.x)/v));var y=n||new Na(t,e,r,c.tileSet,u),x=i||this;y.setPending(x);var b=this.workerPool.getWorker();b.onmessage=a,b.postMessage({tileSet:o,divisions:g,resolution:v,x:t,y:e,z:r,clip:u,offsets:this.offsets})}},Da.prototype.resurrectTile=function(t){if(t.isMesh)return void console.warn("resurrecting the undead!");this.loadTile(t.x,t.y,t.zoom,t)},Da.prototype.tileArea=function(t,e){var r=this.pickCoverage(t),n=r.zoom;if(e&&e.zoom==n)return void console.error("ERROR - looping on tile replacement");this.currentLimits=t,null===this.initialZoom&&(this.initialZoom=n);for(var i=r.min_x;i0&&void 0!==this.progressDial&&(this.progressDial.start("Loading "+this.tilesLoading+" terrain tiles"),this.progressInc=100/(2*this.tilesLoading)),this.currentZoom=n},Da.prototype.setDefaultOverlay=function(t){this.defaultOverlay=t},Da.prototype.setOverlay=function(t,e){function r(e){e.isTile&&(e.setOverlay(t,i.opacity,n),i.overlaysLoading++)}function n(){0==--i.overlaysLoading&&e()}if(!(this.tilesLoading>0)){var i=this,a=this.activeOverlay;if(null!==a){if(a===t)return;a.flushCache(),a.hideAttribution()}this.activeOverlay=t,this.defaultOverlay=t,t.showAttribution(),this.traverse(r)}},Da.prototype.removed=function(){function t(t){t!==e&&t.removed(t)}if(this.dying=!0,!(this.tilesLoading>0)){var e=this;this.traverse(t),this.commonRemoved()}},Da.prototype.setMaterial=function(t){function e(e){e.isTile&&e.setMaterial(t)}this.tilesLoading>0||(this.traverse(e),this.activeOverlay=null,t.opacity=this.opacity,t.needsUpdate=!0,this.material=t)},Da.prototype.setOpacity=function(t){function e(e){e.isTile&&e.setOpacity(t)}this.shadingMode===ys?this.traverse(e):this.material&&(this.material.opacity=t,this.material.needsUpdate=!0),this.opacity=t},Da.prototype.zoomCheck=function(t){function r(e){e!==c&&e.isTile&&(l.intersectsBox(e.getWorldBoundingBox())?0===e.children.length?e.isMesh?e.canZoom&&h.push({tile:e,area:e.projectedArea(t)}):d.push(e):(e.isMesh||!e.evicted||this.parent.resurrectionPending||(e.resurrectionPending=!0,d.push(e)),e.parent.ResurrectionPending&&this.isMesh&&console.warn(" should not get here")):e.isMesh&&u.push(e))}var n,i,a,o=this.tileSet.maxZoom,s=this.initialZoom,c=this,l=new ut,h=[],u=[],d=[],p=!1;if(this.tilesLoading>0)return!0;t.updateMatrix(),t.updateMatrixWorld(),t.matrixWorldInverse.getInverse(t.matrixWorld),l.setFromMatrix((new e).multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse)),this.traverse(r);var f=d.length,m=h.length;if(function(){function t(t,e){return t.evictionCount/t.zoom-e.evictionCount/e.zoom}var e,r=u.length;if(0!==r)for(u.sort(t),e=0;en.evictionCount*Math.pow(2,s-n.zoom)&&n.evict()}}(),0!==f){for(this.progressDial&&this.progressDial.start("Resurrecting tiles"),a=0;a.3&&(i=h[a].tile).zoomthis.slideDepth?(o.addEventListener("transitionend",n),o.classList.add("slide-out"),o.clientHeight):e1&&b.push(E),(E=[]).push({coords:t}),!0)}function d(){var t=I();return E.push({coords:t,type:Ms,survey:A}),R=t,!0}function p(){return console.log("LINE_V2"),!1}function f(){var r=new DataView(t,e),n=_.projection.forward({x:r.getInt32(0,!0)/100,y:r.getInt32(4,!0)/100}),i={x:n.x,y:n.y,z:r.getInt32(8,!0)/100};return O.x=Math.min(i.x,O.x),O.y=Math.min(i.y,O.y),O.z=Math.min(i.z,O.z),N.x=Math.max(i.x,N.x),N.y=Math.max(i.y,N.y),N.z=Math.max(i.z,N.z),e+=12,i}function m(){var r=new DataView(t,e),n={x:r.getInt32(0,!0)/100,y:r.getInt32(4,!0)/100,z:r.getInt32(8,!0)/100};return O.x=Math.min(n.x,O.x),O.y=Math.min(n.y,O.y),O.z=Math.min(n.z,O.z),N.x=Math.max(n.x,N.x),N.y=Math.max(n.y,N.y),N.z=Math.max(n.z,N.z),e+=12,n}var g,v,y,x,b=this.groups,w=this.surveyTree,_=this,M=[],E=[],S="",T=new Map,A=0,L=new Uint8Array(t,0),C=L.length,R={x:0,y:0,z:0},P=new DataView(t,0),I=null===this.projection?m:f,O={x:1/0,y:1/0,z:1/0},N={x:-1/0,y:-1/0,z:-1/0};for(g=0;g<256;g++)M[g]=n;for(M[0]=a,M[-1]=a,M[1]=o,M[2]=s,M[3]=s,M[4]=u,M[5]=d,M[6]=c,M[7]=l,g=64;g<128;g++)M[g]=h;for(g=128;g<256;g++)M[g]=p;if(1===r)for(;e>4,i=15&n):(255!==(n=H[e++])?a=n:(a=new DataView(t,e).getUint32(0,!0),e+=4),255!==(n=H[e++])?i=n:(i=new DataView(t,e).getUint32(0,!0),e+=4)),0!==i||0!==a){if(a&&(z=z.slice(0,-a)),i){for(var o=[],s=0;s1&&P.push(U),U=[],F.add(W.x+":"+W.y+":"+W.z);var t=Y();return U.push({coords:t}),W=t,!0}function _(){return e+=20,!0}function M(t){var r=127&t;if(R(0),!(14&r)||32&r)return e+=12,!0;var n=Y(),i=z.split("."),a=i.slice(0,-1).join(".");if(i.length>1&&!V.has(a)){for(var o=0,s=i[o];V.has(s);)s=s+"."+i[++o];var c=i.slice(o).join(".");(i=i.slice(0,o)).push(c)}return B.set(z,n),O.addPath(i,{p:n,type:4&r?Us:Ds}),!0}function E(r){var n=1&r;R(n);var i=new DataView(t,e);return e+=8,T(n,{l:i.getInt16(0,!0)/100,r:i.getInt16(2,!0)/100,u:i.getInt16(4,!0)/100,d:i.getInt16(6,!0)/100})}function S(r){var n=1&r;R(n);var i=new DataView(t,e);return e+=16,T(n,{l:i.getInt32(0,!0)/100,r:i.getInt32(0,!0)/100,u:i.getInt32(0,!0)/100,d:i.getInt32(0,!0)/100})}function T(t,e){var r=B.get(z);if(r){var n=z.split(".");n.pop();var i=O.getIdByPath(n);k.push({start:W,end:r,lrud:e,survey:i}),W=r;var a=!1;return t?a=!0:F.has([r.x,r.y,r.z].toString())&&(a=!0),a&&(k.length>0&&I.push(k),W={x:0,y:0,z:0},k=[]),!0}}function A(){var r=new DataView(t,e),n=N.projection.forward({x:r.getInt32(0,!0)/100,y:r.getInt32(4,!0)/100}),i={x:n.x,y:n.y,z:r.getInt32(8,!0)/100};return q.x=Math.min(i.x,q.x),q.y=Math.min(i.y,q.y),q.z=Math.min(i.z,q.z),Z.x=Math.max(i.x,Z.x),Z.y=Math.max(i.y,Z.y),Z.z=Math.max(i.z,Z.z),e+=12,i}function L(){var r=new DataView(t,e),n={x:r.getInt32(0,!0)/100,y:r.getInt32(4,!0)/100,z:r.getInt32(8,!0)/100};return q.x=Math.min(n.x,q.x),q.y=Math.min(n.y,q.y),q.z=Math.min(n.z,q.z),Z.x=Math.max(n.x,Z.x),Z.y=Math.max(n.y,Z.y),Z.z=Math.max(n.z,Z.z),e+=12,n}var C,R,P=this.groups,I=this.xGroups,O=this.surveyTree,N=this,D=[],U=[],z="",B=new Map,F=new Set,k=[],G=0,V=new Set,H=new Uint8Array(t,0),j=H.length,W={x:0,y:0,z:0},X=!1,Y=null===this.projection?L:A,q={x:1/0,y:1/0,z:1/0},Z={x:-1/0,y:-1/0,z:-1/0};for(C=0;C<256;C++)D[C]=n;if(8===r){for(D[0]=m,D[1]=m,D[2]=m,D[3]=m,D[4]=m,D[15]=w,D[16]=x,D[17]=g,D[18]=v,D[19]=y,D[31]=_,D[48]=E,D[49]=E,D[50]=S,D[51]=S,C=64;C<128;C++)D[C]=b;for(C=128;C<256;C++)D[C]=M;R=o,e++}else{for(C=1;C<15;C++)D[C]=c;for(D[15]=w,C=16;C<32;C++)D[C]=l;for(D[0]=s,D[32]=u,D[33]=f,D[35]=d,D[36]=x,D[34]=_,D[48]=E,D[49]=E,D[50]=S,D[51]=S,C=64;C<128;C++)D[C]=M;for(C=128;C<192;C++)D[C]=b;R=a}for(6===r&&(D[32]=h,D[33]=p);e1&&I.push(k),P.push(U);var J={x:(q.x+Z.x)/2,y:(q.y+Z.y)/2,z:(q.z+Z.z)/2};O.traverse(i),this.offsets=J,this.limits={min:q,max:Z}},To.prototype.getLineSegments=function(){for(var t=[],e=this.groups,r=this.offsets,n=0,i=e.length;n":is,Plan:as,"N Elevation":os,"S Elevation":ss,"E Elevation":cs,"W Elevation":ls},_d={Orthographic:es,Perspective:rs},Md={init:Po,loadCave:Xo,loadCaveList:jo};t.setEnvironment=i,t.Viewer=ed,t.UI=Md,t.CaveLoader=Ro,t.VERSION=$o,t.MATERIAL_LINE=ts,t.MATERIAL_SURFACE=2,t.CAMERA_ORTHOGRAPHIC=es,t.CAMERA_PERSPECTIVE=rs,t.CAMERA_OFFSET=ns,t.VIEW_NONE=is,t.VIEW_PLAN=as,t.VIEW_ELEVATION_N=os,t.VIEW_ELEVATION_S=ss,t.VIEW_ELEVATION_E=cs,t.VIEW_ELEVATION_W=ls,t.MOUSE_MODE_NORMAL=hs,t.MOUSE_MODE_ROUTE_EDIT=us,t.SHADING_HEIGHT=ds,t.SHADING_LENGTH=ps,t.SHADING_INCLINATION=fs,t.SHADING_CURSOR=ms,t.SHADING_SINGLE=gs,t.SHADING_SURVEY=vs,t.SHADING_OVERLAY=ys,t.SHADING_SHADED=xs,t.SHADING_DEPTH=bs,t.SHADING_PATH=ws,t.SHADING_DEPTH_CURSOR=_s,t.LEG_CAVE=Ms,t.LEG_SPLAY=Es,t.LEG_SURFACE=Ss,t.FEATURE_BOX=Ts,t.FEATURE_SELECTED_BOX=As,t.FEATURE_ENTRANCES=Ls,t.FEATURE_TERRAIN=Cs,t.FEATURE_STATIONS=Rs,t.FEATURE_TRACES=Ps,t.FACE_WALLS=Is,t.FACE_SCRAPS=Os,t.LABEL_STATION=Ns,t.NORMAL=0,t.SURFACE=1,t.SPLAY=2,t.DIVING=3,t.STATION_NORMAL=Ds,t.STATION_ENTRANCE=Us,t.upAxis=zs,Object.defineProperty(t,"__esModule",{value:!0})}); diff --git a/media/jslib/CaveView/js/CaveView.js b/media/jslib/CaveView/js/CaveView.js deleted file mode 100644 index ebbb74e..0000000 --- a/media/jslib/CaveView/js/CaveView.js +++ /dev/null @@ -1,55946 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.CV = global.CV || {}))); -}(this, (function (exports) { 'use strict'; - -// Polyfills - -if ( Number.EPSILON === undefined ) { - - Number.EPSILON = Math.pow( 2, - 52 ); - -} - -if ( Number.isInteger === undefined ) { - - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger - - Number.isInteger = function ( value ) { - - return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value; - - }; - -} - -// - -if ( Math.sign === undefined ) { - - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign - - Math.sign = function ( x ) { - - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; - - }; - -} - -if ( Function.prototype.name === undefined ) { - - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name - - Object.defineProperty( Function.prototype, 'name', { - - get: function () { - - return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ]; - - } - - } ); - -} - -if ( Object.assign === undefined ) { - - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - - ( function () { - - Object.assign = function ( target ) { - - 'use strict'; - - if ( target === undefined || target === null ) { - - throw new TypeError( 'Cannot convert undefined or null to object' ); - - } - - var output = Object( target ); - - for ( var index = 1; index < arguments.length; index ++ ) { - - var source = arguments[ index ]; - - if ( source !== undefined && source !== null ) { - - for ( var nextKey in source ) { - - if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { - - output[ nextKey ] = source[ nextKey ]; - - } - - } - - } - - } - - return output; - - }; - - } )(); - -} - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -var _Math = { - - DEG2RAD: Math.PI / 180, - RAD2DEG: 180 / Math.PI, - - generateUUID: function () { - - // http://www.broofa.com/Tools/Math.uuid.htm - - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); - var uuid = new Array( 36 ); - var rnd = 0, r; - - return function generateUUID() { - - for ( var i = 0; i < 36; i ++ ) { - - if ( i === 8 || i === 13 || i === 18 || i === 23 ) { - - uuid[ i ] = '-'; - - } else if ( i === 14 ) { - - uuid[ i ] = '4'; - - } else { - - if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; - r = rnd & 0xf; - rnd = rnd >> 4; - uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; - - } - - } - - return uuid.join( '' ); - - }; - - }(), - - clamp: function ( value, min, max ) { - - return Math.max( min, Math.min( max, value ) ); - - }, - - // compute euclidian modulo of m % n - // https://en.wikipedia.org/wiki/Modulo_operation - - euclideanModulo: function ( n, m ) { - - return ( ( n % m ) + m ) % m; - - }, - - // Linear mapping from range to range - - mapLinear: function ( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - - }, - - // https://en.wikipedia.org/wiki/Linear_interpolation - - lerp: function ( x, y, t ) { - - return ( 1 - t ) * x + t * y; - - }, - - // http://en.wikipedia.org/wiki/Smoothstep - - smoothstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * ( 3 - 2 * x ); - - }, - - smootherstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - - }, - - // Random integer from interval - - randInt: function ( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - - }, - - // Random float from interval - - randFloat: function ( low, high ) { - - return low + Math.random() * ( high - low ); - - }, - - // Random float from <-range/2, range/2> interval - - randFloatSpread: function ( range ) { - - return range * ( 0.5 - Math.random() ); - - }, - - degToRad: function ( degrees ) { - - return degrees * _Math.DEG2RAD; - - }, - - radToDeg: function ( radians ) { - - return radians * _Math.RAD2DEG; - - }, - - isPowerOfTwo: function ( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - - }, - - nearestPowerOfTwo: function ( value ) { - - return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); - - }, - - nextPowerOfTwo: function ( value ) { - - value --; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value ++; - - return value; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author jordi_ros / http://plattsoft.com - * @author D1plo1d / http://github.com/D1plo1d - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author timknip / http://www.floorplanner.com/ - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - */ - -function Matrix4() { - - this.elements = [ - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ]; - - if ( arguments.length > 0 ) { - - console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - - } - -} - -Object.assign( Matrix4.prototype, { - - isMatrix4: true, - - set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - var te = this.elements; - - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - - return this; - - }, - - identity: function () { - - this.set( - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - clone: function () { - - return new Matrix4().fromArray( this.elements ); - - }, - - copy: function ( m ) { - - var te = this.elements; - var me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - - return this; - - }, - - copyPosition: function ( m ) { - - var te = this.elements, me = m.elements; - - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; - - return this; - - }, - - extractBasis: function ( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); - - return this; - - }, - - makeBasis: function ( xAxis, yAxis, zAxis ) { - - this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); - - return this; - - }, - - extractRotation: function () { - - var v1 = new Vector3(); - - return function extractRotation( m ) { - - var te = this.elements; - var me = m.elements; - - var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length(); - var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length(); - var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length(); - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - - return this; - - }; - - }(), - - makeRotationFromEuler: function ( euler ) { - - if ( ! ( euler && euler.isEuler ) ) { - - console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - - } - - var te = this.elements; - - var x = euler.x, y = euler.y, z = euler.z; - var a = Math.cos( x ), b = Math.sin( x ); - var c = Math.cos( y ), d = Math.sin( y ); - var e = Math.cos( z ), f = Math.sin( z ); - - if ( euler.order === 'XYZ' ) { - - var ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; - - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; - - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YXZ' ) { - - var ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; - - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; - - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZXY' ) { - - var ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; - - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; - - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZYX' ) { - - var ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; - - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; - - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YZX' ) { - - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; - - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; - - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; - - } else if ( euler.order === 'XZY' ) { - - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; - - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; - - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; - - } - - // last column - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; - - // bottom row - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - }, - - makeRotationFromQuaternion: function ( q ) { - - var te = this.elements; - - var x = q._x, y = q._y, z = q._z, w = q._w; - var x2 = x + x, y2 = y + y, z2 = z + z; - var xx = x * x2, xy = x * y2, xz = x * z2; - var yy = y * y2, yz = y * z2, zz = z * z2; - var wx = w * x2, wy = w * y2, wz = w * z2; - - te[ 0 ] = 1 - ( yy + zz ); - te[ 4 ] = xy - wz; - te[ 8 ] = xz + wy; - - te[ 1 ] = xy + wz; - te[ 5 ] = 1 - ( xx + zz ); - te[ 9 ] = yz - wx; - - te[ 2 ] = xz - wy; - te[ 6 ] = yz + wx; - te[ 10 ] = 1 - ( xx + yy ); - - // last column - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; - - // bottom row - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - }, - - lookAt: function () { - - var x = new Vector3(); - var y = new Vector3(); - var z = new Vector3(); - - return function lookAt( eye, target, up ) { - - var te = this.elements; - - z.subVectors( eye, target ); - - if ( z.lengthSq() === 0 ) { - - // eye and target are in the same position - - z.z = 1; - - } - - z.normalize(); - x.crossVectors( up, z ); - - if ( x.lengthSq() === 0 ) { - - // up and z are parallel - - if ( Math.abs( up.z ) === 1 ) { - - z.x += 0.0001; - - } else { - - z.z += 0.0001; - - } - - z.normalize(); - x.crossVectors( up, z ); - - } - - x.normalize(); - y.crossVectors( z, x ); - - te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x; - te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y; - te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z; - - return this; - - }; - - }(), - - multiply: function ( m, n ) { - - if ( n !== undefined ) { - - console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); - - } - - return this.multiplyMatrices( this, m ); - - }, - - premultiply: function ( m ) { - - return this.multiplyMatrices( m, this ); - - }, - - multiplyMatrices: function ( a, b ) { - - var ae = a.elements; - var be = b.elements; - var te = this.elements; - - var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - - var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - - return this; - - }, - - multiplyScalar: function ( s ) { - - var te = this.elements; - - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - - return this; - - }, - - applyToBufferAttribute: function () { - - var v1 = new Vector3(); - - return function applyToBufferAttribute( attribute ) { - - for ( var i = 0, l = attribute.count; i < l; i ++ ) { - - v1.x = attribute.getX( i ); - v1.y = attribute.getY( i ); - v1.z = attribute.getZ( i ); - - v1.applyMatrix4( this ); - - attribute.setXYZ( i, v1.x, v1.y, v1.z ); - - } - - return attribute; - - }; - - }(), - - determinant: function () { - - var te = this.elements; - - var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - - return ( - n41 * ( - + n14 * n23 * n32 - - n13 * n24 * n32 - - n14 * n22 * n33 - + n12 * n24 * n33 - + n13 * n22 * n34 - - n12 * n23 * n34 - ) + - n42 * ( - + n11 * n23 * n34 - - n11 * n24 * n33 - + n14 * n21 * n33 - - n13 * n21 * n34 - + n13 * n24 * n31 - - n14 * n23 * n31 - ) + - n43 * ( - + n11 * n24 * n32 - - n11 * n22 * n34 - - n14 * n21 * n32 - + n12 * n21 * n34 - + n14 * n22 * n31 - - n12 * n24 * n31 - ) + - n44 * ( - - n13 * n22 * n31 - - n11 * n23 * n32 - + n11 * n22 * n33 - + n13 * n21 * n32 - - n12 * n21 * n33 - + n12 * n23 * n31 - ) - - ); - - }, - - transpose: function () { - - var te = this.elements; - var tmp; - - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; - - return this; - - }, - - setPosition: function ( v ) { - - var te = this.elements; - - te[ 12 ] = v.x; - te[ 13 ] = v.y; - te[ 14 ] = v.z; - - return this; - - }, - - getInverse: function ( m, throwOnDegenerate ) { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements, - me = m.elements, - - n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ], - n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ], - n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ], - n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ], - - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - - var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - - if ( det === 0 ) { - - var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; - - if ( throwOnDegenerate === true ) { - - throw new Error( msg ); - - } else { - - console.warn( msg ); - - } - - return this.identity(); - - } - - var detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; - - return this; - - }, - - scale: function ( v ) { - - var te = this.elements; - var x = v.x, y = v.y, z = v.z; - - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; - - return this; - - }, - - getMaxScaleOnAxis: function () { - - var te = this.elements; - - var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; - - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); - - }, - - makeTranslation: function ( x, y, z ) { - - this.set( - - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationX: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationY: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationZ: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationAxis: function ( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - var c = Math.cos( angle ); - var s = Math.sin( angle ); - var t = 1 - c; - var x = axis.x, y = axis.y, z = axis.z; - var tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeScale: function ( x, y, z ) { - - this.set( - - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeShear: function ( x, y, z ) { - - this.set( - - 1, y, z, 0, - x, 1, z, 0, - x, y, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - compose: function ( position, quaternion, scale ) { - - this.makeRotationFromQuaternion( quaternion ); - this.scale( scale ); - this.setPosition( position ); - - return this; - - }, - - decompose: function () { - - var vector = new Vector3(); - var matrix = new Matrix4(); - - return function decompose( 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.copy( this ); - - var invSX = 1 / sx; - var invSY = 1 / sy; - var invSZ = 1 / sz; - - matrix.elements[ 0 ] *= invSX; - matrix.elements[ 1 ] *= invSX; - matrix.elements[ 2 ] *= invSX; - - matrix.elements[ 4 ] *= invSY; - matrix.elements[ 5 ] *= invSY; - matrix.elements[ 6 ] *= invSY; - - matrix.elements[ 8 ] *= invSZ; - matrix.elements[ 9 ] *= invSZ; - matrix.elements[ 10 ] *= invSZ; - - quaternion.setFromRotationMatrix( matrix ); - - scale.x = sx; - scale.y = sy; - scale.z = sz; - - return this; - - }; - - }(), - - makePerspective: function ( left, right, top, bottom, near, far ) { - - if ( far === undefined ) { - - console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); - - } - - var te = this.elements; - var x = 2 * near / ( right - left ); - var y = 2 * near / ( top - bottom ); - - var a = ( right + left ) / ( right - left ); - var b = ( top + bottom ) / ( top - bottom ); - var c = - ( far + near ) / ( far - near ); - var d = - 2 * far * near / ( far - near ); - - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - - return this; - - }, - - makeOrthographic: function ( left, right, top, bottom, near, far ) { - - var te = this.elements; - var w = 1.0 / ( right - left ); - var h = 1.0 / ( top - bottom ); - var p = 1.0 / ( far - near ); - - var x = ( right + left ) * w; - var y = ( top + bottom ) * h; - var z = ( far + near ) * p; - - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - - return this; - - }, - - equals: function ( matrix ) { - - var te = this.elements; - var me = matrix.elements; - - for ( var i = 0; i < 16; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - for ( var i = 0; i < 16; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - var te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; - - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; - - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; - - return array; - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - */ - -function Quaternion( x, y, z, w ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; - -} - -Object.assign( Quaternion, { - - slerp: function ( qa, qb, qm, t ) { - - return qm.copy( qa ).slerp( qb, t ); - - }, - - slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - - // fuzz-free, array-based Quaternion SLERP operation - - var x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ], - - x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - - var s = 1 - t, - - cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; - - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { - - var sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); - - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; - - } - - var tDir = t * dir; - - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; - - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { - - var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; - - } - - } - - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - - } - -} ); - -Object.defineProperties( Quaternion.prototype, { - - x: { - - get: function () { - - return this._x; - - }, - - set: function ( value ) { - - this._x = value; - this.onChangeCallback(); - - } - - }, - - y: { - - get: function () { - - return this._y; - - }, - - set: function ( value ) { - - this._y = value; - this.onChangeCallback(); - - } - - }, - - z: { - - get: function () { - - return this._z; - - }, - - set: function ( value ) { - - this._z = value; - this.onChangeCallback(); - - } - - }, - - w: { - - get: function () { - - return this._w; - - }, - - set: function ( value ) { - - this._w = value; - this.onChangeCallback(); - - } - - } - -} ); - -Object.assign( Quaternion.prototype, { - - set: function ( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this.onChangeCallback(); - - return this; - - }, - - clone: function () { - - return new this.constructor( this._x, this._y, this._z, this._w ); - - }, - - copy: function ( quaternion ) { - - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; - - this.onChangeCallback(); - - return this; - - }, - - setFromEuler: function ( euler, update ) { - - if ( ! ( euler && euler.isEuler ) ) { - - throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - - } - - var x = euler._x, y = euler._y, z = euler._z, order = euler.order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - var cos = Math.cos; - var sin = Math.sin; - - var c1 = cos( x / 2 ); - var c2 = cos( y / 2 ); - var c3 = cos( z / 2 ); - - var s1 = sin( x / 2 ); - var s2 = sin( y / 2 ); - var s3 = sin( z / 2 ); - - if ( order === 'XYZ' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( order === 'YXZ' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } else if ( order === 'ZXY' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( order === 'ZYX' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } else if ( order === 'YZX' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( order === 'XZY' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } - - if ( update !== false ) this.onChangeCallback(); - - return this; - - }, - - setFromAxisAngle: function ( axis, angle ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - - // assumes axis is normalized - - var halfAngle = angle / 2, s = Math.sin( halfAngle ); - - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); - - this.onChangeCallback(); - - return this; - - }, - - setFromRotationMatrix: function ( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - var te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - - trace = m11 + m22 + m33, - s; - - if ( trace > 0 ) { - - s = 0.5 / Math.sqrt( trace + 1.0 ); - - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; - - } else if ( m11 > m22 && m11 > m33 ) { - - s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; - - } else if ( m22 > m33 ) { - - s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; - - } else { - - s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; - - } - - this.onChangeCallback(); - - return this; - - }, - - setFromUnitVectors: function () { - - // assumes direction vectors vFrom and vTo are normalized - - var v1 = new Vector3(); - var r; - - var EPS = 0.000001; - - return function setFromUnitVectors( vFrom, vTo ) { - - if ( v1 === undefined ) v1 = new Vector3(); - - r = vFrom.dot( vTo ) + 1; - - if ( r < EPS ) { - - r = 0; - - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - - v1.set( - vFrom.y, vFrom.x, 0 ); - - } else { - - v1.set( 0, - vFrom.z, vFrom.y ); - - } - - } else { - - v1.crossVectors( vFrom, vTo ); - - } - - this._x = v1.x; - this._y = v1.y; - this._z = v1.z; - this._w = r; - - return this.normalize(); - - }; - - }(), - - inverse: function () { - - return this.conjugate().normalize(); - - }, - - conjugate: function () { - - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; - - this.onChangeCallback(); - - return this; - - }, - - dot: function ( v ) { - - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - - }, - - lengthSq: function () { - - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - - }, - - length: function () { - - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - - }, - - normalize: function () { - - var l = this.length(); - - if ( l === 0 ) { - - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; - - } else { - - l = 1 / l; - - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; - - } - - this.onChangeCallback(); - - return this; - - }, - - multiply: function ( q, p ) { - - if ( p !== undefined ) { - - console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); - - } - - return this.multiplyQuaternions( this, q ); - - }, - - premultiply: function ( q ) { - - return this.multiplyQuaternions( q, this ); - - }, - - multiplyQuaternions: function ( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - - var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - this.onChangeCallback(); - - return this; - - }, - - slerp: function ( qb, t ) { - - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); - - var x = this._x, y = this._y, z = this._z, w = this._w; - - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - - var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { - - this._w = w; - this._x = x; - this._y = y; - this._z = z; - - return this; - - } - - var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); - - if ( Math.abs( sinHalfTheta ) < 0.001 ) { - - this._w = 0.5 * ( w + this._w ); - this._x = 0.5 * ( x + this._x ); - this._y = 0.5 * ( y + this._y ); - this._z = 0.5 * ( z + this._z ); - - return this; - - } - - var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); - - this.onChangeCallback(); - - return this; - - }, - - equals: function ( quaternion ) { - - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; - - this.onChangeCallback(); - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; - - return array; - - }, - - onChange: function ( callback ) { - - this.onChangeCallback = callback; - - return this; - - }, - - onChangeCallback: function () {} - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -function Vector3( x, y, z ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - -} - -Object.assign( Vector3.prototype, { - - isVector3: true, - - set: function ( x, y, z ) { - - this.x = x; - this.y = y; - this.z = z; - - return this; - - }, - - setScalar: function ( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setZ: function ( z ) { - - this.z = z; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); - - } - - }, - - clone: function () { - - return new this.constructor( this.x, this.y, this.z ); - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - this.z += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - - return this; - - }, - - addScaledVector: function ( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - - return this; - - }, - - subScalar: function ( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - - return this; - - }, - - multiply: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); - return this.multiplyVectors( v, w ); - - } - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - 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 = new Quaternion(); - - return function applyEuler( euler ) { - - if ( ! ( euler && euler.isEuler ) ) { - - console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - - } - - return this.applyQuaternion( quaternion.setFromEuler( euler ) ); - - }; - - }(), - - applyAxisAngle: function () { - - var quaternion = new Quaternion(); - - return function applyAxisAngle( axis, angle ) { - - return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); - - }; - - }(), - - applyMatrix3: function ( m ) { - - var x = this.x, y = this.y, z = this.z; - var e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - - return this; - - }, - - applyMatrix4: function ( m ) { - - var x = this.x, y = this.y, z = this.z; - var e = m.elements; - - var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - - 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; - - return this; - - }, - - applyQuaternion: function ( q ) { - - var x = this.x, y = this.y, z = this.z; - var qx = q.x, qy = q.y, qz = q.z, qw = q.w; - - // calculate quat * vector - - var ix = qw * x + qy * z - qz * y; - var iy = qw * y + qz * x - qx * z; - var iz = qw * z + qx * y - qy * x; - var iw = - qx * x - qy * y - qz * z; - - // calculate result * inverse quat - - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; - - return this; - - }, - - project: function () { - - var matrix = new Matrix4(); - - return function project( camera ) { - - matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); - return this.applyMatrix4( matrix ); - - }; - - }(), - - unproject: function () { - - var matrix = new Matrix4(); - - return function unproject( camera ) { - - matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); - return this.applyMatrix4( matrix ); - - }; - - }(), - - transformDirection: function ( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - var x = this.x, y = this.y, z = this.z; - var e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - - return this.normalize(); - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - }, - - divideScalar: function ( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - }, - - min: function ( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - - return this; - - }, - - max: function ( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - - return this; - - }, - - clamp: function ( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - - return this; - - }, - - clampScalar: function () { - - var min = new Vector3(); - var max = new Vector3(); - - return function clampScalar( minVal, maxVal ) { - - min.set( minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - }(), - - clampLength: function ( min, max ) { - - var length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - }, - - floor: function () { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - - return this; - - }, - - ceil: function () { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - - return this; - - }, - - round: function () { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - - return this; - - }, - - roundToZero: function () { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - - return this; - - }, - - negate: function () { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - - return this; - - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; - - }, - - // TODO lengthSquared? - - 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() || 1 ); - - }, - - setLength: function ( length ) { - - return this.normalize().multiplyScalar( length ); - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - - return this; - - }, - - lerpVectors: function ( v1, v2, alpha ) { - - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - }, - - cross: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); - return this.crossVectors( v, w ); - - } - - var x = this.x, y = this.y, z = this.z; - - this.x = y * v.z - z * v.y; - this.y = z * v.x - x * v.z; - this.z = x * v.y - y * v.x; - - return this; - - }, - - crossVectors: function ( a, b ) { - - var ax = a.x, ay = a.y, az = a.z; - var bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - - }, - - projectOnVector: function ( vector ) { - - var scalar = vector.dot( this ) / vector.lengthSq(); - - return this.copy( vector ).multiplyScalar( scalar ); - - }, - - projectOnPlane: function () { - - var v1 = new Vector3(); - - return function projectOnPlane( planeNormal ) { - - 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 = new Vector3(); - - return function reflect( normal ) { - - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - }; - - }(), - - angleTo: function ( v ) { - - var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); - - // clamp, to handle numerical problems - - return Math.acos( _Math.clamp( theta, - 1, 1 ) ); - - }, - - distanceTo: function ( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - }, - - distanceToSquared: function ( v ) { - - var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - }, - - distanceToManhattan: function ( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); - - }, - - setFromSpherical: function ( s ) { - - var sinPhiRadius = Math.sin( s.phi ) * s.radius; - - this.x = sinPhiRadius * Math.sin( s.theta ); - this.y = Math.cos( s.phi ) * s.radius; - this.z = sinPhiRadius * Math.cos( s.theta ); - - return this; - - }, - - setFromCylindrical: function ( c ) { - - this.x = c.radius * Math.sin( c.theta ); - this.y = c.y; - this.z = c.radius * Math.cos( c.theta ); - - return this; - - }, - - setFromMatrixPosition: function ( m ) { - - var e = m.elements; - - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; - - return this; - - }, - - setFromMatrixScale: function ( m ) { - - var sx = this.setFromMatrixColumn( m, 0 ).length(); - var sy = this.setFromMatrixColumn( m, 1 ).length(); - var sz = this.setFromMatrixColumn( m, 2 ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - - }, - - setFromMatrixColumn: function ( m, index ) { - - return this.fromArray( m.elements, index * 4 ); - - }, - - equals: function ( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - - return array; - - }, - - fromBufferAttribute: function ( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - - return this; - - } - -} ); - -var VERSION = '1.2.2'; - -var MATERIAL_LINE = 1; -var MATERIAL_SURFACE = 2; - -var CAMERA_ORTHOGRAPHIC = 1; -var CAMERA_PERSPECTIVE = 2; -var CAMERA_OFFSET = 600; - -// preset camera views - -var VIEW_NONE = 0; -var VIEW_PLAN = 1; -var VIEW_ELEVATION_N = 2; -var VIEW_ELEVATION_S = 3; -var VIEW_ELEVATION_E = 4; -var VIEW_ELEVATION_W = 5; - -// mouse selection operation mode - -var MOUSE_MODE_NORMAL = 0; -var MOUSE_MODE_ROUTE_EDIT = 1; -// shading types - -var SHADING_HEIGHT = 1; -var SHADING_LENGTH = 2; -var SHADING_INCLINATION = 3; -var SHADING_CURSOR = 4; -var SHADING_SINGLE = 5; -var SHADING_SURVEY = 6; -var SHADING_OVERLAY = 7; -var SHADING_SHADED = 8; -var SHADING_DEPTH = 9; -var SHADING_PATH = 10; -var SHADING_DEPTH_CURSOR = 11; - -// layer tags for scene objects - -var LEG_CAVE = 1; -var LEG_SPLAY = 2; -var LEG_SURFACE = 3; -var FEATURE_BOX = 4; -var FEATURE_SELECTED_BOX = 5; -var FEATURE_ENTRANCES = 6; -var FEATURE_TERRAIN = 7; -var FEATURE_STATIONS = 8; -var FEATURE_TRACES = 9; - -var FACE_WALLS = 10; -var FACE_SCRAPS = 11; - -var LABEL_STATION = 12; - -// flags in legs exported by Cave models - -var NORMAL = 0; -var SURFACE = 1; -var SPLAY = 2; -var DIVING = 3; - -var STATION_NORMAL = 0; -var STATION_ENTRANCE = 1; - -var upAxis = new Vector3( 0, 0, 1 ); - -// EOF - -var environment = new Map(); - -function setEnvironment ( envs ) { - - if ( envs === undefined ) return; - - var pName; - - for ( pName in envs ) { - - environment.set ( pName , envs[ pName ] ); - - } - -} - -function getEnvironmentValue ( item, defaultValue ) { - - if ( environment.has( item ) ) { - - return environment.get( item ); - - } else { - - return defaultValue; - - } - -} - -function replaceExtension( fileName, newExtention ) { - - return fileName.split( '.' ).shift() + '.' + newExtention; - -} - -// polyfill padStart for IE11 - now supported for Chrome, FireFox and Edge - -if ( ! String.prototype.padStart ) { - - String.prototype.padStart = function padStart( targetLength, padString ) { - - targetLength = targetLength >> 0; //floor if number or convert non-number to 0; - padString = String( padString || ' ' ); - - if (this.length > targetLength) { - - return String( this ); - - } else { - - targetLength = targetLength - this.length; - - if ( targetLength > padString.length ) { - - padString += padString.repeat( targetLength / padString.length ); //append to original to ensure we are longer than needed - - } - - return padString.slice( 0, targetLength ) + String( this ); - - } - - }; - -} - -if ( ! String.prototype.repeat ) { - - String.prototype.repeat = function( count ) { - - if ( this == null ) throw new TypeError( 'can\'t convert ' + this + ' to object' ); - - var str = '' + this; - - count = +count; - - if ( count != count ) count = 0; - - if ( count < 0 ) throw new RangeError( 'repeat count must be non-negative' ); - - if ( count == Infinity ) throw new RangeError( 'repeat count must be less than infinity' ); - - count = Math.floor( count ); - - if ( str.length == 0 || count == 0 ) return ''; - - // Ensuring count is a 31-bit integer allows us to heavily optimize the - // main part. But anyway, most current (August 2014) browsers can't handle - // strings 1 << 28 chars or longer, so: - - if ( str.length * count >= 1 << 28 ) throw new RangeError('repeat count must not overflow maximum string size'); - - var rpt = ''; - - for (;;) { - - if ( ( count & 1) == 1 ) rpt += str; - - count >>>= 1; - - if ( count == 0 ) break; - - str += str; - - } - - // Could we try: - // return Array(count + 1).join(this); - - return rpt; - - }; - -} - - - - -// EOF - -function HudObject () {} - -HudObject.stdWidth = 40; -HudObject.stdMargin = 5; - -HudObject.prototype.removeDomObjects = function () { - - var obj; - - for ( var i = 0, l = this.domObjects.length; i < l; i++ ) { - - obj = this.domObjects[ i ]; - - obj.parentElement.removeChild( obj ); - - } - - this.domObjects = []; - -}; - -HudObject.prototype.setVisibility = function ( visible ) { - - var style; - - this.visible = visible; - - style = ( visible ? 'block' : 'none' ); - - for ( var i = 0, l = this.domObjects.length; i < l; i++ ) { - - this.domObjects[ i ].style.display = style; - - } - -}; - - - -// EOF - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - -function Color( r, g, b ) { - - if ( g === undefined && b === undefined ) { - - // r is THREE.Color, hex or string - return this.set( r ); - - } - - return this.setRGB( r, g, b ); - -} - -Object.assign( Color.prototype, { - - isColor: true, - - r: 1, g: 1, b: 1, - - set: function ( value ) { - - if ( value && value.isColor ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - return this; - - }, - - setScalar: function ( scalar ) { - - this.r = scalar; - this.g = scalar; - this.b = scalar; - - return this; - - }, - - setHex: function ( hex ) { - - hex = Math.floor( hex ); - - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; - - return this; - - }, - - setRGB: function ( r, g, b ) { - - this.r = r; - this.g = g; - this.b = b; - - return this; - - }, - - setHSL: function () { - - function hue2rgb( p, q, t ) { - - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; - - } - - return function setHSL( h, s, l ) { - - // h,s,l ranges are in 0.0 - 1.0 - h = _Math.euclideanModulo( h, 1 ); - s = _Math.clamp( s, 0, 1 ); - l = _Math.clamp( l, 0, 1 ); - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - var q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } - - return this; - - }; - - }(), - - setStyle: function ( style ) { - - function handleAlpha( string ) { - - if ( string === undefined ) return; - - if ( parseFloat( string ) < 1 ) { - - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - - } - - } - - - var m; - - if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { - - // rgb / hsl - - var color; - var name = m[ 1 ]; - var components = m[ 2 ]; - - switch ( name ) { - - case 'rgb': - case 'rgba': - - if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; - - handleAlpha( color[ 5 ] ); - - return this; - - } - - if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - - handleAlpha( color[ 5 ] ); - - return this; - - } - - break; - - case 'hsl': - case 'hsla': - - if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - var h = parseFloat( color[ 1 ] ) / 360; - var s = parseInt( color[ 2 ], 10 ) / 100; - var l = parseInt( color[ 3 ], 10 ) / 100; - - handleAlpha( color[ 5 ] ); - - return this.setHSL( h, s, l ); - - } - - break; - - } - - } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { - - // hex color - - var hex = m[ 1 ]; - var size = hex.length; - - if ( size === 3 ) { - - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; - - return this; - - } else if ( size === 6 ) { - - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; - - return this; - - } - - } - - if ( style && style.length > 0 ) { - - // color keywords - var hex = ColorKeywords[ style ]; - - if ( hex !== undefined ) { - - // red - this.setHex( hex ); - - } else { - - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); - - } - - } - - return this; - - }, - - clone: function () { - - return new this.constructor( this.r, this.g, this.b ); - - }, - - copy: function ( color ) { - - this.r = color.r; - this.g = color.g; - this.b = color.b; - - return this; - - }, - - copyGammaToLinear: function ( color, gammaFactor ) { - - if ( gammaFactor === undefined ) gammaFactor = 2.0; - - this.r = Math.pow( color.r, gammaFactor ); - this.g = Math.pow( color.g, gammaFactor ); - this.b = Math.pow( color.b, gammaFactor ); - - return this; - - }, - - copyLinearToGamma: function ( color, gammaFactor ) { - - if ( gammaFactor === undefined ) gammaFactor = 2.0; - - var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - - this.r = Math.pow( color.r, safeInverse ); - this.g = Math.pow( color.g, safeInverse ); - this.b = Math.pow( color.b, safeInverse ); - - return this; - - }, - - convertGammaToLinear: function () { - - var r = this.r, g = this.g, b = this.b; - - this.r = r * r; - this.g = g * g; - this.b = b * b; - - return this; - - }, - - convertLinearToGamma: function () { - - this.r = Math.sqrt( this.r ); - this.g = Math.sqrt( this.g ); - this.b = Math.sqrt( this.b ); - - return this; - - }, - - getHex: function () { - - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - - }, - - getHexString: function () { - - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - - }, - - getHSL: function ( optionalTarget ) { - - // h,s,l ranges are in 0.0 - 1.0 - - var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; - - var r = this.r, g = this.g, b = this.b; - - var max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); - - var hue, saturation; - var lightness = ( min + max ) / 2.0; - - if ( min === max ) { - - hue = 0; - saturation = 0; - - } else { - - var delta = max - min; - - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - - switch ( max ) { - - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; - - } - - hue /= 6; - - } - - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; - - return hsl; - - }, - - getStyle: function () { - - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - - }, - - offsetHSL: function ( h, s, l ) { - - var hsl = this.getHSL(); - - hsl.h += h; hsl.s += s; hsl.l += l; - - this.setHSL( hsl.h, hsl.s, hsl.l ); - - return this; - - }, - - add: function ( color ) { - - this.r += color.r; - this.g += color.g; - this.b += color.b; - - return this; - - }, - - addColors: function ( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; - - return this; - - }, - - addScalar: function ( s ) { - - this.r += s; - this.g += s; - this.b += s; - - return this; - - }, - - sub: function( color ) { - - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); - - return this; - - }, - - multiply: function ( color ) { - - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; - - return this; - - }, - - multiplyScalar: function ( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; - - }, - - lerp: function ( color, alpha ) { - - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; - - return this; - - }, - - equals: function ( c ) { - - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; - - return array; - - }, - - toJSON: function () { - - return this.getHex(); - - } - -} ); - -var gradientColours = [[235,99,111],[235,99,112],[234,99,113],[234,100,114],[233,100,114],[233,100,115],[232,100,116],[232,101,117],[231,101,118],[231,101,119],[230,101,119],[230,101,120],[230,102,121],[229,102,122],[229,102,123],[228,102,124],[228,103,124],[227,103,125],[227,103,126],[226,103,127],[226,103,128],[226,104,129],[225,104,129],[225,104,130],[224,104,131],[224,104,132],[223,105,133],[223,105,134],[222,105,134],[222,105,135],[221,106,136],[221,106,137],[221,106,138],[220,106,139],[220,106,139],[219,107,140],[219,107,141],[218,107,142],[218,107,143],[217,108,144],[217,108,144],[216,108,145],[216,108,146],[216,108,147],[215,109,148],[215,109,149],[214,109,149],[214,109,150],[213,110,151],[213,110,152],[212,110,153],[212,110,154],[211,110,154],[211,111,155],[211,111,156],[210,111,157],[210,111,158],[209,111,159],[209,112,159],[208,112,160],[208,112,161],[207,112,162],[207,113,163],[207,113,164],[206,113,164],[206,113,165],[205,113,166],[205,114,167],[204,114,168],[204,114,169],[203,114,169],[203,115,170],[202,115,171],[202,115,172],[201,115,172],[200,116,173],[199,116,173],[198,116,173],[197,117,174],[196,117,174],[194,118,174],[193,118,175],[192,118,175],[191,119,176],[190,119,176],[189,119,176],[188,120,177],[187,120,177],[186,121,177],[185,121,178],[184,121,178],[183,122,178],[181,122,179],[180,122,179],[179,123,179],[178,123,180],[177,124,180],[176,124,181],[175,124,181],[174,125,181],[173,125,182],[172,125,182],[171,126,182],[170,126,183],[168,126,183],[167,127,183],[166,127,184],[165,128,184],[164,128,184],[163,128,185],[162,129,185],[161,129,186],[160,129,186],[159,130,186],[158,130,187],[157,131,187],[155,131,187],[154,131,188],[153,132,188],[152,132,188],[151,132,189],[150,133,189],[149,133,189],[148,133,190],[147,134,190],[146,134,191],[145,135,191],[144,135,191],[142,135,192],[141,136,192],[140,136,192],[139,136,193],[138,137,193],[137,137,193],[136,138,194],[135,138,194],[134,138,194],[133,139,195],[132,139,195],[131,139,196],[129,140,196],[128,140,196],[127,141,197],[126,141,197],[125,141,197],[124,142,198],[123,142,198],[122,142,198],[120,142,197],[119,143,197],[117,143,197],[116,143,197],[114,143,196],[113,144,196],[111,144,196],[110,144,195],[108,144,195],[107,144,195],[105,145,195],[104,145,194],[102,145,194],[101,145,194],[100,146,193],[98,146,193],[97,146,193],[95,146,193],[94,146,192],[92,147,192],[91,147,192],[89,147,191],[88,147,191],[86,147,191],[85,148,191],[83,148,190],[82,148,190],[80,148,190],[79,149,189],[78,149,189],[76,149,189],[75,149,189],[73,149,188],[72,150,188],[70,150,188],[69,150,187],[67,150,187],[66,151,187],[64,151,186],[63,151,186],[61,151,186],[60,151,186],[59,152,185],[57,152,185],[56,152,185],[54,152,184],[53,153,184],[51,153,184],[50,153,184],[48,153,183],[47,153,183],[45,154,183],[44,154,182],[42,154,182],[41,154,182],[39,154,182],[38,155,181],[37,155,181],[35,155,181],[34,155,180],[32,156,180],[31,156,180],[29,156,180],[28,156,179],[26,156,179],[25,157,179],[23,157,178],[22,157,178],[20,157,178],[19,158,178],[17,158,177],[16,158,177],[16,158,176],[17,158,176],[17,158,175],[18,158,174],[18,158,174],[19,158,173],[19,158,172],[20,158,171],[20,158,171],[21,158,170],[21,158,169],[22,158,169],[22,159,168],[23,159,167],[23,159,167],[23,159,166],[24,159,165],[24,159,164],[25,159,164],[25,159,163],[26,159,162],[26,159,162],[27,159,161],[27,159,160],[28,159,160],[28,159,159],[29,159,158],[29,159,157],[30,159,157],[30,159,156],[30,159,155],[31,159,155],[31,159,154],[32,159,153],[32,159,153],[33,159,152],[33,160,151],[34,160,150],[34,160,150],[35,160,149],[35,160,148],[36,160,148],[36,160,147],[36,160,146],[37,160,146],[37,160,145],[38,160,144],[38,160,143],[39,160,143],[39,160,142],[40,160,141],[40,160,141],[41,160,140],[41,160,139],[42,160,139],[42,160,138],[43,160,137],[43,160,136],[43,160,136],[44,160,135],[44,161,134],[45,161,134],[45,161,133],[46,161,132],[46,161,132],[47,161,131],[47,161,130],[48,161,129],[48,161,129],[49,161,128],[49,161,127],[50,161,127],[50,161,126],[51,161,125],[52,161,125],[53,161,124],[54,161,123],[55,161,123],[56,161,122],[56,160,121],[57,160,121],[58,160,120],[59,160,120],[60,160,119],[61,160,118],[62,160,118],[63,160,117],[64,160,116],[65,160,116],[66,160,115],[67,160,114],[67,159,114],[68,159,113],[69,159,112],[70,159,112],[71,159,111],[72,159,111],[73,159,110],[74,159,109],[75,159,109],[76,159,108],[77,159,107],[78,159,107],[78,158,106],[79,158,105],[80,158,105],[81,158,104],[82,158,103],[83,158,103],[84,158,102],[85,158,102],[86,158,101],[87,158,100],[88,158,100],[89,158,99],[89,157,98],[90,157,98],[91,157,97],[92,157,96],[93,157,96],[94,157,95],[95,157,94],[96,157,94],[97,157,93],[98,157,93],[99,157,92],[100,157,91],[100,156,91],[101,156,90],[102,156,89],[103,156,89],[104,156,88],[105,156,87],[106,156,87],[107,156,86],[108,156,85],[109,156,85],[110,156,84],[111,156,84],[111,155,83],[112,155,82],[113,155,82],[114,155,81],[115,155,80],[116,155,80],[117,155,79],[118,155,79],[118,155,79],[119,154,78],[120,154,78],[121,154,78],[121,154,78],[122,154,78],[123,153,77],[123,153,77],[124,153,77],[125,153,77],[126,153,77],[126,152,77],[127,152,76],[128,152,76],[128,152,76],[129,152,76],[130,151,76],[131,151,75],[131,151,75],[132,151,75],[133,150,75],[133,150,75],[134,150,74],[135,150,74],[136,150,74],[136,149,74],[137,149,74],[138,149,73],[138,149,73],[139,149,73],[140,148,73],[141,148,73],[141,148,72],[142,148,72],[143,148,72],[143,147,72],[144,147,72],[145,147,72],[145,147,71],[146,147,71],[147,146,71],[148,146,71],[148,146,71],[149,146,70],[150,146,70],[150,145,70],[151,145,70],[152,145,70],[153,145,69],[153,145,69],[154,144,69],[155,144,69],[155,144,69],[156,144,68],[157,143,68],[158,143,68],[158,143,68],[159,143,68],[160,143,67],[160,142,67],[161,142,67],[162,142,67],[163,142,67],[163,142,67],[164,141,66],[165,141,66],[165,141,66],[166,141,66],[167,141,66],[168,140,65],[168,140,65],[169,140,65],[169,140,65],[170,140,66],[170,139,66],[171,139,66],[171,139,67],[172,139,67],[172,139,67],[172,138,68],[173,138,68],[173,138,68],[174,138,69],[174,138,69],[175,137,69],[175,137,70],[175,137,70],[176,137,70],[176,137,71],[177,136,71],[177,136,71],[177,136,72],[178,136,72],[178,135,72],[179,135,73],[179,135,73],[180,135,73],[180,135,74],[180,134,74],[181,134,74],[181,134,75],[182,134,75],[182,134,75],[183,133,76],[183,133,76],[183,133,76],[184,133,77],[184,133,77],[185,132,77],[185,132,77],[186,132,78],[186,132,78],[186,132,78],[187,131,79],[187,131,79],[188,131,79],[188,131,80],[189,131,80],[189,130,80],[189,130,81],[190,130,81],[190,130,81],[191,130,82],[191,129,82],[192,129,82],[192,129,83],[192,129,83],[193,128,83],[193,128,84],[194,128,84],[194,128,84],[194,128,85],[195,127,85],[195,127,85],[196,127,86],[196,127,86],[197,127,86],[197,126,87],[197,126,87],[198,126,87],[198,126,88],[199,126,88],[199,125,88],[200,125,89],[200,125,89]]; -var depthColours = [[255,255,204],[255,255,203],[255,255,203],[255,254,202],[255,254,202],[255,254,201],[255,254,200],[255,253,200],[255,253,199],[255,253,199],[255,253,198],[255,252,197],[255,252,197],[255,252,196],[255,252,196],[255,251,195],[255,251,194],[255,251,194],[255,251,193],[255,250,193],[255,250,192],[255,250,191],[255,250,191],[255,249,190],[255,249,190],[255,249,189],[255,249,188],[255,248,188],[255,248,187],[255,248,187],[255,248,186],[255,247,185],[255,247,185],[255,247,184],[255,247,184],[255,246,183],[255,246,182],[255,246,182],[255,246,181],[255,245,180],[255,245,180],[255,245,179],[255,245,179],[255,244,178],[255,244,177],[255,244,177],[255,244,176],[255,243,176],[255,243,175],[255,243,174],[255,243,174],[255,242,173],[255,242,173],[255,242,172],[255,242,171],[255,241,171],[255,241,170],[255,241,170],[255,241,169],[255,240,168],[255,240,168],[255,240,167],[255,240,167],[255,239,166],[255,239,165],[255,239,165],[255,239,164],[255,238,164],[255,238,163],[255,238,162],[255,238,162],[255,237,161],[255,237,161],[255,237,160],[255,237,159],[255,236,159],[255,236,158],[255,236,158],[255,236,157],[255,235,157],[255,235,156],[255,235,155],[255,235,155],[255,234,154],[255,234,154],[255,234,153],[255,233,153],[255,233,152],[255,233,151],[255,233,151],[255,232,150],[255,232,150],[255,232,149],[255,232,148],[255,231,148],[255,231,147],[255,231,147],[255,230,146],[255,230,146],[255,230,145],[255,230,144],[255,229,144],[255,229,143],[255,229,143],[255,229,142],[255,228,142],[255,228,141],[255,228,140],[255,227,140],[255,227,139],[254,227,139],[254,227,138],[254,226,138],[254,226,137],[254,226,136],[254,225,136],[254,225,135],[254,225,135],[254,225,134],[254,224,134],[254,224,133],[254,224,132],[254,224,132],[254,223,131],[254,223,131],[254,223,130],[254,222,130],[254,222,129],[254,222,128],[254,222,128],[254,221,127],[254,221,127],[254,221,126],[254,221,125],[254,220,125],[254,220,124],[254,220,124],[254,219,123],[254,219,123],[254,219,122],[254,219,121],[254,218,121],[254,218,120],[254,218,120],[254,218,119],[254,217,119],[254,217,118],[254,216,117],[254,216,117],[254,215,116],[254,215,116],[254,214,115],[254,214,115],[254,213,114],[254,213,113],[254,212,113],[254,212,112],[254,211,112],[254,211,111],[254,210,111],[254,210,110],[254,209,109],[254,208,109],[254,208,108],[254,207,108],[254,207,107],[254,206,106],[254,206,106],[254,205,105],[254,205,105],[254,204,104],[254,204,104],[254,203,103],[254,203,102],[254,202,102],[254,202,101],[254,201,101],[254,200,100],[254,200,100],[254,199,99],[254,199,98],[254,198,98],[254,198,97],[254,197,97],[254,197,96],[254,196,96],[254,196,95],[254,195,94],[254,195,94],[254,194,93],[254,193,93],[254,193,92],[254,192,92],[254,192,91],[254,191,90],[254,191,90],[254,190,89],[254,190,89],[254,189,88],[254,189,88],[254,188,87],[254,188,86],[254,187,86],[254,187,85],[254,186,85],[254,185,84],[254,185,83],[254,184,83],[254,184,82],[254,183,82],[254,183,81],[254,182,81],[254,182,80],[254,181,79],[254,181,79],[254,180,78],[254,180,78],[254,179,77],[254,179,77],[254,178,76],[254,177,76],[254,177,76],[254,176,75],[254,176,75],[254,175,75],[254,175,75],[254,174,74],[254,174,74],[254,173,74],[254,173,74],[254,172,74],[254,172,73],[254,171,73],[254,171,73],[254,170,73],[254,170,72],[254,169,72],[254,169,72],[254,168,72],[254,168,72],[254,167,71],[254,167,71],[254,166,71],[254,166,71],[254,165,71],[254,165,70],[254,164,70],[254,164,70],[254,163,70],[254,163,69],[254,162,69],[254,162,69],[254,161,69],[254,161,69],[254,160,68],[254,160,68],[253,159,68],[253,159,68],[253,158,67],[253,158,67],[253,157,67],[253,157,67],[253,156,67],[253,156,66],[253,155,66],[253,155,66],[253,154,66],[253,154,65],[253,153,65],[253,153,65],[253,152,65],[253,152,65],[253,151,64],[253,151,64],[253,150,64],[253,150,64],[253,149,64],[253,149,63],[253,148,63],[253,148,63],[253,147,63],[253,147,62],[253,146,62],[253,146,62],[253,145,62],[253,145,62],[253,144,61],[253,144,61],[253,143,61],[253,143,61],[253,142,60],[253,142,60],[253,141,60],[253,140,60],[253,139,60],[253,138,59],[253,138,59],[253,137,59],[253,136,59],[253,135,58],[253,134,58],[253,133,58],[253,132,58],[253,132,57],[253,131,57],[253,130,57],[253,129,57],[253,128,56],[253,127,56],[253,126,56],[253,125,56],[253,125,55],[253,124,55],[253,123,55],[253,122,55],[253,121,54],[253,120,54],[253,119,54],[253,119,54],[253,118,53],[253,117,53],[253,116,53],[253,115,53],[253,114,52],[253,113,52],[253,113,52],[253,112,52],[253,111,51],[253,110,51],[252,109,51],[252,108,51],[252,107,50],[252,106,50],[252,106,50],[252,105,50],[252,104,49],[252,103,49],[252,102,49],[252,101,49],[252,100,48],[252,100,48],[252,99,48],[252,98,48],[252,97,47],[252,96,47],[252,95,47],[252,94,47],[252,94,46],[252,93,46],[252,92,46],[252,91,46],[252,90,45],[252,89,45],[252,88,45],[252,87,45],[252,87,44],[252,86,44],[252,85,44],[252,84,44],[252,83,43],[252,82,43],[252,81,43],[252,81,43],[252,80,42],[252,79,42],[252,78,42],[252,77,42],[251,77,42],[251,76,41],[251,75,41],[250,74,41],[250,74,41],[250,73,41],[249,72,40],[249,72,40],[249,71,40],[248,70,40],[248,69,40],[248,69,40],[247,68,39],[247,67,39],[247,67,39],[246,66,39],[246,65,39],[245,64,38],[245,64,38],[245,63,38],[244,62,38],[244,62,38],[244,61,37],[243,60,37],[243,59,37],[243,59,37],[242,58,37],[242,57,36],[242,57,36],[241,56,36],[241,55,36],[241,54,36],[240,54,35],[240,53,35],[240,52,35],[239,52,35],[239,51,35],[239,50,35],[238,50,34],[238,49,34],[238,48,34],[237,47,34],[237,47,34],[237,46,33],[236,45,33],[236,45,33],[236,44,33],[235,43,33],[235,42,32],[235,42,32],[234,41,32],[234,40,32],[234,40,32],[233,39,31],[233,38,31],[232,37,31],[232,37,31],[232,36,31],[231,35,30],[231,35,30],[231,34,30],[230,33,30],[230,32,30],[230,32,30],[229,31,29],[229,30,29],[229,30,29],[228,29,29],[228,28,29],[228,27,28],[227,27,28],[227,26,28],[226,26,28],[226,25,28],[225,25,28],[224,25,29],[224,24,29],[223,24,29],[222,24,29],[222,23,29],[221,23,29],[220,22,29],[219,22,30],[219,22,30],[218,21,30],[217,21,30],[217,21,30],[216,20,30],[215,20,30],[215,20,30],[214,19,31],[213,19,31],[213,19,31],[212,18,31],[211,18,31],[211,17,31],[210,17,31],[209,17,32],[209,16,32],[208,16,32],[207,16,32],[206,15,32],[206,15,32],[205,15,32],[204,14,33],[204,14,33],[203,14,33],[202,13,33],[202,13,33],[201,12,33],[200,12,33],[200,12,33],[199,11,34],[198,11,34],[198,11,34],[197,10,34],[196,10,34],[195,10,34],[195,9,34],[194,9,35],[193,9,35],[193,8,35],[192,8,35],[191,7,35],[191,7,35],[190,7,35],[189,6,36],[189,6,36],[188,6,36],[187,5,36],[187,5,36],[186,5,36],[185,4,36],[185,4,36],[184,4,37],[183,3,37],[182,3,37],[182,2,37],[181,2,37],[180,2,37],[180,1,37],[179,1,38],[178,1,38],[178,0,38],[177,0,38]]; -var inclinationColours = [[255,255,0],[253,254,2],[251,253,4],[249,252,5],[247,251,7],[245,250,9],[243,249,11],[241,249,13],[239,248,14],[237,247,16],[235,246,18],[233,245,20],[231,244,22],[229,243,23],[227,242,25],[225,241,27],[223,240,29],[221,239,31],[219,238,32],[217,237,34],[215,237,36],[213,236,38],[211,235,40],[209,234,41],[207,233,43],[205,232,45],[203,231,47],[201,230,49],[199,229,50],[197,228,52],[195,227,54],[193,226,56],[191,226,58],[189,225,60],[187,224,61],[185,223,63],[183,222,65],[181,221,67],[179,220,69],[177,219,70],[175,218,72],[173,217,74],[171,216,76],[169,215,78],[167,214,79],[165,214,81],[163,213,83],[161,212,85],[159,211,87],[157,210,88],[155,209,90],[153,208,92],[151,207,94],[149,206,96],[147,205,97],[145,204,99],[143,203,101],[141,202,103],[139,202,105],[137,201,106],[135,200,108],[133,199,110],[131,198,112],[129,197,114],[126,196,115],[124,195,117],[122,194,119],[120,193,121],[118,192,123],[116,191,124],[114,191,126],[112,190,128],[110,189,130],[108,188,132],[106,187,133],[104,186,135],[102,185,137],[100,184,139],[98,183,141],[96,182,142],[94,181,144],[92,180,146],[90,179,148],[88,179,150],[86,178,151],[84,177,153],[82,176,155],[80,175,157],[78,174,159],[76,173,160],[74,172,162],[72,171,164],[70,170,166],[68,169,168],[66,168,169],[64,167,171],[62,167,173],[60,166,175],[58,165,177],[56,164,179],[54,163,180],[52,162,182],[50,161,184],[48,160,186],[46,159,188],[44,158,189],[42,157,191],[40,156,193],[38,156,195],[36,155,197],[34,154,198],[32,153,200],[30,152,202],[28,151,204],[26,150,206],[24,149,207],[22,148,209],[20,147,211],[18,146,213],[16,145,215],[14,144,216],[12,144,218],[10,143,220],[8,142,222],[6,141,224],[4,140,225],[2,139,227],[0,138,229]]; -var terrainColours = [[50,205,50],[52,205,52],[53,206,53],[55,206,55],[56,207,56],[58,207,58],[60,207,60],[61,208,61],[63,208,63],[65,209,65],[66,209,66],[68,209,68],[69,210,69],[71,210,71],[73,211,73],[74,211,74],[76,211,76],[77,212,77],[79,212,79],[81,212,81],[82,213,82],[84,213,84],[86,214,86],[87,214,87],[89,214,89],[90,215,90],[92,215,92],[94,216,94],[95,216,95],[97,216,97],[98,217,98],[100,217,100],[102,218,102],[103,218,103],[105,218,105],[106,219,106],[108,219,108],[110,220,110],[111,220,111],[113,220,113],[115,221,115],[116,221,116],[118,222,118],[119,222,119],[121,222,121],[123,223,123],[124,223,124],[126,224,126],[127,224,127],[129,224,129],[131,225,131],[132,225,132],[134,225,134],[136,226,136],[137,226,137],[139,227,139],[140,227,140],[142,227,142],[144,228,144],[145,228,145],[147,229,147],[148,229,148],[150,229,150],[152,230,152],[153,230,153],[155,231,155],[157,231,157],[158,231,158],[160,232,160],[161,232,161],[163,233,163],[165,233,165],[166,233,166],[168,234,168],[169,234,169],[171,235,171],[173,235,173],[174,235,174],[176,236,176],[178,236,178],[179,236,179],[181,237,181],[182,237,182],[184,238,184],[186,238,186],[187,238,187],[189,239,189],[190,239,190],[192,240,192],[194,240,194],[195,240,195],[197,241,197],[199,241,199],[200,242,200],[202,242,202],[203,242,203],[205,243,205],[207,243,207],[208,244,208],[210,244,210],[211,244,211],[213,245,213],[215,245,215],[216,246,216],[218,246,218],[219,246,219],[221,247,221],[223,247,223],[224,248,224],[226,248,226],[228,248,228],[229,249,229],[231,249,231],[232,249,232],[234,250,234],[236,250,236],[237,251,237],[239,251,239],[240,251,240],[242,252,242],[244,252,244],[245,253,245],[247,253,247],[249,253,249],[250,254,250],[252,254,252],[253,255,253],[255,255,255]]; -var surveyColours = [[0xa6,0xce,0xe3],[0x1f,0x78,0xb4],[0xb2,0xdf,0x8a],[0x33,0xa0,0x2c],[0xfb,0x9a,0x99],[0xe3,0x1a,0x1c],[0xfd,0xbf,0x6f],[0xff,0x7f,0x00],[0xca,0xb2,0xd6],[0x6a,0x3d,0x9a],[0xff,0xff,0x99]]; -var spectrumColours = [[100,60,60],[100,63,60],[100,66,60],[100,68,60],[100,71,60],[100,73,60],[100,76,60],[100,79,60],[100,81,60],[100,84,60],[100,86,60],[100,89,60],[100,92,60],[100,94,60],[100,97,60],[99,100,60],[97,100,60],[94,100,60],[92,100,60],[89,100,60],[86,100,60],[84,100,60],[81,100,60],[79,100,60],[76,100,60],[73,100,60],[71,100,60],[68,100,60],[65,100,60],[63,100,60],[60,100,60],[60,100,63],[60,100,66],[60,100,68],[60,100,71],[60,100,73],[60,100,76],[60,100,79],[60,100,81],[60,100,84],[60,100,86],[60,100,89],[60,100,92],[60,100,94],[60,100,97],[60,99,100],[60,97,100],[60,94,100],[60,92,100],[60,89,100],[60,86,100],[60,84,100],[60,81,100],[60,79,100],[60,76,100],[60,73,100],[60,71,100],[60,68,100],[60,65,100],[60,63,100],[60,60,100],[63,60,100],[66,60,100],[68,60,100],[71,60,100],[73,60,100],[76,60,100],[79,60,100],[81,60,100],[84,60,100],[87,60,100],[89,60,100],[92,60,100],[94,60,100],[97,60,100],[100,60,99],[100,60,97],[100,60,94],[100,60,92],[100,60,89],[100,60,86],[100,60,84],[100,60,81],[100,60,78],[100,60,76],[100,60,73],[100,60,71],[100,60,68],[100,60,65],[100,60,63],[100,60,60],[100,63,60],[100,66,60],[100,68,60],[100,71,60],[100,73,60],[100,76,60],[100,79,60],[100,81,60],[100,84,60],[100,87,60],[100,89,60],[100,92,60],[100,94,60],[100,97,60],[99,100,60],[97,100,60],[94,100,60],[92,100,60],[89,100,60],[86,100,60],[84,100,60],[81,100,60],[78,100,60],[76,100,60],[73,100,60],[71,100,60],[68,100,60],[65,100,60],[63,100,60],[60,100,60],[60,100,63],[60,100,66],[60,100,68],[60,100,71],[60,100,74],[60,100,76],[60,100,79]]; - -var Colours = { - inclination: inclinationColours, - terrain: terrainColours, - gradient: gradientColours, - survey: surveyColours, - depth: depthColours, - spectrum: spectrumColours -}; - -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -function EventDispatcher() {} - -Object.assign( EventDispatcher.prototype, { - - addEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - var listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - }, - - hasEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return false; - - var listeners = this._listeners; - - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - - }, - - removeEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - var index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - - } - - }, - - dispatchEvent: function ( event ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - var array = listenerArray.slice( 0 ); - - for ( var i = 0, l = array.length; i < l; i ++ ) { - - array[ i ].call( this, event ); - - } - - } - - } - -} ); - -var REVISION = '86'; -var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; -var CullFaceNone = 0; -var CullFaceBack = 1; -var CullFaceFront = 2; - -var FrontFaceDirectionCW = 0; - - -var PCFShadowMap = 1; -var PCFSoftShadowMap = 2; -var FrontSide = 0; -var BackSide = 1; -var DoubleSide = 2; -var FlatShading = 1; -var SmoothShading = 2; -var NoColors = 0; -var FaceColors = 1; -var VertexColors = 2; -var NoBlending = 0; -var NormalBlending = 1; -var AdditiveBlending = 2; -var SubtractiveBlending = 3; -var MultiplyBlending = 4; -var CustomBlending = 5; -var AddEquation = 100; -var SubtractEquation = 101; -var ReverseSubtractEquation = 102; -var MinEquation = 103; -var MaxEquation = 104; -var ZeroFactor = 200; -var OneFactor = 201; -var SrcColorFactor = 202; -var OneMinusSrcColorFactor = 203; -var SrcAlphaFactor = 204; -var OneMinusSrcAlphaFactor = 205; -var DstAlphaFactor = 206; -var OneMinusDstAlphaFactor = 207; -var DstColorFactor = 208; -var OneMinusDstColorFactor = 209; -var SrcAlphaSaturateFactor = 210; -var NeverDepth = 0; -var AlwaysDepth = 1; -var LessDepth = 2; -var LessEqualDepth = 3; -var EqualDepth = 4; -var GreaterEqualDepth = 5; -var GreaterDepth = 6; -var NotEqualDepth = 7; -var MultiplyOperation = 0; -var MixOperation = 1; -var AddOperation = 2; -var NoToneMapping = 0; -var LinearToneMapping = 1; -var ReinhardToneMapping = 2; -var Uncharted2ToneMapping = 3; -var CineonToneMapping = 4; -var UVMapping = 300; -var CubeReflectionMapping = 301; -var CubeRefractionMapping = 302; -var EquirectangularReflectionMapping = 303; -var EquirectangularRefractionMapping = 304; -var SphericalReflectionMapping = 305; -var CubeUVReflectionMapping = 306; -var CubeUVRefractionMapping = 307; -var RepeatWrapping = 1000; -var ClampToEdgeWrapping = 1001; -var MirroredRepeatWrapping = 1002; -var NearestFilter = 1003; -var NearestMipMapNearestFilter = 1004; -var NearestMipMapLinearFilter = 1005; -var LinearFilter = 1006; -var LinearMipMapNearestFilter = 1007; -var LinearMipMapLinearFilter = 1008; -var UnsignedByteType = 1009; -var ByteType = 1010; -var ShortType = 1011; -var UnsignedShortType = 1012; -var IntType = 1013; -var UnsignedIntType = 1014; -var FloatType = 1015; -var HalfFloatType = 1016; -var UnsignedShort4444Type = 1017; -var UnsignedShort5551Type = 1018; -var UnsignedShort565Type = 1019; -var UnsignedInt248Type = 1020; -var AlphaFormat = 1021; -var RGBFormat = 1022; -var RGBAFormat = 1023; -var LuminanceFormat = 1024; -var LuminanceAlphaFormat = 1025; - -var DepthFormat = 1026; -var DepthStencilFormat = 1027; -var RGB_S3TC_DXT1_Format = 2001; -var RGBA_S3TC_DXT1_Format = 2002; -var RGBA_S3TC_DXT3_Format = 2003; -var RGBA_S3TC_DXT5_Format = 2004; -var RGB_PVRTC_4BPPV1_Format = 2100; -var RGB_PVRTC_2BPPV1_Format = 2101; -var RGBA_PVRTC_4BPPV1_Format = 2102; -var RGBA_PVRTC_2BPPV1_Format = 2103; -var RGB_ETC1_Format = 2151; -var LoopOnce = 2200; -var LoopRepeat = 2201; -var LoopPingPong = 2202; -var InterpolateDiscrete = 2300; -var InterpolateLinear = 2301; -var InterpolateSmooth = 2302; -var ZeroCurvatureEnding = 2400; -var ZeroSlopeEnding = 2401; -var WrapAroundEnding = 2402; -var TrianglesDrawMode = 0; -var TriangleStripDrawMode = 1; -var TriangleFanDrawMode = 2; -var LinearEncoding = 3000; -var sRGBEncoding = 3001; -var GammaEncoding = 3007; -var RGBEEncoding = 3002; - -var RGBM7Encoding = 3004; -var RGBM16Encoding = 3005; -var RGBDEncoding = 3006; -var BasicDepthPacking = 3200; -var RGBADepthPacking = 3201; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author philogb / http://blog.thejit.org/ - * @author egraether / http://egraether.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -function Vector2( x, y ) { - - this.x = x || 0; - this.y = y || 0; - -} - -Object.defineProperties( Vector2.prototype, { - - "width" : { - - get: function () { - - return this.x; - - }, - - set: function ( value ) { - - this.x = value; - - } - - }, - - "height" : { - - get: function () { - - return this.y; - - }, - - set: function ( value ) { - - this.y = value; - - } - - } - -} ); - -Object.assign( Vector2.prototype, { - - isVector2: true, - - set: function ( x, y ) { - - this.x = x; - this.y = y; - - return this; - - }, - - setScalar: function ( scalar ) { - - this.x = scalar; - this.y = scalar; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); - - } - - }, - - clone: function () { - - return new this.constructor( this.x, this.y ); - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - }, - - addScaledVector: function ( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - - return this; - - }, - - subScalar: function ( s ) { - - this.x -= s; - this.y -= s; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - }, - - multiply: function ( v ) { - - this.x *= v.x; - this.y *= v.y; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - this.x *= scalar; - this.y *= scalar; - - return this; - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - }, - - divideScalar: function ( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - }, - - min: function ( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - - return this; - - }, - - max: function ( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - - return this; - - }, - - clamp: function ( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - - return this; - - }, - - clampScalar: function () { - - var min = new Vector2(); - var max = new Vector2(); - - return function clampScalar( minVal, maxVal ) { - - min.set( minVal, minVal ); - max.set( maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - }(), - - clampLength: function ( min, max ) { - - var length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - }, - - floor: function () { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - - return this; - - }, - - ceil: function () { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - - return this; - - }, - - round: function () { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - - return this; - - }, - - roundToZero: function () { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - - return this; - - }, - - negate: function () { - - this.x = - this.x; - this.y = - this.y; - - return this; - - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y; - - }, - - lengthSq: function () { - - return this.x * this.x + this.y * this.y; - - }, - - length: function () { - - return Math.sqrt( this.x * this.x + this.y * this.y ); - - }, - - lengthManhattan: function() { - - return Math.abs( this.x ) + Math.abs( this.y ); - - }, - - normalize: function () { - - return this.divideScalar( this.length() || 1 ); - - }, - - angle: function () { - - // computes the angle in radians with respect to the positive x-axis - - var angle = Math.atan2( this.y, this.x ); - - if ( angle < 0 ) angle += 2 * Math.PI; - - return angle; - - }, - - distanceTo: function ( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - }, - - distanceToSquared: function ( v ) { - - var dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; - - }, - - distanceToManhattan: function ( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); - - }, - - setLength: function ( length ) { - - return this.normalize().multiplyScalar( length ); - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - - return this; - - }, - - lerpVectors: function ( v1, v2, alpha ) { - - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - }, - - equals: function ( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) ); - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - - return array; - - }, - - fromBufferAttribute: function ( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - - return this; - - }, - - rotateAround: function ( center, angle ) { - - var c = Math.cos( angle ), s = Math.sin( angle ); - - var x = this.x - center.x; - var y = this.y - center.y; - - this.x = x * c - y * s + center.x; - this.y = x * s + y * c + center.y; - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ - -var textureId = 0; - -function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - - Object.defineProperty( this, 'id', { value: textureId ++ } ); - - this.uuid = _Math.generateUUID(); - - this.name = ''; - - this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE; - this.mipmaps = []; - - this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING; - - this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping; - - this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter; - - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - - this.format = format !== undefined ? format : RGBAFormat; - this.type = type !== undefined ? type : UnsignedByteType; - - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding !== undefined ? encoding : LinearEncoding; - - this.version = 0; - this.onUpdate = null; - -} - -Texture.DEFAULT_IMAGE = undefined; -Texture.DEFAULT_MAPPING = UVMapping; - -Object.defineProperty( Texture.prototype, "needsUpdate", { - - set: function ( value ) { - - if ( value === true ) this.version ++; - - } - -} ); - -Object.assign( Texture.prototype, EventDispatcher.prototype, { - - constructor: Texture, - - isTexture: true, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( source ) { - - this.name = source.name; - - this.image = source.image; - this.mipmaps = source.mipmaps.slice( 0 ); - - this.mapping = source.mapping; - - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; - - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; - - this.anisotropy = source.anisotropy; - - this.format = source.format; - this.type = source.type; - - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - - this.generateMipmaps = source.generateMipmaps; - this.premultiplyAlpha = source.premultiplyAlpha; - this.flipY = source.flipY; - this.unpackAlignment = source.unpackAlignment; - this.encoding = source.encoding; - - return this; - - }, - - toJSON: function ( meta ) { - - if ( meta.textures[ this.uuid ] !== undefined ) { - - return meta.textures[ this.uuid ]; - - } - - function getDataURL( image ) { - - var canvas; - - if ( image.toDataURL !== undefined ) { - - canvas = image; - - } else { - - canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = image.width; - canvas.height = image.height; - - canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height ); - - } - - if ( canvas.width > 2048 || canvas.height > 2048 ) { - - return canvas.toDataURL( 'image/jpeg', 0.6 ); - - } else { - - return canvas.toDataURL( 'image/png' ); - - } - - } - - var output = { - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, - - uuid: this.uuid, - name: this.name, - - mapping: this.mapping, - - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - wrap: [ this.wrapS, this.wrapT ], - - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, - - flipY: this.flipY - }; - - if ( this.image !== undefined ) { - - // TODO: Move to THREE.Image - - var image = this.image; - - if ( image.uuid === undefined ) { - - image.uuid = _Math.generateUUID(); // UGH - - } - - if ( meta.images[ image.uuid ] === undefined ) { - - meta.images[ image.uuid ] = { - uuid: image.uuid, - url: getDataURL( image ) - }; - - } - - output.image = image.uuid; - - } - - meta.textures[ this.uuid ] = output; - - return output; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - }, - - transformUv: function ( uv ) { - - if ( this.mapping !== UVMapping ) return; - - uv.multiply( this.repeat ); - uv.add( this.offset ); - - if ( uv.x < 0 || uv.x > 1 ) { - - switch ( this.wrapS ) { - - case RepeatWrapping: - - uv.x = uv.x - Math.floor( uv.x ); - break; - - case ClampToEdgeWrapping: - - uv.x = uv.x < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - - uv.x = Math.ceil( uv.x ) - uv.x; - - } else { - - uv.x = uv.x - Math.floor( uv.x ); - - } - break; - - } - - } - - if ( uv.y < 0 || uv.y > 1 ) { - - switch ( this.wrapT ) { - - case RepeatWrapping: - - uv.y = uv.y - Math.floor( uv.y ); - break; - - case ClampToEdgeWrapping: - - uv.y = uv.y < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - - uv.y = Math.ceil( uv.y ) - uv.y; - - } else { - - uv.y = uv.y - Math.floor( uv.y ); - - } - break; - - } - - } - - if ( this.flipY ) { - - uv.y = 1 - uv.y; - - } - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.image = { data: data, width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - -} - -DataTexture.prototype = Object.create( Texture.prototype ); -DataTexture.prototype.constructor = DataTexture; - -DataTexture.prototype.isDataTexture = true; - -// define colors to share THREE.Color objects - -var caches = { - 'colors': [], - 'texture' : [] -}; - -function createTexture ( scale ) { - - var l = scale.length; - var data = new Uint8Array( l * 3 ); - - for ( var i = 0; i < l; ) { - - var c = scale[ l - ++i ]; - var offset = i * 3; - - data[ offset ] = c[0]; - data[ offset + 1 ] = c[1]; - data[ offset + 2 ] = c[2]; - - } - - var texture = new DataTexture( data, l, 1, RGBFormat, UnsignedByteType ); - - texture.needsUpdate = true; - - return texture; - -} - -function createColors ( scale ) { - - var cache = []; - var c; - - for ( var i = 0, l = scale.length; i < l; i++ ) { - - c = scale[ i ]; - - cache[ i ] = new Color( c[ 0 ] / 255, c[ 1 ] / 255, c[ 2 ] / 255 ); - - } - - return cache; - -} - -function getCacheEntry( cacheName, createFunc, name ) { - - var cache = caches[ cacheName ]; - var entry = cache[ name ]; - - if ( entry === undefined ) { - - var scale = Colours[ name ]; - - if ( scale === undefined ) console.error( 'unknown colour scale requested ' + name ); - - entry = createFunc( scale ); - cache[ name ] = entry; - - } - - return entry; - -} - -function getTexture( name ) { - - return getCacheEntry( 'texture', createTexture, name ); - -} - -function getColors( name ) { - - return getCacheEntry( 'colors', createColors, name ); - -} - -var ColourCache = { - getTexture: getTexture, - getColors: getColors, - red: new Color( 0xff0000 ), - yellow: new Color( 0xffff00 ), - green: new Color( 0x00ff00 ), - white: new Color( 0xffffff ), - grey: new Color( 0x444444 ), - lightGrey: new Color( 0x888888 ), - hudBlue: new Color( 0x106f8d ), - hudRed: new Color( 0x802100 ) -}; - -/** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -function Vector4( x, y, z, w ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; - -} - -Object.assign( Vector4.prototype, { - - isVector4: true, - - set: function ( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - return this; - - }, - - setScalar: function ( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setZ: function ( z ) { - - this.z = z; - - return this; - - }, - - setW: function ( w ) { - - this.w = w; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); - - } - - }, - - clone: function () { - - return new this.constructor( this.x, this.y, this.z, this.w ); - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; - - return this; - - }, - - addScaledVector: function ( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; - - }, - - subScalar: function ( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - }, - - applyMatrix4: function ( m ) { - - var x = this.x, y = this.y, z = this.z, w = this.w; - var e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; - this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; - - return this; - - }, - - divideScalar: function ( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - }, - - setAxisAngleFromQuaternion: function ( q ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - - // q is assumed to be normalized - - this.w = 2 * Math.acos( q.w ); - - var s = Math.sqrt( 1 - q.w * q.w ); - - if ( s < 0.0001 ) { - - this.x = 1; - this.y = 0; - this.z = 0; - - } else { - - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; - - } - - return this; - - }, - - setAxisAngleFromRotationMatrix: function ( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - var angle, x, y, z, // variables for result - epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - - te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { - - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - - // this singularity is identity matrix so angle = 0 - - this.set( 1, 0, 0, 0 ); - - return this; // zero angle, arbitrary axis - - } - - // otherwise this singularity is angle = 180 - - angle = Math.PI; - - var xx = ( m11 + 1 ) / 2; - var yy = ( m22 + 1 ) / 2; - var zz = ( m33 + 1 ) / 2; - var xy = ( m12 + m21 ) / 4; - var xz = ( m13 + m31 ) / 4; - var yz = ( m23 + m32 ) / 4; - - if ( ( xx > yy ) && ( xx > zz ) ) { - - // m11 is the largest diagonal term - - if ( xx < epsilon ) { - - x = 0; - y = 0.707106781; - z = 0.707106781; - - } else { - - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; - - } - - } else if ( yy > zz ) { - - // m22 is the largest diagonal term - - if ( yy < epsilon ) { - - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; - - } - - } else { - - // m33 is the largest diagonal term so base result on this - - if ( zz < epsilon ) { - - x = 0.707106781; - y = 0.707106781; - z = 0; - - } else { - - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; - - } - - } - - this.set( x, y, z, angle ); - - return this; // return 180 deg rotation - - } - - // as we have reached here there are no singularities so we can handle normally - - var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - - if ( Math.abs( s ) < 0.001 ) s = 1; - - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case - - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - - return this; - - }, - - min: function ( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - this.w = Math.min( this.w, v.w ); - - return this; - - }, - - max: function ( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); - - return this; - - }, - - clamp: function ( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - - return this; - - }, - - clampScalar: function () { - - var min, max; - - return function clampScalar( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new Vector4(); - max = new Vector4(); - - } - - min.set( minVal, minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - }(), - - clampLength: function ( min, max ) { - - var length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - }, - - 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() || 1 ); - - }, - - setLength: function ( length ) { - - return this.normalize().multiplyScalar( length ); - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; - - return this; - - }, - - lerpVectors: function ( v1, v2, alpha ) { - - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - - }, - - equals: function ( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; - - return array; - - }, - - fromBufferAttribute: function ( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); - - return this; - - } - -} ); - -/** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - * @author Marius Kintel / https://github.com/kintel - */ - -/* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers -*/ -function WebGLRenderTarget( width, height, options ) { - - this.uuid = _Math.generateUUID(); - - this.width = width; - this.height = height; - - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; - - this.viewport = new Vector4( 0, 0, width, height ); - - options = options || {}; - - if ( options.minFilter === undefined ) options.minFilter = LinearFilter; - - this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; - -} - -Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, { - - isWebGLRenderTarget: true, - - setSize: function ( width, height ) { - - if ( this.width !== width || this.height !== height ) { - - this.width = width; - this.height = height; - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( source ) { - - this.width = source.width; - this.height = source.height; - - this.viewport.copy( source.viewport ); - - this.texture = source.texture.clone(); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - this.depthTexture = source.depthTexture; - - return this; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - - Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.flipY = false; - -} - -CubeTexture.prototype = Object.create( Texture.prototype ); -CubeTexture.prototype.constructor = CubeTexture; - -CubeTexture.prototype.isCubeTexture = true; - -Object.defineProperty( CubeTexture.prototype, 'images', { - - get: function () { - - return this.image; - - }, - - set: function ( value ) { - - this.image = value; - - } - -} ); - -/** - * @author tschw - * - * Uniforms of a program. - * Those form a tree structure with a special top-level container for the root, - * which you get by calling 'new WebGLUniforms( gl, program, renderer )'. - * - * - * Properties of inner nodes including the top-level container: - * - * .seq - array of nested uniforms - * .map - nested uniforms by name - * - * - * Methods of all nodes except the top-level container: - * - * .setValue( gl, value, [renderer] ) - * - * uploads a uniform value(s) - * the 'renderer' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (renderer factorizations): - * - * .upload( gl, seq, values, renderer ) - * - * sets uniforms in 'seq' to 'values[id].value' - * - * .seqWithValue( seq, values ) : filteredSeq - * - * filters 'seq' entries with corresponding entry in values - * - * - * Methods of the top-level container (renderer factorizations): - * - * .setValue( gl, name, value ) - * - * sets uniform with name 'name' to 'value' - * - * .set( gl, obj, prop ) - * - * sets uniform from object and property with same name than uniform - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ - -var emptyTexture = new Texture(); -var emptyCubeTexture = new CubeTexture(); - -// --- Base for inner nodes (including the root) --- - -function UniformContainer() { - - this.seq = []; - this.map = {}; - -} - -// --- Utilities --- - -// Array Caches (provide typed arrays for temporary by size) - -var arrayCacheF32 = []; -var arrayCacheI32 = []; - -// Float32Array caches used for uploading Matrix uniforms - -var mat4array = new Float32Array( 16 ); -var mat3array = new Float32Array( 9 ); - -// Flattening for arrays of vectors and matrices - -function flatten( array, nBlocks, blockSize ) { - - var firstElem = array[ 0 ]; - - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 - - var n = nBlocks * blockSize, - r = arrayCacheF32[ n ]; - - if ( r === undefined ) { - - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; - - } - - if ( nBlocks !== 0 ) { - - firstElem.toArray( r, 0 ); - - for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { - - offset += blockSize; - array[ i ].toArray( r, offset ); - - } - - } - - return r; - -} - -// Texture unit allocation - -function allocTexUnits( renderer, n ) { - - var r = arrayCacheI32[ n ]; - - if ( r === undefined ) { - - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; - - } - - for ( var i = 0; i !== n; ++ i ) - r[ i ] = renderer.allocTextureUnit(); - - return r; - -} - -// --- Setters --- - -// Note: Defining these methods externally, because they come in a bunch -// and this way their names minify. - -// Single scalar - -function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); } -function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); } - -// Single float vector (from flat array or THREE.VectorN) - -function setValue2fv( gl, v ) { - - if ( v.x === undefined ) gl.uniform2fv( this.addr, v ); - else gl.uniform2f( this.addr, v.x, v.y ); - -} - -function setValue3fv( gl, v ) { - - if ( v.x !== undefined ) - gl.uniform3f( this.addr, v.x, v.y, v.z ); - else if ( v.r !== undefined ) - gl.uniform3f( this.addr, v.r, v.g, v.b ); - else - gl.uniform3fv( this.addr, v ); - -} - -function setValue4fv( gl, v ) { - - if ( v.x === undefined ) gl.uniform4fv( this.addr, v ); - else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - -} - -// Single matrix (from flat array or MatrixN) - -function setValue2fm( gl, v ) { - - gl.uniformMatrix2fv( this.addr, false, v.elements || v ); - -} - -function setValue3fm( gl, v ) { - - if ( v.elements === undefined ) { - - gl.uniformMatrix3fv( this.addr, false, v ); - - } else { - - mat3array.set( v.elements ); - gl.uniformMatrix3fv( this.addr, false, mat3array ); - - } - -} - -function setValue4fm( gl, v ) { - - if ( v.elements === undefined ) { - - gl.uniformMatrix4fv( this.addr, false, v ); - - } else { - - mat4array.set( v.elements ); - gl.uniformMatrix4fv( this.addr, false, mat4array ); - - } - -} - -// Single texture (2D / Cube) - -function setValueT1( gl, v, renderer ) { - - var unit = renderer.allocTextureUnit(); - gl.uniform1i( this.addr, unit ); - renderer.setTexture2D( v || emptyTexture, unit ); - -} - -function setValueT6( gl, v, renderer ) { - - var unit = renderer.allocTextureUnit(); - gl.uniform1i( this.addr, unit ); - renderer.setTextureCube( v || emptyCubeTexture, unit ); - -} - -// Integer / Boolean vectors or arrays thereof (always flat arrays) - -function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); } -function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); } -function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); } - -// Helper to pick the right setter for the singular case - -function getSingularSetter( type ) { - - switch ( type ) { - - case 0x1406: return setValue1f; // FLOAT - case 0x8b50: return setValue2fv; // _VEC2 - case 0x8b51: return setValue3fv; // _VEC3 - case 0x8b52: return setValue4fv; // _VEC4 - - case 0x8b5a: return setValue2fm; // _MAT2 - case 0x8b5b: return setValue3fm; // _MAT3 - case 0x8b5c: return setValue4fm; // _MAT4 - - case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES - case 0x8b60: return setValueT6; // SAMPLER_CUBE - - case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 - case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 - case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 - - } - -} - -// Array of scalars - -function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); } -function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); } - -// Array of vectors (flat or from THREE classes) - -function setValueV2a( gl, v ) { - - gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) ); - -} - -function setValueV3a( gl, v ) { - - gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) ); - -} - -function setValueV4a( gl, v ) { - - gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) ); - -} - -// Array of matrices (flat or from THREE clases) - -function setValueM2a( gl, v ) { - - gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) ); - -} - -function setValueM3a( gl, v ) { - - gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) ); - -} - -function setValueM4a( gl, v ) { - - gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) ); - -} - -// Array of textures (2D / Cube) - -function setValueT1a( gl, v, renderer ) { - - var n = v.length, - units = allocTexUnits( renderer, n ); - - gl.uniform1iv( this.addr, units ); - - for ( var i = 0; i !== n; ++ i ) { - - renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); - - } - -} - -function setValueT6a( gl, v, renderer ) { - - var n = v.length, - units = allocTexUnits( renderer, n ); - - gl.uniform1iv( this.addr, units ); - - for ( var i = 0; i !== n; ++ i ) { - - renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - - } - -} - -// Helper to pick the right setter for a pure (bottom-level) array - -function getPureArraySetter( type ) { - - switch ( type ) { - - case 0x1406: return setValue1fv; // FLOAT - case 0x8b50: return setValueV2a; // _VEC2 - case 0x8b51: return setValueV3a; // _VEC3 - case 0x8b52: return setValueV4a; // _VEC4 - - case 0x8b5a: return setValueM2a; // _MAT2 - case 0x8b5b: return setValueM3a; // _MAT3 - case 0x8b5c: return setValueM4a; // _MAT4 - - case 0x8b5e: return setValueT1a; // SAMPLER_2D - case 0x8b60: return setValueT6a; // SAMPLER_CUBE - - case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL - case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 - case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 - case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 - - } - -} - -// --- Uniform Classes --- - -function SingleUniform( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.setValue = getSingularSetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - -} - -function PureArrayUniform( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - -} - -function StructuredUniform( id ) { - - this.id = id; - - UniformContainer.call( this ); // mix-in - -} - -StructuredUniform.prototype.setValue = function ( gl, value ) { - - // Note: Don't need an extra 'renderer' parameter, since samplers - // are not allowed in structured uniforms. - - var seq = this.seq; - - for ( var i = 0, n = seq.length; i !== n; ++ i ) { - - var u = seq[ i ]; - u.setValue( gl, value[ u.id ] ); - - } - -}; - -// --- Top-level --- - -// Parser - builds up the property tree from the path strings - -var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g; - -// extracts -// - the identifier (member name or array index) -// - followed by an optional right bracket (found when array index) -// - followed by an optional left bracket or dot (type of subscript) -// -// Note: These portions can be read in a non-overlapping fashion and -// allow straightforward parsing of the hierarchy that WebGL encodes -// in the uniform names. - -function addUniform( container, uniformObject ) { - - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; - -} - -function parseUniform( activeInfo, addr, container ) { - - var path = activeInfo.name, - pathLength = path.length; - - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; - - for ( ; ; ) { - - var match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex, - - id = match[ 1 ], - idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; - - if ( idIsIndex ) id = id | 0; // convert to integer - - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - - // bare name or "pure" bottom-level array "[0]" suffix - - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); - - break; - - } else { - - // step into inner node / create it in case it doesn't exist - - var map = container.map, next = map[ id ]; - - if ( next === undefined ) { - - next = new StructuredUniform( id ); - addUniform( container, next ); - - } - - container = next; - - } - - } - -} - -// Root Container - -function WebGLUniforms( gl, program, renderer ) { - - UniformContainer.call( this ); - - this.renderer = renderer; - - var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); - - for ( var i = 0; i < n; ++ i ) { - - var info = gl.getActiveUniform( program, i ), - path = info.name, - addr = gl.getUniformLocation( program, path ); - - parseUniform( info, addr, this ); - - } - -} - -WebGLUniforms.prototype.setValue = function ( gl, name, value ) { - - var u = this.map[ name ]; - - if ( u !== undefined ) u.setValue( gl, value, this.renderer ); - -}; - -WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { - - var v = object[ name ]; - - if ( v !== undefined ) this.setValue( gl, name, v ); - -}; - - -// Static interface - -WebGLUniforms.upload = function ( gl, seq, values, renderer ) { - - for ( var i = 0, n = seq.length; i !== n; ++ i ) { - - var u = seq[ i ], - v = values[ u.id ]; - - if ( v.needsUpdate !== false ) { - - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, renderer ); - - } - - } - -}; - -WebGLUniforms.seqWithValue = function ( seq, values ) { - - var r = []; - - for ( var i = 0, n = seq.length; i !== n; ++ i ) { - - var u = seq[ i ]; - if ( u.id in values ) r.push( u ); - - } - - return r; - -}; - -/** - * Uniforms library for shared webgl shaders - */ - -var UniformsLib = { - - common: { - - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, - - map: { value: null }, - offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }, - - specularMap: { value: null }, - alphaMap: { value: null }, - - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, - refractionRatio: { value: 0.98 } - - }, - - aomap: { - - aoMap: { value: null }, - aoMapIntensity: { value: 1 } - - }, - - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, - - emissivemap: { - - emissiveMap: { value: null } - - }, - - bumpmap: { - - bumpMap: { value: null }, - bumpScale: { value: 1 } - - }, - - normalmap: { - - normalMap: { value: null }, - normalScale: { value: new Vector2( 1, 1 ) } - - }, - - displacementmap: { - - displacementMap: { value: null }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } - - }, - - roughnessmap: { - - roughnessMap: { value: null } - - }, - - metalnessmap: { - - metalnessMap: { value: null } - - }, - - gradientmap: { - - gradientMap: { value: null } - - }, - - fog: { - - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: new Color( 0xffffff ) } - - }, - - lights: { - - ambientLightColor: { value: [] }, - - directionalLights: { value: [], properties: { - direction: {}, - color: {}, - - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, - - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {}, - - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - spotShadowMap: { value: [] }, - spotShadowMatrix: { value: [] }, - - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {}, - - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, - - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, - - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } } - - }, - - points: { - - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) } - - } - -}; - -/** - * Uniform Utilities - */ - -var UniformsUtils = { - - merge: function ( uniforms ) { - - var merged = {}; - - for ( var u = 0; u < uniforms.length; u ++ ) { - - var tmp = this.clone( uniforms[ u ] ); - - for ( var p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - - }, - - clone: function ( uniforms_src ) { - - var uniforms_dst = {}; - - for ( var u in uniforms_src ) { - - uniforms_dst[ u ] = {}; - - for ( var p in uniforms_src[ u ] ) { - - var parameter_src = uniforms_src[ u ][ p ]; - - if ( parameter_src && ( parameter_src.isColor || - parameter_src.isMatrix3 || parameter_src.isMatrix4 || - parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || - parameter_src.isTexture ) ) { - - uniforms_dst[ u ][ p ] = parameter_src.clone(); - - } else if ( Array.isArray( parameter_src ) ) { - - uniforms_dst[ u ][ p ] = parameter_src.slice(); - - } else { - - uniforms_dst[ u ][ p ] = parameter_src; - - } - - } - - } - - return uniforms_dst; - - } - -}; - -var alphamap_fragment = "#ifdef USE_ALPHAMAP\r\n\r\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\r\n\r\n#endif\r\n"; - -var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\r\n\r\n\tuniform sampler2D alphaMap;\r\n\r\n#endif\r\n"; - -var alphatest_fragment = "#ifdef ALPHATEST\r\n\r\n\tif ( diffuseColor.a < ALPHATEST ) discard;\r\n\r\n#endif\r\n"; - -var aomap_fragment = "#ifdef USE_AOMAP\r\n\r\n\t// reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\r\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\r\n\r\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\r\n\r\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\r\n\r\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\r\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var aomap_pars_fragment = "#ifdef USE_AOMAP\r\n\r\n\tuniform sampler2D aoMap;\r\n\tuniform float aoMapIntensity;\r\n\r\n#endif"; - -var begin_vertex = "\r\nvec3 transformed = vec3( position );\r\n"; - -var beginnormal_vertex = "\r\nvec3 objectNormal = vec3( normal );\r\n"; - -var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\r\n\r\n\tif( decayExponent > 0.0 ) {\r\n\r\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\r\n\r\n\t\t// based upon Frostbite 3 Moving to Physically-based Rendering\r\n\t\t// page 32, equation 26: E[window1]\r\n\t\t// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\n\t\t// this is intended to be used on spot and point lights who are represented as luminous intensity\r\n\t\t// but who must be converted to luminous irradiance for surface lighting calculation\r\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\r\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\r\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\r\n\r\n#else\r\n\r\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\r\n\r\n#endif\r\n\r\n\t}\r\n\r\n\treturn 1.0;\r\n\r\n}\r\n\r\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\r\n\r\n\treturn RECIPROCAL_PI * diffuseColor;\r\n\r\n} // validated\r\n\r\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\r\n\r\n\t// Original approximation by Christophe Schlick '94\r\n\t// float fresnel = pow( 1.0 - dotLH, 5.0 );\r\n\r\n\t// Optimized variant (presented by Epic at SIGGRAPH '13)\r\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\r\n\r\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\r\n\r\n} // validated\r\n\r\n// Microfacet Models for Refraction through Rough Surfaces - equation (34)\r\n// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html\r\n// alpha is \"roughness squared\" in Disney’s reparameterization\r\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\r\n\r\n\t// geometry term = G(l)⋅G(v) / 4(n⋅l)(n⋅v)\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\r\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\r\n\r\n\treturn 1.0 / ( gl * gv );\r\n\r\n} // validated\r\n\r\n// Moving Frostbite to Physically Based Rendering 2.0 - page 12, listing 2\r\n// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\t// dotNL and dotNV are explicitly swapped. This is not a mistake.\r\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\r\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\r\n\r\n\treturn 0.5 / max( gv + gl, EPSILON );\r\n}\r\n\r\n// Microfacet Models for Refraction through Rough Surfaces - equation (33)\r\n// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html\r\n// alpha is \"roughness squared\" in Disney’s reparameterization\r\nfloat D_GGX( const in float alpha, const in float dotNH ) {\r\n\r\n\tfloat a2 = pow2( alpha );\r\n\r\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; // avoid alpha = 0 with dotNH = 1\r\n\r\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\r\n\r\n}\r\n\r\n// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility\r\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\r\n\r\n\tfloat alpha = pow2( roughness ); // UE4's roughness\r\n\r\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\r\n\r\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\r\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\r\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\r\n\r\n\tvec3 F = F_Schlick( specularColor, dotLH );\r\n\r\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\r\n\r\n\tfloat D = D_GGX( alpha, dotNH );\r\n\r\n\treturn F * ( G * D );\r\n\r\n} // validated\r\n\r\n// Rect Area Light\r\n\r\n// Area light computation code adapted from:\r\n// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines\r\n// By: Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt\r\n// https://drive.google.com/file/d/0BzvWIdpUpRx_d09ndGVjNVJzZjA/view\r\n// https://eheitzresearch.wordpress.com/415-2/\r\n// http://blog.selfshadow.com/sandbox/ltc.html\r\n\r\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\r\n\r\n\tconst float LUT_SIZE = 64.0;\r\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\r\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\r\n\r\n\tfloat theta = acos( dot( N, V ) );\r\n\r\n\t// Parameterization of texture:\r\n\t// sqrt(roughness) -> [0,1]\r\n\t// theta -> [0, PI/2]\r\n\tvec2 uv = vec2(\r\n\t\tsqrt( saturate( roughness ) ),\r\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\r\n\r\n\t// Ensure we don't have nonlinearities at the look-up table's edges\r\n\t// see: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter24.html\r\n\t// \"Shader Analysis\" section\r\n\tuv = uv * LUT_SCALE + LUT_BIAS;\r\n\r\n\treturn uv;\r\n\r\n}\r\n\r\n// Real-Time Area Lighting: a Journey from Research to Production\r\n// By: Stephen Hill & Eric Heitz\r\n// http://advances.realtimerendering.com/s2016/s2016_ltc_rnd.pdf\r\n// An approximation for the form factor of a clipped rectangle.\r\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\r\n\r\n\tfloat l = length( f );\r\n\r\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\r\n\r\n}\r\n\r\n// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines\r\n// also Real-Time Area Lighting: a Journey from Research to Production\r\n// http://advances.realtimerendering.com/s2016/s2016_ltc_rnd.pdf\r\n// Normalization by 2*PI is incorporated in this function itself.\r\n// theta/sin(theta) is approximated by rational polynomial\r\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\r\n\r\n\tfloat x = dot( v1, v2 );\r\n\r\n\tfloat y = abs( x );\r\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\r\n\tfloat b = 3.45068 + (4.18814 + y) * y;\r\n\tfloat v = a / b;\r\n\r\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\r\n\r\n\treturn cross( v1, v2 ) * theta_sintheta;\r\n\r\n}\r\n\r\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\r\n\r\n\t// bail if point is on back side of plane of light\r\n\t// assumes ccw winding order of light vertices\r\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\r\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\r\n\tvec3 lightNormal = cross( v1, v2 );\r\n\r\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\r\n\r\n\t// construct orthonormal basis around N\r\n\tvec3 T1, T2;\r\n\tT1 = normalize( V - N * dot( V, N ) );\r\n\tT2 = - cross( N, T1 ); // negated from paper; possibly due to a different assumed handedness of world coordinate system\r\n\r\n\t// compute transform\r\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\r\n\r\n\t// transform rect\r\n\tvec3 coords[ 4 ];\r\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\r\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\r\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\r\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\r\n\r\n\t// project rect onto sphere\r\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\r\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\r\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\r\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\r\n\r\n\t// calculate vector form factor\r\n\tvec3 vectorFormFactor = vec3( 0.0 );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\r\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\r\n\r\n\t// adjust for horizon clipping\r\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\r\n\r\n\treturn result;\r\n\r\n}\r\n\r\n// End Rect Area Light\r\n\r\n// ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile\r\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\r\n\r\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\r\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\r\n\r\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\r\n\r\n\tvec4 r = roughness * c0 + c1;\r\n\r\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\r\n\r\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\r\n\r\n\treturn specularColor * AB.x + AB.y;\r\n\r\n} // validated\r\n\r\n\r\nfloat G_BlinnPhong_Implicit( ) {\r\n\r\n\t// geometry term is (n dot l)(n dot v) / 4(n dot l)(n dot v)\r\n\treturn 0.25;\r\n\r\n}\r\n\r\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\r\n\r\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\r\n\r\n}\r\n\r\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\r\n\r\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\r\n\r\n\t//float dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\r\n\t//float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\r\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\r\n\r\n\tvec3 F = F_Schlick( specularColor, dotLH );\r\n\r\n\tfloat G = G_BlinnPhong_Implicit( );\r\n\r\n\tfloat D = D_BlinnPhong( shininess, dotNH );\r\n\r\n\treturn F * ( G * D );\r\n\r\n} // validated\r\n\r\n// source: http://simonstechblog.blogspot.ca/2011/12/microfacet-brdf.html\r\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\r\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\r\n}\r\n\r\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\r\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\r\n}\r\n"; - -var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\r\n\r\n\tuniform sampler2D bumpMap;\r\n\tuniform float bumpScale;\r\n\r\n\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\r\n\t// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\r\n\r\n\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\r\n\r\n\tvec2 dHdxy_fwd() {\r\n\r\n\t\tvec2 dSTdx = dFdx( vUv );\r\n\t\tvec2 dSTdy = dFdy( vUv );\r\n\r\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\r\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\r\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\r\n\r\n\t\treturn vec2( dBx, dBy );\r\n\r\n\t}\r\n\r\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\r\n\r\n\t\t// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988\r\n\r\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\r\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\r\n\t\tvec3 vN = surf_norm;\t\t// normalized\r\n\r\n\t\tvec3 R1 = cross( vSigmaY, vN );\r\n\t\tvec3 R2 = cross( vN, vSigmaX );\r\n\r\n\t\tfloat fDet = dot( vSigmaX, R1 );\r\n\r\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\r\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\r\n\r\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\r\n\r\n\t\tvec4 plane = clippingPlanes[ i ];\r\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\r\n\r\n\t}\r\n\t\t\r\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\r\n\r\n\t\tbool clipped = true;\r\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\r\n\t\t\tvec4 plane = clippingPlanes[ i ];\r\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\r\n\t\t}\r\n\r\n\t\tif ( clipped ) discard;\r\n\t\r\n\t#endif\r\n\r\n#endif\r\n"; - -var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\r\n\r\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\t\tvarying vec3 vViewPosition;\r\n\t#endif\r\n\r\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\r\n\r\n#endif\r\n"; - -var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\tvarying vec3 vViewPosition;\r\n#endif\r\n"; - -var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\r\n\tvViewPosition = - mvPosition.xyz;\r\n#endif\r\n\r\n"; - -var color_fragment = "#ifdef USE_COLOR\r\n\r\n\tdiffuseColor.rgb *= vColor;\r\n\r\n#endif"; - -var color_pars_fragment = "#ifdef USE_COLOR\r\n\r\n\tvarying vec3 vColor;\r\n\r\n#endif\r\n"; - -var color_pars_vertex = "#ifdef USE_COLOR\r\n\r\n\tvarying vec3 vColor;\r\n\r\n#endif"; - -var color_vertex = "#ifdef USE_COLOR\r\n\r\n\tvColor.xyz = color.xyz;\r\n\r\n#endif"; - -var common = "#define PI 3.14159265359\r\n#define PI2 6.28318530718\r\n#define PI_HALF 1.5707963267949\r\n#define RECIPROCAL_PI 0.31830988618\r\n#define RECIPROCAL_PI2 0.15915494\r\n#define LOG2 1.442695\r\n#define EPSILON 1e-6\r\n\r\n#define saturate(a) clamp( a, 0.0, 1.0 )\r\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\r\n\r\nfloat pow2( const in float x ) { return x*x; }\r\nfloat pow3( const in float x ) { return x*x*x; }\r\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\r\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\r\n// expects values in the range of [0,1]x[0,1], returns values in the [0,1] range.\r\n// do not collapse into a single function per: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/\r\nhighp float rand( const in vec2 uv ) {\r\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\r\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\r\n\treturn fract(sin(sn) * c);\r\n}\r\n\r\nstruct IncidentLight {\r\n\tvec3 color;\r\n\tvec3 direction;\r\n\tbool visible;\r\n};\r\n\r\nstruct ReflectedLight {\r\n\tvec3 directDiffuse;\r\n\tvec3 directSpecular;\r\n\tvec3 indirectDiffuse;\r\n\tvec3 indirectSpecular;\r\n};\r\n\r\nstruct GeometricContext {\r\n\tvec3 position;\r\n\tvec3 normal;\r\n\tvec3 viewDir;\r\n};\r\n\r\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\r\n\r\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\r\n\r\n}\r\n\r\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\r\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\r\n\r\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\r\n\r\n}\r\n\r\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\r\n\r\n\treturn - distance * planeNormal + point;\r\n\r\n}\r\n\r\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\r\n\r\n}\r\n\r\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\r\n\r\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\r\n\r\n}\r\n\r\nmat3 transpose( const in mat3 v ) {\r\n\r\n\tmat3 tmp;\r\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\r\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\r\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\r\n\r\n\treturn tmp;\r\n\r\n}\r\n"; - -var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\r\n\r\n#define cubeUV_textureSize (1024.0)\r\n\r\nint getFaceFromDirection(vec3 direction) {\r\n\tvec3 absDirection = abs(direction);\r\n\tint face = -1;\r\n\tif( absDirection.x > absDirection.z ) {\r\n\t\tif(absDirection.x > absDirection.y )\r\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\r\n\t\telse\r\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\r\n\t}\r\n\telse {\r\n\t\tif(absDirection.z > absDirection.y )\r\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\r\n\t\telse\r\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\r\n\t}\r\n\treturn face;\r\n}\r\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\r\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\r\n\r\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\r\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\r\n\tfloat dxRoughness = dFdx(roughness);\r\n\tfloat dyRoughness = dFdy(roughness);\r\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\r\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\r\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\r\n\t// Clamp the value to the max mip level counts. hard coded to 6 mips\r\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\r\n\tfloat mipLevel = 0.5 * log2(d);\r\n\treturn vec2(floor(mipLevel), fract(mipLevel));\r\n}\r\n\r\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\r\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\r\n\r\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\r\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\r\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\r\n\r\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\r\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\r\n\t// float powScale = exp2(roughnessLevel + mipLevel);\r\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\r\n\t// float scale = 1.0 / exp2(roughnessLevel + 2.0 + mipLevel);\r\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\r\n\t// float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);\r\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\r\n\r\n\tbool bRes = mipLevel == 0.0;\r\n\tscale = bRes && (scale < a) ? a : scale;\r\n\r\n\tvec3 r;\r\n\tvec2 offset;\r\n\tint face = getFaceFromDirection(direction);\r\n\r\n\tfloat rcpPowScale = 1.0 / powScale;\r\n\r\n\tif( face == 0) {\r\n\t\tr = vec3(direction.x, -direction.z, direction.y);\r\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 1) {\r\n\t\tr = vec3(direction.y, direction.x, direction.z);\r\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 2) {\r\n\t\tr = vec3(direction.z, direction.x, direction.y);\r\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\r\n\t}\r\n\telse if( face == 3) {\r\n\t\tr = vec3(direction.x, direction.z, direction.y);\r\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\telse if( face == 4) {\r\n\t\tr = vec3(direction.y, direction.x, -direction.z);\r\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\telse {\r\n\t\tr = vec3(direction.z, -direction.x, direction.y);\r\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\r\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\r\n\t}\r\n\tr = normalize(r);\r\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\r\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\r\n\tvec2 base = offset + vec2( texelOffset );\r\n\treturn base + s * ( scale - 2.0 * texelOffset );\r\n}\r\n\r\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\r\n\r\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\r\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\r\n\tfloat r1 = floor(roughnessVal);\r\n\tfloat r2 = r1 + 1.0;\r\n\tfloat t = fract(roughnessVal);\r\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\r\n\tfloat s = mipInfo.y;\r\n\tfloat level0 = mipInfo.x;\r\n\tfloat level1 = level0 + 1.0;\r\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\r\n\r\n\t// round to nearest mipmap if we are not interpolating.\r\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\r\n\r\n\t// Tri linear interpolation.\r\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\r\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\r\n\r\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\r\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\r\n\r\n\tvec4 result = mix(color10, color20, t);\r\n\r\n\treturn vec4(result.rgb, 1.0);\r\n}\r\n\r\n#endif\r\n"; - -var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\r\n\r\n#ifdef FLIP_SIDED\r\n\r\n\ttransformedNormal = - transformedNormal;\r\n\r\n#endif\r\n"; - -var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\r\n\r\n\tuniform sampler2D displacementMap;\r\n\tuniform float displacementScale;\r\n\tuniform float displacementBias;\r\n\r\n#endif\r\n"; - -var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\r\n\r\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\r\n\r\n#endif\r\n"; - -var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\r\n\r\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\r\n\r\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\r\n\r\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\r\n\r\n#endif\r\n"; - -var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\r\n\r\n\tuniform sampler2D emissiveMap;\r\n\r\n#endif\r\n"; - -var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\r\n"; - -var encodings_pars_fragment = "// For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/\r\n\r\nvec4 LinearToLinear( in vec4 value ) {\r\n\treturn value;\r\n}\r\n\r\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\r\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\r\n}\r\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\r\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\r\n}\r\n\r\nvec4 sRGBToLinear( in vec4 value ) {\r\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\r\n}\r\nvec4 LinearTosRGB( in vec4 value ) {\r\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\r\n}\r\n\r\nvec4 RGBEToLinear( in vec4 value ) {\r\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\r\n}\r\nvec4 LinearToRGBE( in vec4 value ) {\r\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\r\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\r\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\r\n// return vec4( value.brg, ( 3.0 + 128.0 ) / 256.0 );\r\n}\r\n\r\n// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html\r\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\r\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\r\n}\r\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\r\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\r\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\r\n\tM = ceil( M * 255.0 ) / 255.0;\r\n\treturn vec4( value.rgb / ( M * maxRange ), M );\r\n}\r\n\r\n// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html\r\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\r\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\r\n}\r\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\r\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\r\n\tfloat D = max( maxRange / maxRGB, 1.0 );\r\n\tD = min( floor( D ) / 255.0, 1.0 );\r\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\r\n}\r\n\r\n// LogLuv reference: http://graphicrants.blogspot.ca/2009/04/rgbm-color-encoding.html\r\n\r\n// M matrix, for encoding\r\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\r\nvec4 LinearToLogLuv( in vec4 value ) {\r\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\r\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\r\n\tvec4 vResult;\r\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\r\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\r\n\tvResult.w = fract(Le);\r\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\r\n\treturn vResult;\r\n}\r\n\r\n// Inverse M matrix, for decoding\r\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\r\nvec4 LogLuvToLinear( in vec4 value ) {\r\n\tfloat Le = value.z * 255.0 + value.w;\r\n\tvec3 Xp_Y_XYZp;\r\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\r\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\r\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\r\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\r\n\treturn vec4( max(vRGB, 0.0), 1.0 );\r\n}\r\n"; - -var envmap_fragment = "#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\r\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\r\n\r\n\t\t// Transforming Normal Vectors with the Inverse Transformation\r\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t#else\r\n\r\n\t\tvec3 reflectVec = vReflect;\r\n\r\n\t#endif\r\n\r\n\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\r\n\r\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\r\n\r\n\t\tvec2 sampleUV;\r\n\t\tsampleUV.y = asin( flipNormal * reflectVec.y ) * RECIPROCAL_PI + 0.5;\r\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\r\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\r\n\r\n\t#elif defined( ENVMAP_TYPE_SPHERE )\r\n\r\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\r\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\r\n\r\n\t#else\r\n\r\n\t\tvec4 envColor = vec4( 0.0 );\r\n\r\n\t#endif\r\n\r\n\tenvColor = envMapTexelToLinear( envColor );\r\n\r\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\r\n\r\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\r\n\r\n\t#elif defined( ENVMAP_BLENDING_MIX )\r\n\r\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\r\n\r\n\t#elif defined( ENVMAP_BLENDING_ADD )\r\n\r\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\r\n\tuniform float reflectivity;\r\n\tuniform float envMapIntensity;\r\n#endif\r\n\r\n#ifdef USE_ENVMAP\r\n\r\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\r\n\t\tvarying vec3 vWorldPosition;\r\n\t#endif\r\n\r\n\t#ifdef ENVMAP_TYPE_CUBE\r\n\t\tuniform samplerCube envMap;\r\n\t#else\r\n\t\tuniform sampler2D envMap;\r\n\t#endif\r\n\tuniform float flipEnvMap;\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\r\n\t\tuniform float refractionRatio;\r\n\t#else\r\n\t\tvarying vec3 vReflect;\r\n\t#endif\r\n\r\n#endif\r\n"; - -var envmap_pars_vertex = "#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\t\tvarying vec3 vWorldPosition;\r\n\r\n\t#else\r\n\r\n\t\tvarying vec3 vReflect;\r\n\t\tuniform float refractionRatio;\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var envmap_vertex = "#ifdef USE_ENVMAP\r\n\r\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\r\n\r\n\t\tvWorldPosition = worldPosition.xyz;\r\n\r\n\t#else\r\n\r\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\r\n\r\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var fog_vertex = "\r\n#ifdef USE_FOG\r\nfogDepth = -mvPosition.z;\r\n#endif"; - -var fog_pars_vertex = "#ifdef USE_FOG\r\n\r\n varying float fogDepth;\r\n\r\n#endif\r\n"; - -var fog_fragment = "#ifdef USE_FOG\r\n\r\n\t#ifdef FOG_EXP2\r\n\r\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\r\n\r\n\t#else\r\n\r\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\r\n\r\n\t#endif\r\n\r\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\r\n\r\n#endif\r\n"; - -var fog_pars_fragment = "#ifdef USE_FOG\r\n\r\n\tuniform vec3 fogColor;\r\n\tvarying float fogDepth;\r\n\r\n\t#ifdef FOG_EXP2\r\n\r\n\t\tuniform float fogDensity;\r\n\r\n\t#else\r\n\r\n\t\tuniform float fogNear;\r\n\t\tuniform float fogFar;\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var gradientmap_pars_fragment = "#ifdef TOON\r\n\r\n\tuniform sampler2D gradientMap;\r\n\r\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\r\n\r\n\t\t// dotNL will be from -1.0 to 1.0\r\n\t\tfloat dotNL = dot( normal, lightDirection );\r\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\r\n\r\n\t\t#ifdef USE_GRADIENTMAP\r\n\r\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\r\n\r\n\t\t#else\r\n\r\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\r\n\r\n\t\t#endif\r\n\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var lightmap_fragment = "#ifdef USE_LIGHTMAP\r\n\r\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity; // factor of PI should not be present; included here to prevent breakage\r\n\r\n#endif\r\n"; - -var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\r\n\r\n\tuniform sampler2D lightMap;\r\n\tuniform float lightMapIntensity;\r\n\r\n#endif"; - -var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\r\n\r\nGeometricContext geometry;\r\ngeometry.position = mvPosition.xyz;\r\ngeometry.normal = normalize( transformedNormal );\r\ngeometry.viewDir = normalize( -mvPosition.xyz );\r\n\r\nGeometricContext backGeometry;\r\nbackGeometry.position = geometry.position;\r\nbackGeometry.normal = -geometry.normal;\r\nbackGeometry.viewDir = geometry.viewDir;\r\n\r\nvLightFront = vec3( 0.0 );\r\n\r\n#ifdef DOUBLE_SIDED\r\n\tvLightBack = vec3( 0.0 );\r\n#endif\r\n\r\nIncidentLight directLight;\r\nfloat dotNL;\r\nvec3 directLightColor_Diffuse;\r\n\r\n#if NUM_POINT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n\r\n#if NUM_DIR_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\r\n\r\n\t\tdotNL = dot( geometry.normal, directLight.direction );\r\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\r\n\r\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if NUM_HEMI_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\r\n\r\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\r\n\r\n\t\t#ifdef DOUBLE_SIDED\r\n\r\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var lights_pars = "uniform vec3 ambientLightColor;\r\n\r\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\r\n\r\n\tvec3 irradiance = ambientLightColor;\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI;\r\n\r\n\t#endif\r\n\r\n\treturn irradiance;\r\n\r\n}\r\n\r\n#if NUM_DIR_LIGHTS > 0\r\n\r\n\tstruct DirectionalLight {\r\n\t\tvec3 direction;\r\n\t\tvec3 color;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\r\n\r\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tdirectLight.color = directionalLight.color;\r\n\t\tdirectLight.direction = directionalLight.direction;\r\n\t\tdirectLight.visible = true;\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_POINT_LIGHTS > 0\r\n\r\n\tstruct PointLight {\r\n\t\tvec3 position;\r\n\t\tvec3 color;\r\n\t\tfloat distance;\r\n\t\tfloat decay;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\r\n\r\n\t// directLight is an out parameter as having it as a return value caused compiler errors on some devices\r\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tvec3 lVector = pointLight.position - geometry.position;\r\n\t\tdirectLight.direction = normalize( lVector );\r\n\r\n\t\tfloat lightDistance = length( lVector );\r\n\r\n\t\tdirectLight.color = pointLight.color;\r\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\r\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tstruct SpotLight {\r\n\t\tvec3 position;\r\n\t\tvec3 direction;\r\n\t\tvec3 color;\r\n\t\tfloat distance;\r\n\t\tfloat decay;\r\n\t\tfloat coneCos;\r\n\t\tfloat penumbraCos;\r\n\r\n\t\tint shadow;\r\n\t\tfloat shadowBias;\r\n\t\tfloat shadowRadius;\r\n\t\tvec2 shadowMapSize;\r\n\t};\r\n\r\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\r\n\r\n\t// directLight is an out parameter as having it as a return value caused compiler errors on some devices\r\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\r\n\r\n\t\tvec3 lVector = spotLight.position - geometry.position;\r\n\t\tdirectLight.direction = normalize( lVector );\r\n\r\n\t\tfloat lightDistance = length( lVector );\r\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\r\n\r\n\t\tif ( angleCos > spotLight.coneCos ) {\r\n\r\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\r\n\r\n\t\t\tdirectLight.color = spotLight.color;\r\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\r\n\t\t\tdirectLight.visible = true;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tdirectLight.color = vec3( 0.0 );\r\n\t\t\tdirectLight.visible = false;\r\n\r\n\t\t}\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if NUM_RECT_AREA_LIGHTS > 0\r\n\r\n\tstruct RectAreaLight {\r\n\t\tvec3 color;\r\n\t\tvec3 position;\r\n\t\tvec3 halfWidth;\r\n\t\tvec3 halfHeight;\r\n\t};\r\n\r\n\t// Pre-computed values of LinearTransformedCosine approximation of BRDF\r\n\t// BRDF approximation Texture is 64x64\r\n\tuniform sampler2D ltcMat; // RGBA Float\r\n\tuniform sampler2D ltcMag; // Alpha Float (only has w component)\r\n\r\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\r\n\r\n#endif\r\n\r\n\r\n#if NUM_HEMI_LIGHTS > 0\r\n\r\n\tstruct HemisphereLight {\r\n\t\tvec3 direction;\r\n\t\tvec3 skyColor;\r\n\t\tvec3 groundColor;\r\n\t};\r\n\r\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\r\n\r\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\r\n\r\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\r\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\r\n\r\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\r\n\r\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\t\tirradiance *= PI;\r\n\r\n\t\t#endif\r\n\r\n\t\treturn irradiance;\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n\r\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\r\n\r\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\r\n\r\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\r\n\r\n\t\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\r\n\r\n\t\t\t// TODO: replace with properly filtered cubemaps and access the irradiance LOD level, be it the last LOD level\r\n\t\t\t// of a specular cubemap, or just the default level of a specially created irradiance cubemap.\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\t// force the bias high to get the last LOD level as it is the most blurred.\r\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\r\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec4 envMapColor = vec4( 0.0 );\r\n\r\n\t\t#endif\r\n\r\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\r\n\r\n\t}\r\n\r\n\t// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html\r\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\r\n\r\n\t\t//float envMapWidth = pow( 2.0, maxMIPLevelScalar );\r\n\t\t//float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\r\n\r\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\r\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\r\n\r\n\t\t// clamp to allowable LOD ranges.\r\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\r\n\r\n\t}\r\n\r\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\r\n\r\n\t\t#ifdef ENVMAP_MODE_REFLECTION\r\n\r\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\r\n\r\n\t\t#else\r\n\r\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\r\n\r\n\t\t#endif\r\n\r\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\r\n\r\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\r\n\r\n\t\t#ifdef ENVMAP_TYPE_CUBE\r\n\r\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\r\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\r\n\r\n\t\t\tvec2 sampleUV;\r\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\r\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\r\n\r\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\r\n\r\n\t\t\t#ifdef TEXTURE_LOD_EXT\r\n\r\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\r\n\r\n\t\t\t#else\r\n\r\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\r\n\r\n\t\t\t#endif\r\n\r\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\r\n\r\n\t\t#endif\r\n\r\n\t\treturn envMapColor.rgb * envMapIntensity;\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var lights_phong_fragment = "BlinnPhongMaterial material;\r\nmaterial.diffuseColor = diffuseColor.rgb;\r\nmaterial.specularColor = specular;\r\nmaterial.specularShininess = shininess;\r\nmaterial.specularStrength = specularStrength;\r\n"; - -var lights_phong_pars_fragment = "varying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n\r\nstruct BlinnPhongMaterial {\r\n\r\n\tvec3\tdiffuseColor;\r\n\tvec3\tspecularColor;\r\n\tfloat\tspecularShininess;\r\n\tfloat\tspecularStrength;\r\n\r\n};\r\n\r\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t#ifdef TOON\r\n\r\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\r\n\r\n\t#else\r\n\r\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\r\n\t\tvec3 irradiance = dotNL * directLight.color;\r\n\r\n\t#endif\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI; // punctual light\r\n\r\n\t#endif\r\n\r\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\r\n\r\n}\r\n\r\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n}\r\n\r\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\r\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\r\n\r\n#define Material_LightProbeLOD( material )\t(0)\r\n"; - -var lights_physical_fragment = "PhysicalMaterial material;\r\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\r\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\r\n#ifdef STANDARD\r\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\r\n#else\r\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\r\n\tmaterial.clearCoat = saturate( clearCoat ); // Burley clearcoat model\r\n\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\r\n#endif\r\n"; - -var lights_physical_pars_fragment = "struct PhysicalMaterial {\r\n\r\n\tvec3\tdiffuseColor;\r\n\tfloat\tspecularRoughness;\r\n\tvec3\tspecularColor;\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat clearCoat;\r\n\t\tfloat clearCoatRoughness;\r\n\t#endif\r\n\r\n};\r\n\r\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\r\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\r\n\r\n// Clear coat directional hemishperical reflectance (this approximation should be improved)\r\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\r\n\r\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\r\n\r\n}\r\n\r\n#if NUM_RECT_AREA_LIGHTS > 0\r\n\r\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t\tvec3 normal = geometry.normal;\r\n\t\tvec3 viewDir = geometry.viewDir;\r\n\t\tvec3 position = geometry.position;\r\n\t\tvec3 lightPos = rectAreaLight.position;\r\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\r\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\r\n\t\tvec3 lightColor = rectAreaLight.color;\r\n\t\tfloat roughness = material.specularRoughness;\r\n\r\n\t\tvec3 rectCoords[ 4 ];\r\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight; // counterclockwise\r\n\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\r\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\r\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\r\n\r\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\r\n\r\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\r\n\r\n\t\tvec4 t = texture2D( ltcMat, uv );\r\n\r\n\t\tmat3 mInv = mat3(\r\n\t\t\tvec3( 1, 0, t.y ),\r\n\t\t\tvec3( 0, t.z, 0 ),\r\n\t\t\tvec3( t.w, 0, t.x )\r\n\t\t);\r\n\r\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); // no fresnel\r\n\r\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\r\n\r\n\tvec3 irradiance = dotNL * directLight.color;\r\n\r\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\tirradiance *= PI; // punctual light\r\n\r\n\t#endif\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\r\n\t#else\r\n\t\tfloat clearCoatDHR = 0.0;\r\n\t#endif\r\n\r\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\r\n\r\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n\t#ifndef STANDARD\r\n\r\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\r\n\r\n\t#endif\r\n\r\n}\r\n\r\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\r\n\r\n}\r\n\r\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\r\n\r\n\t#ifndef STANDARD\r\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\r\n\t\tfloat dotNL = dotNV;\r\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\r\n\t#else\r\n\t\tfloat clearCoatDHR = 0.0;\r\n\t#endif\r\n\r\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\r\n\r\n\t#ifndef STANDARD\r\n\r\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\r\n\r\n\t#endif\r\n\r\n}\r\n\r\n#define RE_Direct\t\t\t\tRE_Direct_Physical\r\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\r\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\r\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\r\n\r\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\r\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\r\n\r\n// ref: http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf\r\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\r\n\r\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\r\n\r\n}\r\n"; - -var lights_template = "\r\n\r\nGeometricContext geometry;\r\n\r\ngeometry.position = - vViewPosition;\r\ngeometry.normal = normal;\r\ngeometry.viewDir = normalize( vViewPosition );\r\n\r\nIncidentLight directLight;\r\n\r\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tPointLight pointLight;\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tpointLight = pointLights[ i ];\r\n\r\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tSpotLight spotLight;\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tspotLight = spotLights[ i ];\r\n\r\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\r\n\r\n\tDirectionalLight directionalLight;\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tdirectionalLight = directionalLights[ i ];\r\n\r\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\r\n\r\n\t\t#ifdef USE_SHADOWMAP\r\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\r\n\t\t#endif\r\n\r\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\r\n\r\n\tRectAreaLight rectAreaLight;\r\n\r\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\r\n\r\n\t\trectAreaLight = rectAreaLights[ i ];\r\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n#if defined( RE_IndirectDiffuse )\r\n\r\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\r\n\r\n\t#ifdef USE_LIGHTMAP\r\n\r\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\r\n\r\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\r\n\r\n\t\t\tlightMapIrradiance *= PI; // factor of PI should not be present; included here to prevent breakage\r\n\r\n\t\t#endif\r\n\r\n\t\tirradiance += lightMapIrradiance;\r\n\r\n\t#endif\r\n\r\n\t#if ( NUM_HEMI_LIGHTS > 0 )\r\n\r\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\r\n\r\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\r\n\r\n\t\t}\r\n\r\n\t#endif\r\n\r\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\r\n\r\n\t\t// TODO, replace 8 with the real maxMIPLevel\r\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\r\n\r\n\t#endif\r\n\r\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\r\n\r\n#endif\r\n\r\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\r\n\r\n\t// TODO, replace 8 with the real maxMIPLevel\r\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\r\n\r\n\t#ifndef STANDARD\r\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\r\n\t#else\r\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\r\n\t#endif\r\n\r\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\r\n\r\n#endif\r\n"; - -var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\r\n\r\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\r\n\r\n#endif"; - -var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\r\n\r\n\tuniform float logDepthBufFC;\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvarying float vFragDepth;\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvarying float vFragDepth;\r\n\r\n\t#endif\r\n\r\n\tuniform float logDepthBufFC;\r\n\r\n#endif"; - -var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\r\n\r\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\r\n\r\n\t#ifdef USE_LOGDEPTHBUF_EXT\r\n\r\n\t\tvFragDepth = 1.0 + gl_Position.w;\r\n\r\n\t#else\r\n\r\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var map_fragment = "#ifdef USE_MAP\r\n\r\n\tvec4 texelColor = texture2D( map, vUv );\r\n\r\n\ttexelColor = mapTexelToLinear( texelColor );\r\n\tdiffuseColor *= texelColor;\r\n\r\n#endif\r\n"; - -var map_pars_fragment = "#ifdef USE_MAP\r\n\r\n\tuniform sampler2D map;\r\n\r\n#endif\r\n"; - -var map_particle_fragment = "#ifdef USE_MAP\r\n\r\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\r\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\r\n\r\n#endif\r\n"; - -var map_particle_pars_fragment = "#ifdef USE_MAP\r\n\r\n\tuniform vec4 offsetRepeat;\r\n\tuniform sampler2D map;\r\n\r\n#endif\r\n"; - -var metalnessmap_fragment = "float metalnessFactor = metalness;\r\n\r\n#ifdef USE_METALNESSMAP\r\n\r\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\r\n\r\n\t// reads channel B, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\r\n\tmetalnessFactor *= texelMetalness.b;\r\n\r\n#endif\r\n"; - -var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\r\n\r\n\tuniform sampler2D metalnessMap;\r\n\r\n#endif"; - -var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\r\n\r\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\r\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\r\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\r\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\r\n\r\n#endif\r\n"; - -var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\r\n\r\n\t#ifndef USE_MORPHNORMALS\r\n\r\n\tuniform float morphTargetInfluences[ 8 ];\r\n\r\n\t#else\r\n\r\n\tuniform float morphTargetInfluences[ 4 ];\r\n\r\n\t#endif\r\n\r\n#endif"; - -var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\r\n\r\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\r\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\r\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\r\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\r\n\r\n\t#ifndef USE_MORPHNORMALS\r\n\r\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\r\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\r\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\r\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var normal_flip = "#ifdef DOUBLE_SIDED\r\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\r\n#else\r\n\tfloat flipNormal = 1.0;\r\n#endif\r\n"; - -var normal_fragment = "#ifdef FLAT_SHADED\r\n\r\n\t// Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ...\r\n\r\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\r\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\r\n\tvec3 normal = normalize( cross( fdx, fdy ) );\r\n\r\n#else\r\n\r\n\tvec3 normal = normalize( vNormal ) * flipNormal;\r\n\r\n#endif\r\n\r\n#ifdef USE_NORMALMAP\r\n\r\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\r\n\r\n#elif defined( USE_BUMPMAP )\r\n\r\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\r\n\r\n#endif\r\n"; - -var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\r\n\r\n\tuniform sampler2D normalMap;\r\n\tuniform vec2 normalScale;\r\n\r\n\t// Per-Pixel Tangent Space Normal Mapping\r\n\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\r\n\r\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\r\n\r\n\t\t// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988\r\n\r\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\r\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\r\n\t\tvec2 st0 = dFdx( vUv.st );\r\n\t\tvec2 st1 = dFdy( vUv.st );\r\n\r\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\r\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\r\n\t\tvec3 N = normalize( surf_norm );\r\n\r\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\r\n\t\tmapN.xy = normalScale * mapN.xy;\r\n\t\tmat3 tsn = mat3( S, T, N );\r\n\t\treturn normalize( tsn * mapN );\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\r\n\treturn normalize( normal ) * 0.5 + 0.5;\r\n}\r\n\r\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\r\n\treturn 1.0 - 2.0 * rgb.xyz;\r\n}\r\n\r\nconst float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)\r\nconst float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nconst float ShiftRight8 = 1. / 256.;\r\n\r\nvec4 packDepthToRGBA( const in float v ) {\r\n\tvec4 r = vec4( fract( v * PackFactors ), v );\r\n\tr.yzw -= r.xyz * ShiftRight8; // tidy overflow\r\n\treturn r * PackUpscale;\r\n}\r\n\r\nfloat unpackRGBAToDepth( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\n// NOTE: viewZ/eyeZ is < 0 when in front of the camera per OpenGL conventions\r\n\r\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\r\n\treturn ( viewZ + near ) / ( near - far );\r\n}\r\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\r\n\treturn linearClipZ * ( near - far ) - near;\r\n}\r\n\r\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\r\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\r\n}\r\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\r\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\r\n}\r\n"; - -var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\r\n\r\n\t// Get get normal blending with premultipled, use with CustomBlending, OneFactor, OneMinusSrcAlphaFactor, AddEquation.\r\n\tgl_FragColor.rgb *= gl_FragColor.a;\r\n\r\n#endif\r\n"; - -var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\r\n\r\ngl_Position = projectionMatrix * mvPosition;\r\n"; - -var dithering_fragment = "#if defined( DITHERING )\r\n\r\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\r\n\r\n#endif\r\n"; - -var dithering_pars_fragment = "#if defined( DITHERING )\r\n\r\n\t// based on https://www.shadertoy.com/view/MslGR8\r\n\tvec3 dithering( vec3 color ) {\r\n\t\t//Calculate grid position\r\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\r\n\r\n\t\t//Shift the individual colors differently, thus making it even harder to see the dithering pattern\r\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\r\n\r\n\t\t//modify shift acording to grid position.\r\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\r\n\r\n\t\t//shift the color by dither_shift\r\n\t\treturn color + dither_shift_RGB;\r\n\t}\r\n\r\n#endif\r\n"; - -var roughnessmap_fragment = "float roughnessFactor = roughness;\r\n\r\n#ifdef USE_ROUGHNESSMAP\r\n\r\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\r\n\r\n\t// reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\r\n\troughnessFactor *= texelRoughness.g;\r\n\r\n#endif\r\n"; - -var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\r\n\r\n\tuniform sampler2D roughnessMap;\r\n\r\n#endif"; - -var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\r\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\r\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\r\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\r\n\r\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\r\n\r\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\r\n\r\n\t}\r\n\r\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\r\n\r\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\r\n\r\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\r\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\r\n\r\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\r\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\r\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\r\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\r\n\r\n\t\tvec2 f = fract( uv * size + 0.5 );\r\n\r\n\t\tfloat a = mix( lb, lt, f.y );\r\n\t\tfloat b = mix( rb, rt, f.y );\r\n\t\tfloat c = mix( a, b, f.x );\r\n\r\n\t\treturn c;\r\n\r\n\t}\r\n\r\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\r\n\r\n\t\tfloat shadow = 1.0;\r\n\r\n\t\tshadowCoord.xyz /= shadowCoord.w;\r\n\t\tshadowCoord.z += shadowBias;\r\n\r\n\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\r\n\t\t// if ( all( something, something ) ) using this instead\r\n\r\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\r\n\t\tbool inFrustum = all( inFrustumVec );\r\n\r\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\r\n\r\n\t\tbool frustumTest = all( frustumTestVec );\r\n\r\n\t\tif ( frustumTest ) {\r\n\r\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\r\n\r\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\r\n\r\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\r\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\r\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\r\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\r\n\r\n\t\t\tshadow = (\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\r\n\r\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\r\n\r\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\r\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\r\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\r\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\r\n\r\n\t\t\tshadow = (\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\r\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#else // no percentage-closer filtering:\r\n\r\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\r\n\r\n\t\t#endif\r\n\r\n\t\t}\r\n\r\n\t\treturn shadow;\r\n\r\n\t}\r\n\r\n\t// cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D\r\n\t// vector suitable for 2D texture mapping. This code uses the following layout for the\r\n\t// 2D texture:\r\n\t//\r\n\t// xzXZ\r\n\t// y Y\r\n\t//\r\n\t// Y - Positive y direction\r\n\t// y - Negative y direction\r\n\t// X - Positive x direction\r\n\t// x - Negative x direction\r\n\t// Z - Positive z direction\r\n\t// z - Negative z direction\r\n\t//\r\n\t// Source and test bed:\r\n\t// https://gist.github.com/tschw/da10c43c467ce8afd0c4\r\n\r\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\r\n\r\n\t\t// Number of texels to avoid at the edge of each square\r\n\r\n\t\tvec3 absV = abs( v );\r\n\r\n\t\t// Intersect unit cube\r\n\r\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\r\n\t\tabsV *= scaleToCube;\r\n\r\n\t\t// Apply scale to avoid seams\r\n\r\n\t\t// two texels less per square (one texel will do for NEAREST)\r\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\r\n\r\n\t\t// Unwrap\r\n\r\n\t\t// space: -1 ... 1 range for each square\r\n\t\t//\r\n\t\t// #X##\t\tdim := ( 4 , 2 )\r\n\t\t// # #\t\tcenter := ( 1 , 1 )\r\n\r\n\t\tvec2 planar = v.xy;\r\n\r\n\t\tfloat almostATexel = 1.5 * texelSizeY;\r\n\t\tfloat almostOne = 1.0 - almostATexel;\r\n\r\n\t\tif ( absV.z >= almostOne ) {\r\n\r\n\t\t\tif ( v.z > 0.0 )\r\n\t\t\t\tplanar.x = 4.0 - v.x;\r\n\r\n\t\t} else if ( absV.x >= almostOne ) {\r\n\r\n\t\t\tfloat signX = sign( v.x );\r\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\r\n\r\n\t\t} else if ( absV.y >= almostOne ) {\r\n\r\n\t\t\tfloat signY = sign( v.y );\r\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\r\n\t\t\tplanar.y = v.z * signY - 2.0;\r\n\r\n\t\t}\r\n\r\n\t\t// Transform to UV space\r\n\r\n\t\t// scale := 0.5 / dim\r\n\t\t// translate := ( center + 0.5 ) / dim\r\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\r\n\r\n\t}\r\n\r\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\r\n\r\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\r\n\r\n\t\t// for point lights, the uniform @vShadowCoord is re-purposed to hold\r\n\t\t// the distance from the light to the world-space position of the fragment.\r\n\t\tvec3 lightToPosition = shadowCoord.xyz;\r\n\r\n\t\t// bd3D = base direction 3D\r\n\t\tvec3 bd3D = normalize( lightToPosition );\r\n\t\t// dp = distance from light to fragment position\r\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\r\n\r\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\r\n\r\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\r\n\r\n\t\t\treturn (\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\r\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\r\n\t\t\t) * ( 1.0 / 9.0 );\r\n\r\n\t\t#else // no percentage-closer filtering\r\n\r\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\r\n\r\n\t\t#endif\r\n\r\n\t}\r\n\r\n#endif\r\n"; - -var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\r\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\r\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\r\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\r\n\r\n\t#endif\r\n\r\n\r\n\r\n#endif\r\n"; - -var shadowmap_vertex = "#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\r\n\r\n#endif\r\n"; - -var shadowmask_pars_fragment = "float getShadowMask() {\r\n\r\n\tfloat shadow = 1.0;\r\n\r\n\t#ifdef USE_SHADOWMAP\r\n\r\n\t#if NUM_DIR_LIGHTS > 0\r\n\r\n\tDirectionalLight directionalLight;\r\n\r\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\r\n\r\n\t\tdirectionalLight = directionalLights[ i ];\r\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_SPOT_LIGHTS > 0\r\n\r\n\tSpotLight spotLight;\r\n\r\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\r\n\r\n\t\tspotLight = spotLights[ i ];\r\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\t#if NUM_POINT_LIGHTS > 0\r\n\r\n\tPointLight pointLight;\r\n\r\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\r\n\r\n\t\tpointLight = pointLights[ i ];\r\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\r\n\r\n\t}\r\n\r\n\t#endif\r\n\r\n\r\n\r\n\t#endif\r\n\r\n\treturn shadow;\r\n\r\n}\r\n"; - -var skinbase_vertex = "#ifdef USE_SKINNING\r\n\r\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\r\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\r\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\r\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\r\n\r\n#endif"; - -var skinning_pars_vertex = "#ifdef USE_SKINNING\r\n\r\n\tuniform mat4 bindMatrix;\r\n\tuniform mat4 bindMatrixInverse;\r\n\r\n\t#ifdef BONE_TEXTURE\r\n\r\n\t\tuniform sampler2D boneTexture;\r\n\t\tuniform int boneTextureSize;\r\n\r\n\t\tmat4 getBoneMatrix( const in float i ) {\r\n\r\n\t\t\tfloat j = i * 4.0;\r\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\r\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\r\n\r\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\r\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\r\n\r\n\t\t\ty = dy * ( y + 0.5 );\r\n\r\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\r\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\r\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\r\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\r\n\r\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\r\n\r\n\t\t\treturn bone;\r\n\r\n\t\t}\r\n\r\n\t#else\r\n\r\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\r\n\r\n\t\tmat4 getBoneMatrix( const in float i ) {\r\n\r\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\r\n\t\t\treturn bone;\r\n\r\n\t\t}\r\n\r\n\t#endif\r\n\r\n#endif\r\n"; - -var skinning_vertex = "#ifdef USE_SKINNING\r\n\r\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\r\n\r\n\tvec4 skinned = vec4( 0.0 );\r\n\tskinned += boneMatX * skinVertex * skinWeight.x;\r\n\tskinned += boneMatY * skinVertex * skinWeight.y;\r\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\r\n\tskinned += boneMatW * skinVertex * skinWeight.w;\r\n\r\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\r\n\r\n#endif\r\n"; - -var skinnormal_vertex = "#ifdef USE_SKINNING\r\n\r\n\tmat4 skinMatrix = mat4( 0.0 );\r\n\tskinMatrix += skinWeight.x * boneMatX;\r\n\tskinMatrix += skinWeight.y * boneMatY;\r\n\tskinMatrix += skinWeight.z * boneMatZ;\r\n\tskinMatrix += skinWeight.w * boneMatW;\r\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\r\n\r\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\r\n\r\n#endif\r\n"; - -var specularmap_fragment = "float specularStrength;\r\n\r\n#ifdef USE_SPECULARMAP\r\n\r\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\r\n\tspecularStrength = texelSpecular.r;\r\n\r\n#else\r\n\r\n\tspecularStrength = 1.0;\r\n\r\n#endif"; - -var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\r\n\r\n\tuniform sampler2D specularMap;\r\n\r\n#endif"; - -var tonemapping_fragment = "#if defined( TONE_MAPPING )\r\n\r\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\r\n\r\n#endif\r\n"; - -var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\r\n\r\nuniform float toneMappingExposure;\r\nuniform float toneMappingWhitePoint;\r\n\r\n// exposure only\r\nvec3 LinearToneMapping( vec3 color ) {\r\n\r\n\treturn toneMappingExposure * color;\r\n\r\n}\r\n\r\n// source: https://www.cs.utah.edu/~reinhard/cdrom/\r\nvec3 ReinhardToneMapping( vec3 color ) {\r\n\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\r\nvec3 Uncharted2ToneMapping( vec3 color ) {\r\n\r\n\t// John Hable's filmic operator from Uncharted 2 video game\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\nvec3 OptimizedCineonToneMapping( vec3 color ) {\r\n\r\n\t// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson\r\n\tcolor *= toneMappingExposure;\r\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\r\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\r\n\r\n}\r\n"; - -var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvarying vec2 vUv;\r\n\r\n#endif"; - -var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvarying vec2 vUv;\r\n\tuniform vec4 offsetRepeat;\r\n\r\n#endif\r\n"; - -var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\r\n\r\n#endif"; - -var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tvarying vec2 vUv2;\r\n\r\n#endif"; - -var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tattribute vec2 uv2;\r\n\tvarying vec2 vUv2;\r\n\r\n#endif"; - -var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\r\n\r\n\tvUv2 = uv2;\r\n\r\n#endif"; - -var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\r\n\r\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\r\n\r\n#endif\r\n"; - -var cube_frag = "uniform samplerCube tCube;\r\nuniform float tFlip;\r\nuniform float opacity;\r\n\r\nvarying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\r\n\tgl_FragColor.a *= opacity;\r\n\r\n}\r\n"; - -var cube_vert = "varying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tvWorldPosition = transformDirection( position, modelMatrix );\r\n\r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var depth_frag = "#if DEPTH_PACKING == 3200\r\n\r\n\tuniform float opacity;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( 1.0 );\r\n\r\n\t#if DEPTH_PACKING == 3200\r\n\r\n\t\tdiffuseColor.a = opacity;\r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\r\n\t#if DEPTH_PACKING == 3200\r\n\r\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\r\n\r\n\t#elif DEPTH_PACKING == 3201\r\n\r\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\r\n\r\n\t#endif\r\n\r\n}\r\n"; - -var depth_vert = "#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\t#include \r\n\r\n\t#ifdef USE_DISPLACEMENTMAP\r\n\r\n\t\t#include \r\n\t\t#include \r\n\t\t#include \r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var distanceRGBA_frag = "uniform vec3 lightPos;\r\nvarying vec4 vWorldPosition;\r\n\r\n#include \r\n#include \r\n#include \r\n\r\nvoid main () {\r\n\r\n\t#include \r\n\r\n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\r\n\r\n}\r\n"; - -var distanceRGBA_vert = "varying vec4 vWorldPosition;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvWorldPosition = worldPosition;\r\n\r\n}\r\n"; - -var equirect_frag = "uniform sampler2D tEquirect;\r\nuniform float tFlip;\r\n\r\nvarying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\t// \tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\r\n\tvec3 direction = normalize( vWorldPosition );\r\n\tvec2 sampleUV;\r\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\r\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\r\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\r\n\r\n}\r\n"; - -var equirect_vert = "varying vec3 vWorldPosition;\r\n\r\n#include \r\n\r\nvoid main() {\r\n\r\n\tvWorldPosition = transformDirection( position, modelMatrix );\r\n\r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var linedashed_frag = "uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\nuniform float dashSize;\r\nuniform float totalSize;\r\n\r\nvarying float vLineDistance;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\r\n\r\n\t\tdiscard;\r\n\r\n\t}\r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb; // simple shader\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var linedashed_vert = "uniform float scale;\r\nattribute float lineDistance;\r\n\r\nvarying float vLineDistance;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvLineDistance = scale * lineDistance;\r\n\r\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\r\n\tgl_Position = projectionMatrix * mvPosition;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshbasic_frag = "uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\r\n\t// accumulation (baked indirect lighting only)\r\n\t#ifdef USE_LIGHTMAP\r\n\r\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\r\n\r\n\t#else\r\n\r\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\r\n\r\n\t#endif\r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\r\n\r\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\r\n\r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshbasic_vert = "#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_ENVMAP\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshlambert_frag = "uniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform float opacity;\r\n\r\nvarying vec3 vLightFront;\r\n\r\n#ifdef DOUBLE_SIDED\r\n\r\n\tvarying vec3 vLightBack;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\r\n\r\n\t#include \r\n\r\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\r\n\r\n\t#ifdef DOUBLE_SIDED\r\n\r\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\r\n\r\n\t#else\r\n\r\n\t\treflectedLight.directDiffuse = vLightFront;\r\n\r\n\t#endif\r\n\r\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\r\n\r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshlambert_vert = "#define LAMBERT\r\n\r\nvarying vec3 vLightFront;\r\n\r\n#ifdef DOUBLE_SIDED\r\n\r\n\tvarying vec3 vLightBack;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshphong_frag = "#define PHONG\r\n\r\nuniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform vec3 specular;\r\nuniform float shininess;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\t#include \r\n\t#include \r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\r\n\r\n\t#include \r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshphong_vert = "#define PHONG\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshphysical_frag = "#define PHYSICAL\r\n\r\nuniform vec3 diffuse;\r\nuniform vec3 emissive;\r\nuniform float roughness;\r\nuniform float metalness;\r\nuniform float opacity;\r\n\r\n#ifndef STANDARD\r\n\tuniform float clearCoat;\r\n\tuniform float clearCoatRoughness;\r\n#endif\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n\tvec3 totalEmissiveRadiance = emissive;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t// accumulation\r\n\t#include \r\n\t#include \r\n\r\n\t// modulation\r\n\t#include \r\n\r\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var meshphysical_vert = "#define PHYSICAL\r\n\r\nvarying vec3 vViewPosition;\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var normal_frag = "#define NORMAL\r\n\r\nuniform float opacity;\r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvarying vec3 vViewPosition;\r\n\r\n#endif\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\r\n\r\n}\r\n"; - -var normal_vert = "#define NORMAL\r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvarying vec3 vViewPosition;\r\n\r\n#endif\r\n\r\n#ifndef FLAT_SHADED\r\n\r\n\tvarying vec3 vNormal;\r\n\r\n#endif\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\tvNormal = normalize( transformedNormal );\r\n\r\n#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\r\n\r\n\tvViewPosition = - mvPosition.xyz;\r\n\r\n#endif\r\n\r\n}\r\n"; - -var points_frag = "uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var points_vert = "uniform float size;\r\nuniform float scale;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_SIZEATTENUATION\r\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\r\n\t#else\r\n\t\tgl_PointSize = size;\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var shadow_frag = "uniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\r\n\r\n}\r\n"; - -var shadow_vert = "#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var ShaderChunk = { - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_vertex: lights_lambert_vertex, - lights_pars: lights_pars, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_template: lights_template, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_flip: normal_flip, - normal_fragment: normal_fragment, - normalmap_pars_fragment: normalmap_pars_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - dithering_fragment: dithering_fragment, - dithering_pars_fragment: dithering_pars_fragment, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, - worldpos_vertex: worldpos_vertex, - - cube_frag: cube_frag, - cube_vert: cube_vert, - depth_frag: depth_frag, - depth_vert: depth_vert, - distanceRGBA_frag: distanceRGBA_frag, - distanceRGBA_vert: distanceRGBA_vert, - equirect_frag: equirect_frag, - equirect_vert: equirect_vert, - linedashed_frag: linedashed_frag, - linedashed_vert: linedashed_vert, - meshbasic_frag: meshbasic_frag, - meshbasic_vert: meshbasic_vert, - meshlambert_frag: meshlambert_frag, - meshlambert_vert: meshlambert_vert, - meshphong_frag: meshphong_frag, - meshphong_vert: meshphong_vert, - meshphysical_frag: meshphysical_frag, - meshphysical_vert: meshphysical_vert, - normal_frag: normal_frag, - normal_vert: normal_vert, - points_frag: points_frag, - points_vert: points_vert, - shadow_frag: shadow_frag, - shadow_vert: shadow_vert -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - */ - -var ShaderLib = { - - basic: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag - - }, - - lambert: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag - - }, - - phong: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) }, - specular: { value: new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), - - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag - - }, - - standard: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.roughnessmap, - UniformsLib.metalnessmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) }, - roughness: { value: 0.5 }, - metalness: { value: 0.5 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }, - - points: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.points, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag - - }, - - dashed: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), - - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag - - }, - - depth: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), - - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag - - }, - - normal: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), - - vertexShader: ShaderChunk.normal_vert, - fragmentShader: ShaderChunk.normal_frag - - }, - - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - cube: { - - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, - - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag - - }, - - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - equirect: { - - uniforms: { - tEquirect: { value: null }, - tFlip: { value: - 1 } - }, - - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag - - }, - - distanceRGBA: { - - uniforms: { - lightPos: { value: new Vector3() } - }, - - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag - - } - -}; - -ShaderLib.physical = { - - uniforms: UniformsUtils.merge( [ - ShaderLib.standard.uniforms, - { - clearCoat: { value: 0 }, - clearCoatRoughness: { value: 0 } - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - -}; - -/** - * @author bhouston / http://clara.io - */ - -function Box2( min, max ) { - - this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); - -} - -Object.assign( Box2.prototype, { - - set: function ( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - }, - - setFromPoints: function ( points ) { - - this.makeEmpty(); - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - }, - - setFromCenterAndSize: function () { - - var v1 = new Vector2(); - - return function setFromCenterAndSize( center, size ) { - - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - }; - - }(), - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - }, - - makeEmpty: function () { - - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; - - return this; - - }, - - isEmpty: function () { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - - }, - - getCenter: function ( optionalTarget ) { - - var result = optionalTarget || new Vector2(); - return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - getSize: function ( optionalTarget ) { - - var result = optionalTarget || new Vector2(); - return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min ); - - }, - - expandByPoint: function ( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - }, - - expandByVector: function ( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - }, - - expandByScalar: function ( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - }, - - containsPoint: function ( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; - - }, - - containsBox: function ( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; - - }, - - getParameter: function ( point, optionalTarget ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - var result = optionalTarget || new Vector2(); - - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); - - }, - - intersectsBox: function ( box ) { - - // using 4 splitting planes to rule out intersections - - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ? false : true; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new Vector2(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function () { - - var v1 = new Vector2(); - - return function distanceToPoint( point ) { - - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - }; - - }(), - - intersect: function ( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - return this; - - }, - - union: function ( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - }, - - translate: function ( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - }, - - equals: function ( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -function LensFlarePlugin( renderer, flares ) { - - var gl = renderer.context; - var state = renderer.state; - - var vertexBuffer, elementBuffer; - var shader, program, attributes, uniforms; - - var tempTexture, occlusionTexture; - - function init() { - - var vertices = new Float32Array( [ - - 1, - 1, 0, 0, - 1, - 1, 1, 0, - 1, 1, 1, 1, - - 1, 1, 0, 1 - ] ); - - var faces = new Uint16Array( [ - 0, 1, 2, - 0, 2, 3 - ] ); - - // buffers - - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - - // textures - - tempTexture = gl.createTexture(); - occlusionTexture = gl.createTexture(); - - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - - state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); - gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - - shader = { - - vertexShader: [ - - "uniform lowp int renderType;", - - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", - - "uniform sampler2D occlusionMap;", - - "attribute vec2 position;", - "attribute vec2 uv;", - - "varying vec2 vUV;", - "varying float vVisibility;", - - "void main() {", - - "vUV = uv;", - - "vec2 pos = position;", - - "if ( renderType == 2 ) {", - - "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", - - "vVisibility = visibility.r / 9.0;", - "vVisibility *= 1.0 - visibility.g / 9.0;", - "vVisibility *= visibility.b / 9.0;", - "vVisibility *= 1.0 - visibility.a / 9.0;", - - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - - "}", - - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - - "}" - - ].join( "\n" ), - - fragmentShader: [ - - "uniform lowp int renderType;", - - "uniform sampler2D map;", - "uniform float opacity;", - "uniform vec3 color;", - - "varying vec2 vUV;", - "varying float vVisibility;", - - "void main() {", - - // pink square - - "if ( renderType == 0 ) {", - - "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", - - // restore - - "} else if ( renderType == 1 ) {", - - "gl_FragColor = texture2D( map, vUV );", - - // flare - - "} else {", - - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * vVisibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", - - "}", - - "}" - - ].join( "\n" ) - - }; - - program = createProgram( shader ); - - attributes = { - vertex: gl.getAttribLocation ( program, "position" ), - uv: gl.getAttribLocation ( program, "uv" ) - }; - - uniforms = { - renderType: gl.getUniformLocation( program, "renderType" ), - map: gl.getUniformLocation( program, "map" ), - occlusionMap: gl.getUniformLocation( program, "occlusionMap" ), - opacity: gl.getUniformLocation( program, "opacity" ), - color: gl.getUniformLocation( program, "color" ), - scale: gl.getUniformLocation( program, "scale" ), - rotation: gl.getUniformLocation( program, "rotation" ), - screenPosition: gl.getUniformLocation( program, "screenPosition" ) - }; - - } - - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - */ - - this.render = function ( scene, camera, viewport ) { - - if ( flares.length === 0 ) return; - - var tempPosition = new Vector3(); - - var invAspect = viewport.w / viewport.z, - halfViewportWidth = viewport.z * 0.5, - halfViewportHeight = viewport.w * 0.5; - - var size = 16 / viewport.w, - scale = new Vector2( size * invAspect, size ); - - var screenPosition = new Vector3( 1, 1, 0 ), - screenPositionPixels = new Vector2( 1, 1 ); - - var validArea = new Box2(); - - validArea.min.set( viewport.x, viewport.y ); - validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); - - if ( program === undefined ) { - - init(); - - } - - gl.useProgram( program ); - - state.initAttributes(); - state.enableAttribute( attributes.vertex ); - state.enableAttribute( attributes.uv ); - state.disableUnusedAttributes(); - - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/uniforms - - gl.uniform1i( uniforms.occlusionMap, 0 ); - gl.uniform1i( uniforms.map, 1 ); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); - gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - - state.disable( gl.CULL_FACE ); - state.buffers.depth.setMask( false ); - - for ( var i = 0, l = flares.length; i < l; i ++ ) { - - size = 16 / viewport.w; - scale.set( size * invAspect, size ); - - // calc object screen position - - var flare = flares[ i ]; - - tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); - - tempPosition.applyMatrix4( camera.matrixWorldInverse ); - tempPosition.applyMatrix4( camera.projectionMatrix ); - - // setup arrays for gl programs - - screenPosition.copy( tempPosition ); - - // horizontal and vertical coordinate of the lower left corner of the pixels to copy - - screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8; - screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8; - - // screen cull - - if ( validArea.containsPoint( screenPositionPixels ) === true ) { - - // save current RGB to temp texture - - state.activeTexture( gl.TEXTURE0 ); - state.bindTexture( gl.TEXTURE_2D, null ); - state.activeTexture( gl.TEXTURE1 ); - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); - - - // render pink quad - - gl.uniform1i( uniforms.renderType, 0 ); - gl.uniform2f( uniforms.scale, scale.x, scale.y ); - gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - - state.disable( gl.BLEND ); - state.enable( gl.DEPTH_TEST ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - - // copy result to occlusionMap - - state.activeTexture( gl.TEXTURE0 ); - state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); - - - // restore graphics - - gl.uniform1i( uniforms.renderType, 1 ); - state.disable( gl.DEPTH_TEST ); - - state.activeTexture( gl.TEXTURE1 ); - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - - // update object positions - - flare.positionScreen.copy( screenPosition ); - - if ( flare.customUpdateCallback ) { - - flare.customUpdateCallback( flare ); - - } else { - - flare.updateLensFlares(); - - } - - // render flares - - gl.uniform1i( uniforms.renderType, 2 ); - state.enable( gl.BLEND ); - - for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - - var sprite = flare.lensFlares[ j ]; - - if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; - - size = sprite.size * sprite.scale / viewport.w; - - scale.x = size * invAspect; - scale.y = size; - - gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - gl.uniform2f( uniforms.scale, scale.x, scale.y ); - gl.uniform1f( uniforms.rotation, sprite.rotation ); - - gl.uniform1f( uniforms.opacity, sprite.opacity ); - gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); - - state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - renderer.setTexture2D( sprite.texture, 1 ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - } - - } - - } - - } - - // restore gl - - state.enable( gl.CULL_FACE ); - state.enable( gl.DEPTH_TEST ); - state.buffers.depth.setMask( true ); - - renderer.resetGLState(); - - }; - - function createProgram( shader ) { - - var program = gl.createProgram(); - - var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); - var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - - var prefix = "precision " + renderer.getPrecision() + " float;\n"; - - gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - - gl.compileShader( fragmentShader ); - gl.compileShader( vertexShader ); - - gl.attachShader( program, fragmentShader ); - gl.attachShader( program, vertexShader ); - - gl.linkProgram( program ); - - return program; - - } - -} - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -function SpritePlugin( renderer, sprites ) { - - var gl = renderer.context; - var state = renderer.state; - - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; - - var texture; - - // decompose matrixWorld - - var spritePosition = new Vector3(); - var spriteRotation = new Quaternion(); - var spriteScale = new Vector3(); - - function init() { - - var vertices = new Float32Array( [ - - 0.5, - 0.5, 0, 0, - 0.5, - 0.5, 1, 0, - 0.5, 0.5, 1, 1, - - 0.5, 0.5, 0, 1 - ] ); - - var faces = new Uint16Array( [ - 0, 1, 2, - 0, 2, 3 - ] ); - - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - - program = createProgram(); - - attributes = { - position: gl.getAttribLocation ( program, 'position' ), - uv: gl.getAttribLocation ( program, 'uv' ) - }; - - uniforms = { - uvOffset: gl.getUniformLocation( program, 'uvOffset' ), - uvScale: gl.getUniformLocation( program, 'uvScale' ), - - rotation: gl.getUniformLocation( program, 'rotation' ), - scale: gl.getUniformLocation( program, 'scale' ), - - color: gl.getUniformLocation( program, 'color' ), - map: gl.getUniformLocation( program, 'map' ), - opacity: gl.getUniformLocation( program, 'opacity' ), - - modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), - projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), - - fogType: gl.getUniformLocation( program, 'fogType' ), - fogDensity: gl.getUniformLocation( program, 'fogDensity' ), - fogNear: gl.getUniformLocation( program, 'fogNear' ), - fogFar: gl.getUniformLocation( program, 'fogFar' ), - fogColor: gl.getUniformLocation( program, 'fogColor' ), - - alphaTest: gl.getUniformLocation( program, 'alphaTest' ) - }; - - var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = 8; - canvas.height = 8; - - var context = canvas.getContext( '2d' ); - context.fillStyle = 'white'; - context.fillRect( 0, 0, 8, 8 ); - - texture = new Texture( canvas ); - texture.needsUpdate = true; - - } - - this.render = function ( scene, camera ) { - - if ( sprites.length === 0 ) return; - - // setup gl - - if ( program === undefined ) { - - init(); - - } - - gl.useProgram( program ); - - state.initAttributes(); - state.enableAttribute( attributes.position ); - state.enableAttribute( attributes.uv ); - state.disableUnusedAttributes(); - - state.disable( gl.CULL_FACE ); - state.enable( gl.BLEND ); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); - gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - - gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - - state.activeTexture( gl.TEXTURE0 ); - gl.uniform1i( uniforms.map, 0 ); - - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; - - if ( fog ) { - - gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); - - if ( fog.isFog ) { - - gl.uniform1f( uniforms.fogNear, fog.near ); - gl.uniform1f( uniforms.fogFar, fog.far ); - - gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; - - } else if ( fog.isFogExp2 ) { - - gl.uniform1f( uniforms.fogDensity, fog.density ); - - gl.uniform1i( uniforms.fogType, 2 ); - oldFogType = 2; - sceneFogType = 2; - - } - - } else { - - gl.uniform1i( uniforms.fogType, 0 ); - oldFogType = 0; - sceneFogType = 0; - - } - - - // update positions and sort - - for ( var i = 0, l = sprites.length; i < l; i ++ ) { - - var sprite = sprites[ i ]; - - sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); - sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; - - } - - sprites.sort( painterSortStable ); - - // render all sprites - - var scale = []; - - for ( var i = 0, l = sprites.length; i < l; i ++ ) { - - var sprite = sprites[ i ]; - var material = sprite.material; - - if ( material.visible === false ) continue; - - sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined ); - - gl.uniform1f( uniforms.alphaTest, material.alphaTest ); - gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); - - sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); - - scale[ 0 ] = spriteScale.x; - scale[ 1 ] = spriteScale.y; - - var fogType = 0; - - if ( scene.fog && material.fog ) { - - fogType = sceneFogType; - - } - - if ( oldFogType !== fogType ) { - - gl.uniform1i( uniforms.fogType, fogType ); - oldFogType = fogType; - - } - - if ( material.map !== null ) { - - gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); - gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); - - } else { - - gl.uniform2f( uniforms.uvOffset, 0, 0 ); - gl.uniform2f( uniforms.uvScale, 1, 1 ); - - } - - gl.uniform1f( uniforms.opacity, material.opacity ); - gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); - - gl.uniform1f( uniforms.rotation, material.rotation ); - gl.uniform2fv( uniforms.scale, scale ); - - state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); - state.buffers.depth.setTest( material.depthTest ); - state.buffers.depth.setMask( material.depthWrite ); - - if ( material.map ) { - - renderer.setTexture2D( material.map, 0 ); - - } else { - - renderer.setTexture2D( texture, 0 ); - - } - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined ); - - } - - // restore gl - - state.enable( gl.CULL_FACE ); - - renderer.resetGLState(); - - }; - - function createProgram() { - - var program = gl.createProgram(); - - var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); - - gl.shaderSource( vertexShader, [ - - 'precision ' + renderer.getPrecision() + ' float;', - - '#define SHADER_NAME ' + 'SpriteMaterial', - - '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;', - - '#define SHADER_NAME ' + 'SpriteMaterial', - - 'uniform vec3 color;', - 'uniform sampler2D map;', - 'uniform float opacity;', - - 'uniform int fogType;', - 'uniform vec3 fogColor;', - 'uniform float fogDensity;', - 'uniform float fogNear;', - 'uniform float fogFar;', - 'uniform float alphaTest;', - - 'varying vec2 vUV;', - - 'void main() {', - - 'vec4 texture = texture2D( map, vUV );', - - 'if ( texture.a < alphaTest ) discard;', - - 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', - - 'if ( fogType > 0 ) {', - - 'float depth = gl_FragCoord.z / gl_FragCoord.w;', - 'float fogFactor = 0.0;', - - 'if ( fogType == 1 ) {', - - 'fogFactor = smoothstep( fogNear, fogFar, depth );', - - '} else {', - - 'const float LOG2 = 1.442695;', - 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', - 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', - - '}', - - 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', - - '}', - - '}' - - ].join( '\n' ) ); - - gl.compileShader( vertexShader ); - gl.compileShader( fragmentShader ); - - gl.attachShader( program, vertexShader ); - gl.attachShader( program, fragmentShader ); - - gl.linkProgram( program ); - - return program; - - } - - function painterSortStable( a, b ) { - - if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return b.id - a.id; - - } - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -var materialId = 0; - -function Material() { - - Object.defineProperty( this, 'id', { value: materialId ++ } ); - - this.uuid = _Math.generateUUID(); - - this.name = ''; - this.type = 'Material'; - - this.fog = true; - this.lights = true; - - this.blending = NormalBlending; - this.side = FrontSide; - this.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading - this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors - - this.opacity = 1; - this.transparent = false; - - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; - - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; - - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; - - this.colorWrite = true; - - this.precision = null; // override the renderer's default precision for this material - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.dithering = false; - - this.alphaTest = 0; - this.premultipliedAlpha = false; - - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - - this.visible = true; - - this.needsUpdate = true; - -} - -Object.assign( Material.prototype, EventDispatcher.prototype, { - - isMaterial: true, - - onBeforeCompile: function () {}, - - setValues: function ( values ) { - - if ( values === undefined ) return; - - for ( var key in values ) { - - var newValue = values[ key ]; - - if ( newValue === undefined ) { - - console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); - continue; - - } - - var currentValue = this[ key ]; - - if ( currentValue === undefined ) { - - console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); - continue; - - } - - if ( currentValue && currentValue.isColor ) { - - currentValue.set( newValue ); - - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - - currentValue.copy( newValue ); - - } else if ( key === 'overdraw' ) { - - // ensure overdraw is backwards-compatible with legacy boolean type - this[ key ] = Number( newValue ); - - } else { - - this[ key ] = newValue; - - } - - } - - }, - - toJSON: function ( meta ) { - - var isRoot = meta === undefined; - - if ( isRoot ) { - - meta = { - textures: {}, - images: {} - }; - - } - - var data = { - metadata: { - version: 4.5, - type: 'Material', - generator: 'Material.toJSON' - } - }; - - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; - - if ( this.name !== '' ) data.name = this.name; - - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); - - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; - - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); - if ( this.shininess !== undefined ) data.shininess = this.shininess; - if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat; - if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness; - - if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; - if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; - if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid; - if ( this.bumpMap && this.bumpMap.isTexture ) { - - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; - - } - if ( this.normalMap && this.normalMap.isTexture ) { - - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalScale = this.normalScale.toArray(); - - } - if ( this.displacementMap && this.displacementMap.isTexture ) { - - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; - - } - if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; - if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; - - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - - if ( this.envMap && this.envMap.isTexture ) { - - data.envMap = this.envMap.toJSON( meta ).uuid; - data.reflectivity = this.reflectivity; // Scale behind envMap - - } - - if ( this.gradientMap && this.gradientMap.isTexture ) { - - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - - } - - if ( this.size !== undefined ) data.size = this.size; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.shading !== SmoothShading ) data.shading = this.shading; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors; - - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; - - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; - if ( this.wireframe === true ) data.wireframe = this.wireframe; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - - data.skinning = this.skinning; - data.morphTargets = this.morphTargets; - - data.dithering = this.dithering; - - // TODO: Copied from Object3D.toJSON - - function extractFromCache( cache ) { - - var values = []; - - for ( var key in cache ) { - - var data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - if ( isRoot ) { - - var textures = extractFromCache( meta.textures ); - var images = extractFromCache( meta.images ); - - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - - } - - return data; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( source ) { - - this.name = source.name; - - this.fog = source.fog; - this.lights = source.lights; - - this.blending = source.blending; - this.side = source.side; - this.shading = source.shading; - this.vertexColors = source.vertexColors; - - this.opacity = source.opacity; - this.transparent = source.transparent; - - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; - - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; - - this.colorWrite = source.colorWrite; - - this.precision = source.precision; - - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; - - this.dithering = source.dithering; - - this.alphaTest = source.alphaTest; - - this.premultipliedAlpha = source.premultipliedAlpha; - - this.overdraw = source.overdraw; - - this.visible = source.visible; - this.clipShadows = source.clipShadows; - this.clipIntersection = source.clipIntersection; - - var srcPlanes = source.clippingPlanes, - dstPlanes = null; - - if ( srcPlanes !== null ) { - - var n = srcPlanes.length; - dstPlanes = new Array( n ); - - for ( var i = 0; i !== n; ++ i ) - dstPlanes[ i ] = srcPlanes[ i ].clone(); - - } - - this.clippingPlanes = dstPlanes; - - return this; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * defines: { "label" : "value" }, - * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, - * - * fragmentShader: , - * vertexShader: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ - -function ShaderMaterial( parameters ) { - - Material.call( this ); - - this.type = 'ShaderMaterial'; - - this.defines = {}; - this.uniforms = {}; - - this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; - this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; - - this.linewidth = 1; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes - - this.skinning = false; // set to use skinning attribute streams - this.morphTargets = false; // set to use morph targets - this.morphNormals = false; // set to use morph normals - - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD - }; - - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] - }; - - this.index0AttributeName = undefined; - - if ( parameters !== undefined ) { - - if ( parameters.attributes !== undefined ) { - - console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); - - } - - this.setValues( parameters ); - - } - -} - -ShaderMaterial.prototype = Object.create( Material.prototype ); -ShaderMaterial.prototype.constructor = ShaderMaterial; - -ShaderMaterial.prototype.isShaderMaterial = true; - -ShaderMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; - - this.uniforms = UniformsUtils.clone( source.uniforms ); - - this.defines = source.defines; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.lights = source.lights; - this.clipping = source.clipping; - - this.skinning = source.skinning; - - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; - - this.extensions = source.extensions; - - return this; - -}; - -ShaderMaterial.prototype.toJSON = function ( meta ) { - - var data = Material.prototype.toJSON.call( this, meta ); - - data.uniforms = this.uniforms; - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; - - return data; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / https://clara.io - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * - * opacity: , - * - * map: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -function MeshDepthMaterial( parameters ) { - - Material.call( this ); - - this.type = 'MeshDepthMaterial'; - - this.depthPacking = BasicDepthPacking; - - this.skinning = false; - this.morphTargets = false; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; - this.lights = false; - - this.setValues( parameters ); - -} - -MeshDepthMaterial.prototype = Object.create( Material.prototype ); -MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; - -MeshDepthMaterial.prototype.isMeshDepthMaterial = true; - -MeshDepthMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.depthPacking = source.depthPacking; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - return this; - -}; - -/** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - */ - -function Box3( min, max ) { - - this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); - -} - -Object.assign( Box3.prototype, { - - isBox3: true, - - set: function ( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - }, - - setFromArray: function ( array ) { - - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; - - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; - - for ( var i = 0, l = array.length; i < l; i += 3 ) { - - var x = array[ i ]; - var y = array[ i + 1 ]; - var z = array[ i + 2 ]; - - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; - - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; - - } - - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); - - return this; - - }, - - setFromBufferAttribute: function ( attribute ) { - - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; - - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; - - for ( var i = 0, l = attribute.count; i < l; i ++ ) { - - var x = attribute.getX( i ); - var y = attribute.getY( i ); - var z = attribute.getZ( i ); - - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; - - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; - - } - - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); - - return this; - - }, - - setFromPoints: function ( points ) { - - this.makeEmpty(); - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - }, - - setFromCenterAndSize: function () { - - var v1 = new Vector3(); - - return function setFromCenterAndSize( center, size ) { - - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - }; - - }(), - - setFromObject: function ( object ) { - - this.makeEmpty(); - - return this.expandByObject( object ); - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - }, - - makeEmpty: function () { - - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; - - return this; - - }, - - isEmpty: function () { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - - }, - - getCenter: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - getSize: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min ); - - }, - - expandByPoint: function ( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - }, - - expandByVector: function ( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - }, - - expandByScalar: function ( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - }, - - expandByObject: function () { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms - - var v1 = new Vector3(); - - return function expandByObject( object ) { - - var scope = this; - - object.updateMatrixWorld( true ); - - object.traverse( function ( node ) { - - var i, l; - - var geometry = node.geometry; - - if ( geometry !== undefined ) { - - if ( geometry.isGeometry ) { - - var vertices = geometry.vertices; - - for ( i = 0, l = vertices.length; i < l; i ++ ) { - - v1.copy( vertices[ i ] ); - v1.applyMatrix4( node.matrixWorld ); - - scope.expandByPoint( v1 ); - - } - - } else if ( geometry.isBufferGeometry ) { - - var attribute = geometry.attributes.position; - - if ( attribute !== undefined ) { - - for ( i = 0, l = attribute.count; i < l; i ++ ) { - - v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); - - scope.expandByPoint( v1 ); - - } - - } - - } - - } - - } ); - - return this; - - }; - - }(), - - containsPoint: function ( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; - - }, - - containsBox: function ( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; - - }, - - getParameter: function ( point, optionalTarget ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - var result = optionalTarget || new Vector3(); - - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); - - }, - - intersectsBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; - - }, - - intersectsSphere: ( function () { - - var closestPoint = new Vector3(); - - return function intersectsSphere( sphere ) { - - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, closestPoint ); - - // If that point is inside the sphere, the AABB and sphere intersect. - return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - - }; - - } )(), - - intersectsPlane: function ( plane ) { - - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. - - var min, max; - - if ( plane.normal.x > 0 ) { - - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; - - } else { - - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; - - } - - if ( plane.normal.y > 0 ) { - - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; - - } else { - - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; - - } else { - - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; - - } - - return ( min <= plane.constant && max >= plane.constant ); - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function () { - - var v1 = new Vector3(); - - return function distanceToPoint( point ) { - - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - }; - - }(), - - getBoundingSphere: function () { - - var v1 = new Vector3(); - - return function getBoundingSphere( optionalTarget ) { - - var result = optionalTarget || new Sphere(); - - this.getCenter( result.center ); - - result.radius = this.getSize( v1 ).length() * 0.5; - - return result; - - }; - - }(), - - intersect: function ( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if( this.isEmpty() ) this.makeEmpty(); - - return this; - - }, - - union: function ( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - }, - - applyMatrix4: function () { - - var points = [ - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3() - ]; - - return function applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - - this.setFromPoints( points ); - - return this; - - }; - - }(), - - translate: function ( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - }, - - equals: function ( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - -} ); - -/** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ - -function Sphere( center, radius ) { - - this.center = ( center !== undefined ) ? center : new Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; - -} - -Object.assign( Sphere.prototype, { - - set: function ( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - - }, - - setFromPoints: function () { - - var box = new Box3(); - - return function setFromPoints( points, optionalCenter ) { - - var center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - box.setFromPoints( points ).getCenter( center ); - - } - - var maxRadiusSq = 0; - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - - } - - this.radius = Math.sqrt( maxRadiusSq ); - - return this; - - }; - - }(), - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( sphere ) { - - this.center.copy( sphere.center ); - this.radius = sphere.radius; - - return this; - - }, - - empty: function () { - - return ( this.radius <= 0 ); - - }, - - containsPoint: function ( point ) { - - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - - }, - - distanceToPoint: function ( point ) { - - return ( point.distanceTo( this.center ) - this.radius ); - - }, - - intersectsSphere: function ( sphere ) { - - var radiusSum = this.radius + sphere.radius; - - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - - }, - - intersectsBox: function ( box ) { - - return box.intersectsSphere( this ); - - }, - - intersectsPlane: function ( plane ) { - - // We use the following equation to compute the signed distance from - // the center of the sphere to the plane. - // - // distance = q * n - d - // - // If this distance is greater than the radius of the sphere, - // then there is no intersection. - - return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var deltaLengthSq = this.center.distanceToSquared( point ); - - var result = optionalTarget || new Vector3(); - - result.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - result.sub( this.center ).normalize(); - result.multiplyScalar( this.radius ).add( this.center ); - - } - - return result; - - }, - - getBoundingBox: function ( optionalTarget ) { - - var box = optionalTarget || new Box3(); - - box.set( this.center, this.center ); - box.expandByScalar( this.radius ); - - return box; - - }, - - applyMatrix4: function ( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); - - return this; - - }, - - translate: function ( offset ) { - - this.center.add( offset ); - - return this; - - }, - - equals: function ( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - * @author tschw - */ - -function Matrix3() { - - this.elements = [ - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ]; - - if ( arguments.length > 0 ) { - - console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); - - } - -} - -Object.assign( Matrix3.prototype, { - - isMatrix3: true, - - set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - var te = this.elements; - - te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; - te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; - te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; - - return this; - - }, - - identity: function () { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - }, - - clone: function () { - - return new this.constructor().fromArray( this.elements ); - - }, - - copy: function ( m ) { - - var te = this.elements; - var me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; - te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; - te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; - - return this; - - }, - - setFromMatrix4: function ( m ) { - - var me = m.elements; - - this.set( - - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] - - ); - - return this; - - }, - - applyToBufferAttribute: function () { - - var v1 = new Vector3(); - - return function applyToBufferAttribute( attribute ) { - - for ( var i = 0, l = attribute.count; i < l; i ++ ) { - - v1.x = attribute.getX( i ); - v1.y = attribute.getY( i ); - v1.z = attribute.getZ( i ); - - v1.applyMatrix3( this ); - - attribute.setXYZ( i, v1.x, v1.y, v1.z ); - - } - - return attribute; - - }; - - }(), - - multiply: function ( m ) { - - return this.multiplyMatrices( this, m ); - - }, - - premultiply: function ( m ) { - - return this.multiplyMatrices( m, this ); - - }, - - multiplyMatrices: function ( a, b ) { - - var ae = a.elements; - var be = b.elements; - var te = this.elements; - - var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - - var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; - te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; - te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; - te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; - te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; - - return this; - - }, - - multiplyScalar: function ( s ) { - - var te = this.elements; - - te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; - te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; - te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; - - return this; - - }, - - determinant: function () { - - var te = this.elements; - - var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - - }, - - getInverse: function ( matrix, throwOnDegenerate ) { - - if ( matrix && matrix.isMatrix4 ) { - - console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." ); - - } - - var me = matrix.elements, - te = this.elements, - - n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], - n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ], - n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ], - - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, - - det = n11 * t11 + n21 * t12 + n31 * t13; - - if ( det === 0 ) { - - var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0"; - - if ( throwOnDegenerate === true ) { - - throw new Error( msg ); - - } else { - - console.warn( msg ); - - } - - return this.identity(); - - } - - var detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - - te[ 3 ] = t12 * detInv; - te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; - te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - - te[ 6 ] = t13 * detInv; - te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; - te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; - - return this; - - }, - - transpose: function () { - - var tmp, m = this.elements; - - tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; - tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; - tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; - - return this; - - }, - - getNormalMatrix: function ( matrix4 ) { - - return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose(); - - }, - - transposeIntoArray: function ( r ) { - - var m = this.elements; - - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; - - return this; - - }, - - equals: function ( matrix ) { - - var te = this.elements; - var me = matrix.elements; - - for ( var i = 0; i < 9; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - }, - - fromArray: function ( array, offset ) { - - if ( offset === undefined ) offset = 0; - - for ( var i = 0; i < 9; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - var te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - - array[ offset + 3 ] = te[ 3 ]; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; - - return array; - - } - -} ); - -/** - * @author bhouston / http://clara.io - */ - -function Plane( normal, constant ) { - - this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; - -} - -Object.assign( Plane.prototype, { - - set: function ( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; - - return this; - - }, - - setComponents: function ( x, y, z, w ) { - - this.normal.set( x, y, z ); - this.constant = w; - - return this; - - }, - - setFromNormalAndCoplanarPoint: function ( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized - - return this; - - }, - - setFromCoplanarPoints: function () { - - var v1 = new Vector3(); - var v2 = new Vector3(); - - return function setFromCoplanarPoints( a, b, c ) { - - var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); - - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - - this.setFromNormalAndCoplanarPoint( normal, a ); - - return this; - - }; - - }(), - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; - - return this; - - }, - - normalize: function () { - - // Note: will lead to a divide by zero if the plane is invalid. - - var inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; - - return this; - - }, - - negate: function () { - - this.constant *= - 1; - this.normal.negate(); - - return this; - - }, - - distanceToPoint: function ( point ) { - - return this.normal.dot( point ) + this.constant; - - }, - - distanceToSphere: function ( sphere ) { - - return this.distanceToPoint( sphere.center ) - sphere.radius; - - }, - - projectPoint: function ( point, optionalTarget ) { - - return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); - - }, - - orthoPoint: function ( point, optionalTarget ) { - - var perpendicularMagnitude = this.distanceToPoint( point ); - - var result = optionalTarget || new Vector3(); - return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); - - }, - - intersectLine: function () { - - var v1 = new Vector3(); - - return function intersectLine( line, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - var direction = line.delta( v1 ); - - var denominator = this.normal.dot( direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { - - return result.copy( line.start ); - - } - - // Unsure if this is the correct method to handle this case. - return undefined; - - } - - var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if ( t < 0 || t > 1 ) { - - return undefined; - - } - - return result.copy( direction ).multiplyScalar( t ).add( line.start ); - - }; - - }(), - - intersectsLine: function ( line ) { - - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - - var startSign = this.distanceToPoint( line.start ); - var endSign = this.distanceToPoint( line.end ); - - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - - }, - - intersectsBox: function ( box ) { - - return box.intersectsPlane( this ); - - }, - - intersectsSphere: function ( sphere ) { - - return sphere.intersectsPlane( this ); - - }, - - coplanarPoint: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return result.copy( this.normal ).multiplyScalar( - this.constant ); - - }, - - applyMatrix4: function () { - - var v1 = new Vector3(); - var m1 = new Matrix3(); - - return function applyMatrix4( matrix, optionalNormalMatrix ) { - - var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); - - // transform normal based on theory here: - // http://www.songho.ca/opengl/gl_normaltransform.html - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); - var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - - // recalculate constant (like in setFromNormalAndCoplanarPoint) - this.constant = - referencePoint.dot( normal ); - - return this; - - }; - - }(), - - translate: function ( offset ) { - - this.constant = this.constant - offset.dot( this.normal ); - - return this; - - }, - - equals: function ( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://clara.io - */ - -function Frustum( p0, p1, p2, p3, p4, p5 ) { - - this.planes = [ - - ( p0 !== undefined ) ? p0 : new Plane(), - ( p1 !== undefined ) ? p1 : new Plane(), - ( p2 !== undefined ) ? p2 : new Plane(), - ( p3 !== undefined ) ? p3 : new Plane(), - ( p4 !== undefined ) ? p4 : new Plane(), - ( p5 !== undefined ) ? p5 : new Plane() - - ]; - -} - -Object.assign( Frustum.prototype, { - - set: function ( p0, p1, p2, p3, p4, p5 ) { - - var planes = this.planes; - - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( frustum ) { - - var planes = this.planes; - - for ( var i = 0; i < 6; i ++ ) { - - planes[ i ].copy( frustum.planes[ i ] ); - - } - - return this; - - }, - - setFromMatrix: function ( m ) { - - var planes = this.planes; - var me = m.elements; - var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - - return this; - - }, - - intersectsObject: function () { - - var sphere = new Sphere(); - - return function intersectsObject( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) - geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ) - .applyMatrix4( object.matrixWorld ); - - return this.intersectsSphere( sphere ); - - }; - - }(), - - intersectsSprite: function () { - - var sphere = new Sphere(); - - return function intersectsSprite( sprite ) { - - sphere.center.set( 0, 0, 0 ); - sphere.radius = 0.7071067811865476; - sphere.applyMatrix4( sprite.matrixWorld ); - - return this.intersectsSphere( sphere ); - - }; - - }(), - - intersectsSphere: function ( sphere ) { - - var planes = this.planes; - var center = sphere.center; - var negRadius = - sphere.radius; - - for ( var i = 0; i < 6; i ++ ) { - - var distance = planes[ i ].distanceToPoint( center ); - - if ( distance < negRadius ) { - - return false; - - } - - } - - return true; - - }, - - intersectsBox: function () { - - var p1 = new Vector3(), - p2 = new Vector3(); - - return function intersectsBox( box ) { - - var planes = this.planes; - - for ( var i = 0; i < 6; i ++ ) { - - var plane = planes[ i ]; - - p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; - p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; - p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; - p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; - p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; - p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; - - var d1 = plane.distanceToPoint( p1 ); - var d2 = plane.distanceToPoint( p2 ); - - // if both outside plane, no intersection - - if ( d1 < 0 && d2 < 0 ) { - - return false; - - } - - } - - return true; - - }; - - }(), - - containsPoint: function ( point ) { - - var planes = this.planes; - - for ( var i = 0; i < 6; i ++ ) { - - if ( planes[ i ].distanceToPoint( point ) < 0 ) { - - return false; - - } - - } - - return true; - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) { - - var _gl = _renderer.context, - _state = _renderer.state, - _frustum = new Frustum(), - _projScreenMatrix = new Matrix4(), - - _lightShadows = _lights.shadows, - - _shadowMapSize = new Vector2(), - _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ), - - _lookTarget = new Vector3(), - _lightPositionWorld = new Vector3(), - - _MorphingFlag = 1, - _SkinningFlag = 2, - - _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, - - _depthMaterials = new Array( _NumberOfMaterialVariants ), - _distanceMaterials = new Array( _NumberOfMaterialVariants ), - - _materialCache = {}; - - var cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; - - var cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; - - var cube2DViewPorts = [ - new Vector4(), new Vector4(), new Vector4(), - new Vector4(), new Vector4(), new Vector4() - ]; - - // init - - var depthMaterialTemplate = new MeshDepthMaterial(); - depthMaterialTemplate.depthPacking = RGBADepthPacking; - depthMaterialTemplate.clipping = true; - - var distanceShader = ShaderLib[ "distanceRGBA" ]; - var distanceUniforms = UniformsUtils.clone( distanceShader.uniforms ); - - for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { - - var useMorphing = ( i & _MorphingFlag ) !== 0; - var useSkinning = ( i & _SkinningFlag ) !== 0; - - var depthMaterial = depthMaterialTemplate.clone(); - depthMaterial.morphTargets = useMorphing; - depthMaterial.skinning = useSkinning; - - _depthMaterials[ i ] = depthMaterial; - - var distanceMaterial = new ShaderMaterial( { - defines: { - 'USE_SHADOWMAP': '' - }, - uniforms: distanceUniforms, - vertexShader: distanceShader.vertexShader, - fragmentShader: distanceShader.fragmentShader, - morphTargets: useMorphing, - skinning: useSkinning, - clipping: true - } ); - - _distanceMaterials[ i ] = distanceMaterial; - - } - - // - - var scope = this; - - this.enabled = false; - - this.autoUpdate = true; - this.needsUpdate = false; - - this.type = PCFShadowMap; - - this.renderReverseSided = true; - this.renderSingleSided = true; - - this.render = function ( scene, camera ) { - - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - - if ( _lightShadows.length === 0 ) return; - - // Set GL state for depth map. - _state.disable( _gl.BLEND ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); - - // render depth map - - var faceCount; - - for ( var i = 0, il = _lightShadows.length; i < il; i ++ ) { - - var light = _lightShadows[ i ]; - var shadow = light.shadow; - var isPointLight = light && light.isPointLight; - - if ( shadow === undefined ) { - - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; - - } - - var shadowCamera = shadow.camera; - - _shadowMapSize.copy( shadow.mapSize ); - _shadowMapSize.min( _maxShadowMapSize ); - - if ( isPointLight ) { - - var vpWidth = _shadowMapSize.x; - var vpHeight = _shadowMapSize.y; - - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction - - // positive X - cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); - // negative X - cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); - // positive Z - cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); - // negative Z - cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); - // positive Y - cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); - // negative Y - cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); - - _shadowMapSize.x *= 4.0; - _shadowMapSize.y *= 2.0; - - } - - if ( shadow.map === null ) { - - var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + ".shadowMap"; - - shadowCamera.updateProjectionMatrix(); - - } - - if ( shadow.isSpotLightShadow ) { - - shadow.update( light ); - - } - - var shadowMap = shadow.map; - var shadowMatrix = shadow.matrix; - - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld ); - - if ( isPointLight ) { - - faceCount = 6; - - // for point lights we set the shadow matrix to be a translation-only matrix - // equal to inverse of the light's position - - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - - } else { - - faceCount = 1; - - _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); - - // 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 ); - - } - - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); - - // render shadow map for each cube face (if omni-directional) or - // run a single pass if not - - for ( var face = 0; face < faceCount; face ++ ) { - - if ( isPointLight ) { - - _lookTarget.copy( shadowCamera.position ); - _lookTarget.add( cubeDirections[ face ] ); - shadowCamera.up.copy( cubeUps[ face ] ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); - - var vpDimensions = cube2DViewPorts[ face ]; - _state.viewport( vpDimensions ); - - } - - // update camera matrices and frustum - - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - // set object matrices & frustum culling - - renderObject( scene, camera, shadowCamera, isPointLight ); - - } - - } - - // Restore GL state. - var clearColor = _renderer.getClearColor(); - var clearAlpha = _renderer.getClearAlpha(); - _renderer.setClearColor( clearColor, clearAlpha ); - - scope.needsUpdate = false; - - }; - - function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) { - - var geometry = object.geometry; - - var result = null; - - var materialVariants = _depthMaterials; - var customMaterial = object.customDepthMaterial; - - if ( isPointLight ) { - - materialVariants = _distanceMaterials; - customMaterial = object.customDistanceMaterial; - - } - - if ( ! customMaterial ) { - - var useMorphing = false; - - if ( material.morphTargets ) { - - if ( geometry && geometry.isBufferGeometry ) { - - useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; - - } else if ( geometry && geometry.isGeometry ) { - - useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; - - } - - } - - if ( object.isSkinnedMesh && material.skinning === false ) { - - console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); - - } - - var useSkinning = object.isSkinnedMesh && material.skinning; - - var variantIndex = 0; - - if ( useMorphing ) variantIndex |= _MorphingFlag; - if ( useSkinning ) variantIndex |= _SkinningFlag; - - result = materialVariants[ variantIndex ]; - - } else { - - result = customMaterial; - - } - - if ( _renderer.localClippingEnabled && - material.clipShadows === true && - material.clippingPlanes.length !== 0 ) { - - // in this case we need a unique material instance reflecting the - // appropriate state - - var keyA = result.uuid, keyB = material.uuid; - - var materialsForVariant = _materialCache[ keyA ]; - - if ( materialsForVariant === undefined ) { - - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; - - } - - var cachedMaterial = materialsForVariant[ keyB ]; - - if ( cachedMaterial === undefined ) { - - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; - - } - - result = cachedMaterial; - - } - - result.visible = material.visible; - result.wireframe = material.wireframe; - - var side = material.side; - - if ( scope.renderSingleSided && side == DoubleSide ) { - - side = FrontSide; - - } - - if ( scope.renderReverseSided ) { - - if ( side === FrontSide ) side = BackSide; - else if ( side === BackSide ) side = FrontSide; - - } - - result.side = side; - - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; - - if ( isPointLight && result.uniforms.lightPos !== undefined ) { - - result.uniforms.lightPos.value.copy( lightPositionWorld ); - - } - - return result; - - } - - function renderObject( object, camera, shadowCamera, isPointLight ) { - - if ( object.visible === false ) return; - - var visible = object.layers.test( camera.layers ); - - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - - if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - var geometry = _objects.update( object ); - var material = object.material; - - if ( Array.isArray( material ) ) { - - var groups = geometry.groups; - - for ( var k = 0, kl = groups.length; k < kl; k ++ ) { - - var group = groups[ k ]; - var groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - - } - - } - - } else if ( material.visible ) { - - var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - - } - - } - - } - - var children = object.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - renderObject( children[ i ], camera, shadowCamera, isPointLight ); - - } - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLAttributes( gl ) { - - var buffers = {}; - - function createBuffer( attribute, bufferType ) { - - var array = attribute.array; - var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; - - var buffer = gl.createBuffer(); - - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); - - attribute.onUploadCallback(); - - var type = gl.FLOAT; - - if ( array instanceof Float32Array ) { - - type = gl.FLOAT; - - } else if ( array instanceof Float64Array ) { - - console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); - - } else if ( array instanceof Uint16Array ) { - - type = gl.UNSIGNED_SHORT; - - } else if ( array instanceof Int16Array ) { - - type = gl.SHORT; - - } else if ( array instanceof Uint32Array ) { - - type = gl.UNSIGNED_INT; - - } else if ( array instanceof Int32Array ) { - - type = gl.INT; - - } else if ( array instanceof Int8Array ) { - - type = gl.BYTE; - - } else if ( array instanceof Uint8Array ) { - - type = gl.UNSIGNED_BYTE; - - } - - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version - }; - - } - - function updateBuffer( buffer, attribute, bufferType ) { - - var array = attribute.array; - var updateRange = attribute.updateRange; - - gl.bindBuffer( bufferType, buffer ); - - if ( attribute.dynamic === false ) { - - gl.bufferData( bufferType, array, gl.STATIC_DRAW ); - - } else if ( updateRange.count === - 1 ) { - - // Not using update ranges - - gl.bufferSubData( bufferType, 0, array ); - - } else if ( updateRange.count === 0 ) { - - console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); - - } else { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - - updateRange.count = -1; // reset range - - } - - } - - // - - function get( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - return buffers[ attribute.uuid ]; - - } - - function remove( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - var data = buffers[ attribute.uuid ]; - - if ( data ) { - - gl.deleteBuffer( data.buffer ); - - delete buffers[ attribute.uuid ]; - - } - - } - - function update( attribute, bufferType ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - var data = buffers[ attribute.uuid ]; - - if ( data === undefined ) { - - buffers[ attribute.uuid ] = createBuffer( attribute, bufferType ); - - } else if ( data.version < attribute.version ) { - - updateBuffer( data.buffer, attribute, bufferType ); - - data.version = attribute.version; - - } - - } - - return { - - get: get, - remove: remove, - update: update - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - */ - -function Euler( x, y, z, order ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || Euler.DefaultOrder; - -} - -Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - -Euler.DefaultOrder = 'XYZ'; - -Object.defineProperties( Euler.prototype, { - - x: { - - get: function () { - - return this._x; - - }, - - set: function ( value ) { - - this._x = value; - this.onChangeCallback(); - - } - - }, - - y: { - - get: function () { - - return this._y; - - }, - - set: function ( value ) { - - this._y = value; - this.onChangeCallback(); - - } - - }, - - z: { - - get: function () { - - return this._z; - - }, - - set: function ( value ) { - - this._z = value; - this.onChangeCallback(); - - } - - }, - - order: { - - get: function () { - - return this._order; - - }, - - set: function ( value ) { - - this._order = value; - this.onChangeCallback(); - - } - - } - -} ); - -Object.assign( Euler.prototype, { - - isEuler: true, - - set: function ( x, y, z, order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; - - this.onChangeCallback(); - - return this; - - }, - - clone: function () { - - return new this.constructor( this._x, this._y, this._z, this._order ); - - }, - - copy: function ( euler ) { - - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; - - this.onChangeCallback(); - - return this; - - }, - - setFromRotationMatrix: function ( m, order, update ) { - - var clamp = _Math.clamp; - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - var te = m.elements; - var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - order = order || this._order; - - if ( order === 'XYZ' ) { - - this._y = Math.asin( clamp( m13, - 1, 1 ) ); - - if ( Math.abs( m13 ) < 0.99999 ) { - - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); - - } else { - - this._x = Math.atan2( m32, m22 ); - this._z = 0; - - } - - } else if ( order === 'YXZ' ) { - - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - - if ( Math.abs( m23 ) < 0.99999 ) { - - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); - - } else { - - this._y = Math.atan2( - m31, m11 ); - this._z = 0; - - } - - } else if ( order === 'ZXY' ) { - - this._x = Math.asin( clamp( m32, - 1, 1 ) ); - - if ( Math.abs( m32 ) < 0.99999 ) { - - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); - - } else { - - this._y = 0; - this._z = Math.atan2( m21, m11 ); - - } - - } else if ( order === 'ZYX' ) { - - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - - if ( Math.abs( m31 ) < 0.99999 ) { - - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); - - } else { - - this._x = 0; - this._z = Math.atan2( - m12, m22 ); - - } - - } else if ( order === 'YZX' ) { - - this._z = Math.asin( clamp( m21, - 1, 1 ) ); - - if ( Math.abs( m21 ) < 0.99999 ) { - - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); - - } else { - - this._x = 0; - this._y = Math.atan2( m13, m33 ); - - } - - } else if ( order === 'XZY' ) { - - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - - if ( Math.abs( m12 ) < 0.99999 ) { - - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); - - } else { - - this._x = Math.atan2( - m23, m33 ); - this._y = 0; - - } - - } else { - - console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); - - } - - this._order = order; - - if ( update !== false ) this.onChangeCallback(); - - return this; - - }, - - setFromQuaternion: function () { - - var matrix = new Matrix4(); - - return function setFromQuaternion( q, order, update ) { - - matrix.makeRotationFromQuaternion( q ); - - return this.setFromRotationMatrix( matrix, order, update ); - - }; - - }(), - - setFromVector3: function ( v, order ) { - - return this.set( v.x, v.y, v.z, order || this._order ); - - }, - - reorder: function () { - - // WARNING: this discards revolution information -bhouston - - var q = new Quaternion(); - - return function reorder( newOrder ) { - - q.setFromEuler( this ); - - return this.setFromQuaternion( q, newOrder ); - - }; - - }(), - - equals: function ( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - - }, - - fromArray: function ( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - - this.onChangeCallback(); - - return this; - - }, - - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; - - return array; - - }, - - toVector3: function ( optionalResult ) { - - if ( optionalResult ) { - - return optionalResult.set( this._x, this._y, this._z ); - - } else { - - return new Vector3( this._x, this._y, this._z ); - - } - - }, - - onChange: function ( callback ) { - - this.onChangeCallback = callback; - - return this; - - }, - - onChangeCallback: function () {} - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function Layers() { - - this.mask = 1 | 0; - -} - -Object.assign( Layers.prototype, { - - set: function ( channel ) { - - this.mask = 1 << channel | 0; - - }, - - enable: function ( channel ) { - - this.mask |= 1 << channel | 0; - - }, - - toggle: function ( channel ) { - - this.mask ^= 1 << channel | 0; - - }, - - disable: function ( channel ) { - - this.mask &= ~ ( 1 << channel | 0 ); - - }, - - test: function ( layers ) { - - return ( this.mask & layers.mask ) !== 0; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author elephantatwork / www.elephantatwork.ch - */ - -var object3DId = 0; - -function Object3D() { - - Object.defineProperty( this, 'id', { value: object3DId ++ } ); - - this.uuid = _Math.generateUUID(); - - this.name = ''; - this.type = 'Object3D'; - - this.parent = null; - this.children = []; - - this.up = Object3D.DefaultUp.clone(); - - var position = new Vector3(); - var rotation = new Euler(); - var quaternion = new Quaternion(); - var scale = new Vector3( 1, 1, 1 ); - - function onRotationChange() { - - quaternion.setFromEuler( rotation, false ); - - } - - function onQuaternionChange() { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } - - rotation.onChange( onRotationChange ); - quaternion.onChange( onQuaternionChange ); - - Object.defineProperties( this, { - position: { - enumerable: true, - value: position - }, - rotation: { - enumerable: true, - value: rotation - }, - quaternion: { - enumerable: true, - value: quaternion - }, - scale: { - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() - } - } ); - - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); - - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; - - this.layers = new Layers(); - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - this.renderOrder = 0; - - this.userData = {}; -} - -Object3D.DefaultUp = new Vector3( 0, 1, 0 ); -Object3D.DefaultMatrixAutoUpdate = true; - -Object.assign( Object3D.prototype, EventDispatcher.prototype, { - - isObject3D: true, - - onBeforeRender: function () {}, - onAfterRender: function () {}, - - applyMatrix: function ( matrix ) { - - this.matrix.multiplyMatrices( matrix, this.matrix ); - - this.matrix.decompose( this.position, this.quaternion, this.scale ); - - }, - - applyQuaternion: function ( q ) { - - this.quaternion.premultiply( q ); - - return this; - - }, - - setRotationFromAxisAngle: function ( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - }, - - setRotationFromEuler: function ( euler ) { - - this.quaternion.setFromEuler( euler, true ); - - }, - - setRotationFromMatrix: function ( m ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - this.quaternion.setFromRotationMatrix( m ); - - }, - - setRotationFromQuaternion: function ( q ) { - - // assumes q is normalized - - this.quaternion.copy( q ); - - }, - - rotateOnAxis: function () { - - // rotate object on axis in object space - // axis is assumed to be normalized - - var q1 = new Quaternion(); - - return function rotateOnAxis( axis, angle ) { - - q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( q1 ); - - return this; - - }; - - }(), - - rotateX: function () { - - var v1 = new Vector3( 1, 0, 0 ); - - return function rotateX( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateY: function () { - - var v1 = new Vector3( 0, 1, 0 ); - - return function rotateY( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateZ: function () { - - var v1 = new Vector3( 0, 0, 1 ); - - return function rotateZ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - translateOnAxis: function () { - - // translate object by distance along axis in object space - // axis is assumed to be normalized - - var v1 = new Vector3(); - - return function translateOnAxis( axis, distance ) { - - v1.copy( axis ).applyQuaternion( this.quaternion ); - - this.position.add( v1.multiplyScalar( distance ) ); - - return this; - - }; - - }(), - - translateX: function () { - - var v1 = new Vector3( 1, 0, 0 ); - - return function translateX( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateY: function () { - - var v1 = new Vector3( 0, 1, 0 ); - - return function translateY( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateZ: function () { - - var v1 = new Vector3( 0, 0, 1 ); - - return function translateZ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - localToWorld: function ( vector ) { - - return vector.applyMatrix4( this.matrixWorld ); - - }, - - worldToLocal: function () { - - var m1 = new Matrix4(); - - return function worldToLocal( vector ) { - - return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); - - }; - - }(), - - lookAt: function () { - - // This method does not support objects with rotated and/or translated parent(s) - - var m1 = new Matrix4(); - - return function lookAt( vector ) { - - if ( this.isCamera ) { - - m1.lookAt( this.position, vector, this.up ); - - } else { - - m1.lookAt( vector, this.position, this.up ); - - } - - this.quaternion.setFromRotationMatrix( m1 ); - - }; - - }(), - - add: function ( object ) { - - if ( arguments.length > 1 ) { - - for ( var i = 0; i < arguments.length; i ++ ) { - - this.add( arguments[ i ] ); - - } - - return this; - - } - - if ( object === this ) { - - console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); - return this; - - } - - if ( ( object && object.isObject3D ) ) { - - if ( object.parent !== null ) { - - object.parent.remove( object ); - - } - - object.parent = this; - object.dispatchEvent( { type: 'added' } ); - - this.children.push( object ); - - } else { - - console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - - } - - return this; - - }, - - remove: function ( object ) { - - if ( arguments.length > 1 ) { - - for ( var i = 0; i < arguments.length; i ++ ) { - - this.remove( arguments[ i ] ); - - } - - return this; - - } - - var index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = null; - - object.dispatchEvent( { type: 'removed' } ); - - this.children.splice( index, 1 ); - - } - - return this; - - }, - - getObjectById: function ( id ) { - - return this.getObjectByProperty( 'id', id ); - - }, - - getObjectByName: function ( name ) { - - return this.getObjectByProperty( 'name', name ); - - }, - - getObjectByProperty: function ( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; - var object = child.getObjectByProperty( name, value ); - - if ( object !== undefined ) { - - return object; - - } - - } - - return undefined; - - }, - - getWorldPosition: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - this.updateMatrixWorld( true ); - - return result.setFromMatrixPosition( this.matrixWorld ); - - }, - - getWorldQuaternion: function () { - - var position = new Vector3(); - var scale = new Vector3(); - - return function getWorldQuaternion( optionalTarget ) { - - var result = optionalTarget || new Quaternion(); - - this.updateMatrixWorld( true ); - - this.matrixWorld.decompose( position, result, scale ); - - return result; - - }; - - }(), - - getWorldRotation: function () { - - var quaternion = new Quaternion(); - - return function getWorldRotation( optionalTarget ) { - - var result = optionalTarget || new Euler(); - - this.getWorldQuaternion( quaternion ); - - return result.setFromQuaternion( quaternion, this.rotation.order, false ); - - }; - - }(), - - getWorldScale: function () { - - var position = new Vector3(); - var quaternion = new Quaternion(); - - return function getWorldScale( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - this.updateMatrixWorld( true ); - - this.matrixWorld.decompose( position, quaternion, result ); - - return result; - - }; - - }(), - - getWorldDirection: function () { - - var quaternion = new Quaternion(); - - return function getWorldDirection( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - this.getWorldQuaternion( quaternion ); - - return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); - - }; - - }(), - - raycast: function () {}, - - traverse: function ( callback ) { - - callback( this ); - - var children = this.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverse( callback ); - - } - - }, - - traverseVisible: function ( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - var children = this.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverseVisible( callback ); - - } - - }, - - traverseAncestors: function ( callback ) { - - var parent = this.parent; - - if ( parent !== null ) { - - callback( parent ); - - parent.traverseAncestors( callback ); - - } - - }, - - updateMatrix: function () { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - - }, - - updateMatrixWorld: function ( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - var children = this.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].updateMatrixWorld( force ); - - } - - }, - - toJSON: function ( meta ) { - - // meta is '' when called from JSON.stringify - var isRootObject = ( meta === undefined || meta === '' ); - - var output = {}; - - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { - - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {} - }; - - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; - - } - - // standard Object3D serialization - - var object = {}; - - object.uuid = this.uuid; - object.type = this.type; - - if ( this.name !== '' ) object.name = this.name; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - - object.matrix = this.matrix.toArray(); - - // - - function serialize( library, element ) { - - if ( library[ element.uuid ] === undefined ) { - - library[ element.uuid ] = element.toJSON( meta ); - - } - - return element.uuid; - - } - - if ( this.geometry !== undefined ) { - - object.geometry = serialize( meta.geometries, this.geometry ); - - } - - if ( this.material !== undefined ) { - - if ( Array.isArray( this.material ) ) { - - var uuids = []; - - for ( var i = 0, l = this.material.length; i < l; i ++ ) { - - uuids.push( serialize( meta.materials, this.material[ i ] ) ); - - } - - object.material = uuids; - - } else { - - object.material = serialize( meta.materials, this.material ); - - } - - } - - // - - if ( this.children.length > 0 ) { - - object.children = []; - - for ( var i = 0; i < this.children.length; i ++ ) { - - object.children.push( this.children[ i ].toJSON( meta ).object ); - - } - - } - - if ( isRootObject ) { - - var geometries = extractFromCache( meta.geometries ); - var materials = extractFromCache( meta.materials ); - var textures = extractFromCache( meta.textures ); - var images = extractFromCache( meta.images ); - - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - - } - - output.object = object; - - return output; - - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { - - var values = []; - for ( var key in cache ) { - - var data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - return values; - - } - - }, - - clone: function ( recursive ) { - - return new this.constructor().copy( this, recursive ); - - }, - - copy: function ( source, recursive ) { - - if ( recursive === undefined ) recursive = true; - - this.name = source.name; - - this.up.copy( source.up ); - - this.position.copy( source.position ); - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); - - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - - this.layers.mask = source.layers.mask; - this.visible = source.visible; - - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; - - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - if ( recursive === true ) { - - for ( var i = 0; i < source.children.length; i ++ ) { - - var child = source.children[ i ]; - this.add( child.clone() ); - - } - - } - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ - -function Camera() { - - Object3D.call( this ); - - this.type = 'Camera'; - - this.matrixWorldInverse = new Matrix4(); - this.projectionMatrix = new Matrix4(); - -} - -Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Camera, - - isCamera: true, - - copy: function ( source, recursive ) { - - Object3D.prototype.copy.call( this, source, recursive ); - - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - this.projectionMatrix.copy( source.projectionMatrix ); - - return this; - - }, - - getWorldDirection: function () { - - var quaternion = new Quaternion(); - - return function getWorldDirection( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - this.getWorldQuaternion( quaternion ); - - return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - - }; - - }(), - - updateMatrixWorld: function ( force ) { - - Object3D.prototype.updateMatrixWorld.call( this, force ); - - this.matrixWorldInverse.getInverse( this.matrixWorld ); - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - * @author arose / http://github.com/arose - */ - -function OrthographicCamera( left, right, top, bottom, near, far ) { - - Camera.call( this ); - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; - - this.updateProjectionMatrix(); - -} - -OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - - constructor: OrthographicCamera, - - isOrthographicCamera: true, - - copy: function ( source, recursive ) { - - Camera.prototype.copy.call( this, source, recursive ); - - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; - - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - return this; - - }, - - setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) { - - this.view = { - fullWidth: fullWidth, - fullHeight: fullHeight, - offsetX: x, - offsetY: y, - width: width, - height: height - }; - - this.updateProjectionMatrix(); - - }, - - clearViewOffset: function() { - - this.view = null; - this.updateProjectionMatrix(); - - }, - - updateProjectionMatrix: function () { - - var dx = ( this.right - this.left ) / ( 2 * this.zoom ); - var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - var cx = ( this.right + this.left ) / 2; - var cy = ( this.top + this.bottom ) / 2; - - var left = cx - dx; - var right = cx + dx; - var top = cy + dy; - var bottom = cy - dy; - - if ( this.view !== null ) { - - var zoomW = this.zoom / ( this.view.width / this.view.fullWidth ); - var zoomH = this.zoom / ( this.view.height / this.view.fullHeight ); - var scaleW = ( this.right - this.left ) / this.view.width; - var scaleH = ( this.top - this.bottom ) / this.view.height; - - left += scaleW * ( this.view.offsetX / zoomW ); - right = left + scaleW * ( this.view.width / zoomW ); - top -= scaleH * ( this.view.offsetY / zoomH ); - bottom = top - scaleH * ( this.view.height / zoomH ); - - } - - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); - - }, - - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); - - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - return data; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author tschw - */ - -function PerspectiveCamera( fov, aspect, near, far ) { - - Camera.call( this ); - - this.type = 'PerspectiveCamera'; - - this.fov = fov !== undefined ? fov : 50; - this.zoom = 1; - - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; - this.focus = 10; - - this.aspect = aspect !== undefined ? aspect : 1; - this.view = null; - - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) - - this.updateProjectionMatrix(); - -} - -PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - - constructor: PerspectiveCamera, - - isPerspectiveCamera: true, - - copy: function ( source, recursive ) { - - Camera.prototype.copy.call( this, source, recursive ); - - this.fov = source.fov; - this.zoom = source.zoom; - - this.near = source.near; - this.far = source.far; - this.focus = source.focus; - - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; - - return this; - - }, - - /** - * Sets the FOV by focal length in respect to the current .filmGauge. - * - * The default film gauge is 35, so that the focal length can be specified for - * a 35mm (full frame) camera. - * - * Values for focal length and film gauge must have the same unit. - */ - setFocalLength: function ( focalLength ) { - - // see http://www.bobatkins.com/photography/technical/field_of_view.html - var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - - this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); - - }, - - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength: function () { - - var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); - - return 0.5 * this.getFilmHeight() / vExtentSlope; - - }, - - getEffectiveFOV: function () { - - return _Math.RAD2DEG * 2 * Math.atan( - Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); - - }, - - getFilmWidth: function () { - - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); - - }, - - getFilmHeight: function () { - - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); - - }, - - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * var w = 1920; - * var h = 1080; - * var fullWidth = w * 3; - * var fullHeight = h * 2; - * - * --A-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { - - this.aspect = fullWidth / fullHeight; - - this.view = { - fullWidth: fullWidth, - fullHeight: fullHeight, - offsetX: x, - offsetY: y, - width: width, - height: height - }; - - this.updateProjectionMatrix(); - - }, - - clearViewOffset: function () { - - this.view = null; - this.updateProjectionMatrix(); - - }, - - updateProjectionMatrix: function () { - - var near = this.near, - top = near * Math.tan( - _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom, - height = 2 * top, - width = this.aspect * height, - left = - 0.5 * width, - view = this.view; - - if ( view !== null ) { - - var fullWidth = view.fullWidth, - fullHeight = view.fullHeight; - - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; - - } - - var skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); - - }, - - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); - - data.object.fov = this.fov; - data.object.zoom = this.zoom; - - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; - - data.object.aspect = this.aspect; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; - - return data; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function Face3( a, b, c, normal, color, materialIndex ) { - - this.a = a; - this.b = b; - this.c = c; - - this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); - this.vertexNormals = Array.isArray( normal ) ? normal : []; - - this.color = ( color && color.isColor ) ? color : new Color(); - this.vertexColors = Array.isArray( color ) ? color : []; - - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - -} - -Object.assign( Face3.prototype, { - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( source ) { - - this.a = source.a; - this.b = source.b; - this.c = source.c; - - this.normal.copy( source.normal ); - this.color.copy( source.color ); - - this.materialIndex = source.materialIndex; - - for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { - - this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); - - } - - for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { - - this.vertexColors[ i ] = source.vertexColors[ i ].clone(); - - } - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author bhouston / http://clara.io - */ - -var count = 0; -function GeometryIdCount() { return count++; } - -function Geometry() { - - Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); - - this.uuid = _Math.generateUUID(); - - this.name = ''; - this.type = 'Geometry'; - - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; - - this.morphTargets = []; - this.morphNormals = []; - - this.skinWeights = []; - this.skinIndices = []; - - this.lineDistances = []; - - this.boundingBox = null; - this.boundingSphere = null; - - // update flags - - this.elementsNeedUpdate = false; - this.verticesNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; - this.groupsNeedUpdate = false; - -} - -Object.assign( Geometry.prototype, EventDispatcher.prototype, { - - isGeometry: true, - - applyMatrix: function ( matrix ) { - - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); - - } - - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); - - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - - } - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - this.verticesNeedUpdate = true; - this.normalsNeedUpdate = true; - - return this; - - }, - - rotateX: function () { - - // rotate geometry around world x-axis - - var m1 = new Matrix4(); - - return function rotateX( angle ) { - - m1.makeRotationX( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - rotateY: function () { - - // rotate geometry around world y-axis - - var m1 = new Matrix4(); - - return function rotateY( angle ) { - - m1.makeRotationY( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - rotateZ: function () { - - // rotate geometry around world z-axis - - var m1 = new Matrix4(); - - return function rotateZ( angle ) { - - m1.makeRotationZ( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - translate: function () { - - // translate geometry - - var m1 = new Matrix4(); - - return function translate( x, y, z ) { - - m1.makeTranslation( x, y, z ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - scale: function () { - - // scale geometry - - var m1 = new Matrix4(); - - return function scale( x, y, z ) { - - m1.makeScale( x, y, z ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - lookAt: function () { - - var obj = new Object3D(); - - return function lookAt( vector ) { - - obj.lookAt( vector ); - - obj.updateMatrix(); - - this.applyMatrix( obj.matrix ); - - }; - - }(), - - fromBufferGeometry: function ( geometry ) { - - var scope = this; - - var indices = geometry.index !== null ? geometry.index.array : undefined; - var attributes = geometry.attributes; - - var positions = attributes.position.array; - var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; - var colors = attributes.color !== undefined ? attributes.color.array : undefined; - var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; - var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; - - if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; - - var tempNormals = []; - var tempUVs = []; - var tempUVs2 = []; - - for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { - - scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) ); - - if ( normals !== undefined ) { - - tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); - - } - - if ( colors !== undefined ) { - - scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); - - } - - if ( uvs !== undefined ) { - - tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) ); - - } - - if ( uvs2 !== undefined ) { - - tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); - - } - - } - - function addFace( a, b, c, materialIndex ) { - - var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; - var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; - - var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); - - scope.faces.push( face ); - - if ( uvs !== undefined ) { - - scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - - } - - if ( uvs2 !== undefined ) { - - scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); - - } - - } - - var groups = geometry.groups; - - if ( groups.length > 0 ) { - - for ( var i = 0; i < groups.length; i ++ ) { - - var group = groups[ i ]; - - var start = group.start; - var count = group.count; - - for ( var j = start, jl = start + count; j < jl; j += 3 ) { - - if ( indices !== undefined ) { - - addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); - - } else { - - addFace( j, j + 1, j + 2, group.materialIndex ); - - } - - } - - } - - } else { - - if ( indices !== undefined ) { - - for ( var i = 0; i < indices.length; i += 3 ) { - - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - - } - - } else { - - for ( var i = 0; i < positions.length / 3; i += 3 ) { - - addFace( i, i + 1, i + 2 ); - - } - - } - - } - - this.computeFaceNormals(); - - if ( geometry.boundingBox !== null ) { - - this.boundingBox = geometry.boundingBox.clone(); - - } - - if ( geometry.boundingSphere !== null ) { - - this.boundingSphere = geometry.boundingSphere.clone(); - - } - - return this; - - }, - - center: function () { - - this.computeBoundingBox(); - - var offset = this.boundingBox.getCenter().negate(); - - this.translate( offset.x, offset.y, offset.z ); - - return offset; - - }, - - normalize: function () { - - this.computeBoundingSphere(); - - var center = this.boundingSphere.center; - var radius = this.boundingSphere.radius; - - var s = radius === 0 ? 1 : 1.0 / radius; - - var matrix = new Matrix4(); - matrix.set( - s, 0, 0, - s * center.x, - 0, s, 0, - s * center.y, - 0, 0, s, - s * center.z, - 0, 0, 0, 1 - ); - - this.applyMatrix( matrix ); - - return this; - - }, - - computeFaceNormals: function () { - - var cb = new Vector3(), ab = new Vector3(); - - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - - var face = this.faces[ f ]; - - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; - - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); - - cb.normalize(); - - face.normal.copy( cb ); - - } - - }, - - computeVertexNormals: function ( areaWeighted ) { - - if ( areaWeighted === undefined ) areaWeighted = true; - - var v, vl, f, fl, face, vertices; - - vertices = new Array( this.vertices.length ); - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - vertices[ v ] = new Vector3(); - - } - - if ( areaWeighted ) { - - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm - - var vA, vB, vC; - var cb = new Vector3(), ab = new Vector3(); - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; - - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); - - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); - - } - - } else { - - this.computeFaceNormals(); - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); - - } - - } - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - vertices[ v ].normalize(); - - } - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - var vertexNormals = face.vertexNormals; - - if ( vertexNormals.length === 3 ) { - - vertexNormals[ 0 ].copy( vertices[ face.a ] ); - vertexNormals[ 1 ].copy( vertices[ face.b ] ); - vertexNormals[ 2 ].copy( vertices[ face.c ] ); - - } else { - - vertexNormals[ 0 ] = vertices[ face.a ].clone(); - vertexNormals[ 1 ] = vertices[ face.b ].clone(); - vertexNormals[ 2 ] = vertices[ face.c ].clone(); - - } - - } - - if ( this.faces.length > 0 ) { - - this.normalsNeedUpdate = true; - - } - - }, - - computeFlatVertexNormals: function () { - - var f, fl, face; - - this.computeFaceNormals(); - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - var vertexNormals = face.vertexNormals; - - if ( vertexNormals.length === 3 ) { - - vertexNormals[ 0 ].copy( face.normal ); - vertexNormals[ 1 ].copy( face.normal ); - vertexNormals[ 2 ].copy( face.normal ); - - } else { - - vertexNormals[ 0 ] = face.normal.clone(); - vertexNormals[ 1 ] = face.normal.clone(); - vertexNormals[ 2 ] = face.normal.clone(); - - } - - } - - if ( this.faces.length > 0 ) { - - this.normalsNeedUpdate = true; - - } - - }, - - computeMorphNormals: function () { - - var i, il, f, fl, face; - - // save original normals - // - create temp variables on first access - // otherwise just copy (for faster repeated calls) - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - if ( ! face.__originalFaceNormal ) { - - face.__originalFaceNormal = face.normal.clone(); - - } else { - - face.__originalFaceNormal.copy( face.normal ); - - } - - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - - if ( ! face.__originalVertexNormals[ i ] ) { - - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - - } else { - - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - - } - - } - - } - - // use temp geometry to compute face and vertex normals for each morph - - var tmpGeo = new Geometry(); - tmpGeo.faces = this.faces; - - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - - // create on first access - - if ( ! this.morphNormals[ i ] ) { - - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; - - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - - var faceNormal, vertexNormals; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - faceNormal = new Vector3(); - vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; - - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); - - } - - } - - var morphNormals = this.morphNormals[ i ]; - - // set vertices to morph target - - tmpGeo.vertices = this.morphTargets[ i ].vertices; - - // compute morph normals - - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); - - // store morph normals - - var faceNormal, vertexNormals; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; - - faceNormal.copy( face.normal ); - - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); - - } - - } - - // restore original normals - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; - - } - - }, - - computeLineDistances: function () { - - var d = 0; - var vertices = this.vertices; - - for ( var i = 0, il = vertices.length; i < il; i ++ ) { - - if ( i > 0 ) { - - d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); - - } - - this.lineDistances[ i ] = d; - - } - - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - this.boundingBox.setFromPoints( this.vertices ); - - }, - - computeBoundingSphere: function () { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - this.boundingSphere.setFromPoints( this.vertices ); - - }, - - merge: function ( geometry, matrix, materialIndexOffset ) { - - if ( ! ( geometry && geometry.isGeometry ) ) { - - console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); - return; - - } - - var normalMatrix, - vertexOffset = this.vertices.length, - vertices1 = this.vertices, - vertices2 = geometry.vertices, - faces1 = this.faces, - faces2 = geometry.faces, - uvs1 = this.faceVertexUvs[ 0 ], - uvs2 = geometry.faceVertexUvs[ 0 ], - colors1 = this.colors, - colors2 = geometry.colors; - - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - - if ( matrix !== undefined ) { - - normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - } - - // vertices - - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - - var vertex = vertices2[ i ]; - - var vertexCopy = vertex.clone(); - - if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); - - vertices1.push( vertexCopy ); - - } - - // colors - - for ( var i = 0, il = colors2.length; i < il; i ++ ) { - - colors1.push( colors2[ i ].clone() ); - - } - - // faces - - for ( i = 0, il = faces2.length; i < il; i ++ ) { - - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; - - faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); - - if ( normalMatrix !== undefined ) { - - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - - } - - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - - normal = faceVertexNormals[ j ].clone(); - - if ( normalMatrix !== undefined ) { - - normal.applyMatrix3( normalMatrix ).normalize(); - - } - - faceCopy.vertexNormals.push( normal ); - - } - - faceCopy.color.copy( face.color ); - - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { - - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); - - } - - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - - faces1.push( faceCopy ); - - } - - // uvs - - for ( i = 0, il = uvs2.length; i < il; i ++ ) { - - var uv = uvs2[ i ], uvCopy = []; - - if ( uv === undefined ) { - - continue; - - } - - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - - uvCopy.push( uv[ j ].clone() ); - - } - - uvs1.push( uvCopy ); - - } - - }, - - mergeMesh: function ( mesh ) { - - if ( ! ( mesh && mesh.isMesh ) ) { - - console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); - return; - - } - - mesh.matrixAutoUpdate && mesh.updateMatrix(); - - this.merge( mesh.geometry, mesh.matrix ); - - }, - - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ - - mergeVertices: function () { - - var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) - var unique = [], changes = []; - - var v, key; - var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 - var precision = Math.pow( 10, precisionPoints ); - var i, il, face; - var indices, j, jl; - - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { - - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); - - if ( verticesMap[ key ] === undefined ) { - - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; - - } else { - - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; - - } - - } - - - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; - - for ( i = 0, il = this.faces.length; i < il; i ++ ) { - - face = this.faces[ i ]; - - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; - - indices = [ face.a, face.b, face.c ]; - - // if any duplicate vertices are found in a Face3 - // we have to remove the face as nothing can be saved - for ( var n = 0; n < 3; n ++ ) { - - if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { - - faceIndicesToRemove.push( i ); - break; - - } - - } - - } - - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - - var idx = faceIndicesToRemove[ i ]; - - this.faces.splice( idx, 1 ); - - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - - this.faceVertexUvs[ j ].splice( idx, 1 ); - - } - - } - - // Use unique set of vertices - - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; - - }, - - sortFacesByMaterialIndex: function () { - - var faces = this.faces; - var length = faces.length; - - // tag faces - - for ( var i = 0; i < length; i ++ ) { - - faces[ i ]._id = i; - - } - - // sort faces - - function materialIndexSort( a, b ) { - - return a.materialIndex - b.materialIndex; - - } - - faces.sort( materialIndexSort ); - - // sort uvs - - var uvs1 = this.faceVertexUvs[ 0 ]; - var uvs2 = this.faceVertexUvs[ 1 ]; - - var newUvs1, newUvs2; - - if ( uvs1 && uvs1.length === length ) newUvs1 = []; - if ( uvs2 && uvs2.length === length ) newUvs2 = []; - - for ( var i = 0; i < length; i ++ ) { - - var id = faces[ i ]._id; - - if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); - if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); - - } - - if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; - if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; - - }, - - toJSON: function () { - - var data = { - metadata: { - version: 4.5, - type: 'Geometry', - generator: 'Geometry.toJSON' - } - }; - - // standard Geometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - - if ( this.parameters !== undefined ) { - - var parameters = this.parameters; - - for ( var key in parameters ) { - - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - - } - - return data; - - } - - var vertices = []; - - for ( var i = 0; i < this.vertices.length; i ++ ) { - - var vertex = this.vertices[ i ]; - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - var faces = []; - var normals = []; - var normalsHash = {}; - var colors = []; - var colorsHash = {}; - var uvs = []; - var uvsHash = {}; - - for ( var i = 0; i < this.faces.length; i ++ ) { - - var face = this.faces[ i ]; - - var hasMaterial = true; - var hasFaceUv = false; // deprecated - var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; - var hasFaceNormal = face.normal.length() > 0; - var hasFaceVertexNormal = face.vertexNormals.length > 0; - var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; - var hasFaceVertexColor = face.vertexColors.length > 0; - - var faceType = 0; - - faceType = setBit( faceType, 0, 0 ); // isQuad - faceType = setBit( faceType, 1, hasMaterial ); - faceType = setBit( faceType, 2, hasFaceUv ); - faceType = setBit( faceType, 3, hasFaceVertexUv ); - faceType = setBit( faceType, 4, hasFaceNormal ); - faceType = setBit( faceType, 5, hasFaceVertexNormal ); - faceType = setBit( faceType, 6, hasFaceColor ); - faceType = setBit( faceType, 7, hasFaceVertexColor ); - - faces.push( faceType ); - faces.push( face.a, face.b, face.c ); - faces.push( face.materialIndex ); - - if ( hasFaceVertexUv ) { - - var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; - - faces.push( - getUvIndex( faceVertexUvs[ 0 ] ), - getUvIndex( faceVertexUvs[ 1 ] ), - getUvIndex( faceVertexUvs[ 2 ] ) - ); - - } - - if ( hasFaceNormal ) { - - faces.push( getNormalIndex( face.normal ) ); - - } - - if ( hasFaceVertexNormal ) { - - var vertexNormals = face.vertexNormals; - - faces.push( - getNormalIndex( vertexNormals[ 0 ] ), - getNormalIndex( vertexNormals[ 1 ] ), - getNormalIndex( vertexNormals[ 2 ] ) - ); - - } - - if ( hasFaceColor ) { - - faces.push( getColorIndex( face.color ) ); - - } - - if ( hasFaceVertexColor ) { - - var vertexColors = face.vertexColors; - - faces.push( - getColorIndex( vertexColors[ 0 ] ), - getColorIndex( vertexColors[ 1 ] ), - getColorIndex( vertexColors[ 2 ] ) - ); - - } - - } - - function setBit( value, position, enabled ) { - - return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); - - } - - function getNormalIndex( normal ) { - - var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); - - if ( normalsHash[ hash ] !== undefined ) { - - return normalsHash[ hash ]; - - } - - normalsHash[ hash ] = normals.length / 3; - normals.push( normal.x, normal.y, normal.z ); - - return normalsHash[ hash ]; - - } - - function getColorIndex( color ) { - - var hash = color.r.toString() + color.g.toString() + color.b.toString(); - - if ( colorsHash[ hash ] !== undefined ) { - - return colorsHash[ hash ]; - - } - - colorsHash[ hash ] = colors.length; - colors.push( color.getHex() ); - - return colorsHash[ hash ]; - - } - - function getUvIndex( uv ) { - - var hash = uv.x.toString() + uv.y.toString(); - - if ( uvsHash[ hash ] !== undefined ) { - - return uvsHash[ hash ]; - - } - - uvsHash[ hash ] = uvs.length / 2; - uvs.push( uv.x, uv.y ); - - return uvsHash[ hash ]; - - } - - data.data = {}; - - data.data.vertices = vertices; - data.data.normals = normals; - if ( colors.length > 0 ) data.data.colors = colors; - if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility - data.data.faces = faces; - - return data; - - }, - - clone: function () { - - /* - // Handle primitives - - var parameters = this.parameters; - - if ( parameters !== undefined ) { - - var values = []; - - for ( var key in parameters ) { - - values.push( parameters[ key ] ); - - } - - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; - - } - - return new this.constructor().copy( this ); - */ - - return new Geometry().copy( this ); - - }, - - copy: function ( source ) { - - var i, il, j, jl, k, kl; - - // reset - - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; - this.morphTargets = []; - this.morphNormals = []; - this.skinWeights = []; - this.skinIndices = []; - this.lineDistances = []; - this.boundingBox = null; - this.boundingSphere = null; - - // name - - this.name = source.name; - - // vertices - - var vertices = source.vertices; - - for ( i = 0, il = vertices.length; i < il; i ++ ) { - - this.vertices.push( vertices[ i ].clone() ); - - } - - // colors - - var colors = source.colors; - - for ( i = 0, il = colors.length; i < il; i ++ ) { - - this.colors.push( colors[ i ].clone() ); - - } - - // faces - - var faces = source.faces; - - for ( i = 0, il = faces.length; i < il; i ++ ) { - - this.faces.push( faces[ i ].clone() ); - - } - - // face vertex uvs - - for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { - - var faceVertexUvs = source.faceVertexUvs[ i ]; - - if ( this.faceVertexUvs[ i ] === undefined ) { - - this.faceVertexUvs[ i ] = []; - - } - - for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - - var uvs = faceVertexUvs[ j ], uvsCopy = []; - - for ( k = 0, kl = uvs.length; k < kl; k ++ ) { - - var uv = uvs[ k ]; - - uvsCopy.push( uv.clone() ); - - } - - this.faceVertexUvs[ i ].push( uvsCopy ); - - } - - } - - // morph targets - - var morphTargets = source.morphTargets; - - for ( i = 0, il = morphTargets.length; i < il; i ++ ) { - - var morphTarget = {}; - morphTarget.name = morphTargets[ i ].name; - - // vertices - - if ( morphTargets[ i ].vertices !== undefined ) { - - morphTarget.vertices = []; - - for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { - - morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); - - } - - } - - // normals - - if ( morphTargets[ i ].normals !== undefined ) { - - morphTarget.normals = []; - - for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { - - morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); - - } - - } - - this.morphTargets.push( morphTarget ); - - } - - // morph normals - - var morphNormals = source.morphNormals; - - for ( i = 0, il = morphNormals.length; i < il; i ++ ) { - - var morphNormal = {}; - - // vertex normals - - if ( morphNormals[ i ].vertexNormals !== undefined ) { - - morphNormal.vertexNormals = []; - - for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { - - var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; - var destVertexNormal = {}; - - destVertexNormal.a = srcVertexNormal.a.clone(); - destVertexNormal.b = srcVertexNormal.b.clone(); - destVertexNormal.c = srcVertexNormal.c.clone(); - - morphNormal.vertexNormals.push( destVertexNormal ); - - } - - } - - // face normals - - if ( morphNormals[ i ].faceNormals !== undefined ) { - - morphNormal.faceNormals = []; - - for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { - - morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); - - } - - } - - this.morphNormals.push( morphNormal ); - - } - - // skin weights - - var skinWeights = source.skinWeights; - - for ( i = 0, il = skinWeights.length; i < il; i ++ ) { - - this.skinWeights.push( skinWeights[ i ].clone() ); - - } - - // skin indices - - var skinIndices = source.skinIndices; - - for ( i = 0, il = skinIndices.length; i < il; i ++ ) { - - this.skinIndices.push( skinIndices[ i ].clone() ); - - } - - // line distances - - var lineDistances = source.lineDistances; - - for ( i = 0, il = lineDistances.length; i < il; i ++ ) { - - this.lineDistances.push( lineDistances[ i ] ); - - } - - // bounding box - - var boundingBox = source.boundingBox; - - if ( boundingBox !== null ) { - - this.boundingBox = boundingBox.clone(); - - } - - // bounding sphere - - var boundingSphere = source.boundingSphere; - - if ( boundingSphere !== null ) { - - this.boundingSphere = boundingSphere.clone(); - - } - - // update flags - - this.elementsNeedUpdate = source.elementsNeedUpdate; - this.verticesNeedUpdate = source.verticesNeedUpdate; - this.uvsNeedUpdate = source.uvsNeedUpdate; - this.normalsNeedUpdate = source.normalsNeedUpdate; - this.colorsNeedUpdate = source.colorsNeedUpdate; - this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate; - this.groupsNeedUpdate = source.groupsNeedUpdate; - - return this; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function BufferAttribute( array, itemSize, normalized ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.uuid = _Math.generateUUID(); - this.name = ''; - - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; - - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; - - this.onUploadCallback = function () {}; - - this.version = 0; - -} - -Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { - - set: function ( value ) { - - if ( value === true ) this.version ++; - - } - -} ); - -Object.assign( BufferAttribute.prototype, { - - isBufferAttribute: true, - - setArray: function ( array ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.count = array !== undefined ? array.length / this.itemSize : 0; - this.array = array; - - }, - - setDynamic: function ( value ) { - - this.dynamic = value; - - return this; - - }, - - copy: function ( source ) { - - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; - - this.dynamic = source.dynamic; - - return this; - - }, - - copyAt: function ( index1, attribute, index2 ) { - - index1 *= this.itemSize; - index2 *= attribute.itemSize; - - for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - }, - - copyArray: function ( array ) { - - this.array.set( array ); - - return this; - - }, - - copyColorsArray: function ( colors ) { - - var array = this.array, offset = 0; - - for ( var i = 0, l = colors.length; i < l; i ++ ) { - - var color = colors[ i ]; - - if ( color === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); - color = new Color(); - - } - - array[ offset ++ ] = color.r; - array[ offset ++ ] = color.g; - array[ offset ++ ] = color.b; - - } - - return this; - - }, - - copyIndicesArray: function ( indices ) { - - var array = this.array, offset = 0; - - for ( var i = 0, l = indices.length; i < l; i ++ ) { - - var index = indices[ i ]; - - array[ offset ++ ] = index.a; - array[ offset ++ ] = index.b; - array[ offset ++ ] = index.c; - - } - - return this; - - }, - - copyVector2sArray: function ( vectors ) { - - var array = this.array, offset = 0; - - for ( var i = 0, l = vectors.length; i < l; i ++ ) { - - var vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); - vector = new Vector2(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - - } - - return this; - - }, - - copyVector3sArray: function ( vectors ) { - - var array = this.array, offset = 0; - - for ( var i = 0, l = vectors.length; i < l; i ++ ) { - - var vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); - vector = new Vector3(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - - } - - return this; - - }, - - copyVector4sArray: function ( vectors ) { - - var array = this.array, offset = 0; - - for ( var i = 0, l = vectors.length; i < l; i ++ ) { - - var vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); - vector = new Vector4(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - array[ offset ++ ] = vector.w; - - } - - return this; - - }, - - set: function ( value, offset ) { - - if ( offset === undefined ) offset = 0; - - this.array.set( value, offset ); - - return this; - - }, - - getX: function ( index ) { - - return this.array[ index * this.itemSize ]; - - }, - - setX: function ( index, x ) { - - this.array[ index * this.itemSize ] = x; - - return this; - - }, - - getY: function ( index ) { - - return this.array[ index * this.itemSize + 1 ]; - - }, - - setY: function ( index, y ) { - - this.array[ index * this.itemSize + 1 ] = y; - - return this; - - }, - - getZ: function ( index ) { - - return this.array[ index * this.itemSize + 2 ]; - - }, - - setZ: function ( index, z ) { - - this.array[ index * this.itemSize + 2 ] = z; - - return this; - - }, - - getW: function ( index ) { - - return this.array[ index * this.itemSize + 3 ]; - - }, - - setW: function ( index, w ) { - - this.array[ index * this.itemSize + 3 ] = w; - - return this; - - }, - - setXY: function ( index, x, y ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - - return this; - - }, - - setXYZ: function ( index, x, y, z ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - - return this; - - }, - - setXYZW: function ( index, x, y, z, w ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; - - return this; - - }, - - onUpload: function ( callback ) { - - this.onUploadCallback = callback; - - return this; - - }, - - clone: function () { - - return new this.constructor( this.array, this.itemSize ).copy( this ); - - } - -} ); - -function Uint16BufferAttribute( array, itemSize ) { - - BufferAttribute.call( this, new Uint16Array( array ), itemSize ); - -} - -Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; - - -function Uint32BufferAttribute( array, itemSize ) { - - BufferAttribute.call( this, new Uint32Array( array ), itemSize ); - -} - -Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; - - -function Float32BufferAttribute( array, itemSize ) { - - BufferAttribute.call( this, new Float32Array( array ), itemSize ); - -} - -Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function DirectGeometry() { - - this.indices = []; - this.vertices = []; - this.normals = []; - this.colors = []; - this.uvs = []; - this.uvs2 = []; - - this.groups = []; - - this.morphTargets = {}; - - this.skinWeights = []; - this.skinIndices = []; - - // this.lineDistances = []; - - this.boundingBox = null; - this.boundingSphere = null; - - // update flags - - this.verticesNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.groupsNeedUpdate = false; - -} - -Object.assign( DirectGeometry.prototype, { - - computeGroups: function ( geometry ) { - - var group; - var groups = []; - var materialIndex = undefined; - - var faces = geometry.faces; - - for ( var i = 0; i < faces.length; i ++ ) { - - var face = faces[ i ]; - - // materials - - if ( face.materialIndex !== materialIndex ) { - - materialIndex = face.materialIndex; - - if ( group !== undefined ) { - - group.count = ( i * 3 ) - group.start; - groups.push( group ); - - } - - group = { - start: i * 3, - materialIndex: materialIndex - }; - - } - - } - - if ( group !== undefined ) { - - group.count = ( i * 3 ) - group.start; - groups.push( group ); - - } - - this.groups = groups; - - }, - - fromGeometry: function ( geometry ) { - - var faces = geometry.faces; - var vertices = geometry.vertices; - var faceVertexUvs = geometry.faceVertexUvs; - - var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; - var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; - - // morphs - - var morphTargets = geometry.morphTargets; - var morphTargetsLength = morphTargets.length; - - var morphTargetsPosition; - - if ( morphTargetsLength > 0 ) { - - morphTargetsPosition = []; - - for ( var i = 0; i < morphTargetsLength; i ++ ) { - - morphTargetsPosition[ i ] = []; - - } - - this.morphTargets.position = morphTargetsPosition; - - } - - var morphNormals = geometry.morphNormals; - var morphNormalsLength = morphNormals.length; - - var morphTargetsNormal; - - if ( morphNormalsLength > 0 ) { - - morphTargetsNormal = []; - - for ( var i = 0; i < morphNormalsLength; i ++ ) { - - morphTargetsNormal[ i ] = []; - - } - - this.morphTargets.normal = morphTargetsNormal; - - } - - // skins - - var skinIndices = geometry.skinIndices; - var skinWeights = geometry.skinWeights; - - var hasSkinIndices = skinIndices.length === vertices.length; - var hasSkinWeights = skinWeights.length === vertices.length; - - // - - for ( var i = 0; i < faces.length; i ++ ) { - - var face = faces[ i ]; - - this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); - - var vertexNormals = face.vertexNormals; - - if ( vertexNormals.length === 3 ) { - - this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); - - } else { - - var normal = face.normal; - - this.normals.push( normal, normal, normal ); - - } - - var vertexColors = face.vertexColors; - - if ( vertexColors.length === 3 ) { - - this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); - - } else { - - var color = face.color; - - this.colors.push( color, color, color ); - - } - - if ( hasFaceVertexUv === true ) { - - var vertexUvs = faceVertexUvs[ 0 ][ i ]; - - if ( vertexUvs !== undefined ) { - - this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - - } else { - - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); - - this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); - - } - - } - - if ( hasFaceVertexUv2 === true ) { - - var vertexUvs = faceVertexUvs[ 1 ][ i ]; - - if ( vertexUvs !== undefined ) { - - this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - - } else { - - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); - - this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); - - } - - } - - // morphs - - for ( var j = 0; j < morphTargetsLength; j ++ ) { - - var morphTarget = morphTargets[ j ].vertices; - - morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); - - } - - for ( var j = 0; j < morphNormalsLength; j ++ ) { - - var morphNormal = morphNormals[ j ].vertexNormals[ i ]; - - morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); - - } - - // skins - - if ( hasSkinIndices ) { - - this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); - - } - - if ( hasSkinWeights ) { - - this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); - - } - - } - - this.computeGroups( geometry ); - - this.verticesNeedUpdate = geometry.verticesNeedUpdate; - this.normalsNeedUpdate = geometry.normalsNeedUpdate; - this.colorsNeedUpdate = geometry.colorsNeedUpdate; - this.uvsNeedUpdate = geometry.uvsNeedUpdate; - this.groupsNeedUpdate = geometry.groupsNeedUpdate; - - return this; - - } - -} ); - -function arrayMax( array ) { - - if ( array.length === 0 ) return - Infinity; - - var max = array[ 0 ]; - - for ( var i = 1, l = array.length; i < l; ++ i ) { - - if ( array[ i ] > max ) max = array[ i ]; - - } - - return max; - -} - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -function BufferGeometry() { - - Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); - - this.uuid = _Math.generateUUID(); - - this.name = ''; - this.type = 'BufferGeometry'; - - this.index = null; - this.attributes = {}; - - this.morphAttributes = {}; - - this.groups = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.drawRange = { start: 0, count: Infinity }; - -} - -BufferGeometry.MaxIndex = 65535; - -Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, { - - isBufferGeometry: true, - - getIndex: function () { - - return this.index; - - }, - - setIndex: function ( index ) { - - if ( Array.isArray( index ) ) { - - this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - - } else { - - this.index = index; - - } - - }, - - addAttribute: function ( name, attribute ) { - - if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) { - - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - - this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); - - return; - - } - - if ( name === 'index' ) { - - console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); - this.setIndex( attribute ); - - return; - - } - - this.attributes[ name ] = attribute; - - return this; - - }, - - getAttribute: function ( name ) { - - return this.attributes[ name ]; - - }, - - removeAttribute: function ( name ) { - - delete this.attributes[ name ]; - - return this; - - }, - - addGroup: function ( start, count, materialIndex ) { - - this.groups.push( { - - start: start, - count: count, - materialIndex: materialIndex !== undefined ? materialIndex : 0 - - } ); - - }, - - clearGroups: function () { - - this.groups = []; - - }, - - setDrawRange: function ( start, count ) { - - this.drawRange.start = start; - this.drawRange.count = count; - - }, - - applyMatrix: function ( matrix ) { - - var position = this.attributes.position; - - if ( position !== undefined ) { - - matrix.applyToBufferAttribute( position ); - position.needsUpdate = true; - - } - - var normal = this.attributes.normal; - - if ( normal !== undefined ) { - - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - normalMatrix.applyToBufferAttribute( normal ); - normal.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - return this; - - }, - - rotateX: function () { - - // rotate geometry around world x-axis - - var m1 = new Matrix4(); - - return function rotateX( angle ) { - - m1.makeRotationX( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - rotateY: function () { - - // rotate geometry around world y-axis - - var m1 = new Matrix4(); - - return function rotateY( angle ) { - - m1.makeRotationY( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - rotateZ: function () { - - // rotate geometry around world z-axis - - var m1 = new Matrix4(); - - return function rotateZ( angle ) { - - m1.makeRotationZ( angle ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - translate: function () { - - // translate geometry - - var m1 = new Matrix4(); - - return function translate( x, y, z ) { - - m1.makeTranslation( x, y, z ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - scale: function () { - - // scale geometry - - var m1 = new Matrix4(); - - return function scale( x, y, z ) { - - m1.makeScale( x, y, z ); - - this.applyMatrix( m1 ); - - return this; - - }; - - }(), - - lookAt: function () { - - var obj = new Object3D(); - - return function lookAt( vector ) { - - obj.lookAt( vector ); - - obj.updateMatrix(); - - this.applyMatrix( obj.matrix ); - - }; - - }(), - - center: function () { - - this.computeBoundingBox(); - - var offset = this.boundingBox.getCenter().negate(); - - this.translate( offset.x, offset.y, offset.z ); - - return offset; - - }, - - setFromObject: function ( object ) { - - // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); - - var geometry = object.geometry; - - if ( object.isPoints || object.isLine ) { - - var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); - var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); - - this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); - this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); - - if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { - - var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); - - this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); - - } - - if ( geometry.boundingSphere !== null ) { - - this.boundingSphere = geometry.boundingSphere.clone(); - - } - - if ( geometry.boundingBox !== null ) { - - this.boundingBox = geometry.boundingBox.clone(); - - } - - } else if ( object.isMesh ) { - - if ( geometry && geometry.isGeometry ) { - - this.fromGeometry( geometry ); - - } - - } - - return this; - - }, - - updateFromObject: function ( object ) { - - var geometry = object.geometry; - - if ( object.isMesh ) { - - var direct = geometry.__directGeometry; - - if ( geometry.elementsNeedUpdate === true ) { - - direct = undefined; - geometry.elementsNeedUpdate = false; - - } - - if ( direct === undefined ) { - - return this.fromGeometry( geometry ); - - } - - direct.verticesNeedUpdate = geometry.verticesNeedUpdate; - direct.normalsNeedUpdate = geometry.normalsNeedUpdate; - direct.colorsNeedUpdate = geometry.colorsNeedUpdate; - direct.uvsNeedUpdate = geometry.uvsNeedUpdate; - direct.groupsNeedUpdate = geometry.groupsNeedUpdate; - - geometry.verticesNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.groupsNeedUpdate = false; - - geometry = direct; - - } - - var attribute; - - if ( geometry.verticesNeedUpdate === true ) { - - attribute = this.attributes.position; - - if ( attribute !== undefined ) { - - attribute.copyVector3sArray( geometry.vertices ); - attribute.needsUpdate = true; - - } - - geometry.verticesNeedUpdate = false; - - } - - if ( geometry.normalsNeedUpdate === true ) { - - attribute = this.attributes.normal; - - if ( attribute !== undefined ) { - - attribute.copyVector3sArray( geometry.normals ); - attribute.needsUpdate = true; - - } - - geometry.normalsNeedUpdate = false; - - } - - if ( geometry.colorsNeedUpdate === true ) { - - attribute = this.attributes.color; - - if ( attribute !== undefined ) { - - attribute.copyColorsArray( geometry.colors ); - attribute.needsUpdate = true; - - } - - geometry.colorsNeedUpdate = false; - - } - - if ( geometry.uvsNeedUpdate ) { - - attribute = this.attributes.uv; - - if ( attribute !== undefined ) { - - attribute.copyVector2sArray( geometry.uvs ); - attribute.needsUpdate = true; - - } - - geometry.uvsNeedUpdate = false; - - } - - if ( geometry.lineDistancesNeedUpdate ) { - - attribute = this.attributes.lineDistance; - - if ( attribute !== undefined ) { - - attribute.copyArray( geometry.lineDistances ); - attribute.needsUpdate = true; - - } - - geometry.lineDistancesNeedUpdate = false; - - } - - if ( geometry.groupsNeedUpdate ) { - - geometry.computeGroups( object.geometry ); - this.groups = geometry.groups; - - geometry.groupsNeedUpdate = false; - - } - - return this; - - }, - - fromGeometry: function ( geometry ) { - - geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); - - return this.fromDirectGeometry( geometry.__directGeometry ); - - }, - - fromDirectGeometry: function ( geometry ) { - - var positions = new Float32Array( geometry.vertices.length * 3 ); - this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); - - if ( geometry.normals.length > 0 ) { - - var normals = new Float32Array( geometry.normals.length * 3 ); - this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); - - } - - if ( geometry.colors.length > 0 ) { - - var colors = new Float32Array( geometry.colors.length * 3 ); - this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); - - } - - if ( geometry.uvs.length > 0 ) { - - var uvs = new Float32Array( geometry.uvs.length * 2 ); - this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); - - } - - if ( geometry.uvs2.length > 0 ) { - - var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); - this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); - - } - - if ( geometry.indices.length > 0 ) { - - var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array; - var indices = new TypeArray( geometry.indices.length * 3 ); - this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); - - } - - // groups - - this.groups = geometry.groups; - - // morphs - - for ( var name in geometry.morphTargets ) { - - var array = []; - var morphTargets = geometry.morphTargets[ name ]; - - for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { - - var morphTarget = morphTargets[ i ]; - - var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 ); - - array.push( attribute.copyVector3sArray( morphTarget ) ); - - } - - this.morphAttributes[ name ] = array; - - } - - // skinning - - if ( geometry.skinIndices.length > 0 ) { - - var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); - this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); - - } - - if ( geometry.skinWeights.length > 0 ) { - - var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); - this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); - - } - - // - - if ( geometry.boundingSphere !== null ) { - - this.boundingSphere = geometry.boundingSphere.clone(); - - } - - if ( geometry.boundingBox !== null ) { - - this.boundingBox = geometry.boundingBox.clone(); - - } - - return this; - - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - var position = this.attributes.position; - - if ( position !== undefined ) { - - this.boundingBox.setFromBufferAttribute( position ); - - } else { - - this.boundingBox.makeEmpty(); - - } - - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - - } - - }, - - computeBoundingSphere: function () { - - var box = new Box3(); - var vector = new Vector3(); - - return function computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - var position = this.attributes.position; - - if ( position ) { - - var center = this.boundingSphere.center; - - box.setFromBufferAttribute( position ); - box.getCenter( center ); - - // hoping to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - - var maxRadiusSq = 0; - - for ( var i = 0, il = position.count; i < il; i ++ ) { - - vector.x = position.getX( i ); - vector.y = position.getY( i ); - vector.z = position.getZ( i ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - }; - - }(), - - computeFaceNormals: function () { - - // backwards compatibility - - }, - - computeVertexNormals: function () { - - var index = this.index; - var attributes = this.attributes; - var groups = this.groups; - - if ( attributes.position ) { - - var positions = attributes.position.array; - - if ( attributes.normal === undefined ) { - - this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); - - } else { - - // reset existing normals to zero - - var array = attributes.normal.array; - - for ( var i = 0, il = array.length; i < il; i ++ ) { - - array[ i ] = 0; - - } - - } - - var normals = attributes.normal.array; - - var vA, vB, vC; - var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - var cb = new Vector3(), ab = new Vector3(); - - // indexed elements - - if ( index ) { - - var indices = index.array; - - if ( groups.length === 0 ) { - - this.addGroup( 0, indices.length ); - - } - - for ( var j = 0, jl = groups.length; j < jl; ++ j ) { - - var group = groups[ j ]; - - var start = group.start; - var count = group.count; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - vA = indices[ i + 0 ] * 3; - vB = indices[ i + 1 ] * 3; - vC = indices[ i + 2 ] * 3; - - pA.fromArray( positions, vA ); - pB.fromArray( positions, vB ); - pC.fromArray( positions, vC ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normals[ vA ] += cb.x; - normals[ vA + 1 ] += cb.y; - normals[ vA + 2 ] += cb.z; - - normals[ vB ] += cb.x; - normals[ vB + 1 ] += cb.y; - normals[ vB + 2 ] += cb.z; - - normals[ vC ] += cb.x; - normals[ vC + 1 ] += cb.y; - normals[ vC + 2 ] += cb.z; - - } - - } - - } else { - - // non-indexed elements (unconnected triangle soup) - - for ( var i = 0, il = positions.length; i < il; i += 9 ) { - - pA.fromArray( positions, i ); - pB.fromArray( positions, i + 3 ); - pC.fromArray( positions, i + 6 ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; - - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; - - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; - - } - - } - - this.normalizeNormals(); - - attributes.normal.needsUpdate = true; - - } - - }, - - merge: function ( geometry, offset ) { - - if ( ! ( geometry && geometry.isBufferGeometry ) ) { - - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); - return; - - } - - if ( offset === undefined ) offset = 0; - - var attributes = this.attributes; - - for ( var key in attributes ) { - - if ( geometry.attributes[ key ] === undefined ) continue; - - var attribute1 = attributes[ key ]; - var attributeArray1 = attribute1.array; - - var attribute2 = geometry.attributes[ key ]; - var attributeArray2 = attribute2.array; - - var attributeSize = attribute2.itemSize; - - for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { - - attributeArray1[ j ] = attributeArray2[ i ]; - - } - - } - - return this; - - }, - - normalizeNormals: function () { - - var normals = this.attributes.normal; - - var x, y, z, n; - - for ( var i = 0, il = normals.count; i < il; i ++ ) { - - x = normals.getX( i ); - y = normals.getY( i ); - z = normals.getZ( i ); - - n = 1.0 / Math.sqrt( x * x + y * y + z * z ); - - normals.setXYZ( i, x * n, y * n, z * n ); - - } - - }, - - toNonIndexed: function () { - - if ( this.index === null ) { - - console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); - return this; - - } - - var geometry2 = new BufferGeometry(); - - var indices = this.index.array; - var attributes = this.attributes; - - for ( var name in attributes ) { - - var attribute = attributes[ name ]; - - var array = attribute.array; - var itemSize = attribute.itemSize; - - var array2 = new array.constructor( indices.length * itemSize ); - - var index = 0, index2 = 0; - - for ( var i = 0, l = indices.length; i < l; i ++ ) { - - index = indices[ i ] * itemSize; - - for ( var j = 0; j < itemSize; j ++ ) { - - array2[ index2 ++ ] = array[ index ++ ]; - - } - - } - - geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); - - } - - return geometry2; - - }, - - toJSON: function () { - - var data = { - metadata: { - version: 4.5, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; - - // standard BufferGeometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - - if ( this.parameters !== undefined ) { - - var parameters = this.parameters; - - for ( var key in parameters ) { - - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - - } - - return data; - - } - - data.data = { attributes: {} }; - - var index = this.index; - - if ( index !== null ) { - - var array = Array.prototype.slice.call( index.array ); - - data.data.index = { - type: index.array.constructor.name, - array: array - }; - - } - - var attributes = this.attributes; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - - var array = Array.prototype.slice.call( attribute.array ); - - data.data.attributes[ key ] = { - itemSize: attribute.itemSize, - type: attribute.array.constructor.name, - array: array, - normalized: attribute.normalized - }; - - } - - var groups = this.groups; - - if ( groups.length > 0 ) { - - data.data.groups = JSON.parse( JSON.stringify( groups ) ); - - } - - var boundingSphere = this.boundingSphere; - - if ( boundingSphere !== null ) { - - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; - - } - - return data; - - }, - - clone: function () { - - /* - // Handle primitives - - var parameters = this.parameters; - - if ( parameters !== undefined ) { - - var values = []; - - for ( var key in parameters ) { - - values.push( parameters[ key ] ); - - } - - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; - - } - - return new this.constructor().copy( this ); - */ - - return new BufferGeometry().copy( this ); - - }, - - copy: function ( source ) { - - var name, i, l; - - // reset - - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; - - // name - - this.name = source.name; - - // index - - var index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone() ); - - } - - // attributes - - var attributes = source.attributes; - - for ( name in attributes ) { - - var attribute = attributes[ name ]; - this.addAttribute( name, attribute.clone() ); - - } - - // morph attributes - - var morphAttributes = source.morphAttributes; - - for ( name in morphAttributes ) { - - var array = []; - var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { - - array.push( morphAttribute[ i ].clone() ); - - } - - this.morphAttributes[ name ] = array; - - } - - // groups - - var groups = source.groups; - - for ( i = 0, l = groups.length; i < l; i ++ ) { - - var group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - // bounding box - - var boundingBox = source.boundingBox; - - if ( boundingBox !== null ) { - - this.boundingBox = boundingBox.clone(); - - } - - // bounding sphere - - var boundingSphere = source.boundingSphere; - - if ( boundingSphere !== null ) { - - this.boundingSphere = boundingSphere.clone(); - - } - - // draw range - - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; - - return this; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// BoxGeometry - -function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - Geometry.call( this ); - - this.type = 'BoxGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); - this.mergeVertices(); - -} - -BoxGeometry.prototype = Object.create( Geometry.prototype ); -BoxGeometry.prototype.constructor = BoxGeometry; - -// BoxBufferGeometry - -function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - BufferGeometry.call( this ); - - this.type = 'BoxBufferGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - var scope = this; - - // segments - - widthSegments = Math.floor( widthSegments ) || 1; - heightSegments = Math.floor( heightSegments ) || 1; - depthSegments = Math.floor( depthSegments ) || 1; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var numberOfVertices = 0; - var groupStart = 0; - - // build each side of the box geometry - - buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px - buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx - buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py - buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny - buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz - buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { - - var segmentWidth = width / gridX; - var segmentHeight = height / gridY; - - var widthHalf = width / 2; - var heightHalf = height / 2; - var depthHalf = depth / 2; - - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; - - var vertexCounter = 0; - var groupCount = 0; - - var ix, iy; - - var vector = new Vector3(); - - // generate vertices, normals and uvs - - for ( iy = 0; iy < gridY1; iy ++ ) { - - var y = iy * segmentHeight - heightHalf; - - for ( ix = 0; ix < gridX1; ix ++ ) { - - var x = ix * segmentWidth - widthHalf; - - // set values to correct vector component - - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; - - // now apply vector to vertex buffer - - vertices.push( vector.x, vector.y, vector.z ); - - // set values to correct vector component - - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; - - // now apply vector to normal buffer - - normals.push( vector.x, vector.y, vector.z ); - - // uvs - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - // counters - - vertexCounter += 1; - - } - - } - - // indices - - // 1. you need three indices to draw a single face - // 2. a single segment consists of two faces - // 3. so we need to generate six (2*3) indices per segment - - for ( iy = 0; iy < gridY; iy ++ ) { - - for ( ix = 0; ix < gridX; ix ++ ) { - - var a = numberOfVertices + ix + gridX1 * iy; - var b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // increase counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, materialIndex ); - - // calculate new start value for groups - - groupStart += groupCount; - - // update total number of vertices - - numberOfVertices += vertexCounter; - - } - -} - -BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// PlaneGeometry - -function PlaneGeometry( width, height, widthSegments, heightSegments ) { - - Geometry.call( this ); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - this.mergeVertices(); - -} - -PlaneGeometry.prototype = Object.create( Geometry.prototype ); -PlaneGeometry.prototype.constructor = PlaneGeometry; - -// PlaneBufferGeometry - -function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { - - BufferGeometry.call( this ); - - this.type = 'PlaneBufferGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - var width_half = width / 2; - var height_half = height / 2; - - var gridX = Math.floor( widthSegments ) || 1; - var gridY = Math.floor( heightSegments ) || 1; - - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; - - var segment_width = width / gridX; - var segment_height = height / gridY; - - var ix, iy; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // generate vertices, normals and uvs - - for ( iy = 0; iy < gridY1; iy ++ ) { - - var y = iy * segment_height - height_half; - - for ( ix = 0; ix < gridX1; ix ++ ) { - - var x = ix * segment_width - width_half; - - vertices.push( x, - y, 0 ); - - normals.push( 0, 0, 1 ); - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - } - - } - - // indices - - for ( iy = 0; iy < gridY; iy ++ ) { - - for ( ix = 0; ix < gridX; ix ++ ) { - - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: - * } - */ - -function MeshBasicMaterial( parameters ) { - - Material.call( this ); - - this.type = 'MeshBasicMaterial'; - - this.color = new Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.skinning = false; - this.morphTargets = false; - - this.lights = false; - - this.setValues( parameters ); - -} - -MeshBasicMaterial.prototype = Object.create( Material.prototype ); -MeshBasicMaterial.prototype.constructor = MeshBasicMaterial; - -MeshBasicMaterial.prototype.isMeshBasicMaterial = true; - -MeshBasicMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - - return this; - -}; - -/** - * @author bhouston / http://clara.io - */ - -function Ray( origin, direction ) { - - this.origin = ( origin !== undefined ) ? origin : new Vector3(); - this.direction = ( direction !== undefined ) ? direction : new Vector3(); - -} - -Object.assign( Ray.prototype, { - - set: function ( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - }, - - at: function ( t, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - - }, - - lookAt: function ( v ) { - - this.direction.copy( v ).sub( this.origin ).normalize(); - - return this; - - }, - - recast: function () { - - var v1 = new Vector3(); - - return function recast( t ) { - - this.origin.copy( this.at( t, v1 ) ); - - return this; - - }; - - }(), - - closestPointToPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - result.subVectors( point, this.origin ); - var directionDistance = result.dot( this.direction ); - - if ( directionDistance < 0 ) { - - return result.copy( this.origin ); - - } - - return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - }, - - distanceToPoint: function ( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - }, - - distanceSqToPoint: function () { - - var v1 = new Vector3(); - - return function distanceSqToPoint( point ) { - - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceToSquared( point ); - - } - - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - return v1.distanceToSquared( point ); - - }; - - }(), - - distanceSqToSegment: function () { - - var segCenter = new Vector3(); - var segDir = new Vector3(); - var diff = new Vector3(); - - return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment - - segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - segDir.copy( v1 ).sub( v0 ).normalize(); - diff.copy( this.origin ).sub( segCenter ); - - var segExtent = v0.distanceTo( v1 ) * 0.5; - var a01 = - this.direction.dot( segDir ); - var b0 = diff.dot( this.direction ); - var b1 = - diff.dot( segDir ); - var c = diff.lengthSq(); - var det = Math.abs( 1 - a01 * a01 ); - var s0, s1, sqrDist, extDet; - - if ( det > 0 ) { - - // The ray and segment are not parallel. - - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; - - if ( s0 >= 0 ) { - - if ( s1 >= - extDet ) { - - if ( s1 <= extDet ) { - - // region 0 - // Minimum at interior points of ray and segment. - - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - - } else { - - // region 1 - - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - // region 5 - - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - if ( s1 <= - extDet ) { - - // region 4 - - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } else if ( s1 <= extDet ) { - - // region 3 - - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; - - } else { - - // region 2 - - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } - - } else { - - // Ray and segment are parallel. - - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - if ( optionalPointOnRay ) { - - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - - } - - if ( optionalPointOnSegment ) { - - optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); - - } - - return sqrDist; - - }; - - }(), - - intersectSphere: function () { - - var v1 = new Vector3(); - - return function intersectSphere( sphere, optionalTarget ) { - - v1.subVectors( sphere.center, this.origin ); - var tca = v1.dot( this.direction ); - var d2 = v1.dot( v1 ) - tca * tca; - var radius2 = sphere.radius * sphere.radius; - - if ( d2 > radius2 ) return null; - - var thc = Math.sqrt( radius2 - d2 ); - - // t0 = first intersect point - entrance on front of sphere - var t0 = tca - thc; - - // t1 = second intersect point - exit point on back of sphere - var t1 = tca + thc; - - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; - - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, optionalTarget ); - - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, optionalTarget ); - - }; - - }(), - - intersectsSphere: function ( sphere ) { - - return this.distanceToPoint( sphere.center ) <= sphere.radius; - - }, - - distanceToPlane: function ( plane ) { - - var denominator = plane.normal.dot( this.direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { - - return 0; - - } - - // Null is preferable to undefined since undefined means.... it is undefined - - return null; - - } - - var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane - - return t >= 0 ? t : null; - - }, - - intersectPlane: function ( plane, optionalTarget ) { - - var t = this.distanceToPlane( plane ); - - if ( t === null ) { - - return null; - - } - - return this.at( t, optionalTarget ); - - }, - - intersectsPlane: function ( plane ) { - - // check if the ray lies on the plane first - - var distToPoint = plane.distanceToPoint( this.origin ); - - if ( distToPoint === 0 ) { - - return true; - - } - - var denominator = plane.normal.dot( this.direction ); - - if ( denominator * distToPoint < 0 ) { - - return true; - - } - - // ray origin is behind the plane (and is pointing behind it) - - return false; - - }, - - intersectBox: function ( box, optionalTarget ) { - - var tmin, tmax, tymin, tymax, tzmin, tzmax; - - var invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; - - var origin = this.origin; - - if ( invdirx >= 0 ) { - - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; - - } else { - - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; - - } - - if ( invdiry >= 0 ) { - - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; - - } else { - - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; - - } - - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN - - if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - - if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - - if ( invdirz >= 0 ) { - - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; - - } else { - - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; - - } - - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - - //return point closest to the ray (positive side) - - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); - - }, - - intersectsBox: ( function () { - - var v = new Vector3(); - - return function intersectsBox( box ) { - - return this.intersectBox( box, v ) !== null; - - }; - - } )(), - - intersectTriangle: function () { - - // Compute the offset origin, edges, and normal. - var diff = new Vector3(); - var edge1 = new Vector3(); - var edge2 = new Vector3(); - var normal = new Vector3(); - - return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) { - - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - - edge1.subVectors( b, a ); - edge2.subVectors( c, a ); - normal.crossVectors( edge1, edge2 ); - - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - var DdN = this.direction.dot( normal ); - var sign; - - if ( DdN > 0 ) { - - if ( backfaceCulling ) return null; - sign = 1; - - } else if ( DdN < 0 ) { - - sign = - 1; - DdN = - DdN; - - } else { - - return null; - - } - - diff.subVectors( this.origin, a ); - var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); - - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { - - return null; - - } - - var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); - - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; - - } - - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { - - return null; - - } - - // Line intersects triangle, check if ray does. - var QdN = - sign * diff.dot( normal ); - - // t < 0, no intersection - if ( QdN < 0 ) { - - return null; - - } - - // Ray intersects triangle. - return this.at( QdN / DdN, optionalTarget ); - - }; - - }(), - - applyMatrix4: function ( matrix4 ) { - - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); - - return this; - - }, - - equals: function ( ray ) { - - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - - } - -} ); - -/** - * @author bhouston / http://clara.io - */ - -function Line3( start, end ) { - - this.start = ( start !== undefined ) ? start : new Vector3(); - this.end = ( end !== undefined ) ? end : new Vector3(); - -} - -Object.assign( Line3.prototype, { - - set: function ( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - }, - - getCenter: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - }, - - delta: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return result.subVectors( this.end, this.start ); - - }, - - distanceSq: function () { - - return this.start.distanceToSquared( this.end ); - - }, - - distance: function () { - - return this.start.distanceTo( this.end ); - - }, - - at: function ( t, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - return this.delta( result ).multiplyScalar( t ).add( this.start ); - - }, - - closestPointToPointParameter: function () { - - var startP = new Vector3(); - var startEnd = new Vector3(); - - return function closestPointToPointParameter( point, clampToLine ) { - - startP.subVectors( point, this.start ); - startEnd.subVectors( this.end, this.start ); - - var startEnd2 = startEnd.dot( startEnd ); - var startEnd_startP = startEnd.dot( startP ); - - var t = startEnd_startP / startEnd2; - - if ( clampToLine ) { - - t = _Math.clamp( t, 0, 1 ); - - } - - return t; - - }; - - }(), - - closestPointToPoint: function ( point, clampToLine, optionalTarget ) { - - var t = this.closestPointToPointParameter( point, clampToLine ); - - var result = optionalTarget || new Vector3(); - - return this.delta( result ).multiplyScalar( t ).add( this.start ); - - }, - - applyMatrix4: function ( matrix ) { - - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - }, - - equals: function ( line ) { - - return line.start.equals( this.start ) && line.end.equals( this.end ); - - } - -} ); - -/** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ - -function Triangle( a, b, c ) { - - this.a = ( a !== undefined ) ? a : new Vector3(); - this.b = ( b !== undefined ) ? b : new Vector3(); - this.c = ( c !== undefined ) ? c : new Vector3(); - -} - -Object.assign( Triangle, { - - normal: function () { - - var v0 = new Vector3(); - - return function normal( a, b, c, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - - result.subVectors( c, b ); - v0.subVectors( a, b ); - result.cross( v0 ); - - var resultLengthSq = result.lengthSq(); - if ( resultLengthSq > 0 ) { - - return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); - - } - - return result.set( 0, 0, 0 ); - - }; - - }(), - - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - barycoordFromPoint: function () { - - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); - - return function barycoordFromPoint( point, a, b, c, optionalTarget ) { - - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); - - var dot00 = v0.dot( v0 ); - var dot01 = v0.dot( v1 ); - var dot02 = v0.dot( v2 ); - var dot11 = v1.dot( v1 ); - var dot12 = v1.dot( v2 ); - - var denom = ( dot00 * dot11 - dot01 * dot01 ); - - var result = optionalTarget || new Vector3(); - - // collinear or singular triangle - if ( denom === 0 ) { - - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return result.set( - 2, - 1, - 1 ); - - } - - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - - // barycentric coordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); - - }; - - }(), - - containsPoint: function () { - - var v1 = new Vector3(); - - return function containsPoint( point, a, b, c ) { - - var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); - - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - - }; - - }() - -} ); - -Object.assign( Triangle.prototype, { - - set: function ( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); - - return this; - - }, - - setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); - - return this; - - }, - - area: function () { - - var v0 = new Vector3(); - var v1 = new Vector3(); - - return function area() { - - v0.subVectors( this.c, this.b ); - v1.subVectors( this.a, this.b ); - - return v0.cross( v1 ).length() * 0.5; - - }; - - }(), - - midpoint: function ( optionalTarget ) { - - var result = optionalTarget || new Vector3(); - return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - }, - - normal: function ( optionalTarget ) { - - return Triangle.normal( this.a, this.b, this.c, optionalTarget ); - - }, - - plane: function ( optionalTarget ) { - - var result = optionalTarget || new Plane(); - - return result.setFromCoplanarPoints( this.a, this.b, this.c ); - - }, - - barycoordFromPoint: function ( point, optionalTarget ) { - - return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); - - }, - - containsPoint: function ( point ) { - - return Triangle.containsPoint( point, this.a, this.b, this.c ); - - }, - - closestPointToPoint: function () { - - var plane = new Plane(); - var edgeList = [ new Line3(), new Line3(), new Line3() ]; - var projectedPoint = new Vector3(); - var closestPoint = new Vector3(); - - return function closestPointToPoint( point, optionalTarget ) { - - var result = optionalTarget || new Vector3(); - var minDistance = Infinity; - - // project the point onto the plane of the triangle - - plane.setFromCoplanarPoints( this.a, this.b, this.c ); - plane.projectPoint( point, projectedPoint ); - - // check if the projection lies within the triangle - - if( this.containsPoint( projectedPoint ) === true ) { - - // if so, this is the closest point - - result.copy( projectedPoint ); - - } else { - - // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices - - edgeList[ 0 ].set( this.a, this.b ); - edgeList[ 1 ].set( this.b, this.c ); - edgeList[ 2 ].set( this.c, this.a ); - - for( var i = 0; i < edgeList.length; i ++ ) { - - edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint ); - - var distance = projectedPoint.distanceToSquared( closestPoint ); - - if( distance < minDistance ) { - - minDistance = distance; - - result.copy( closestPoint ); - - } - - } - - } - - return result; - - }; - - }(), - - equals: function ( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ - -function Mesh( geometry, material ) { - - Object3D.call( this ); - - this.type = 'Mesh'; - - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.drawMode = TrianglesDrawMode; - - this.updateMorphTargets(); - -} - -Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Mesh, - - isMesh: true, - - setDrawMode: function ( value ) { - - this.drawMode = value; - - }, - - copy: function ( source ) { - - Object3D.prototype.copy.call( this, source ); - - this.drawMode = source.drawMode; - - return this; - - }, - - updateMorphTargets: function () { - - var geometry = this.geometry; - var m, ml, name; - - if ( geometry.isBufferGeometry ) { - - var morphAttributes = geometry.morphAttributes; - var keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - var morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } else { - - var morphTargets = geometry.morphTargets; - - if ( morphTargets !== undefined && morphTargets.length > 0 ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) { - - name = morphTargets[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - }, - - raycast: ( function () { - - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); - - var vA = new Vector3(); - var vB = new Vector3(); - var vC = new Vector3(); - - var tempA = new Vector3(); - var tempB = new Vector3(); - var tempC = new Vector3(); - - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); - - var barycoord = new Vector3(); - - var intersectionPoint = new Vector3(); - var intersectionPointWorld = new Vector3(); - - function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { - - Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); - - uv1.multiplyScalar( barycoord.x ); - uv2.multiplyScalar( barycoord.y ); - uv3.multiplyScalar( barycoord.z ); - - uv1.add( uv2 ).add( uv3 ); - - return uv1.clone(); - - } - - function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) { - - var intersect; - var material = object.material; - - if ( material.side === BackSide ) { - - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - - } else { - - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); - - } - - if ( intersect === null ) return null; - - intersectionPointWorld.copy( point ); - intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: intersectionPointWorld.clone(), - object: object - }; - - } - - function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) { - - vA.fromBufferAttribute( position, a ); - vB.fromBufferAttribute( position, b ); - vC.fromBufferAttribute( position, c ); - - var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint ); - - if ( intersection ) { - - if ( uv ) { - - uvA.fromBufferAttribute( uv, a ); - uvB.fromBufferAttribute( uv, b ); - uvC.fromBufferAttribute( uv, c ); - - intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); - - } - - intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) ); - intersection.faceIndex = a; - - } - - return intersection; - - } - - return function raycast( raycaster, intersects ) { - - var geometry = this.geometry; - var material = this.material; - var matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; - - // - - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - // Check boundingBox before continuing - - if ( geometry.boundingBox !== null ) { - - if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; - - } - - var intersection; - - if ( geometry.isBufferGeometry ) { - - var a, b, c; - var index = geometry.index; - var position = geometry.attributes.position; - var uv = geometry.attributes.uv; - var i, l; - - if ( index !== null ) { - - // indexed buffer geometry - - for ( i = 0, l = index.count; i < l; i += 3 ) { - - a = index.getX( i ); - b = index.getX( i + 1 ); - c = index.getX( i + 2 ); - - intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics - intersects.push( intersection ); - - } - - } - - } else { - - // non-indexed buffer geometry - - for ( i = 0, l = position.count; i < l; i += 3 ) { - - a = i; - b = i + 1; - c = i + 2; - - intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); - - if ( intersection ) { - - intersection.index = a; // triangle number in positions buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } else if ( geometry.isGeometry ) { - - var fvA, fvB, fvC; - var isMultiMaterial = Array.isArray( material ); - - var vertices = geometry.vertices; - var faces = geometry.faces; - var uvs; - - var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; - if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; - - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { - - var face = faces[ f ]; - var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; - - if ( faceMaterial === undefined ) continue; - - fvA = vertices[ face.a ]; - fvB = vertices[ face.b ]; - fvC = vertices[ face.c ]; - - if ( faceMaterial.morphTargets === true ) { - - var morphTargets = geometry.morphTargets; - var morphInfluences = this.morphTargetInfluences; - - vA.set( 0, 0, 0 ); - vB.set( 0, 0, 0 ); - vC.set( 0, 0, 0 ); - - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - - var influence = morphInfluences[ t ]; - - if ( influence === 0 ) continue; - - var targets = morphTargets[ t ].vertices; - - vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); - vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); - vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); - - } - - vA.add( fvA ); - vB.add( fvB ); - vC.add( fvC ); - - fvA = vA; - fvB = vB; - fvC = vC; - - } - - intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); - - if ( intersection ) { - - if ( uvs && uvs[ f ] ) { - - var uvs_f = uvs[ f ]; - uvA.copy( uvs_f[ 0 ] ); - uvB.copy( uvs_f[ 1 ] ); - uvC.copy( uvs_f[ 2 ] ); - - intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC ); - - } - - intersection.face = face; - intersection.faceIndex = f; - intersects.push( intersection ); - - } - - } - - } - - }; - - }() ), - - clone: function () { - - return new this.constructor( this.geometry, this.material ).copy( this ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { - - var clearColor = new Color( 0x000000 ); - var clearAlpha = 0; - - var planeCamera, planeMesh; - var boxCamera, boxMesh; - - function render( scene, camera, forceClear ) { - - var background = scene.background; - - if ( background === null ) { - - setClear( clearColor, clearAlpha ); - - } else if ( background && background.isColor ) { - - setClear( background, 1 ); - forceClear = true; - - } - - if ( renderer.autoClear || forceClear ) { - - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - - } - - if ( background && background.isCubeTexture ) { - - if ( boxCamera === undefined ) { - - boxCamera = new PerspectiveCamera(); - - boxMesh = new Mesh( - new BoxBufferGeometry( 5, 5, 5 ), - new ShaderMaterial( { - uniforms: ShaderLib.cube.uniforms, - vertexShader: ShaderLib.cube.vertexShader, - fragmentShader: ShaderLib.cube.fragmentShader, - side: BackSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - } - - boxCamera.projectionMatrix.copy( camera.projectionMatrix ); - - boxCamera.matrixWorld.extractRotation( camera.matrixWorld ); - boxCamera.matrixWorldInverse.getInverse( boxCamera.matrixWorld ); - - boxMesh.material.uniforms[ "tCube" ].value = background; - boxMesh.modelViewMatrix.multiplyMatrices( boxCamera.matrixWorldInverse, boxMesh.matrixWorld ); - - objects.update( boxMesh ); - - renderer.renderBufferDirect( boxCamera, null, boxMesh.geometry, boxMesh.material, boxMesh, null ); - - } else if ( background && background.isTexture ) { - - if ( planeCamera === undefined ) { - - planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); - - planeMesh = new Mesh( - new PlaneBufferGeometry( 2, 2 ), - new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } ) - ); - - } - - planeMesh.material.map = background; - - objects.update( planeMesh ); - - renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null ); - - } - - } - - function setClear( color, alpha ) { - - state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); - - } - - return { - - getClearColor: function () { - - return clearColor; - - }, - setClearColor: function ( color, alpha ) { - - clearColor.set( color ); - clearAlpha = alpha !== undefined ? alpha : 1; - setClear( clearColor, clearAlpha ); - - }, - getClearAlpha: function () { - - return clearAlpha; - - }, - setClearAlpha: function ( alpha ) { - - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - render: render - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function painterSortStable( a, b ) { - - if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.program && b.program && a.program !== b.program ) { - - return a.program.id - b.program.id; - - } else if ( a.material.id !== b.material.id ) { - - return a.material.id - b.material.id; - - } else if ( a.z !== b.z ) { - - return a.z - b.z; - - } else { - - return a.id - b.id; - - } - -} - -function reversePainterSortStable( a, b ) { - - if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - -} - -function WebGLRenderList() { - - var opaque = []; - var opaqueLastIndex = - 1; - - var transparent = []; - var transparentLastIndex = - 1; - - function init() { - - opaqueLastIndex = - 1; - transparentLastIndex = - 1; - - } - - function push( object, geometry, material, z, group ) { - - var array, index; - - // allocate the next position in the appropriate array - - if ( material.transparent ) { - - array = transparent; - index = ++ transparentLastIndex; - - } else { - - array = opaque; - index = ++ opaqueLastIndex; - - } - - // recycle existing render item or grow the array - - var renderItem = array[ index ]; - - if ( renderItem ) { - - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.program = material.program; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; - - } else { - - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - program: material.program, - renderOrder: object.renderOrder, - z: z, - group: group - }; - - // assert( index === array.length ); - array.push( renderItem ); - - } - - } - - function finish() { - - opaque.length = opaqueLastIndex + 1; - transparent.length = transparentLastIndex + 1; - - } - - function sort() { - - opaque.sort( painterSortStable ); - transparent.sort( reversePainterSortStable ); - - } - - return { - opaque: opaque, - transparent: transparent, - - init: init, - push: push, - finish: finish, - - sort: sort - }; - -} - -function WebGLRenderLists() { - - var lists = {}; - - function get( scene, camera ) { - - var hash = scene.id + ',' + camera.id; - var list = lists[ hash ]; - - if ( list === undefined ) { - - // console.log( 'THREE.WebGLRenderLists:', hash ); - - list = new WebGLRenderList(); - lists[ hash ] = list; - - } - - return list; - - } - - function dispose() { - - lists = {}; - - } - - return { - get: get, - dispose: dispose - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) { - - var mode; - - function setMode( value ) { - - mode = value; - - } - - var type, bytesPerElement; - - function setIndex( value ) { - - type = value.type; - bytesPerElement = value.bytesPerElement; - - } - - function render( start, count ) { - - gl.drawElements( mode, count, type, start * bytesPerElement ); - - infoRender.calls ++; - infoRender.vertices += count; - - if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; - - } - - function renderInstances( geometry, start, count ) { - - var extension = extensions.get( 'ANGLE_instanced_arrays' ); - - if ( extension === null ) { - - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount ); - - infoRender.calls ++; - infoRender.vertices += count * geometry.maxInstancedCount; - - if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; - - } - - // - - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLBufferRenderer( gl, extensions, infoRender ) { - - var mode; - - function setMode( value ) { - - mode = value; - - } - - function render( start, count ) { - - gl.drawArrays( mode, start, count ); - - infoRender.calls ++; - infoRender.vertices += count; - - if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; - - } - - function renderInstances( geometry, start, count ) { - - var extension = extensions.get( 'ANGLE_instanced_arrays' ); - - if ( extension === null ) { - - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - var position = geometry.attributes.position; - - if ( position.isInterleavedBufferAttribute ) { - - count = position.data.count; - - extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); - - } else { - - extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount ); - - } - - infoRender.calls ++; - infoRender.vertices += count * geometry.maxInstancedCount; - - if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; - - } - - // - - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLGeometries( gl, attributes, infoMemory ) { - - var geometries = {}; - var wireframeAttributes = {}; - - function onGeometryDispose( event ) { - - var geometry = event.target; - var buffergeometry = geometries[ geometry.id ]; - - if ( buffergeometry.index !== null ) { - - attributes.remove( buffergeometry.index ); - - } - - for ( var name in buffergeometry.attributes ) { - - attributes.remove( buffergeometry.attributes[ name ] ); - - } - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - delete geometries[ geometry.id ]; - - // TODO Remove duplicate code - - var attribute = wireframeAttributes[ geometry.id ]; - - if ( attribute ) { - - attributes.remove( attribute ); - delete wireframeAttributes[ geometry.id ]; - - } - - attribute = wireframeAttributes[ buffergeometry.id ]; - - if ( attribute ) { - - attributes.remove( attribute ); - delete wireframeAttributes[ buffergeometry.id ]; - - } - - // - - infoMemory.geometries --; - - } - - function get( object, geometry ) { - - var buffergeometry = geometries[ geometry.id ]; - - if ( buffergeometry ) return buffergeometry; - - geometry.addEventListener( 'dispose', onGeometryDispose ); - - if ( geometry.isBufferGeometry ) { - - buffergeometry = geometry; - - } else if ( geometry.isGeometry ) { - - if ( geometry._bufferGeometry === undefined ) { - - geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); - - } - - buffergeometry = geometry._bufferGeometry; - - } - - geometries[ geometry.id ] = buffergeometry; - - infoMemory.geometries ++; - - return buffergeometry; - - } - - function update( geometry ) { - - var index = geometry.index; - var geometryAttributes = geometry.attributes; - - if ( index !== null ) { - - attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); - - } - - for ( var name in geometryAttributes ) { - - attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); - - } - - // morph targets - - var morphAttributes = geometry.morphAttributes; - - for ( var name in morphAttributes ) { - - var array = morphAttributes[ name ]; - - for ( var i = 0, l = array.length; i < l; i ++ ) { - - attributes.update( array[ i ], gl.ARRAY_BUFFER ); - - } - - } - - } - - function getWireframeAttribute( geometry ) { - - var attribute = wireframeAttributes[ geometry.id ]; - - if ( attribute ) return attribute; - - var indices = []; - - var geometryIndex = geometry.index; - var geometryAttributes = geometry.attributes; - - // console.time( 'wireframe' ); - - if ( geometryIndex !== null ) { - - var array = geometryIndex.array; - - for ( var i = 0, l = array.length; i < l; i += 3 ) { - - var a = array[ i + 0 ]; - var b = array[ i + 1 ]; - var c = array[ i + 2 ]; - - indices.push( a, b, b, c, c, a ); - - } - - } else { - - var array = geometryAttributes.position.array; - - for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - - var a = i + 0; - var b = i + 1; - var c = i + 2; - - indices.push( a, b, b, c, c, a ); - - } - - } - - // console.timeEnd( 'wireframe' ); - - attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - - attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER ); - - wireframeAttributes[ geometry.id ] = attribute; - - return attribute; - - } - - return { - - get: get, - update: update, - - getWireframeAttribute: getWireframeAttribute - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLLights() { - - var lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - var uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color(), - - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0, - - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0, - - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'HemisphereLight': - uniforms = { - direction: new Vector3(), - skyColor: new Color(), - groundColor: new Color() - }; - break; - - case 'RectAreaLight': - uniforms = { - color: new Color(), - position: new Vector3(), - halfWidth: new Vector3(), - halfHeight: new Vector3() - // TODO (abelnation): set RectAreaLight shadow uniforms - }; - break; - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLObjects( gl, geometries, infoRender ) { - - var updateList = {}; - - function update( object ) { - - var frame = infoRender.frame; - - var geometry = object.geometry; - var buffergeometry = geometries.get( object, geometry ); - - // Update once per frame - - if ( updateList[ buffergeometry.id ] !== frame ) { - - if ( geometry.isGeometry ) { - - buffergeometry.updateFromObject( object ); - - } - - geometries.update( buffergeometry ); - - updateList[ buffergeometry.id ] = frame; - - } - - return buffergeometry; - - } - - function clear() { - - updateList = {}; - - } - - return { - - update: update, - clear: clear - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function addLineNumbers( string ) { - - var lines = string.split( '\n' ); - - for ( var i = 0; i < lines.length; i ++ ) { - - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - - } - - return lines.join( '\n' ); - -} - -function WebGLShader( gl, type, string ) { - - var shader = gl.createShader( type ); - - gl.shaderSource( shader, string ); - gl.compileShader( shader ); - - if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); - - } - - if ( gl.getShaderInfoLog( shader ) !== '' ) { - - console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); - - } - - // --enable-privileged-webgl-extension - // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - - return shader; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -var programIdCount = 0; - -function getEncodingComponents( encoding ) { - - switch ( encoding ) { - - case LinearEncoding: - return [ 'Linear','( value )' ]; - case sRGBEncoding: - return [ 'sRGB','( value )' ]; - case RGBEEncoding: - return [ 'RGBE','( value )' ]; - case RGBM7Encoding: - return [ 'RGBM','( value, 7.0 )' ]; - case RGBM16Encoding: - return [ 'RGBM','( value, 16.0 )' ]; - case RGBDEncoding: - return [ 'RGBD','( value, 256.0 )' ]; - case GammaEncoding: - return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ]; - default: - throw new Error( 'unsupported encoding: ' + encoding ); - - } - -} - -function getTexelDecodingFunction( functionName, encoding ) { - - var components = getEncodingComponents( encoding ); - return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }"; - -} - -function getTexelEncodingFunction( functionName, encoding ) { - - var components = getEncodingComponents( encoding ); - return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }"; - -} - -function getToneMappingFunction( functionName, toneMapping ) { - - var toneMappingName; - - switch ( toneMapping ) { - - case LinearToneMapping: - toneMappingName = "Linear"; - break; - - case ReinhardToneMapping: - toneMappingName = "Reinhard"; - break; - - case Uncharted2ToneMapping: - toneMappingName = "Uncharted2"; - break; - - case CineonToneMapping: - toneMappingName = "OptimizedCineon"; - break; - - default: - throw new Error( 'unsupported toneMapping: ' + toneMapping ); - - } - - return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }"; - -} - -function generateExtensions( extensions, parameters, rendererExtensions ) { - - extensions = extensions || {}; - - var chunks = [ - ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', - ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - -} - -function generateDefines( defines ) { - - var chunks = []; - - for ( var name in defines ) { - - var value = defines[ name ]; - - if ( value === false ) continue; - - chunks.push( '#define ' + name + ' ' + value ); - - } - - return chunks.join( '\n' ); - -} - -function fetchAttributeLocations( gl, program, identifiers ) { - - var attributes = {}; - - var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); - - for ( var i = 0; i < n; i ++ ) { - - var info = gl.getActiveAttrib( program, i ); - var name = info.name; - - // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i ); - - attributes[ name ] = gl.getAttribLocation( program, name ); - - } - - return attributes; - -} - -function filterEmptyLine( string ) { - - return string !== ''; - -} - -function replaceLightNums( string, parameters ) { - - return string - .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) - .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) - .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) - .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) - .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ); - -} - -function parseIncludes( string ) { - - var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm; - - function replace( match, include ) { - - var replace = ShaderChunk[ include ]; - - if ( replace === undefined ) { - - throw new Error( 'Can not resolve #include <' + include + '>' ); - - } - - return parseIncludes( replace ); - - } - - return string.replace( pattern, replace ); - -} - -function unrollLoops( string ) { - - var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; - - function replace( match, start, end, snippet ) { - - var unroll = ''; - - for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { - - unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' ); - - } - - return unroll; - - } - - return string.replace( pattern, replace ); - -} - -function WebGLProgram( renderer, code, material, shader, parameters ) { - - var gl = renderer.context; - - var extensions = material.extensions; - var defines = material.defines; - - var vertexShader = shader.vertexShader; - var fragmentShader = shader.fragmentShader; - - var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - - if ( parameters.shadowMapType === PCFShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - - } - - var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - - if ( parameters.envMap ) { - - switch ( material.envMap.mapping ) { - - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; - - case CubeUVReflectionMapping: - case CubeUVRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; - - case EquirectangularReflectionMapping: - case EquirectangularRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; - break; - - case SphericalReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; - break; - - } - - switch ( material.envMap.mapping ) { - - case CubeRefractionMapping: - case EquirectangularRefractionMapping: - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; - - } - - switch ( material.combine ) { - - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; - - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; - - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; - - } - - } - - var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - - // console.log( 'building new program ' ); - - // - - var customExtensions = generateExtensions( extensions, parameters, renderer.extensions ); - - var customDefines = generateDefines( defines ); - - // - - var program = gl.createProgram(); - - var prefixVertex, prefixFragment; - - if ( material.isRawShaderMaterial ) { - - prefixVertex = [ - - customDefines, - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - prefixFragment = [ - - customExtensions, - customDefines, - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - } else { - - prefixVertex = [ - - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', - - '#define SHADER_NAME ' + shader.name, - - customDefines, - - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - '#define GAMMA_FACTOR ' + gammaFactorDefine, - - '#define MAX_BONES ' + parameters.maxBones, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.skinning ? '#define USE_SKINNING' : '', - parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', - - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', - - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', - - '#ifdef USE_COLOR', - - ' attribute vec3 color;', - - '#endif', - - '#ifdef USE_MORPHTARGETS', - - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', - - ' #ifdef USE_MORPHNORMALS', - - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', - - ' #else', - - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', - - ' #endif', - - '#endif', - - '#ifdef USE_SKINNING', - - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', - - '#endif', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - prefixFragment = [ - - customExtensions, - - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', - - '#define SHADER_NAME ' + shader.name, - - customDefines, - - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', - - '#define GAMMA_FACTOR ' + gammaFactorDefine, - - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapTypeDefine : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.envMap ? '#define ' + envMapBlendingDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, - '#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection), - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '', - - parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - parameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '', - - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - - ( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '', - ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below - ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '', - - parameters.dithering ? '#define DITHERING' : '', - - ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below - parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', - parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', - parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', - parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '', - - parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - } - - vertexShader = parseIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - - fragmentShader = parseIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - - if ( ! material.isShaderMaterial ) { - - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); - - } - - var vertexGlsl = prefixVertex + vertexShader; - var fragmentGlsl = prefixFragment + fragmentShader; - - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); - - var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); - var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); - - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); - - // Force a particular attribute to index 0. - - if ( material.index0AttributeName !== undefined ) { - - gl.bindAttribLocation( program, 0, material.index0AttributeName ); - - } else if ( parameters.morphTargets === true ) { - - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); - - } - - gl.linkProgram( program ); - - var programLog = gl.getProgramInfoLog( program ); - var vertexLog = gl.getShaderInfoLog( glVertexShader ); - var fragmentLog = gl.getShaderInfoLog( glFragmentShader ); - - var runnable = true; - var haveDiagnostics = true; - - // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); - // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); - - if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - - runnable = false; - - console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); - - } else if ( programLog !== '' ) { - - console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); - - } else if ( vertexLog === '' || fragmentLog === '' ) { - - haveDiagnostics = false; - - } - - if ( haveDiagnostics ) { - - this.diagnostics = { - - runnable: runnable, - material: material, - - programLog: programLog, - - vertexShader: { - - log: vertexLog, - prefix: prefixVertex - - }, - - fragmentShader: { - - log: fragmentLog, - prefix: prefixFragment - - } - - }; - - } - - // clean up - - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); - - // set up caching for uniform locations - - var cachedUniforms; - - this.getUniforms = function() { - - if ( cachedUniforms === undefined ) { - - cachedUniforms = - new WebGLUniforms( gl, program, renderer ); - - } - - return cachedUniforms; - - }; - - // set up caching for attribute locations - - var cachedAttributes; - - this.getAttributes = function() { - - if ( cachedAttributes === undefined ) { - - cachedAttributes = fetchAttributeLocations( gl, program ); - - } - - return cachedAttributes; - - }; - - // free resource - - this.destroy = function() { - - gl.deleteProgram( program ); - this.program = undefined; - - }; - - // DEPRECATED - - Object.defineProperties( this, { - - uniforms: { - get: function() { - - console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); - return this.getUniforms(); - - } - }, - - attributes: { - get: function() { - - console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); - return this.getAttributes(); - - } - } - - } ); - - - // - - this.id = programIdCount ++; - this.code = code; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; - - return this; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLPrograms( renderer, capabilities ) { - - var programs = []; - - var shaderIDs = { - MeshDepthMaterial: 'depth', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'phong', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points' - }; - - var parameterNames = [ - "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding", - "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap", - "roughnessMap", "metalnessMap", "gradientMap", - "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", - "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", - "maxBones", "useVertexTexture", "morphTargets", "morphNormals", - "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", - "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", - "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', - "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering" - ]; - - - function allocateBones( object ) { - - var skeleton = object.skeleton; - var bones = skeleton.bones; - - if ( capabilities.floatVertexTextures ) { - - return 1024; - - } else { - - // default for when object is not specified - // ( for example when prebuilding shader to be used with multiple objects ) - // - // - leave some extra space for other uniforms - // - limit here is ANGLE's 254 max uniform vectors - // (up to 54 should be safe) - - var nVertexUniforms = capabilities.maxVertexUniforms; - var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - - var maxBones = Math.min( nVertexMatrices, bones.length ); - - if ( maxBones < bones.length ) { - - console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); - return 0; - - } - - return maxBones; - - } - - } - - function getTextureEncodingFromMap( map, gammaOverrideLinear ) { - - var encoding; - - if ( ! map ) { - - encoding = LinearEncoding; - - } else if ( map.isTexture ) { - - encoding = map.encoding; - - } else if ( map.isWebGLRenderTarget ) { - - console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); - encoding = map.texture.encoding; - - } - - // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point. - if ( encoding === LinearEncoding && gammaOverrideLinear ) { - - encoding = GammaEncoding; - - } - - return encoding; - - } - - this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) { - - var shaderID = shaderIDs[ material.type ]; - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0; - var precision = renderer.getPrecision(); - - if ( material.precision !== null ) { - - precision = capabilities.getMaxPrecision( material.precision ); - - if ( precision !== material.precision ) { - - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - - } - - } - - var currentRenderTarget = renderer.getRenderTarget(); - - var parameters = { - - shaderID: shaderID, - - precision: precision, - supportsVertexTextures: capabilities.vertexTextures, - outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ), - map: !! material.map, - mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ), - envMap: !! material.envMap, - envMapMode: material.envMap && material.envMap.mapping, - envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ), - envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ), - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - alphaMap: !! material.alphaMap, - - gradientMap: !! material.gradientMap, - - combine: material.combine, - - vertexColors: material.vertexColors, - - fog: !! fog, - useFog: material.fog, - fogExp: ( fog && fog.isFogExp2 ), - - flatShading: material.shading === FlatShading, - - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, - - skinning: material.skinning && maxBones > 0, - maxBones: maxBones, - useVertexTexture: capabilities.floatVertexTextures, - - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: renderer.maxMorphTargets, - maxMorphNormals: renderer.maxMorphNormals, - - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, - - numClippingPlanes: nClipPlanes, - numClipIntersection: nClipIntersection, - - dithering: material.dithering, - - shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0, - shadowMapType: renderer.shadowMap.type, - - toneMapping: renderer.toneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, - - premultipliedAlpha: material.premultipliedAlpha, - - alphaTest: material.alphaTest, - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, - - depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false - - }; - - return parameters; - - }; - - this.getProgramCode = function ( material, parameters ) { - - var array = []; - - if ( parameters.shaderID ) { - - array.push( parameters.shaderID ); - - } else { - - array.push( material.fragmentShader ); - array.push( material.vertexShader ); - - } - - if ( material.defines !== undefined ) { - - for ( var name in material.defines ) { - - array.push( name ); - array.push( material.defines[ name ] ); - - } - - } - - for ( var i = 0; i < parameterNames.length; i ++ ) { - - array.push( parameters[ parameterNames[ i ] ] ); - - } - - array.push( material.onBeforeCompile.toString() ); - - array.push( renderer.gammaOutput ); - - return array.join(); - - }; - - this.acquireProgram = function ( material, shader, parameters, code ) { - - var program; - - // Check if code has been already compiled - for ( var p = 0, pl = programs.length; p < pl; p ++ ) { - - var programInfo = programs[ p ]; - - if ( programInfo.code === code ) { - - program = programInfo; - ++ program.usedTimes; - - break; - - } - - } - - if ( program === undefined ) { - - program = new WebGLProgram( renderer, code, material, shader, parameters ); - programs.push( program ); - - } - - return program; - - }; - - this.releaseProgram = function ( program ) { - - if ( -- program.usedTimes === 0 ) { - - // Remove from unordered set - var i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); - - // Free WebGL resources - program.destroy(); - - } - - }; - - // Exposed for resource monitoring & error feedback via renderer.info: - this.programs = programs; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, infoMemory ) { - - var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); - - // - - function clampToMaxSize( image, maxSize ) { - - if ( image.width > maxSize || image.height > maxSize ) { - - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. - - var scale = maxSize / Math.max( image.width, image.height ); - - var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = Math.floor( image.width * scale ); - canvas.height = Math.floor( image.height * scale ); - - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - - console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); - - return canvas; - - } - - return image; - - } - - function isPowerOfTwo( image ) { - - return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); - - } - - function makePowerOfTwo( image ) { - - if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) { - - var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = _Math.nearestPowerOfTwo( image.width ); - canvas.height = _Math.nearestPowerOfTwo( image.height ); - - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, canvas.width, canvas.height ); - - console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); - - return canvas; - - } - - return image; - - } - - function textureNeedsPowerOfTwo( texture ) { - - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - - } - - function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) { - - return texture.generateMipmaps && isPowerOfTwo && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - - } - - // Fallback filters for non-power-of-2 textures - - function filterFallback( f ) { - - if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { - - return _gl.NEAREST; - - } - - return _gl.LINEAR; - - } - - // - - function onTextureDispose( event ) { - - var texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - infoMemory.textures --; - - - } - - function onRenderTargetDispose( event ) { - - var renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - infoMemory.textures --; - - } - - // - - function deallocateTexture( texture ) { - - var textureProperties = properties.get( texture ); - - if ( texture.image && textureProperties.__image__webglTextureCube ) { - - // cube texture - - _gl.deleteTexture( textureProperties.__image__webglTextureCube ); - - } else { - - // 2D texture - - if ( textureProperties.__webglInit === undefined ) return; - - _gl.deleteTexture( textureProperties.__webglTexture ); - - } - - // remove all webgl properties - properties.remove( texture ); - - } - - function deallocateRenderTarget( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); - - if ( ! renderTarget ) return; - - if ( textureProperties.__webglTexture !== undefined ) { - - _gl.deleteTexture( textureProperties.__webglTexture ); - - } - - if ( renderTarget.depthTexture ) { - - renderTarget.depthTexture.dispose(); - - } - - if ( renderTarget.isWebGLRenderTargetCube ) { - - for ( var i = 0; i < 6; i ++ ) { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); - - } - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - - } - - properties.remove( renderTarget.texture ); - properties.remove( renderTarget ); - - } - - // - - - - function setTexture2D( texture, slot ) { - - var textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - var image = texture.image; - - if ( image === undefined ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); - - } else if ( image.complete === false ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); - - } else { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - } - - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - - } - - function setTextureCube( texture, slot ) { - - var textureProperties = properties.get( texture ); - - if ( texture.image.length === 6 ) { - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - if ( ! textureProperties.__image__webglTextureCube ) { - - texture.addEventListener( 'dispose', onTextureDispose ); - - textureProperties.__image__webglTextureCube = _gl.createTexture(); - - infoMemory.textures ++; - - } - - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - - var isCompressed = ( texture && texture.isCompressedTexture ); - var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - - var cubeImage = []; - - for ( var i = 0; i < 6; i ++ ) { - - if ( ! isCompressed && ! isDataTexture ) { - - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); - - } else { - - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - - } - - } - - var image = cubeImage[ 0 ], - isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage ); - - for ( var i = 0; i < 6; i ++ ) { - - if ( ! isCompressed ) { - - if ( isDataTexture ) { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - - } - - } else { - - var mipmap, mipmaps = cubeImage[ i ].mipmaps; - - for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - - mipmap = mipmaps[ j ]; - - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { - - state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()" ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { - - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - - } - - textureProperties.__version = texture.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } else { - - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); - - } - - } - - } - - function setTextureCubeDynamic( texture, slot ) { - - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); - - } - - function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { - - var extension; - - if ( isPowerOfTwoImage ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); - - } else { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture ); - - } - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture ); - - } - - } - - extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( extension ) { - - if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; - if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; - - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; - - } - - } - - } - - function uploadTexture( textureProperties, texture, slot ) { - - if ( textureProperties.__webglInit === undefined ) { - - textureProperties.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - textureProperties.__webglTexture = _gl.createTexture(); - - infoMemory.textures ++; - - } - - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - - var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); - - if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { - - image = makePowerOfTwo( image ); - - } - - var isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage ); - - var mipmap, mipmaps = texture.mipmaps; - - if ( texture.isDepthTexture ) { - - // populate depth texture with dummy data - - var internalFormat = _gl.DEPTH_COMPONENT; - - if ( texture.type === FloatType ) { - - if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0'); - internalFormat = _gl.DEPTH_COMPONENT32F; - - } else if ( _isWebGL2 ) { - - // WebGL 2.0 requires signed internalformat for glTexImage2D - internalFormat = _gl.DEPTH_COMPONENT16; - - } - - if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) { - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - - texture.type = UnsignedShortType; - glType = paramThreeToGL( texture.type ); - - } - - } - - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.format === DepthStencilFormat ) { - - internalFormat = _gl.DEPTH_STENCIL; - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedInt248Type ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - - texture.type = UnsignedInt248Type; - glType = paramThreeToGL( texture.type ); - - } - - } - - state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null ); - - } else if ( texture.isDataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isPowerOfTwoImage ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - texture.generateMipmaps = false; - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - - } - - } else if ( texture.isCompressedTexture ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { - - state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); - - } - - } else { - - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } else { - - // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isPowerOfTwoImage ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - - } - - texture.generateMipmaps = false; - - } else { - - state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image ); - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D ); - - textureProperties.__version = texture.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - // Render targets - - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { - - var glFormat = paramThreeToGL( renderTarget.texture.format ); - var glType = paramThreeToGL( renderTarget.texture.type ); - state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget ) { - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - } else { - - // FIXME: We don't support !depth !stencil - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - - } - - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { - - var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); - if ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!'); - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - - throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture'); - - } - - // upload an empty depth texture with framebuffer size - if ( !properties.get( renderTarget.depthTexture ).__webglTexture || - renderTarget.depthTexture.image.width !== renderTarget.width || - renderTarget.depthTexture.image.height !== renderTarget.height ) { - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; - } - - setTexture2D( renderTarget.depthTexture, 0 ); - - var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - - if ( renderTarget.depthTexture.format === DepthFormat ) { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); - - } else { - - throw new Error('Unknown depthTexture format') - - } - - } - - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); - - var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); - - if ( renderTarget.depthTexture ) { - - if ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets'); - - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - - } else { - - if ( isCube ) { - - renderTargetProperties.__webglDepthbuffer = []; - - for ( var i = 0; i < 6; i ++ ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); - - } - - } else { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); - - } - - } - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - textureProperties.__webglTexture = _gl.createTexture(); - - infoMemory.textures ++; - - var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); - - // Setup framebuffer - - if ( isCube ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( var i = 0; i < 6; i ++ ) { - - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - - } - - // Setup color buffer - - if ( isCube ) { - - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); - - for ( var i = 0; i < 6; i ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); - - } - - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - - } else { - - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D ); - - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D ); - state.bindTexture( _gl.TEXTURE_2D, null ); - - } - - // Setup depth and stencil buffers - - if ( renderTarget.depthBuffer ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - function updateRenderTargetMipmap( renderTarget ) { - - var texture = renderTarget.texture; - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); - - if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) { - - var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; - var webglTexture = properties.get( texture ).__webglTexture; - - state.bindTexture( target, webglTexture ); - _gl.generateMipmap( target ); - state.bindTexture( target, null ); - - } - - } - - this.setTexture2D = setTexture2D; - this.setTextureCube = setTextureCube; - this.setTextureCubeDynamic = setTextureCubeDynamic; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - -} - -/** - * @author fordacious / fordacious.github.io - */ - -function WebGLProperties() { - - var properties = {}; - - function get( object ) { - - var uuid = object.uuid; - var map = properties[ uuid ]; - - if ( map === undefined ) { - - map = {}; - properties[ uuid ] = map; - - } - - return map; - - } - - function remove( object ) { - - delete properties[ object.uuid ]; - - } - - function clear() { - - properties = {}; - - } - - return { - get: get, - remove: remove, - clear: clear - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLState( gl, extensions, paramThreeToGL ) { - - function ColorBuffer() { - - var locked = false; - - var color = new Vector4(); - var currentColorMask = null; - var currentColorClear = new Vector4(); - - return { - - setMask: function ( colorMask ) { - - if ( currentColorMask !== colorMask && ! locked ) { - - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( r, g, b, a, premultipliedAlpha ) { - - if ( premultipliedAlpha === true ) { - - r *= a; g *= a; b *= a; - - } - - color.set( r, g, b, a ); - - if ( currentColorClear.equals( color ) === false ) { - - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); - - } - - }, - - reset: function () { - - locked = false; - - currentColorMask = null; - currentColorClear.set( 0, 0, 0, 1 ); - - } - - }; - - } - - function DepthBuffer() { - - var locked = false; - - var currentDepthMask = null; - var currentDepthFunc = null; - var currentDepthClear = null; - - return { - - setTest: function ( depthTest ) { - - if ( depthTest ) { - - enable( gl.DEPTH_TEST ); - - } else { - - disable( gl.DEPTH_TEST ); - - } - - }, - - setMask: function ( depthMask ) { - - if ( currentDepthMask !== depthMask && ! locked ) { - - gl.depthMask( depthMask ); - currentDepthMask = depthMask; - - } - - }, - - setFunc: function ( depthFunc ) { - - if ( currentDepthFunc !== depthFunc ) { - - if ( depthFunc ) { - - switch ( depthFunc ) { - - case NeverDepth: - - gl.depthFunc( gl.NEVER ); - break; - - case AlwaysDepth: - - gl.depthFunc( gl.ALWAYS ); - break; - - case LessDepth: - - gl.depthFunc( gl.LESS ); - break; - - case LessEqualDepth: - - gl.depthFunc( gl.LEQUAL ); - break; - - case EqualDepth: - - gl.depthFunc( gl.EQUAL ); - break; - - case GreaterEqualDepth: - - gl.depthFunc( gl.GEQUAL ); - break; - - case GreaterDepth: - - gl.depthFunc( gl.GREATER ); - break; - - case NotEqualDepth: - - gl.depthFunc( gl.NOTEQUAL ); - break; - - default: - - gl.depthFunc( gl.LEQUAL ); - - } - - } else { - - gl.depthFunc( gl.LEQUAL ); - - } - - currentDepthFunc = depthFunc; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( depth ) { - - if ( currentDepthClear !== depth ) { - - gl.clearDepth( depth ); - currentDepthClear = depth; - - } - - }, - - reset: function () { - - locked = false; - - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; - - } - - }; - - } - - function StencilBuffer() { - - var locked = false; - - var currentStencilMask = null; - var currentStencilFunc = null; - var currentStencilRef = null; - var currentStencilFuncMask = null; - var currentStencilFail = null; - var currentStencilZFail = null; - var currentStencilZPass = null; - var currentStencilClear = null; - - return { - - setTest: function ( stencilTest ) { - - if ( stencilTest ) { - - enable( gl.STENCIL_TEST ); - - } else { - - disable( gl.STENCIL_TEST ); - - } - - }, - - setMask: function ( stencilMask ) { - - if ( currentStencilMask !== stencilMask && ! locked ) { - - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; - - } - - }, - - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { - - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; - - } - - }, - - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { - - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( stencil ) { - - if ( currentStencilClear !== stencil ) { - - gl.clearStencil( stencil ); - currentStencilClear = stencil; - - } - - }, - - reset: function () { - - locked = false; - - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; - - } - - }; - - } - - // - - var colorBuffer = new ColorBuffer(); - var depthBuffer = new DepthBuffer(); - var stencilBuffer = new StencilBuffer(); - - var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - var newAttributes = new Uint8Array( maxVertexAttributes ); - var enabledAttributes = new Uint8Array( maxVertexAttributes ); - var attributeDivisors = new Uint8Array( maxVertexAttributes ); - - var capabilities = {}; - - var compressedTextureFormats = null; - - var currentBlending = null; - var currentBlendEquation = null; - var currentBlendSrc = null; - var currentBlendDst = null; - var currentBlendEquationAlpha = null; - var currentBlendSrcAlpha = null; - var currentBlendDstAlpha = null; - var currentPremultipledAlpha = false; - - var currentFlipSided = null; - var currentCullFace = null; - - var currentLineWidth = null; - - var currentPolygonOffsetFactor = null; - var currentPolygonOffsetUnits = null; - - var currentScissorTest = null; - - var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); - - var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] ); - var lineWidthAvailable = parseFloat( version ) >= 1.0; - - var currentTextureSlot = null; - var currentBoundTextures = {}; - - var currentScissor = new Vector4(); - var currentViewport = new Vector4(); - - function createTexture( type, target, count ) { - - var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - var texture = gl.createTexture(); - - gl.bindTexture( type, texture ); - gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - - for ( var i = 0; i < count; i ++ ) { - - gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); - - } - - return texture; - - } - - var emptyTextures = {}; - emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); - emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); - - // - - function init() { - - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); - - enable( gl.DEPTH_TEST ); - depthBuffer.setFunc( LessEqualDepth ); - - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( gl.CULL_FACE ); - - enable( gl.BLEND ); - setBlending( NormalBlending ); - - } - - function initAttributes() { - - for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { - - newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== 0 ) { - - var extension = extensions.get( 'ANGLE_instanced_arrays' ); - - extension.vertexAttribDivisorANGLE( attribute, 0 ); - attributeDivisors[ attribute ] = 0; - - } - - } - - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - - var extension = extensions.get( 'ANGLE_instanced_arrays' ); - - extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; - - } - - } - - function disableUnusedAttributes() { - - for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) { - - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - } - - function enable( id ) { - - if ( capabilities[ id ] !== true ) { - - gl.enable( id ); - capabilities[ id ] = true; - - } - - } - - function disable( id ) { - - if ( capabilities[ id ] !== false ) { - - gl.disable( id ); - capabilities[ id ] = false; - - } - - } - - function getCompressedTextureFormats() { - - if ( compressedTextureFormats === null ) { - - compressedTextureFormats = []; - - if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || - extensions.get( 'WEBGL_compressed_texture_s3tc' ) || - extensions.get( 'WEBGL_compressed_texture_etc1' ) ) { - - var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); - - for ( var i = 0; i < formats.length; i ++ ) { - - compressedTextureFormats.push( formats[ i ] ); - - } - - } - - } - - return compressedTextureFormats; - - } - - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { - - if ( blending !== NoBlending ) { - - enable( gl.BLEND ); - - } else { - - disable( gl.BLEND ); - - } - - if ( ( blending !== CustomBlending ) && ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) ) { - - if ( blending === AdditiveBlending ) { - - if ( premultipliedAlpha ) { - - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE ); - - } else { - - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - - } - - } else if ( blending === SubtractiveBlending ) { - - if ( premultipliedAlpha ) { - - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA ); - - } else { - - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); - - } - - } else if ( blending === MultiplyBlending ) { - - if ( premultipliedAlpha ) { - - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); - - } else { - - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - - } - - } else { - - if ( premultipliedAlpha ) { - - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - - } else { - - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - - } - - } - - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; - - } - - if ( blending === CustomBlending ) { - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - - gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - - gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; - - } - - } else { - - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - - } - - } - - function setMaterial( material ) { - - material.side === DoubleSide - ? disable( gl.CULL_FACE ) - : enable( gl.CULL_FACE ); - - setFlipSided( material.side === BackSide ); - - material.transparent === true - ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) - : setBlending( NoBlending ); - - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); - - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - } - - // - - function setFlipSided( flipSided ) { - - if ( currentFlipSided !== flipSided ) { - - if ( flipSided ) { - - gl.frontFace( gl.CW ); - - } else { - - gl.frontFace( gl.CCW ); - - } - - currentFlipSided = flipSided; - - } - - } - - function setCullFace( cullFace ) { - - if ( cullFace !== CullFaceNone ) { - - enable( gl.CULL_FACE ); - - if ( cullFace !== currentCullFace ) { - - if ( cullFace === CullFaceBack ) { - - gl.cullFace( gl.BACK ); - - } else if ( cullFace === CullFaceFront ) { - - gl.cullFace( gl.FRONT ); - - } else { - - gl.cullFace( gl.FRONT_AND_BACK ); - - } - - } - - } else { - - disable( gl.CULL_FACE ); - - } - - currentCullFace = cullFace; - - } - - function setLineWidth( width ) { - - if ( width !== currentLineWidth ) { - - if ( lineWidthAvailable ) gl.lineWidth( width ); - - currentLineWidth = width; - - } - - } - - function setPolygonOffset( polygonOffset, factor, units ) { - - if ( polygonOffset ) { - - enable( gl.POLYGON_OFFSET_FILL ); - - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - - gl.polygonOffset( factor, units ); - - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; - - } - - } else { - - disable( gl.POLYGON_OFFSET_FILL ); - - } - - } - - function getScissorTest() { - - return currentScissorTest; - - } - - function setScissorTest( scissorTest ) { - - currentScissorTest = scissorTest; - - if ( scissorTest ) { - - enable( gl.SCISSOR_TEST ); - - } else { - - disable( gl.SCISSOR_TEST ); - - } - - } - - // texture - - function activeTexture( webglSlot ) { - - if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - } - - function bindTexture( webglType, webglTexture ) { - - if ( currentTextureSlot === null ) { - - activeTexture(); - - } - - var boundTexture = currentBoundTextures[ currentTextureSlot ]; - - if ( boundTexture === undefined ) { - - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ currentTextureSlot ] = boundTexture; - - } - - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - - boundTexture.type = webglType; - boundTexture.texture = webglTexture; - - } - - } - - function compressedTexImage2D() { - - try { - - gl.compressedTexImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage2D() { - - try { - - gl.texImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - // - - function scissor( scissor ) { - - if ( currentScissor.equals( scissor ) === false ) { - - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); - - } - - } - - function viewport( viewport ) { - - if ( currentViewport.equals( viewport ) === false ) { - - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); - - } - - } - - // - - function reset() { - - for ( var i = 0; i < enabledAttributes.length; i ++ ) { - - if ( enabledAttributes[ i ] === 1 ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - capabilities = {}; - - compressedTextureFormats = null; - - currentTextureSlot = null; - currentBoundTextures = {}; - - currentBlending = null; - - currentFlipSided = null; - currentCullFace = null; - - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); - - } - - return { - - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, - - init: init, - initAttributes: initAttributes, - enableAttribute: enableAttribute, - enableAttributeAndDivisor: enableAttributeAndDivisor, - disableUnusedAttributes: disableUnusedAttributes, - enable: enable, - disable: disable, - getCompressedTextureFormats: getCompressedTextureFormats, - - setBlending: setBlending, - setMaterial: setMaterial, - - setFlipSided: setFlipSided, - setCullFace: setCullFace, - - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, - - getScissorTest: getScissorTest, - setScissorTest: setScissorTest, - - activeTexture: activeTexture, - bindTexture: bindTexture, - compressedTexImage2D: compressedTexImage2D, - texImage2D: texImage2D, - - scissor: scissor, - viewport: viewport, - - reset: reset - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLCapabilities( gl, extensions, parameters ) { - - var maxAnisotropy; - - function getMaxAnisotropy() { - - if ( maxAnisotropy !== undefined ) return maxAnisotropy; - - var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( extension !== null ) { - - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - - } else { - - maxAnisotropy = 0; - - } - - return maxAnisotropy; - - } - - function getMaxPrecision( precision ) { - - if ( precision === 'highp' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { - - return 'highp'; - - } - - precision = 'mediump'; - - } - - if ( precision === 'mediump' ) { - - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { - - return 'mediump'; - - } - - } - - return 'lowp'; - - } - - var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - var maxPrecision = getMaxPrecision( precision ); - - if ( maxPrecision !== precision ) { - - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; - - } - - var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' ); - - var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); - var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); - var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - - var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); - var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); - var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); - - var vertexTextures = maxVertexTextures > 0; - var floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); - var floatVertexTextures = vertexTextures && floatFragmentTextures; - - return { - - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, - - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, - - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, - - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function ArrayCamera( array ) { - - PerspectiveCamera.call( this ); - - this.cameras = array || []; - -} - -ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { - - constructor: ArrayCamera, - - isArrayCamera: true - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebVRManager( renderer ) { - - var scope = this; - - var device = null; - var frameData = null; - - if ( 'VRFrameData' in window ) { - - frameData = new window.VRFrameData(); - - } - - var matrixWorldInverse = new Matrix4(); - - var standingMatrix = new Matrix4(); - var standingMatrixInverse = new Matrix4(); - - var cameraL = new PerspectiveCamera(); - cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 ); - cameraL.layers.enable( 1 ); - - var cameraR = new PerspectiveCamera(); - cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 ); - cameraR.layers.enable( 2 ); - - var cameraVR = new ArrayCamera( [ cameraL, cameraR ] ); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); - - // - - var currentSize, currentPixelRatio; - - function onVRDisplayPresentChange() { - - if ( device.isPresenting ) { - - var eyeParameters = device.getEyeParameters( 'left' ); - var renderWidth = eyeParameters.renderWidth; - var renderHeight = eyeParameters.renderHeight; - - currentPixelRatio = renderer.getPixelRatio(); - currentSize = renderer.getSize(); - - renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 ); - - } else if ( scope.enabled ) { - - renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio ); - - } - - } - - window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); - - // - - this.enabled = false; - this.standing = false; - - this.getDevice = function () { - - return device; - - }; - - this.setDevice = function ( value ) { - - if ( value !== undefined ) device = value; - - }; - - this.getCamera = function ( camera ) { - - if ( device === null ) return camera; - - device.depthNear = camera.near; - device.depthFar = camera.far; - - device.getFrameData( frameData ); - - // - - var pose = frameData.pose; - - if ( pose.position !== null ) { - - camera.position.fromArray( pose.position ); - - } else { - - camera.position.set( 0, 0, 0 ); - - } - - if ( pose.orientation !== null ) { - - camera.quaternion.fromArray( pose.orientation ); - - } - - camera.updateMatrixWorld(); - - var stageParameters = device.stageParameters; - - if ( this.standing && stageParameters ) { - - standingMatrix.fromArray( stageParameters.sittingToStandingTransform ); - standingMatrixInverse.getInverse( standingMatrix ); - - camera.matrixWorld.multiply( standingMatrix ); - camera.matrixWorldInverse.multiply( standingMatrixInverse ); - - } - - if ( device.isPresenting === false ) return camera; - - // - - cameraVR.matrixWorld.copy( camera.matrixWorld ); - cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse ); - - cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix ); - cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix ); - - if ( this.standing && stageParameters ) { - - cameraL.matrixWorldInverse.multiply( standingMatrixInverse ); - cameraR.matrixWorldInverse.multiply( standingMatrixInverse ); - - } - - var parent = camera.parent; - - if ( parent !== null ) { - - matrixWorldInverse.getInverse( parent.matrixWorld ); - - cameraL.matrixWorldInverse.multiply( matrixWorldInverse ); - cameraR.matrixWorldInverse.multiply( matrixWorldInverse ); - - } - - // envMap and Mirror needs camera.matrixWorld - - cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse ); - cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse ); - - cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix ); - cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix ); - - // HACK @mrdoob - // https://github.com/w3c/webvr/issues/203 - - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); - - // - - var layers = device.getLayers(); - - if ( layers.length ) { - - var layer = layers[ 0 ]; - - if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) { - - cameraL.bounds.fromArray( layer.leftBounds ); - - } - - if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) { - - cameraR.bounds.fromArray( layer.rightBounds ); - - } - - } - - return cameraVR; - - }; - - this.getStandingMatrix = function () { - - return standingMatrix; - - }; - - this.submitFrame = function () { - - if ( device && device.isPresenting ) device.submitFrame(); - - }; - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLExtensions( gl ) { - - var extensions = {}; - - return { - - get: function ( name ) { - - if ( extensions[ name ] !== undefined ) { - - return extensions[ name ]; - - } - - var extension; - - switch ( name ) { - - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; - - case 'EXT_texture_filter_anisotropic': - extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - break; - - case 'WEBGL_compressed_texture_s3tc': - extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - break; - - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; - - case 'WEBGL_compressed_texture_etc1': - extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' ); - break; - - default: - extension = gl.getExtension( name ); - - } - - if ( extension === null ) { - - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - - } - - extensions[ name ] = extension; - - return extension; - - } - - }; - -} - -/** - * @author tschw - */ - -function WebGLClipping() { - - var scope = this, - - globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false, - - plane = new Plane(), - viewNormalMatrix = new Matrix3(), - - uniform = { value: null, needsUpdate: false }; - - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; - - this.init = function( planes, enableLocalClipping, camera ) { - - var enabled = - planes.length !== 0 || - enableLocalClipping || - // enable state of previous frame - the clipping code has to - // run another frame in order to reset the state: - numGlobalPlanes !== 0 || - localClippingEnabled; - - localClippingEnabled = enableLocalClipping; - - globalState = projectPlanes( planes, camera, 0 ); - numGlobalPlanes = planes.length; - - return enabled; - - }; - - this.beginShadows = function() { - - renderingShadows = true; - projectPlanes( null ); - - }; - - this.endShadows = function() { - - renderingShadows = false; - resetGlobalState(); - - }; - - this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { - - if ( ! localClippingEnabled || - planes === null || planes.length === 0 || - renderingShadows && ! clipShadows ) { - // there's no local clipping - - if ( renderingShadows ) { - // there's no global clipping - - projectPlanes( null ); - - } else { - - resetGlobalState(); - } - - } else { - - var nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4, - - dstArray = cache.clippingState || null; - - uniform.value = dstArray; // ensure unique state - - dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); - - for ( var i = 0; i !== lGlobal; ++ i ) { - - dstArray[ i ] = globalState[ i ]; - - } - - cache.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; - - } - - - }; - - function resetGlobalState() { - - if ( uniform.value !== globalState ) { - - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; - - } - - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; - - } - - function projectPlanes( planes, camera, dstOffset, skipTransform ) { - - var nPlanes = planes !== null ? planes.length : 0, - dstArray = null; - - if ( nPlanes !== 0 ) { - - dstArray = uniform.value; - - if ( skipTransform !== true || dstArray === null ) { - - var flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; - - viewNormalMatrix.getNormalMatrix( viewMatrix ); - - if ( dstArray === null || dstArray.length < flatSize ) { - - dstArray = new Float32Array( flatSize ); - - } - - for ( var i = 0, i4 = dstOffset; - i !== nPlanes; ++ i, i4 += 4 ) { - - plane.copy( planes[ i ] ). - applyMatrix4( viewMatrix, viewNormalMatrix ); - - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; - - } - - } - - uniform.value = dstArray; - uniform.needsUpdate = true; - - } - - scope.numPlanes = nPlanes; - - return dstArray; - - } - -} - -// import { Sphere } from '../math/Sphere'; -/** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - * @author tschw - */ - -function WebGLRenderer( parameters ) { - - console.log( 'THREE.WebGLRenderer', REVISION ); - - parameters = parameters || {}; - - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), - _context = parameters.context !== undefined ? parameters.context : null, - - _alpha = parameters.alpha !== undefined ? parameters.alpha : false, - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false; - - var lights = []; - - var currentRenderList = null; - - var morphInfluences = new Float32Array( 8 ); - - var sprites = []; - var lensFlares = []; - - // public properties - - this.domElement = _canvas; - this.context = null; - - // clearing - - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; - - // scene graph - - this.sortObjects = true; - - // user-defined clipping - - this.clippingPlanes = []; - this.localClippingEnabled = false; - - // physically based shading - - this.gammaFactor = 2.0; // for backwards compatibility - this.gammaInput = false; - this.gammaOutput = false; - - // physical lights - - this.physicallyCorrectLights = false; - - // tone mapping - - this.toneMapping = LinearToneMapping; - this.toneMappingExposure = 1.0; - this.toneMappingWhitePoint = 1.0; - - // morphs - - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; - - // internal properties - - var _this = this, - - // internal state cache - - _currentProgram = null, - _currentRenderTarget = null, - _currentFramebuffer = null, - _currentMaterialId = - 1, - _currentGeometryProgram = '', - - _currentCamera = null, - _currentArrayCamera = null, - - _currentScissor = new Vector4(), - _currentScissorTest = null, - - _currentViewport = new Vector4(), - - // - - _usedTextureUnits = 0, - - // - - _width = _canvas.width, - _height = _canvas.height, - - _pixelRatio = 1, - - _scissor = new Vector4( 0, 0, _width, _height ), - _scissorTest = false, - - _viewport = new Vector4( 0, 0, _width, _height ), - - // frustum - - _frustum = new Frustum(), - - // clipping - - _clipping = new WebGLClipping(), - _clippingEnabled = false, - _localClippingEnabled = false, - - // camera matrices cache - - _projScreenMatrix = new Matrix4(), - - _vector3 = new Vector3(), - _matrix4 = new Matrix4(), - _matrix42 = new Matrix4(), - - // light arrays cache - - _lights = { - - hash: '', - - ambient: [ 0, 0, 0 ], - directional: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotShadowMap: [], - spotShadowMatrix: [], - rectArea: [], - point: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [], - - shadows: [] - - }, - - // info - - _infoMemory = { - geometries: 0, - textures: 0 - }, - - _infoRender = { - - frame: 0, - calls: 0, - vertices: 0, - faces: 0, - points: 0 - - }; - - this.info = { - - render: _infoRender, - memory: _infoMemory, - programs: null - - }; - - - // initialize - - var _gl; - - try { - - var contextAttributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer - }; - - _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); - - if ( _gl === null ) { - - if ( _canvas.getContext( 'webgl' ) !== null ) { - - throw 'Error creating WebGL context with your selected attributes.'; - - } else { - - throw 'Error creating WebGL context.'; - - } - - } - - // Some experimental-webgl implementations do not have getShaderPrecisionFormat - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function () { - - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - - }; - - } - - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - - } catch ( error ) { - - console.error( 'THREE.WebGLRenderer: ' + error ); - - } - - var extensions = new WebGLExtensions( _gl ); - - extensions.get( 'WEBGL_depth_texture' ); - extensions.get( 'OES_texture_float' ); - extensions.get( 'OES_texture_float_linear' ); - extensions.get( 'OES_texture_half_float' ); - extensions.get( 'OES_texture_half_float_linear' ); - extensions.get( 'OES_standard_derivatives' ); - extensions.get( 'ANGLE_instanced_arrays' ); - - if ( extensions.get( 'OES_element_index_uint' ) ) { - - BufferGeometry.MaxIndex = 4294967296; - - } - - var capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - - var state = new WebGLState( _gl, extensions, paramThreeToGL ); - - var properties = new WebGLProperties(); - var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, _infoMemory ); - var attributes = new WebGLAttributes( _gl ); - var geometries = new WebGLGeometries( _gl, attributes, _infoMemory ); - var objects = new WebGLObjects( _gl, geometries, _infoRender ); - var programCache = new WebGLPrograms( this, capabilities ); - var lightCache = new WebGLLights(); - var renderLists = new WebGLRenderLists(); - - var background = new WebGLBackground( this, state, objects, _premultipliedAlpha ); - var vr = new WebVRManager( this ); - - this.info.programs = programCache.programs; - - var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender ); - var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); - - // - - function getTargetPixelRatio() { - - return _currentRenderTarget === null ? _pixelRatio : 1; - - } - - function setDefaultGLState() { - - state.init(); - - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); - - } - - function resetGLState() { - - _currentProgram = null; - _currentCamera = null; - - _currentGeometryProgram = ''; - _currentMaterialId = - 1; - - state.reset(); - - } - - setDefaultGLState(); - - this.context = _gl; - this.capabilities = capabilities; - this.extensions = extensions; - this.properties = properties; - this.renderLists = renderLists; - this.state = state; - this.vr = vr; - - // shadow map - - var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities ); - - this.shadowMap = shadowMap; - - - // Plugins - - var spritePlugin = new SpritePlugin( this, sprites ); - var lensFlarePlugin = new LensFlarePlugin( this, lensFlares ); - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.getContextAttributes = function () { - - return _gl.getContextAttributes(); - - }; - - this.forceContextLoss = function () { - - var extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); - - }; - - this.getMaxAnisotropy = function () { - - return capabilities.getMaxAnisotropy(); - - }; - - this.getPrecision = function () { - - return capabilities.precision; - - }; - - this.getPixelRatio = function () { - - return _pixelRatio; - - }; - - this.setPixelRatio = function ( value ) { - - if ( value === undefined ) return; - - _pixelRatio = value; - - this.setSize( _width, _height, false ); - - }; - - this.getSize = function () { - - return { - width: _width, - height: _height - }; - - }; - - this.setSize = function ( width, height, updateStyle ) { - - var device = vr.getDevice(); - - if ( device && device.isPresenting ) { - - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; - - } - - _width = width; - _height = height; - - _canvas.width = width * _pixelRatio; - _canvas.height = height * _pixelRatio; - - if ( updateStyle !== false ) { - - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; - - } - - this.setViewport( 0, 0, width, height ); - - }; - - this.getDrawingBufferSize = function () { - - return { - width: _width * _pixelRatio, - height: _height * _pixelRatio - }; - - }; - - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - - _width = width; - _height = height; - - _pixelRatio = pixelRatio; - - _canvas.width = width * pixelRatio; - _canvas.height = height * pixelRatio; - - this.setViewport( 0, 0, width, height ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - _viewport.set( x, _height - y - height, width, height ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - _scissor.set( x, _height - y - height, width, height ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); - - }; - - this.setScissorTest = function ( boolean ) { - - state.setScissorTest( _scissorTest = boolean ); - - }; - - // Clearing - - this.getClearColor = background.getClearColor; - this.setClearColor = background.setClearColor; - this.getClearAlpha = background.getClearAlpha; - this.setClearAlpha = background.setClearAlpha; - - this.clear = function ( color, depth, stencil ) { - - var bits = 0; - - if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; - if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - this.clear( true, false, false ); - - }; - - this.clearDepth = function () { - - this.clear( false, true, false ); - - }; - - this.clearStencil = function () { - - this.clear( false, false, true ); - - }; - - this.clearTarget = function ( renderTarget, color, depth, stencil ) { - - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); - - }; - - // Reset - - this.resetGLState = resetGLState; - - this.dispose = function () { - - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - - renderLists.dispose(); - - }; - - // Events - - function onContextLost( event ) { - - event.preventDefault(); - - resetGLState(); - setDefaultGLState(); - - properties.clear(); - objects.clear(); - - } - - function onMaterialDispose( event ) { - - var material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - } - - // Buffer deallocation - - function deallocateMaterial( material ) { - - releaseMaterialProgramReference( material ); - - properties.remove( material ); - - } - - - function releaseMaterialProgramReference( material ) { - - var programInfo = properties.get( material ).program; - - material.program = undefined; - - if ( programInfo !== undefined ) { - - programCache.releaseProgram( programInfo ); - - } - - } - - // Buffer rendering - - function renderObjectImmediate( object, program, material ) { - - object.render( function ( object ) { - - _this.renderBufferImmediate( object, program, material ); - - } ); - - } - - this.renderBufferImmediate = function ( object, program, material ) { - - state.initAttributes(); - - var buffers = properties.get( object ); - - if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); - if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); - if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); - if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); - - var programAttributes = program.getAttributes(); - - if ( object.hasPositions ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( programAttributes.position ); - _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); - - if ( ! material.isMeshPhongMaterial && - ! material.isMeshStandardMaterial && - ! material.isMeshNormalMaterial && - material.shading === FlatShading ) { - - for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { - - var array = object.normalArray; - - var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; - var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; - var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; - - array[ i + 0 ] = nx; - array[ i + 1 ] = ny; - array[ i + 2 ] = nz; - - array[ i + 3 ] = nx; - array[ i + 4 ] = ny; - array[ i + 5 ] = nz; - - array[ i + 6 ] = nx; - array[ i + 7 ] = ny; - array[ i + 8 ] = nz; - - } - - } - - _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( programAttributes.normal ); - - _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasUvs && material.map ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( programAttributes.uv ); - - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasColors && material.vertexColors !== NoColors ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - - state.enableAttribute( programAttributes.color ); - - _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } - - state.disableUnusedAttributes(); - - _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); - - object.count = 0; - - }; - - function absNumericalSort( a, b ) { - - return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] ); - - } - - this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { - - state.setMaterial( material ); - - var program = setProgram( camera, fog, material, object ); - var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true ); - - var updateBuffers = false; - - if ( geometryProgram !== _currentGeometryProgram ) { - - _currentGeometryProgram = geometryProgram; - updateBuffers = true; - - } - - // morph targets - - var morphTargetInfluences = object.morphTargetInfluences; - - if ( morphTargetInfluences !== undefined ) { - - // TODO Remove allocations - - var activeInfluences = []; - - for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { - - var influence = morphTargetInfluences[ i ]; - activeInfluences.push( [ influence, i ] ); - - } - - activeInfluences.sort( absNumericalSort ); - - if ( activeInfluences.length > 8 ) { - - activeInfluences.length = 8; - - } - - var morphAttributes = geometry.morphAttributes; - - for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) { - - var influence = activeInfluences[ i ]; - morphInfluences[ i ] = influence[ 0 ]; - - if ( influence[ 0 ] !== 0 ) { - - var index = influence[ 1 ]; - - if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] ); - if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] ); - - } else { - - if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i ); - if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i ); - - } - - } - - for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) { - - morphInfluences[ i ] = 0.0; - - } - - program.getUniforms().setValue( _gl, 'morphTargetInfluences', morphInfluences ); - - updateBuffers = true; - - } - - // - - var index = geometry.index; - var position = geometry.attributes.position; - var rangeFactor = 1; - - if ( material.wireframe === true ) { - - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; - - } - - var attribute; - var renderer = bufferRenderer; - - if ( index !== null ) { - - attribute = attributes.get( index ); - - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); - - } - - if ( updateBuffers ) { - - setupVertexAttributes( material, program, geometry ); - - if ( index !== null ) { - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer ); - - } - - } - - // - - var dataCount = 0; - - if ( index !== null ) { - - dataCount = index.count; - - } else if ( position !== undefined ) { - - dataCount = position.count; - - } - - var rangeStart = geometry.drawRange.start * rangeFactor; - var rangeCount = geometry.drawRange.count * rangeFactor; - - var groupStart = group !== null ? group.start * rangeFactor : 0; - var groupCount = group !== null ? group.count * rangeFactor : Infinity; - - var drawStart = Math.max( rangeStart, groupStart ); - var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; - - var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); - - if ( drawCount === 0 ) return; - - // - - if ( object.isMesh ) { - - if ( material.wireframe === true ) { - - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( _gl.LINES ); - - } else { - - switch ( object.drawMode ) { - - case TrianglesDrawMode: - renderer.setMode( _gl.TRIANGLES ); - break; - - case TriangleStripDrawMode: - renderer.setMode( _gl.TRIANGLE_STRIP ); - break; - - case TriangleFanDrawMode: - renderer.setMode( _gl.TRIANGLE_FAN ); - break; - - } - - } - - - } else if ( object.isLine ) { - - var lineWidth = material.linewidth; - - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - - state.setLineWidth( lineWidth * getTargetPixelRatio() ); - - if ( object.isLineSegments ) { - - renderer.setMode( _gl.LINES ); - - } else if ( object.isLineLoop ) { - - renderer.setMode( _gl.LINE_LOOP ); - - } else { - - renderer.setMode( _gl.LINE_STRIP ); - - } - - } else if ( object.isPoints ) { - - renderer.setMode( _gl.POINTS ); - - } - - if ( geometry && geometry.isInstancedBufferGeometry ) { - - if ( geometry.maxInstancedCount > 0 ) { - - renderer.renderInstances( geometry, drawStart, drawCount ); - - } - - } else { - - renderer.render( drawStart, drawCount ); - - } - - }; - - function setupVertexAttributes( material, program, geometry, startIndex ) { - - if ( geometry && geometry.isInstancedBufferGeometry ) { - - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { - - console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - if ( startIndex === undefined ) startIndex = 0; - - state.initAttributes(); - - var geometryAttributes = geometry.attributes; - - var programAttributes = program.getAttributes(); - - var materialDefaultAttributeValues = material.defaultAttributeValues; - - for ( var name in programAttributes ) { - - var programAttribute = programAttributes[ name ]; - - if ( programAttribute >= 0 ) { - - var geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute !== undefined ) { - - var normalized = geometryAttribute.normalized; - var size = geometryAttribute.itemSize; - - var attribute = attributes.get( geometryAttribute ); - - var buffer = attribute.buffer; - var type = attribute.type; - var bytesPerElement = attribute.bytesPerElement; - - if ( geometryAttribute.isInterleavedBufferAttribute ) { - - var data = geometryAttribute.data; - var stride = data.stride; - var offset = geometryAttribute.offset; - - if ( data && data.isInstancedInterleavedBuffer ) { - - state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); - - if ( geometry.maxInstancedCount === undefined ) { - - geometry.maxInstancedCount = data.meshPerAttribute * data.count; - - } - - } else { - - state.enableAttribute( programAttribute ); - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement ); - - } else { - - if ( geometryAttribute.isInstancedBufferAttribute ) { - - state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); - - if ( geometry.maxInstancedCount === undefined ) { - - geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - - } - - } else { - - state.enableAttribute( programAttribute ); - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement ); - - } - - } else if ( materialDefaultAttributeValues !== undefined ) { - - var value = materialDefaultAttributeValues[ name ]; - - if ( value !== undefined ) { - - switch ( value.length ) { - - case 2: - _gl.vertexAttrib2fv( programAttribute, value ); - break; - - case 3: - _gl.vertexAttrib3fv( programAttribute, value ); - break; - - case 4: - _gl.vertexAttrib4fv( programAttribute, value ); - break; - - default: - _gl.vertexAttrib1fv( programAttribute, value ); - - } - - } - - } - - } - - } - - state.disableUnusedAttributes(); - - } - - // Compile - - this.compile = function ( scene, camera ) { - - lights = []; - - scene.traverse( function ( object ) { - - if ( object.isLight ) { - - lights.push( object ); - - } - - } ); - - setupLights( lights, camera ); - - scene.traverse( function ( object ) { - - if ( object.material ) { - - if ( Array.isArray( object.material ) ) { - - for ( var i = 0; i < object.material.length; i ++ ) { - - initMaterial( object.material[ i ], scene.fog, object ); - - } - - } else { - - initMaterial( object.material, scene.fog, object ); - - } - - } - - } ); - - }; - - // Rendering - - this.animate = function ( callback ) { - - function onFrame() { - - callback(); - - ( vr.getDevice() || window ).requestAnimationFrame( onFrame ); - - } - - ( vr.getDevice() || window ).requestAnimationFrame( onFrame ); - - }; - - this.render = function ( scene, camera, renderTarget, forceClear ) { - - if ( ! ( camera && camera.isCamera ) ) { - - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - // reset caching for this frame - - _currentGeometryProgram = ''; - _currentMaterialId = - 1; - _currentCamera = null; - - // update scene graph - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === null ) camera.updateMatrixWorld(); - - if ( vr.enabled ) { - - camera = vr.getCamera( camera ); - - } - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - lights.length = 0; - sprites.length = 0; - lensFlares.length = 0; - - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - - currentRenderList = renderLists.get( scene, camera ); - currentRenderList.init(); - - projectObject( scene, camera, _this.sortObjects ); - - currentRenderList.finish(); - - if ( _this.sortObjects === true ) { - - currentRenderList.sort(); - - } - - // - - if ( _clippingEnabled ) _clipping.beginShadows(); - - setupShadows( lights ); - - shadowMap.render( scene, camera ); - - setupLights( lights, camera ); - - if ( _clippingEnabled ) _clipping.endShadows(); - - // - - _infoRender.frame ++; - _infoRender.calls = 0; - _infoRender.vertices = 0; - _infoRender.faces = 0; - _infoRender.points = 0; - - if ( renderTarget === undefined ) { - - renderTarget = null; - - } - - this.setRenderTarget( renderTarget ); - - // - - background.render( scene, camera, forceClear ); - - // render scene - - var opaqueObjects = currentRenderList.opaque; - var transparentObjects = currentRenderList.transparent; - - if ( scene.overrideMaterial ) { - - var overrideMaterial = scene.overrideMaterial; - - if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); - if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); - - } else { - - // opaque pass (front-to-back order) - - if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); - - // transparent pass (back-to-front order) - - if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); - - } - - // custom render plugins (post pass) - - spritePlugin.render( scene, camera ); - lensFlarePlugin.render( scene, camera, _currentViewport ); - - // Generate mipmap if we're using any kind of mipmap filtering - - if ( renderTarget ) { - - textures.updateRenderTargetMipmap( renderTarget ); - - } - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); - - if ( camera.isArrayCamera ) { - - _this.setScissorTest( false ); - - } - - if ( vr.enabled ) { - - vr.submitFrame(); - - } - - // _gl.finish(); - - }; - - /* - // TODO Duplicated code (Frustum) - - var _sphere = new Sphere(); - - function isObjectViewable( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) - geometry.computeBoundingSphere(); - - _sphere.copy( geometry.boundingSphere ). - applyMatrix4( object.matrixWorld ); - - return isSphereViewable( _sphere ); - - } - - function isSpriteViewable( sprite ) { - - _sphere.center.set( 0, 0, 0 ); - _sphere.radius = 0.7071067811865476; - _sphere.applyMatrix4( sprite.matrixWorld ); - - return isSphereViewable( _sphere ); - - } - - function isSphereViewable( sphere ) { - - if ( ! _frustum.intersectsSphere( sphere ) ) return false; - - var numPlanes = _clipping.numPlanes; - - if ( numPlanes === 0 ) return true; - - var planes = _this.clippingPlanes, - - center = sphere.center, - negRad = - sphere.radius, - i = 0; - - do { - - // out when deeper than radius in the negative halfspace - if ( planes[ i ].distanceToPoint( center ) < negRad ) return false; - - } while ( ++ i !== numPlanes ); - - return true; - - } - */ - - function projectObject( object, camera, sortObjects ) { - - if ( ! object.visible ) return; - - var visible = object.layers.test( camera.layers ); - - if ( visible ) { - - if ( object.isLight ) { - - lights.push( object ); - - } else if ( object.isSprite ) { - - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - - sprites.push( object ); - - } - - } else if ( object.isLensFlare ) { - - lensFlares.push( object ); - - } else if ( object.isImmediateRenderObject ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - currentRenderList.push( object, null, object.material, _vector3.z, null ); - - } else if ( object.isMesh || object.isLine || object.isPoints ) { - - if ( object.isSkinnedMesh ) { - - object.skeleton.update(); - - } - - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - var geometry = objects.update( object ); - var material = object.material; - - if ( Array.isArray( material ) ) { - - var groups = geometry.groups; - - for ( var i = 0, l = groups.length; i < l; i ++ ) { - - var group = groups[ i ]; - var groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group ); - - } - - } - - } else if ( material.visible ) { - - currentRenderList.push( object, geometry, material, _vector3.z, null ); - - } - - } - - } - - } - - var children = object.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - projectObject( children[ i ], camera, sortObjects ); - - } - - } - - function renderObjects( renderList, scene, camera, overrideMaterial ) { - - for ( var i = 0, l = renderList.length; i < l; i ++ ) { - - var renderItem = renderList[ i ]; - - var object = renderItem.object; - var geometry = renderItem.geometry; - var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; - var group = renderItem.group; - - if ( camera.isArrayCamera ) { - - _currentArrayCamera = camera; - - var cameras = camera.cameras; - - for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { - - var camera2 = cameras[ j ]; - - if ( object.layers.test( camera2.layers ) ) { - - var bounds = camera2.bounds; - - var x = bounds.x * _width; - var y = bounds.y * _height; - var width = bounds.z * _width; - var height = bounds.w * _height; - - _this.setViewport( x, y, width, height ); - _this.setScissor( x, y, width, height ); - _this.setScissorTest( true ); - - renderObject( object, scene, camera2, geometry, material, group ); - - } - - } - - } else { - - _currentArrayCamera = null; - - renderObject( object, scene, camera, geometry, material, group ); - - } - - } - - } - - function renderObject( object, scene, camera, geometry, material, group ) { - - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - - if ( object.isImmediateRenderObject ) { - - state.setMaterial( material ); - - var program = setProgram( camera, scene.fog, material, object ); - - _currentGeometryProgram = ''; - - renderObjectImmediate( object, program, material ); - - } else { - - _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); - - } - - object.onAfterRender( _this, scene, camera, geometry, material, group ); - - } - - function initMaterial( material, fog, object ) { - - var materialProperties = properties.get( material ); - - var parameters = programCache.getParameters( - material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object ); - - var code = programCache.getProgramCode( material, parameters ); - - var program = materialProperties.program; - var programChange = true; - - if ( program === undefined ) { - - // new material - material.addEventListener( 'dispose', onMaterialDispose ); - - } else if ( program.code !== code ) { - - // changed glsl or parameters - releaseMaterialProgramReference( material ); - - } else if ( parameters.shaderID !== undefined ) { - - // same glsl and uniform list - return; - - } else { - - // only rebuild uniform list - programChange = false; - - } - - if ( programChange ) { - - if ( parameters.shaderID ) { - - var shader = ShaderLib[ parameters.shaderID ]; - - materialProperties.shader = { - name: material.type, - uniforms: UniformsUtils.clone( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader - }; - - } else { - - materialProperties.shader = { - name: material.type, - uniforms: material.uniforms, - vertexShader: material.vertexShader, - fragmentShader: material.fragmentShader - }; - - } - - material.onBeforeCompile( materialProperties.shader ); - - program = programCache.acquireProgram( material, materialProperties.shader, parameters, code ); - - materialProperties.program = program; - material.program = program; - - } - - var programAttributes = program.getAttributes(); - - if ( material.morphTargets ) { - - material.numSupportedMorphTargets = 0; - - for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - - if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { - - material.numSupportedMorphTargets ++; - - } - - } - - } - - if ( material.morphNormals ) { - - material.numSupportedMorphNormals = 0; - - for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { - - if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { - - material.numSupportedMorphNormals ++; - - } - - } - - } - - var uniforms = materialProperties.shader.uniforms; - - if ( ! material.isShaderMaterial && - ! material.isRawShaderMaterial || - material.clipping === true ) { - - materialProperties.numClippingPlanes = _clipping.numPlanes; - materialProperties.numIntersection = _clipping.numIntersection; - uniforms.clippingPlanes = _clipping.uniform; - - } - - materialProperties.fog = fog; - - // store the light setup it was created for - - materialProperties.lightsHash = _lights.hash; - - if ( material.lights ) { - - // wire up the material to this renderer's lighting state - - uniforms.ambientLightColor.value = _lights.ambient; - uniforms.directionalLights.value = _lights.directional; - uniforms.spotLights.value = _lights.spot; - uniforms.rectAreaLights.value = _lights.rectArea; - uniforms.pointLights.value = _lights.point; - uniforms.hemisphereLights.value = _lights.hemi; - - uniforms.directionalShadowMap.value = _lights.directionalShadowMap; - uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix; - uniforms.spotShadowMap.value = _lights.spotShadowMap; - uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix; - uniforms.pointShadowMap.value = _lights.pointShadowMap; - uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix; - // TODO (abelnation): add area lights shadow info to uniforms - - } - - var progUniforms = materialProperties.program.getUniforms(), - uniformsList = - WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - - materialProperties.uniformsList = uniformsList; - - } - - function setProgram( camera, fog, material, object ) { - - _usedTextureUnits = 0; - - var materialProperties = properties.get( material ); - - if ( _clippingEnabled ) { - - if ( _localClippingEnabled || camera !== _currentCamera ) { - - var useCache = - camera === _currentCamera && - material.id === _currentMaterialId; - - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - _clipping.setState( - material.clippingPlanes, material.clipIntersection, material.clipShadows, - camera, materialProperties, useCache ); - - } - - } - - if ( material.needsUpdate === false ) { - - if ( materialProperties.program === undefined ) { - - material.needsUpdate = true; - - } else if ( material.fog && materialProperties.fog !== fog ) { - - material.needsUpdate = true; - - } else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) { - - material.needsUpdate = true; - - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== _clipping.numPlanes || - materialProperties.numIntersection !== _clipping.numIntersection ) ) { - - material.needsUpdate = true; - - } - - } - - if ( material.needsUpdate ) { - - initMaterial( material, fog, object ); - material.needsUpdate = false; - - } - - var refreshProgram = false; - var refreshMaterial = false; - var refreshLights = false; - - var program = materialProperties.program, - p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.shader.uniforms; - - if ( program.id !== _currentProgram ) { - - _gl.useProgram( program.program ); - _currentProgram = program.id; - - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; - - } - - if ( material.id !== _currentMaterialId ) { - - _currentMaterialId = material.id; - - refreshMaterial = true; - - } - - if ( refreshProgram || camera !== _currentCamera ) { - - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - - if ( capabilities.logarithmicDepthBuffer ) { - - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - - } - - // Avoid unneeded uniform updates per ArrayCamera's sub-camera - - if ( _currentCamera !== ( _currentArrayCamera || camera ) ) { - - _currentCamera = ( _currentArrayCamera || camera ); - - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: - - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done - - } - - // load material specific uniforms - // (shader material also gets them for the sake of genericity) - - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshStandardMaterial || - material.envMap ) { - - var uCamPos = p_uniforms.map.cameraPosition; - - if ( uCamPos !== undefined ) { - - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - - } - - } - - if ( material.isMeshPhongMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.skinning ) { - - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - - } - - } - - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen - - if ( material.skinning ) { - - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - - var skeleton = object.skeleton; - - if ( skeleton ) { - - var bones = skeleton.bones; - - if ( capabilities.floatVertexTextures ) { - - if ( skeleton.boneTexture === undefined ) { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - - - var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix - size = _Math.nextPowerOfTwo( Math.ceil( size ) ); - size = Math.max( size, 4 ); - - var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( skeleton.boneMatrices ); // copy current values - - var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - - skeleton.boneMatrices = boneMatrices; - skeleton.boneTexture = boneTexture; - skeleton.boneTextureSize = size; - - } - - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); - - } else { - - p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); - - } - - } - - } - - if ( refreshMaterial ) { - - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); - - if ( material.lights ) { - - // the current material requires lighting info - - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required - - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - - } - - // refresh uniforms common to several materials - - if ( fog && material.fog ) { - - refreshUniformsFog( m_uniforms, fog ); - - } - - if ( material.isMeshBasicMaterial || - material.isMeshLambertMaterial || - material.isMeshPhongMaterial || - material.isMeshStandardMaterial || - material.isMeshNormalMaterial || - material.isMeshDepthMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - - } - - // refresh single material specific uniforms - - if ( material.isLineBasicMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - - } else if ( material.isLineDashedMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - refreshUniformsDash( m_uniforms, material ); - - } else if ( material.isPointsMaterial ) { - - refreshUniformsPoints( m_uniforms, material ); - - } else if ( material.isMeshLambertMaterial ) { - - refreshUniformsLambert( m_uniforms, material ); - - } else if ( material.isMeshToonMaterial ) { - - refreshUniformsToon( m_uniforms, material ); - - } else if ( material.isMeshPhongMaterial ) { - - refreshUniformsPhong( m_uniforms, material ); - - } else if ( material.isMeshPhysicalMaterial ) { - - refreshUniformsPhysical( m_uniforms, material ); - - } else if ( material.isMeshStandardMaterial ) { - - refreshUniformsStandard( m_uniforms, material ); - - } else if ( material.isMeshDepthMaterial ) { - - if ( material.displacementMap ) { - - m_uniforms.displacementMap.value = material.displacementMap; - m_uniforms.displacementScale.value = material.displacementScale; - m_uniforms.displacementBias.value = material.displacementBias; - - } - - } else if ( material.isMeshNormalMaterial ) { - - refreshUniformsNormal( m_uniforms, material ); - - } - - // RectAreaLight Texture - // TODO (mrdoob): Find a nicer implementation - - if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE; - if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE; - - WebGLUniforms.upload( - _gl, materialProperties.uniformsList, m_uniforms, _this ); - - } - - - // common matrices - - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - - return program; - - } - - // Uniforms (refresh uniforms objects) - - function refreshUniformsCommon( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value = material.color; - - if ( material.emissive ) { - - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - } - - uniforms.map.value = material.map; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; - - if ( material.lightMap ) { - - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; - - } - - if ( material.aoMap ) { - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map - - var uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.roughnessMap ) { - - uvScaleMap = material.roughnessMap; - - } else if ( material.metalnessMap ) { - - uvScaleMap = material.metalnessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; - - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - - } - - uniforms.envMap.value = material.envMap; - - // don't flip CubeTexture envMaps, flip everything else: - // WebGLRenderTargetCube will be flipped for backwards compatibility - // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture - // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future - uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; - - } - - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - - } - - function refreshUniformsDash( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsPoints( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * _pixelRatio; - uniforms.scale.value = _height * 0.5; - - uniforms.map.value = material.map; - - if ( material.map !== null ) { - - var offset = material.map.offset; - var repeat = material.map.repeat; - - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - - } - - } - - function refreshUniformsFog( uniforms, fog ) { - - uniforms.fogColor.value = fog.color; - - if ( fog.isFog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog.isFogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - } - - function refreshUniformsLambert( uniforms, material ) { - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - } - - function refreshUniformsPhong( uniforms, material ) { - - uniforms.specular.value = material.specular; - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - function refreshUniformsToon( uniforms, material ) { - - refreshUniformsPhong( uniforms, material ); - - if ( material.gradientMap ) { - - uniforms.gradientMap.value = material.gradientMap; - - } - - } - - function refreshUniformsStandard( uniforms, material ) { - - uniforms.roughness.value = material.roughness; - uniforms.metalness.value = material.metalness; - - if ( material.roughnessMap ) { - - uniforms.roughnessMap.value = material.roughnessMap; - - } - - if ( material.metalnessMap ) { - - uniforms.metalnessMap.value = material.metalnessMap; - - } - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - if ( material.envMap ) { - - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; - - } - - } - - function refreshUniformsPhysical( uniforms, material ) { - - uniforms.clearCoat.value = material.clearCoat; - uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - - refreshUniformsStandard( uniforms, material ); - - } - - function refreshUniformsNormal( uniforms, material ) { - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - // If uniforms are marked as clean, they don't need to be loaded to the GPU. - - function markUniformsLightsNeedsUpdate( uniforms, value ) { - - uniforms.ambientLightColor.needsUpdate = value; - - uniforms.directionalLights.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; - - } - - // Lighting - - function setupShadows( lights ) { - - var lightShadowsLength = 0; - - for ( var i = 0, l = lights.length; i < l; i ++ ) { - - var light = lights[ i ]; - - if ( light.castShadow ) { - - _lights.shadows[ lightShadowsLength ] = light; - lightShadowsLength ++; - - } - - } - - _lights.shadows.length = lightShadowsLength; - - } - - function setupLights( lights, camera ) { - - var l, ll, light, shadow, - r = 0, g = 0, b = 0, - color, - intensity, - distance, - shadowMap, - - viewMatrix = camera.matrixWorldInverse, - - directionalLength = 0, - pointLength = 0, - spotLength = 0, - rectAreaLength = 0, - hemiLength = 0; - - for ( l = 0, ll = lights.length; l < ll; l ++ ) { - - light = lights[ l ]; - - color = light.color; - intensity = light.intensity; - distance = light.distance; - - shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - - if ( light.isAmbientLight ) { - - r += color.r * intensity; - g += color.g * intensity; - b += color.b * intensity; - - } else if ( light.isDirectionalLight ) { - - var uniforms = lightCache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( _vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - uniforms.shadow = light.castShadow; - - if ( light.castShadow ) { - - shadow = light.shadow; - - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; - - } - - _lights.directionalShadowMap[ directionalLength ] = shadowMap; - _lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - _lights.directional[ directionalLength ] = uniforms; - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - var uniforms = lightCache.get( light ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - uniforms.color.copy( color ).multiplyScalar( intensity ); - uniforms.distance = distance; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( _vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; - - uniforms.shadow = light.castShadow; - - if ( light.castShadow ) { - - shadow = light.shadow; - - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; - - } - - _lights.spotShadowMap[ spotLength ] = shadowMap; - _lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - _lights.spot[ spotLength ] = uniforms; - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - var uniforms = lightCache.get( light ); - - // (a) intensity controls irradiance of entire light - uniforms.color - .copy( color ) - .multiplyScalar( intensity / ( light.width * light.height ) ); - - // (b) intensity controls the radiance per light area - // uniforms.color.copy( color ).multiplyScalar( intensity ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - // extract local rotation of light to derive width/height half vectors - _matrix42.identity(); - _matrix4.copy( light.matrixWorld ); - _matrix4.premultiply( viewMatrix ); - _matrix42.extractRotation( _matrix4 ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - uniforms.halfWidth.applyMatrix4( _matrix42 ); - uniforms.halfHeight.applyMatrix4( _matrix42 ); - - // TODO (abelnation): RectAreaLight distance? - // uniforms.distance = distance; - - _lights.rectArea[ rectAreaLength ] = uniforms; - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - var uniforms = lightCache.get( light ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); - uniforms.distance = light.distance; - uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; - - uniforms.shadow = light.castShadow; - - if ( light.castShadow ) { - - shadow = light.shadow; - - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; - - } - - _lights.pointShadowMap[ pointLength ] = shadowMap; - _lights.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - _lights.point[ pointLength ] = uniforms; - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - var uniforms = lightCache.get( light ); - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - uniforms.direction.normalize(); - - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); - - _lights.hemi[ hemiLength ] = uniforms; - - hemiLength ++; - - } - - } - - _lights.ambient[ 0 ] = r; - _lights.ambient[ 1 ] = g; - _lights.ambient[ 2 ] = b; - - _lights.directional.length = directionalLength; - _lights.spot.length = spotLength; - _lights.rectArea.length = rectAreaLength; - _lights.point.length = pointLength; - _lights.hemi.length = hemiLength; - - // TODO (sam-g-steel) why aren't we using join - _lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length; - - } - - // GL state setting - - this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - - state.setCullFace( cullFace ); - state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW ); - - }; - - // Textures - - function allocTextureUnit() { - - var textureUnit = _usedTextureUnits; - - if ( textureUnit >= capabilities.maxTextures ) { - - console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); - - } - - _usedTextureUnits += 1; - - return textureUnit; - - } - - this.allocTextureUnit = allocTextureUnit; - - // this.setTexture2D = setTexture2D; - this.setTexture2D = ( function () { - - var warned = false; - - // backwards compatibility: peel texture.texture - return function setTexture2D( texture, slot ) { - - if ( texture && texture.isWebGLRenderTarget ) { - - if ( ! warned ) { - - console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); - warned = true; - - } - - texture = texture.texture; - - } - - textures.setTexture2D( texture, slot ); - - }; - - }() ); - - this.setTexture = ( function () { - - var warned = false; - - return function setTexture( texture, slot ) { - - if ( ! warned ) { - - console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); - warned = true; - - } - - textures.setTexture2D( texture, slot ); - - }; - - }() ); - - this.setTextureCube = ( function () { - - var warned = false; - - return function setTextureCube( texture, slot ) { - - // backwards compatibility: peel texture.texture - if ( texture && texture.isWebGLRenderTargetCube ) { - - if ( ! warned ) { - - console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); - warned = true; - - } - - texture = texture.texture; - - } - - // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture - // TODO: unify these code paths - if ( ( texture && texture.isCubeTexture ) || - ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { - - // CompressedTexture can have Array in image :/ - - // this function alone should take care of cube textures - textures.setTextureCube( texture, slot ); - - } else { - - // assumed: texture property of THREE.WebGLRenderTargetCube - - textures.setTextureCubeDynamic( texture, slot ); - - } - - }; - - }() ); - - this.getRenderTarget = function () { - - return _currentRenderTarget; - - }; - - this.setRenderTarget = function ( renderTarget ) { - - _currentRenderTarget = renderTarget; - - if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { - - textures.setupRenderTarget( renderTarget ); - - } - - var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); - var framebuffer; - - if ( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); - - if ( isCube ) { - - framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ]; - - } else { - - framebuffer = renderTargetProperties.__webglFramebuffer; - - } - - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; - - _currentViewport.copy( renderTarget.viewport ); - - } else { - - framebuffer = null; - - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); - _currentScissorTest = _scissorTest; - - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); - - } - - if ( _currentFramebuffer !== framebuffer ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _currentFramebuffer = framebuffer; - - } - - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); - - state.viewport( _currentViewport ); - - if ( isCube ) { - - var textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); - - } - - }; - - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { - - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; - - } - - var framebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( framebuffer ) { - - var restore = false; - - if ( framebuffer !== _currentFramebuffer ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - - restore = true; - - } - - try { - - var texture = renderTarget.texture; - var textureFormat = texture.format; - var textureType = texture.type; - - if ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; - - } - - if ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; - - } - - if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - - _gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer ); - - } - - } else { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - - } - - } finally { - - if ( restore ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - - } - - } - - } - - }; - - // Map three.js constants to WebGL constants - - function paramThreeToGL( p ) { - - var extension; - - if ( p === RepeatWrapping ) return _gl.REPEAT; - if ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; - if ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; - - if ( p === NearestFilter ) return _gl.NEAREST; - if ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; - if ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; - - if ( p === LinearFilter ) return _gl.LINEAR; - if ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; - if ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; - - if ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE; - if ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; - if ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; - - if ( p === ByteType ) return _gl.BYTE; - if ( p === ShortType ) return _gl.SHORT; - if ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT; - if ( p === IntType ) return _gl.INT; - if ( p === UnsignedIntType ) return _gl.UNSIGNED_INT; - if ( p === FloatType ) return _gl.FLOAT; - - if ( p === HalfFloatType ) { - - extension = extensions.get( 'OES_texture_half_float' ); - - if ( extension !== null ) return extension.HALF_FLOAT_OES; - - } - - if ( p === AlphaFormat ) return _gl.ALPHA; - if ( p === RGBFormat ) return _gl.RGB; - if ( p === RGBAFormat ) return _gl.RGBA; - if ( p === LuminanceFormat ) return _gl.LUMINANCE; - if ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; - if ( p === DepthFormat ) return _gl.DEPTH_COMPONENT; - if ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL; - - if ( p === AddEquation ) return _gl.FUNC_ADD; - if ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT; - if ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; - - if ( p === ZeroFactor ) return _gl.ZERO; - if ( p === OneFactor ) return _gl.ONE; - if ( p === SrcColorFactor ) return _gl.SRC_COLOR; - if ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; - if ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA; - if ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; - if ( p === DstAlphaFactor ) return _gl.DST_ALPHA; - if ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; - - if ( p === DstColorFactor ) return _gl.DST_COLOR; - if ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; - if ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; - - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || - p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } - - } - - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || - p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - if ( extension !== null ) { - - if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - - } - - } - - if ( p === RGB_ETC1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - - if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; - - } - - if ( p === MinEquation || p === MaxEquation ) { - - extension = extensions.get( 'EXT_blend_minmax' ); - - if ( extension !== null ) { - - if ( p === MinEquation ) return extension.MIN_EXT; - if ( p === MaxEquation ) return extension.MAX_EXT; - - } - - } - - if ( p === UnsignedInt248Type ) { - - extension = extensions.get( 'WEBGL_depth_texture' ); - - if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; - - } - - return 0; - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function FogExp2 ( color, density ) { - - this.name = ''; - - this.color = new Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; - -} - -FogExp2.prototype.isFogExp2 = true; - -FogExp2.prototype.clone = function () { - - return new FogExp2( this.color.getHex(), this.density ); - -}; - -FogExp2.prototype.toJSON = function ( meta ) { - - return { - type: 'FogExp2', - color: this.color.getHex(), - density: this.density - }; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function Fog ( color, near, far ) { - - this.name = ''; - - this.color = new Color( color ); - - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; - -} - -Fog.prototype.isFog = true; - -Fog.prototype.clone = function () { - - return new Fog( this.color.getHex(), this.near, this.far ); - -}; - -Fog.prototype.toJSON = function ( meta ) { - - return { - type: 'Fog', - color: this.color.getHex(), - near: this.near, - far: this.far - }; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function Scene () { - - Object3D.call( this ); - - this.type = 'Scene'; - - this.background = null; - this.fog = null; - this.overrideMaterial = null; - - this.autoUpdate = true; // checked by the renderer - -} - -Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Scene, - - copy: function ( source, recursive ) { - - Object3D.prototype.copy.call( this, source, recursive ); - - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - - this.autoUpdate = source.autoUpdate; - this.matrixAutoUpdate = source.matrixAutoUpdate; - - return this; - - }, - - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); - - if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - - return data; - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -function LensFlare( texture, size, distance, blending, color ) { - - Object3D.call( this ); - - this.lensFlares = []; - - this.positionScreen = new Vector3(); - this.customUpdateCallback = undefined; - - if ( texture !== undefined ) { - - this.add( texture, size, distance, blending, color ); - - } - -} - -LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: LensFlare, - - isLensFlare: true, - - copy: function ( source ) { - - Object3D.prototype.copy.call( this, source ); - - this.positionScreen.copy( source.positionScreen ); - this.customUpdateCallback = source.customUpdateCallback; - - for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { - - this.lensFlares.push( source.lensFlares[ i ] ); - - } - - return this; - - }, - - add: function ( texture, size, distance, blending, color, opacity ) { - - if ( size === undefined ) size = - 1; - if ( distance === undefined ) distance = 0; - if ( opacity === undefined ) opacity = 1; - if ( color === undefined ) color = new Color( 0xffffff ); - if ( blending === undefined ) blending = NormalBlending; - - distance = Math.min( distance, Math.max( 0, distance ) ); - - this.lensFlares.push( { - texture: texture, // THREE.Texture - size: size, // size in pixels (-1 = use texture.width) - distance: distance, // distance (0-1) from light source (0=at light source) - x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back - scale: 1, // scale - rotation: 0, // rotation - opacity: opacity, // opacity - color: color, // color - blending: blending // blending - } ); - - }, - - /* - * Update lens flares update positions on all flares based on the screen position - * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. - */ - - updateLensFlares: function () { - - var f, fl = this.lensFlares.length; - var flare; - var vecX = - this.positionScreen.x * 2; - var vecY = - this.positionScreen.y * 2; - - for ( f = 0; f < fl; f ++ ) { - - flare = this.lensFlares[ f ]; - - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; - - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - - } - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2() - * } - */ - -function SpriteMaterial( parameters ) { - - Material.call( this ); - - this.type = 'SpriteMaterial'; - - this.color = new Color( 0xffffff ); - this.map = null; - - this.rotation = 0; - - this.fog = false; - this.lights = false; - - this.setValues( parameters ); - -} - -SpriteMaterial.prototype = Object.create( Material.prototype ); -SpriteMaterial.prototype.constructor = SpriteMaterial; -SpriteMaterial.prototype.isSpriteMaterial = true; - -SpriteMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - this.map = source.map; - - this.rotation = source.rotation; - - return this; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -function Sprite( material ) { - - Object3D.call( this ); - - this.type = 'Sprite'; - - this.material = ( material !== undefined ) ? material : new SpriteMaterial(); - -} - -Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Sprite, - - isSprite: true, - - raycast: ( function () { - - var intersectPoint = new Vector3(); - var worldPosition = new Vector3(); - var worldScale = new Vector3(); - - return function raycast( raycaster, intersects ) { - - worldPosition.setFromMatrixPosition( this.matrixWorld ); - raycaster.ray.closestPointToPoint( worldPosition, intersectPoint ); - - worldScale.setFromMatrixScale( this.matrixWorld ); - var guessSizeSq = worldScale.x * worldScale.y / 4; - - if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return; - - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - point: intersectPoint.clone(), - face: null, - object: this - - } ); - - }; - - }() ), - - clone: function () { - - return new this.constructor( this.material ).copy( this ); - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -function LOD() { - - Object3D.call( this ); - - this.type = 'LOD'; - - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - } - } ); - -} - -LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: LOD, - - copy: function ( source ) { - - Object3D.prototype.copy.call( this, source, false ); - - var levels = source.levels; - - for ( var i = 0, l = levels.length; i < l; i ++ ) { - - var level = levels[ i ]; - - this.addLevel( level.object.clone(), level.distance ); - - } - - return this; - - }, - - addLevel: function ( object, distance ) { - - if ( distance === undefined ) distance = 0; - - distance = Math.abs( distance ); - - var levels = this.levels; - - for ( var l = 0; l < levels.length; l ++ ) { - - if ( distance < levels[ l ].distance ) { - - break; - - } - - } - - levels.splice( l, 0, { distance: distance, object: object } ); - - this.add( object ); - - }, - - getObjectForDistance: function ( distance ) { - - var levels = this.levels; - - for ( var i = 1, l = levels.length; i < l; i ++ ) { - - if ( distance < levels[ i ].distance ) { - - break; - - } - - } - - return levels[ i - 1 ].object; - - }, - - raycast: ( function () { - - var matrixPosition = new Vector3(); - - return function raycast( raycaster, intersects ) { - - matrixPosition.setFromMatrixPosition( this.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - - }; - - }() ), - - update: function () { - - var v1 = new Vector3(); - var v2 = new Vector3(); - - return function update( camera ) { - - var levels = this.levels; - - if ( levels.length > 1 ) { - - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); - - var distance = v1.distanceTo( v2 ); - - levels[ 0 ].object.visible = true; - - for ( var i = 1, l = levels.length; i < l; i ++ ) { - - if ( distance >= levels[ i ].distance ) { - - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; - - } else { - - break; - - } - - } - - for ( ; i < l; i ++ ) { - - levels[ i ].object.visible = false; - - } - - } - - }; - - }(), - - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); - - data.object.levels = []; - - var levels = this.levels; - - for ( var i = 0, l = levels.length; i < l; i ++ ) { - - var level = levels[ i ]; - - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance - } ); - - } - - return data; - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author michael guerrero / http://realitymeltdown.com - * @author ikerr / http://verold.com - */ - -function Skeleton( bones, boneInverses ) { - - // copy the bone array - - bones = bones || []; - - this.bones = bones.slice( 0 ); - this.boneMatrices = new Float32Array( this.bones.length * 16 ); - - // use the supplied bone inverses or calculate the inverses - - if ( boneInverses === undefined ) { - - this.calculateInverses(); - - } else { - - if ( this.bones.length === boneInverses.length ) { - - this.boneInverses = boneInverses.slice( 0 ); - - } else { - - console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); - - this.boneInverses = []; - - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - - this.boneInverses.push( new Matrix4() ); - - } - - } - - } - -} - -Object.assign( Skeleton.prototype, { - - calculateInverses: function () { - - this.boneInverses = []; - - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - - var inverse = new Matrix4(); - - if ( this.bones[ i ] ) { - - inverse.getInverse( this.bones[ i ].matrixWorld ); - - } - - this.boneInverses.push( inverse ); - - } - - }, - - pose: function () { - - var bone, i, il; - - // recover the bind-time world matrices - - for ( i = 0, il = this.bones.length; i < il; i ++ ) { - - bone = this.bones[ i ]; - - if ( bone ) { - - bone.matrixWorld.getInverse( this.boneInverses[ i ] ); - - } - - } - - // compute the local matrices, positions, rotations and scales - - for ( i = 0, il = this.bones.length; i < il; i ++ ) { - - bone = this.bones[ i ]; - - if ( bone ) { - - if ( bone.parent && bone.parent.isBone ) { - - bone.matrix.getInverse( bone.parent.matrixWorld ); - bone.matrix.multiply( bone.matrixWorld ); - - } else { - - bone.matrix.copy( bone.matrixWorld ); - - } - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - } - - } - - }, - - update: ( function () { - - var offsetMatrix = new Matrix4(); - var identityMatrix = new Matrix4(); - - return function update() { - - var bones = this.bones; - var boneInverses = this.boneInverses; - var boneMatrices = this.boneMatrices; - var boneTexture = this.boneTexture; - - // flatten bone matrices to array - - for ( var i = 0, il = bones.length; i < il; i ++ ) { - - // compute the offset between the current and the original transform - - var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix; - - offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - offsetMatrix.toArray( boneMatrices, i * 16 ); - - } - - if ( boneTexture !== undefined ) { - - boneTexture.needsUpdate = true; - - } - - }; - - } )(), - - clone: function () { - - return new Skeleton( this.bones, this.boneInverses ); - - } - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ - -function Bone() { - - Object3D.call( this ); - - this.type = 'Bone'; - -} - -Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Bone, - - isBone: true - -} ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ - -function SkinnedMesh( geometry, material ) { - - Mesh.call( this, geometry, material ); - - this.type = 'SkinnedMesh'; - - this.bindMode = 'attached'; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); - - var bones = this.initBones(); - var skeleton = new Skeleton( bones ); - - this.bind( skeleton, this.matrixWorld ); - - this.normalizeSkinWeights(); - -} - -SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { - - constructor: SkinnedMesh, - - isSkinnedMesh: true, - - initBones: function () { - - var bones = [], bone, gbone; - var i, il; - - if ( this.geometry && this.geometry.bones !== undefined ) { - - // first, create array of 'Bone' objects from geometry data - - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { - - gbone = this.geometry.bones[ i ]; - - // create new 'Bone' object - - bone = new Bone(); - bones.push( bone ); - - // apply values - - bone.name = gbone.name; - bone.position.fromArray( gbone.pos ); - bone.quaternion.fromArray( gbone.rotq ); - if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); - - } - - // second, create bone hierarchy - - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { - - gbone = this.geometry.bones[ i ]; - - if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) { - - // subsequent bones in the hierarchy - - bones[ gbone.parent ].add( bones[ i ] ); - - } else { - - // topmost bone, immediate child of the skinned mesh - - this.add( bones[ i ] ); - - } - - } - - } - - // now the bones are part of the scene graph and children of the skinned mesh. - // let's update the corresponding matrices - - this.updateMatrixWorld( true ); - - return bones; - - }, - - bind: function ( skeleton, bindMatrix ) { - - this.skeleton = skeleton; - - if ( bindMatrix === undefined ) { - - this.updateMatrixWorld( true ); - - this.skeleton.calculateInverses(); - - bindMatrix = this.matrixWorld; - - } - - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.getInverse( bindMatrix ); - - }, - - pose: function () { - - this.skeleton.pose(); - - }, - - normalizeSkinWeights: function () { - - var scale, i; - - if ( this.geometry && this.geometry.isGeometry ) { - - for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) { - - var sw = this.geometry.skinWeights[ i ]; - - scale = 1.0 / sw.lengthManhattan(); - - if ( scale !== Infinity ) { - - sw.multiplyScalar( scale ); - - } else { - - sw.set( 1, 0, 0, 0 ); // do something reasonable - - } - - } - - } else if ( this.geometry && this.geometry.isBufferGeometry ) { - - var vec = new Vector4(); - - var skinWeight = this.geometry.attributes.skinWeight; - - for ( i = 0; i < skinWeight.count; i ++ ) { - - vec.x = skinWeight.getX( i ); - vec.y = skinWeight.getY( i ); - vec.z = skinWeight.getZ( i ); - vec.w = skinWeight.getW( i ); - - scale = 1.0 / vec.lengthManhattan(); - - if ( scale !== Infinity ) { - - vec.multiplyScalar( scale ); - - } else { - - vec.set( 1, 0, 0, 0 ); // do something reasonable - - } - - skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w ); - - } - - } - - }, - - updateMatrixWorld: function ( force ) { - - Mesh.prototype.updateMatrixWorld.call( this, force ); - - if ( this.bindMode === 'attached' ) { - - this.bindMatrixInverse.getInverse( this.matrixWorld ); - - } else if ( this.bindMode === 'detached' ) { - - this.bindMatrixInverse.getInverse( this.bindMatrix ); - - } else { - - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - - } - - }, - - clone: function () { - - return new this.constructor( this.geometry, this.material ).copy( this ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round" - * } - */ - -function LineBasicMaterial( parameters ) { - - Material.call( this ); - - this.type = 'LineBasicMaterial'; - - this.color = new Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.lights = false; - - this.setValues( parameters ); - -} - -LineBasicMaterial.prototype = Object.create( Material.prototype ); -LineBasicMaterial.prototype.constructor = LineBasicMaterial; - -LineBasicMaterial.prototype.isLineBasicMaterial = true; - -LineBasicMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; - - return this; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function Line( geometry, material, mode ) { - - if ( mode === 1 ) { - - console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); - return new LineSegments( geometry, material ); - - } - - Object3D.call( this ); - - this.type = 'Line'; - - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); - -} - -Line.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Line, - - isLine: true, - - raycast: ( function () { - - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); - - return function raycast( raycaster, intersects ) { - - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; - - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; - - // - - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - var vStart = new Vector3(); - var vEnd = new Vector3(); - var interSegment = new Vector3(); - var interRay = new Vector3(); - var step = (this && this.isLineSegments) ? 2 : 1; - - if ( geometry.isBufferGeometry ) { - - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; - - if ( index !== null ) { - - var indices = index.array; - - for ( var i = 0, l = indices.length - 1; i < l; i += step ) { - - var a = indices[ i ]; - var b = indices[ i + 1 ]; - - vStart.fromArray( positions, a * 3 ); - vEnd.fromArray( positions, b * 3 ); - - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > precisionSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - var distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } else { - - for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { - - vStart.fromArray( positions, 3 * i ); - vEnd.fromArray( positions, 3 * i + 3 ); - - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > precisionSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - var distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - } else if ( geometry.isGeometry ) { - - var vertices = geometry.vertices; - var nbVertices = vertices.length; - - for ( var i = 0; i < nbVertices - 1; i += step ) { - - var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - - if ( distSq > precisionSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - var distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - }; - - }() ), - - clone: function () { - - return new this.constructor( this.geometry, this.material ).copy( this ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function LineSegments( geometry, material ) { - - Line.call( this, geometry, material ); - - this.type = 'LineSegments'; - -} - -LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { - - constructor: LineSegments, - - isLineSegments: true - -} ); - -/** - * @author mgreter / http://github.com/mgreter - */ - -function LineLoop( geometry, material ) { - - Line.call( this, geometry, material ); - - this.type = 'LineLoop'; - -} - -LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { - - constructor: LineLoop, - - isLineLoop: true, - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * sizeAttenuation: - * } - */ - -function PointsMaterial( parameters ) { - - Material.call( this ); - - this.type = 'PointsMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.lights = false; - - this.setValues( parameters ); - -} - -PointsMaterial.prototype = Object.create( Material.prototype ); -PointsMaterial.prototype.constructor = PointsMaterial; - -PointsMaterial.prototype.isPointsMaterial = true; - -PointsMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; - - return this; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function Points( geometry, material ) { - - Object3D.call( this ); - - this.type = 'Points'; - - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); - -} - -Points.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Points, - - isPoints: true, - - raycast: ( function () { - - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); - - return function raycast( raycaster, intersects ) { - - var object = this; - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; - var threshold = raycaster.params.Points.threshold; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - sphere.radius += threshold; - - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; - - // - - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var localThresholdSq = localThreshold * localThreshold; - var position = new Vector3(); - - function testPoint( point, index ) { - - var rayPointDistanceSq = ray.distanceSqToPoint( point ); - - if ( rayPointDistanceSq < localThresholdSq ) { - - var intersectPoint = ray.closestPointToPoint( point ); - intersectPoint.applyMatrix4( matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint.clone(), - index: index, - face: null, - object: object - - } ); - - } - - } - - if ( geometry.isBufferGeometry ) { - - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; - - if ( index !== null ) { - - var indices = index.array; - - for ( var i = 0, il = indices.length; i < il; i ++ ) { - - var a = indices[ i ]; - - position.fromArray( positions, a * 3 ); - - testPoint( position, a ); - - } - - } else { - - for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { - - position.fromArray( positions, i * 3 ); - - testPoint( position, i ); - - } - - } - - } else { - - var vertices = geometry.vertices; - - for ( var i = 0, l = vertices.length; i < l; i ++ ) { - - testPoint( vertices[ i ], i ); - - } - - } - - }; - - }() ), - - clone: function () { - - return new this.constructor( this.geometry, this.material ).copy( this ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function Group() { - - Object3D.call( this ); - - this.type = 'Group'; - -} - -Group.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Group - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - this.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - this.generateMipmaps = false; - -} - -CompressedTexture.prototype = Object.create( Texture.prototype ); -CompressedTexture.prototype.constructor = CompressedTexture; - -CompressedTexture.prototype.isCompressedTexture = true; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.needsUpdate = true; - -} - -CanvasTexture.prototype = Object.create( Texture.prototype ); -CanvasTexture.prototype.constructor = CanvasTexture; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -function WireframeGeometry( geometry ) { - - BufferGeometry.call( this ); - - this.type = 'WireframeGeometry'; - - // buffer - - var vertices = []; - - // helper variables - - var i, j, l, o, ol; - var edge = [ 0, 0 ], edges = {}, e, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; - var vertex; - - // different logic for Geometry and BufferGeometry - - if ( geometry && geometry.isGeometry ) { - - // create a data structure that contains all edges without duplicates - - var faces = geometry.faces; - - for ( i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( j = 0; j < 3; j ++ ) { - - edge1 = face[ keys[ j ] ]; - edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; - edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates - edge[ 1 ] = Math.max( edge1, edge2 ); - - key = edge[ 0 ] + ',' + edge[ 1 ]; - - if ( edges[ key ] === undefined ) { - - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; - - } - - } - - } - - // generate vertices - - for ( key in edges ) { - - e = edges[ key ]; - - vertex = geometry.vertices[ e.index1 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); - - vertex = geometry.vertices[ e.index2 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } else if ( geometry && geometry.isBufferGeometry ) { - - var position, indices, groups; - var group, start, count; - var index1, index2; - - vertex = new Vector3(); - - if ( geometry.index !== null ) { - - // indexed BufferGeometry - - position = geometry.attributes.position; - indices = geometry.index; - groups = geometry.groups; - - if ( groups.length === 0 ) { - - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - - } - - // create a data structure that contains all eges without duplicates - - for ( o = 0, ol = groups.length; o < ol; ++ o ) { - - group = groups[ o ]; - - start = group.start; - count = group.count; - - for ( i = start, l = ( start + count ); i < l; i += 3 ) { - - for ( j = 0; j < 3; j ++ ) { - - edge1 = indices.getX( i + j ); - edge2 = indices.getX( i + ( j + 1 ) % 3 ); - edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates - edge[ 1 ] = Math.max( edge1, edge2 ); - - key = edge[ 0 ] + ',' + edge[ 1 ]; - - if ( edges[ key ] === undefined ) { - - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; - - } - - } - - } - - } - - // generate vertices - - for ( key in edges ) { - - e = edges[ key ]; - - vertex.fromBufferAttribute( position, e.index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); - - vertex.fromBufferAttribute( position, e.index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } else { - - // non-indexed BufferGeometry - - position = geometry.attributes.position; - - for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - - for ( j = 0; j < 3; j ++ ) { - - // three edges per triangle, an edge is represented as (index1, index2) - // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - - index1 = 3 * i + j; - vertex.fromBufferAttribute( position, index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); - - index2 = 3 * i + ( ( j + 1 ) % 3 ); - vertex.fromBufferAttribute( position, index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - } - - } - - // build geometry - - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - -} - -WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); -WireframeGeometry.prototype.constructor = WireframeGeometry; - -/** - * @author zz85 / https://github.com/zz85 - * @author Mugen87 / https://github.com/Mugen87 - * - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - */ - -// ParametricGeometry - -function ParametricGeometry( func, slices, stacks ) { - - Geometry.call( this ); - - this.type = 'ParametricGeometry'; - - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; - - this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); - this.mergeVertices(); - -} - -ParametricGeometry.prototype = Object.create( Geometry.prototype ); -ParametricGeometry.prototype.constructor = ParametricGeometry; - -// ParametricBufferGeometry - -function ParametricBufferGeometry( func, slices, stacks ) { - - BufferGeometry.call( this ); - - this.type = 'ParametricBufferGeometry'; - - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - var EPS = 0.00001; - - var normal = new Vector3(); - - var p0 = new Vector3(), p1 = new Vector3(); - var pu = new Vector3(), pv = new Vector3(); - - var i, j; - - // generate vertices, normals and uvs - - var sliceCount = slices + 1; - - for ( i = 0; i <= stacks; i ++ ) { - - var v = i / stacks; - - for ( j = 0; j <= slices; j ++ ) { - - var u = j / slices; - - // vertex - - p0 = func( u, v, p0 ); - vertices.push( p0.x, p0.y, p0.z ); - - // normal - - // approximate tangent vectors via finite differences - - if ( u - EPS >= 0 ) { - - p1 = func( u - EPS, v, p1 ); - pu.subVectors( p0, p1 ); - - } else { - - p1 = func( u + EPS, v, p1 ); - pu.subVectors( p1, p0 ); - - } - - if ( v - EPS >= 0 ) { - - p1 = func( u, v - EPS, p1 ); - pv.subVectors( p0, p1 ); - - } else { - - p1 = func( u, v + EPS, p1 ); - pv.subVectors( p1, p0 ); - - } - - // cross product of tangent vectors returns surface normal - - normal.crossVectors( pu, pv ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, v ); - - } - - } - - // generate indices - - for ( i = 0; i < stacks; i ++ ) { - - for ( j = 0; j < slices; j ++ ) { - - var a = i * sliceCount + j; - var b = i * sliceCount + j + 1; - var c = ( i + 1 ) * sliceCount + j + 1; - var d = ( i + 1 ) * sliceCount + j; - - // faces one and two - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; - -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ - -// PolyhedronGeometry - -function PolyhedronGeometry( vertices, indices, radius, detail ) { - - Geometry.call( this ); - - this.type = 'PolyhedronGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); - this.mergeVertices(); - -} - -PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); -PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; - -// PolyhedronBufferGeometry - -function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { - - BufferGeometry.call( this ); - - this.type = 'PolyhedronBufferGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - radius = radius || 1; - detail = detail || 0; - - // default buffer data - - var vertexBuffer = []; - var uvBuffer = []; - - // the subdivision creates the vertex buffer data - - subdivide( detail ); - - // all vertices should lie on a conceptual sphere with a given radius - - appplyRadius( radius ); - - // finally, create the uv data - - generateUVs(); - - // build non-indexed geometry - - this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - - if ( detail === 0 ) { - - this.computeVertexNormals(); // flat normals - - } else { - - this.normalizeNormals(); // smooth normals - - } - - // helper functions - - function subdivide( detail ) { - - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); - - // iterate over all faces and apply a subdivison with the given detail value - - for ( var i = 0; i < indices.length; i += 3 ) { - - // get the vertices of the face - - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); - - // perform subdivision - - subdivideFace( a, b, c, detail ); - - } - - } - - function subdivideFace( a, b, c, detail ) { - - var cols = Math.pow( 2, detail ); - - // we use this multidimensional array as a data structure for creating the subdivision - - var v = []; - - var i, j; - - // construct all of the vertices for this subdivision - - for ( i = 0; i <= cols; i ++ ) { - - v[ i ] = []; - - var aj = a.clone().lerp( c, i / cols ); - var bj = b.clone().lerp( c, i / cols ); - - var rows = cols - i; - - for ( j = 0; j <= rows; j ++ ) { - - if ( j === 0 && i === cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - - } - - } - - } - - // construct all of the faces - - for ( i = 0; i < cols; i ++ ) { - - for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - - var k = Math.floor( j / 2 ); - - if ( j % 2 === 0 ) { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); - - } else { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - - } - - } - - } - - } - - function appplyRadius( radius ) { - - var vertex = new Vector3(); - - // iterate over the entire buffer and apply the radius to each vertex - - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - vertex.normalize().multiplyScalar( radius ); - - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; - - } - - } - - function generateUVs() { - - var vertex = new Vector3(); - - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - var u = azimuth( vertex ) / 2 / Math.PI + 0.5; - var v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); - - } - - correctUVs(); - - correctSeam(); - - } - - function correctSeam() { - - // handle case when face straddles the seam, see #3269 - - for ( var i = 0; i < uvBuffer.length; i += 6 ) { - - // uv data of a single face - - var x0 = uvBuffer[ i + 0 ]; - var x1 = uvBuffer[ i + 2 ]; - var x2 = uvBuffer[ i + 4 ]; - - var max = Math.max( x0, x1, x2 ); - var min = Math.min( x0, x1, x2 ); - - // 0.9 is somewhat arbitrary - - if ( max > 0.9 && min < 0.1 ) { - - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - - } - - } - - } - - function pushVertex( vertex ) { - - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - - } - - function getVertexByIndex( index, vertex ) { - - var stride = index * 3; - - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; - - } - - function correctUVs() { - - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); - - var centroid = new Vector3(); - - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); - - for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); - - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - - var azi = azimuth( centroid ); - - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); - - } - - } - - function correctUV( uv, stride, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - - uvBuffer[ stride ] = uv.x - 1; - - } - - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - - } - - } - - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { - - return Math.atan2( vector.z, - vector.x ); - - } - - - // Angle above the XZ plane. - - function inclination( vector ) { - - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - - } - -} - -PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; - -/** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ - -// TetrahedronGeometry - -function TetrahedronGeometry( radius, detail ) { - - Geometry.call( this ); - - this.type = 'TetrahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); - -} - -TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); -TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; - -// TetrahedronBufferGeometry - -function TetrahedronBufferGeometry( radius, detail ) { - - var vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; - - var indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; - - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'TetrahedronBufferGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - -} - -TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; - -/** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ - -// OctahedronGeometry - -function OctahedronGeometry( radius, detail ) { - - Geometry.call( this ); - - this.type = 'OctahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); - -} - -OctahedronGeometry.prototype = Object.create( Geometry.prototype ); -OctahedronGeometry.prototype.constructor = OctahedronGeometry; - -// OctahedronBufferGeometry - -function OctahedronBufferGeometry( radius, detail ) { - - var vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; - - var indices = [ - 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2 - ]; - - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'OctahedronBufferGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - -} - -OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; - -/** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ - -// IcosahedronGeometry - -function IcosahedronGeometry( radius, detail ) { - - Geometry.call( this ); - - this.type = 'IcosahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); - -} - -IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); -IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; - -// IcosahedronBufferGeometry - -function IcosahedronBufferGeometry( radius, detail ) { - - var t = ( 1 + Math.sqrt( 5 ) ) / 2; - - var vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; - - var indices = [ - 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, - 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, - 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, - 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 - ]; - - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'IcosahedronBufferGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - -} - -IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; - -/** - * @author Abe Pazos / https://hamoid.com - * @author Mugen87 / https://github.com/Mugen87 - */ - -// DodecahedronGeometry - -function DodecahedronGeometry( radius, detail ) { - - Geometry.call( this ); - - this.type = 'DodecahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); - -} - -DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); -DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; - -// DodecahedronBufferGeometry - -function DodecahedronBufferGeometry( radius, detail ) { - - var t = ( 1 + Math.sqrt( 5 ) ) / 2; - var r = 1 / t; - - var vertices = [ - - // (±1, ±1, ±1) - - 1, - 1, - 1, - 1, - 1, 1, - - 1, 1, - 1, - 1, 1, 1, - 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, 1, 1, 1, - - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, - - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, - - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; - - var indices = [ - 3, 11, 7, 3, 7, 15, 3, 15, 13, - 7, 19, 17, 7, 17, 6, 7, 6, 15, - 17, 4, 8, 17, 8, 10, 17, 10, 6, - 8, 0, 16, 8, 16, 2, 8, 2, 10, - 0, 12, 1, 0, 1, 18, 0, 18, 16, - 6, 10, 2, 6, 2, 13, 6, 13, 15, - 2, 16, 18, 2, 18, 3, 2, 3, 13, - 18, 1, 9, 18, 9, 11, 18, 11, 3, - 4, 14, 12, 4, 12, 0, 4, 0, 8, - 11, 9, 5, 11, 5, 19, 11, 19, 7, - 19, 5, 14, 19, 14, 4, 19, 4, 17, - 1, 12, 14, 1, 14, 5, 1, 5, 9 - ]; - - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - - this.type = 'DodecahedronBufferGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - -} - -DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; - -/** - * @author oosmoxiecode / https://github.com/oosmoxiecode - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * @author jonobr1 / https://github.com/jonobr1 - * @author Mugen87 / https://github.com/Mugen87 - * - */ - -// TubeGeometry - -function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { - - Geometry.call( this ); - - this.type = 'TubeGeometry'; - - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); - - var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); - - // expose internals - - this.tangents = bufferGeometry.tangents; - this.normals = bufferGeometry.normals; - this.binormals = bufferGeometry.binormals; - - // create geometry - - this.fromBufferGeometry( bufferGeometry ); - this.mergeVertices(); - -} - -TubeGeometry.prototype = Object.create( Geometry.prototype ); -TubeGeometry.prototype.constructor = TubeGeometry; - -// TubeBufferGeometry - -function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { - - BufferGeometry.call( this ); - - this.type = 'TubeBufferGeometry'; - - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - tubularSegments = tubularSegments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; - - var frames = path.computeFrenetFrames( tubularSegments, closed ); - - // expose internals - - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; - - // helper variables - - var vertex = new Vector3(); - var normal = new Vector3(); - var uv = new Vector2(); - - var i, j; - - // buffer - - var vertices = []; - var normals = []; - var uvs = []; - var indices = []; - - // create buffer data - - generateBufferData(); - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // functions - - function generateBufferData() { - - for ( i = 0; i < tubularSegments; i ++ ) { - - generateSegment( i ); - - } - - // if the geometry is not closed, generate the last row of vertices and normals - // at the regular position on the given path - // - // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) - - generateSegment( ( closed === false ) ? tubularSegments : 0 ); - - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries - - generateUVs(); - - // finally create faces - - generateIndices(); - - } - - function generateSegment( i ) { - - // we use getPointAt to sample evenly distributed points from the given path - - var P = path.getPointAt( i / tubularSegments ); - - // retrieve corresponding normal and binormal - - var N = frames.normals[ i ]; - var B = frames.binormals[ i ]; - - // generate normals and vertices for the current segment - - for ( j = 0; j <= radialSegments; j ++ ) { - - var v = j / radialSegments * Math.PI * 2; - - var sin = Math.sin( v ); - var cos = - Math.cos( v ); - - // normal - - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // vertex - - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - function generateIndices() { - - for ( j = 1; j <= tubularSegments; j ++ ) { - - for ( i = 1; i <= radialSegments; i ++ ) { - - var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - var b = ( radialSegments + 1 ) * j + ( i - 1 ); - var c = ( radialSegments + 1 ) * j + i; - var d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - } - - function generateUVs() { - - for ( i = 0; i <= tubularSegments; i ++ ) { - - for ( j = 0; j <= radialSegments; j ++ ) { - - uv.x = i / tubularSegments; - uv.y = j / radialSegments; - - uvs.push( uv.x, uv.y ); - - } - - } - - } - -} - -TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; - -/** - * @author oosmoxiecode - * @author Mugen87 / https://github.com/Mugen87 - * - * based on http://www.blackpawn.com/texts/pqtorus/ - */ - -// TorusKnotGeometry - -function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { - - Geometry.call( this ); - - this.type = 'TorusKnotGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; - - if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); - - this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); - this.mergeVertices(); - -} - -TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); -TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; - -// TorusKnotBufferGeometry - -function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { - - BufferGeometry.call( this ); - - this.type = 'TorusKnotBufferGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; - - radius = radius || 100; - tube = tube || 40; - tubularSegments = Math.floor( tubularSegments ) || 64; - radialSegments = Math.floor( radialSegments ) || 8; - p = p || 2; - q = q || 3; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var i, j; - - var vertex = new Vector3(); - var normal = new Vector3(); - - var P1 = new Vector3(); - var P2 = new Vector3(); - - var B = new Vector3(); - var T = new Vector3(); - var N = new Vector3(); - - // generate vertices, normals and uvs - - for ( i = 0; i <= tubularSegments; ++ i ) { - - // the radian "u" is used to calculate the position on the torus curve of the current tubular segement - - var u = i / tubularSegments * p * Math.PI * 2; - - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions - - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - - // calculate orthonormal basis - - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); - - // normalize B, N. T can be ignored, we don't use it - - B.normalize(); - N.normalize(); - - for ( j = 0; j <= radialSegments; ++ j ) { - - // now calculate the vertices. they are nothing more than an extrusion of the torus curve. - // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. - - var v = j / radialSegments * Math.PI * 2; - var cx = - tube * Math.cos( v ); - var cy = tube * Math.sin( v ); - - // now calculate the final vertex position. - // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve - - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - - normal.subVectors( vertex, P1 ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( j = 1; j <= tubularSegments; j ++ ) { - - for ( i = 1; i <= radialSegments; i ++ ) { - - // indices - - var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - var b = ( radialSegments + 1 ) * j + ( i - 1 ); - var c = ( radialSegments + 1 ) * j + i; - var d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // this function calculates the current position on the torus curve - - function calculatePositionOnCurve( u, p, q, radius, position ) { - - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = q / p * u; - var cs = Math.cos( quOverP ); - - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; - - } - -} - -TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; - -/** - * @author oosmoxiecode - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// TorusGeometry - -function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { - - Geometry.call( this ); - - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); - this.mergeVertices(); - -} - -TorusGeometry.prototype = Object.create( Geometry.prototype ); -TorusGeometry.prototype.constructor = TorusGeometry; - -// TorusBufferGeometry - -function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { - - BufferGeometry.call( this ); - - this.type = 'TorusBufferGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radius = radius || 100; - tube = tube || 40; - radialSegments = Math.floor( radialSegments ) || 8; - tubularSegments = Math.floor( tubularSegments ) || 6; - arc = arc || Math.PI * 2; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var center = new Vector3(); - var vertex = new Vector3(); - var normal = new Vector3(); - - var j, i; - - // generate vertices, normals and uvs - - for ( j = 0; j <= radialSegments; j ++ ) { - - for ( i = 0; i <= tubularSegments; i ++ ) { - - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; - - // vertex - - vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = tube * Math.sin( v ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( j = 1; j <= radialSegments; j ++ ) { - - for ( i = 1; i <= tubularSegments; i ++ ) { - - // indices - - var a = ( tubularSegments + 1 ) * j + i - 1; - var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - var d = ( tubularSegments + 1 ) * j + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -var ShapeUtils = { - - // calculate area of the contour polygon - - area: function ( contour ) { - - var n = contour.length; - var a = 0.0; - - for ( var p = n - 1, q = 0; q < n; p = q ++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - }, - - triangulate: ( function () { - - /** - * This code is a quick port of code written in C++ which was submitted to - * flipcode.com by John W. Ratcliff // July 22, 2000 - * See original code and more information here: - * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml - * - * ported to actionscript by Zevan Rosser - * www.actionsnippet.com - * - * ported to javascript by Joshua Koo - * http://www.lab4games.net/zz85/blog - * - */ - - function snip( contour, u, v, w, n, verts ) { - - var p; - var ax, ay, bx, by; - var cx, cy, px, py; - - ax = contour[ verts[ u ] ].x; - ay = contour[ verts[ u ] ].y; - - bx = contour[ verts[ v ] ].x; - by = contour[ verts[ v ] ].y; - - cx = contour[ verts[ w ] ].x; - cy = contour[ verts[ w ] ].y; - - if ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false; - - var aX, aY, bX, bY, cX, cY; - var apx, apy, bpx, bpy, cpx, cpy; - var cCROSSap, bCROSScp, aCROSSbp; - - aX = cx - bx; aY = cy - by; - bX = ax - cx; bY = ay - cy; - cX = bx - ax; cY = by - ay; - - for ( p = 0; p < n; p ++ ) { - - px = contour[ verts[ p ] ].x; - py = contour[ verts[ p ] ].y; - - if ( ( ( px === ax ) && ( py === ay ) ) || - ( ( px === bx ) && ( py === by ) ) || - ( ( px === cx ) && ( py === cy ) ) ) continue; - - apx = px - ax; apy = py - ay; - bpx = px - bx; bpy = py - by; - cpx = px - cx; cpy = py - cy; - - // see if p is inside triangle abc - - aCROSSbp = aX * bpy - aY * bpx; - cCROSSap = cX * apy - cY * apx; - bCROSScp = bX * cpy - bY * cpx; - - if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false; - - } - - return true; - - } - - // takes in an contour array and returns - - return function triangulate( contour, indices ) { - - var n = contour.length; - - if ( n < 3 ) return null; - - var result = [], - verts = [], - vertIndices = []; - - /* we want a counter-clockwise polygon in verts */ - - var u, v, w; - - if ( ShapeUtils.area( contour ) > 0.0 ) { - - for ( v = 0; v < n; v ++ ) verts[ v ] = v; - - } else { - - for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; - - } - - var nv = n; - - /* remove nv - 2 vertices, creating 1 triangle every time */ - - var count = 2 * nv; /* error detection */ - - for ( v = nv - 1; nv > 2; ) { - - /* if we loop, it is probably a non-simple polygon */ - - if ( ( count -- ) <= 0 ) { - - //** Triangulate: ERROR - probable bad polygon! - - //throw ( "Warning, unable to triangulate polygon!" ); - //return null; - // Sometimes warning is fine, especially polygons are triangulated in reverse. - console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' ); - - if ( indices ) return vertIndices; - return result; - - } - - /* three consecutive vertices in current polygon, */ - - u = v; if ( nv <= u ) u = 0; /* previous */ - v = u + 1; if ( nv <= v ) v = 0; /* new v */ - w = v + 1; if ( nv <= w ) w = 0; /* next */ - - if ( snip( contour, u, v, w, nv, verts ) ) { - - var a, b, c, s, t; - - /* true names of the vertices */ - - a = verts[ u ]; - b = verts[ v ]; - c = verts[ w ]; - - /* output Triangle */ - - result.push( [ contour[ a ], - contour[ b ], - contour[ c ] ] ); - - - vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); - - /* remove v from the remaining polygon */ - - for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { - - verts[ s ] = verts[ t ]; - - } - - nv --; - - /* reset error detection counter */ - - count = 2 * nv; - - } - - } - - if ( indices ) return vertIndices; - return result; - - } - - } )(), - - triangulateShape: function ( contour, holes ) { - - function removeDupEndPts(points) { - - var l = points.length; - - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - - points.pop(); - - } - - } - - removeDupEndPts( contour ); - holes.forEach( removeDupEndPts ); - - function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { - - // inOtherPt needs to be collinear to the inSegment - if ( inSegPt1.x !== inSegPt2.x ) { - - if ( inSegPt1.x < inSegPt2.x ) { - - return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); - - } else { - - return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); - - } - - } else { - - if ( inSegPt1.y < inSegPt2.y ) { - - return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); - - } else { - - return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); - - } - - } - - } - - function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { - - var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; - var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; - - var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; - var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; - - var limit = seg1dy * seg2dx - seg1dx * seg2dy; - var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; - - if ( Math.abs( limit ) > Number.EPSILON ) { - - // not parallel - - var perpSeg2; - if ( limit > 0 ) { - - if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; - perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; - if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; - - } else { - - if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; - perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; - if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; - - } - - // i.e. to reduce rounding errors - // intersection at endpoint of segment#1? - if ( perpSeg2 === 0 ) { - - if ( ( inExcludeAdjacentSegs ) && - ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; - return [ inSeg1Pt1 ]; - - } - if ( perpSeg2 === limit ) { - - if ( ( inExcludeAdjacentSegs ) && - ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; - return [ inSeg1Pt2 ]; - - } - // intersection at endpoint of segment#2? - if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ]; - if ( perpSeg1 === limit ) return [ inSeg2Pt2 ]; - - // return real intersection point - var factorSeg1 = perpSeg2 / limit; - return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, - y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; - - } else { - - // parallel or collinear - if ( ( perpSeg1 !== 0 ) || - ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return []; - - // they are collinear or degenerate - var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point? - var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point? - // both segments are points - if ( seg1Pt && seg2Pt ) { - - if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) || - ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points - return [ inSeg1Pt1 ]; // they are the same point - - } - // segment#1 is a single point - if ( seg1Pt ) { - - if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 - return [ inSeg1Pt1 ]; - - } - // segment#2 is a single point - if ( seg2Pt ) { - - if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 - return [ inSeg2Pt1 ]; - - } - - // they are collinear segments, which might overlap - var seg1min, seg1max, seg1minVal, seg1maxVal; - var seg2min, seg2max, seg2minVal, seg2maxVal; - if ( seg1dx !== 0 ) { - - // the segments are NOT on a vertical line - if ( inSeg1Pt1.x < inSeg1Pt2.x ) { - - seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; - seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; - - } else { - - seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; - seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; - - } - if ( inSeg2Pt1.x < inSeg2Pt2.x ) { - - seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; - seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; - - } else { - - seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; - seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; - - } - - } else { - - // the segments are on a vertical line - if ( inSeg1Pt1.y < inSeg1Pt2.y ) { - - seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; - seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; - - } else { - - seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; - seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; - - } - if ( inSeg2Pt1.y < inSeg2Pt2.y ) { - - seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; - seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; - - } else { - - seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; - seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; - - } - - } - if ( seg1minVal <= seg2minVal ) { - - if ( seg1maxVal < seg2minVal ) return []; - if ( seg1maxVal === seg2minVal ) { - - if ( inExcludeAdjacentSegs ) return []; - return [ seg2min ]; - - } - if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; - return [ seg2min, seg2max ]; - - } else { - - if ( seg1minVal > seg2maxVal ) return []; - if ( seg1minVal === seg2maxVal ) { - - if ( inExcludeAdjacentSegs ) return []; - return [ seg1min ]; - - } - if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; - return [ seg1min, seg2max ]; - - } - - } - - } - - function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { - - // The order of legs is important - - // translation of all points, so that Vertex is at (0,0) - var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; - var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; - var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; - - // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. - var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; - var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - - if ( Math.abs( from2toAngle ) > Number.EPSILON ) { - - // angle != 180 deg. - - var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; - // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - - if ( from2toAngle > 0 ) { - - // main angle < 180 deg. - return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); - - } else { - - // main angle > 180 deg. - return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); - - } - - } else { - - // angle == 180 deg. - // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); - return ( from2otherAngle > 0 ); - - } - - } - - - function removeHoles( contour, holes ) { - - var shape = contour.concat(); // work on this shape - var hole; - - function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { - - // Check if hole point lies within angle around shape point - var lastShapeIdx = shape.length - 1; - - var prevShapeIdx = inShapeIdx - 1; - if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; - - var nextShapeIdx = inShapeIdx + 1; - if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; - - var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] ); - if ( ! insideAngle ) { - - // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); - return false; - - } - - // Check if shape point lies within angle around hole point - var lastHoleIdx = hole.length - 1; - - var prevHoleIdx = inHoleIdx - 1; - if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; - - var nextHoleIdx = inHoleIdx + 1; - if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; - - insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] ); - if ( ! insideAngle ) { - - // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); - return false; - - } - - return true; - - } - - function intersectsShapeEdge( inShapePt, inHolePt ) { - - // checks for intersections with shape edges - var sIdx, nextIdx, intersection; - for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { - - nextIdx = sIdx + 1; nextIdx %= shape.length; - intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true ); - if ( intersection.length > 0 ) return true; - - } - - return false; - - } - - var indepHoles = []; - - function intersectsHoleEdge( inShapePt, inHolePt ) { - - // checks for intersections with hole edges - var ihIdx, chkHole, - hIdx, nextIdx, intersection; - for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { - - chkHole = holes[ indepHoles[ ihIdx ]]; - for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { - - nextIdx = hIdx + 1; nextIdx %= chkHole.length; - intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true ); - if ( intersection.length > 0 ) return true; - - } - - } - return false; - - } - - var holeIndex, shapeIndex, - shapePt, holePt, - holeIdx, cutKey, failedCuts = [], - tmpShape1, tmpShape2, - tmpHole1, tmpHole2; - - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - - indepHoles.push( h ); - - } - - var minShapeIndex = 0; - var counter = indepHoles.length * 2; - while ( indepHoles.length > 0 ) { - - counter --; - if ( counter < 0 ) { - - console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); - break; - - } - - // search for shape-vertex and hole-vertex, - // which can be connected without intersections - for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { - - shapePt = shape[ shapeIndex ]; - holeIndex = - 1; - - // search for hole which can be reached without intersections - for ( var h = 0; h < indepHoles.length; h ++ ) { - - holeIdx = indepHoles[ h ]; - - // prevent multiple checks - cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; - if ( failedCuts[ cutKey ] !== undefined ) continue; - - hole = holes[ holeIdx ]; - for ( var h2 = 0; h2 < hole.length; h2 ++ ) { - - holePt = hole[ h2 ]; - if ( ! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; - if ( intersectsShapeEdge( shapePt, holePt ) ) continue; - if ( intersectsHoleEdge( shapePt, holePt ) ) continue; - - holeIndex = h2; - indepHoles.splice( h, 1 ); - - tmpShape1 = shape.slice( 0, shapeIndex + 1 ); - tmpShape2 = shape.slice( shapeIndex ); - tmpHole1 = hole.slice( holeIndex ); - tmpHole2 = hole.slice( 0, holeIndex + 1 ); - - shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); - - minShapeIndex = shapeIndex; - - // Debug only, to show the selected cuts - // glob_CutLines.push( [ shapePt, holePt ] ); - - break; - - } - if ( holeIndex >= 0 ) break; // hole-vertex found - - failedCuts[ cutKey ] = true; // remember failure - - } - if ( holeIndex >= 0 ) break; // hole-vertex found - - } - - } - - return shape; /* shape with no holes */ - - } - - - var i, il, f, face, - key, index, - allPointsMap = {}; - - // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. - - var allpoints = contour.concat(); - - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - - Array.prototype.push.apply( allpoints, holes[ h ] ); - - } - - //console.log( "allpoints",allpoints, allpoints.length ); - - // prepare all points map - - for ( i = 0, il = allpoints.length; i < il; i ++ ) { - - key = allpoints[ i ].x + ":" + allpoints[ i ].y; - - if ( allPointsMap[ key ] !== undefined ) { - - console.warn( "THREE.ShapeUtils: Duplicate point", key, i ); - - } - - allPointsMap[ key ] = i; - - } - - // remove holes by cutting paths to holes and adding them to the shape - var shapeWithoutHoles = removeHoles( contour, holes ); - - var triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape - //console.log( "triangles",triangles, triangles.length ); - - // check all face vertices against all points map - - for ( i = 0, il = triangles.length; i < il; i ++ ) { - - face = triangles[ i ]; - - for ( f = 0; f < 3; f ++ ) { - - key = face[ f ].x + ":" + face[ f ].y; - - index = allPointsMap[ key ]; - - if ( index !== undefined ) { - - face[ f ] = index; - - } - - } - - } - - return triangles.concat(); - - }, - - isClockWise: function ( pts ) { - - return ShapeUtils.area( pts ) < 0; - - } - -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too - * amount: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline is bevel - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * frames: // containing arrays of tangents, normals, binormals - * - * UVGenerator: // object that provides UV generator functions - * - * } - */ - -// ExtrudeGeometry - -function ExtrudeGeometry( shapes, options ) { - - Geometry.call( this ); - - this.type = 'ExtrudeGeometry'; - - this.parameters = { - shapes: shapes, - options: options - }; - - this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); - this.mergeVertices(); - -} - -ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); -ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; - -// ExtrudeBufferGeometry - -function ExtrudeBufferGeometry( shapes, options ) { - - if ( typeof ( shapes ) === "undefined" ) { - - return; - - } - - BufferGeometry.call( this ); - - this.type = 'ExtrudeBufferGeometry'; - - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - - this.addShapeList( shapes, options ); - - this.computeVertexNormals(); - - // 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 ) ); - -} - -ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; - -ExtrudeBufferGeometry.prototype.getArrays = function () { - - var positionAttribute = this.getAttribute( "position" ); - var verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : []; - - var uvAttribute = this.getAttribute( "uv" ); - var uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : []; - - var IndexAttribute = this.index; - var indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : []; - - return { - position: verticesArray, - uv: uvArray, - index: indicesArray - }; - -}; - -ExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) { - - var sl = shapes.length; - options.arrays = this.getArrays(); - - for ( var s = 0; s < sl; s ++ ) { - - var shape = shapes[ s ]; - this.addShape( shape, options ); - - } - - this.setIndex( options.arrays.index ); - this.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) ); - -}; - -ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) { - - var arrays = options.arrays ? options.arrays : this.getArrays(); - var verticesArray = arrays.position; - var indicesArray = arrays.index; - var uvArray = arrays.uv; - - var placeholder = []; - - - var amount = options.amount !== undefined ? options.amount : 100; - - var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 - var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 - var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false - - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - - var steps = options.steps !== undefined ? options.steps : 1; - - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; - - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator; - - var splineTube, binormal, normal, position2; - if ( extrudePath ) { - - extrudePts = extrudePath.getSpacedPoints( steps ); - - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion - - // SETUP TNB variables - - // TODO1 - have a .isClosed in spline? - - splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false ); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - - } - - // Variables initialization - - var ahole, h, hl; // looping of holes - var scope = this; - - var shapePoints = shape.extractPoints( curveSegments ); - - var vertices = shapePoints.shape; - var holes = shapePoints.holes; - - var reverse = ! ShapeUtils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe ... - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - if ( ShapeUtils.isClockWise( ahole ) ) { - - holes[ h ] = ahole.reverse(); - - } - - } - - } - - - var faces = ShapeUtils.triangulateShape( vertices, holes ); - - /* Vertices */ - - var contour = vertices; // vertices has all points but contour has only points of circumference - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - vertices = vertices.concat( ahole ); - - } - - - function scalePt2( pt, vec, size ) { - - if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); - - return vec.clone().multiplyScalar( size ).add( pt ); - - } - - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length; - - - // Find directions for point movement - - - function getBevelVec( inPt, inPrev, inNext ) { - - // computes for inPt the corresponding point inPt' on a new contour - // shifted by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. - - var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html - - var v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - var v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; - - var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - - // check for collinear edges - var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( collinear0 ) > Number.EPSILON ) { - - // not collinear - - // length of vectors for normalizing - - var v_prev_len = Math.sqrt( v_prev_lensq ); - var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - - // shift adjacent points by unit vectors to the left - - var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - - var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - - // scaling factor for v_prev to intersection point - - var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - // vector from inPt to intersection point - - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { - - return new Vector2( v_trans_x, v_trans_y ); - - } else { - - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - - } - - } else { - - // handle special case of collinear edges - - var direction_eq = false; // assumes: opposite - if ( v_prev_x > Number.EPSILON ) { - - if ( v_next_x > Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( v_prev_x < - Number.EPSILON ) { - - if ( v_next_x < - Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - - direction_eq = true; - - } - - } - - } - - if ( direction_eq ) { - - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); - - } else { - - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); - - } - - } - - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - - } - - - var contourMovements = []; - - for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) - - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - - } - - var holesMovements = [], - oneHoleMovements, verticesMovements = contourMovements.concat(); - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - oneHoleMovements = []; - - for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - - } - - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); - - } - - - // Loop bevelSegments, 1 for the front, 1 for the back - - for ( b = 0; b < bevelSegments; b ++ ) { - - //for ( b = bevelSegments; b > 0; b -- ) { - - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); - - // contract shape - - for ( i = 0, il = contour.length; i < il; i ++ ) { - - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - // expand holes - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( i = 0, il = ahole.length; i < il; i ++ ) { - - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - } - - } - - bs = bevelSize; - - // Back facing vertices - - for ( i = 0; i < vlen; i ++ ) { - - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, 0 ); - - } else { - - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - // Add stepped vertices... - // Including front facing vertices - - var s; - - for ( s = 1; s <= steps; s ++ ) { - - for ( i = 0; i < vlen; i ++ ) { - - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, amount / steps * s ); - - } else { - - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - } - - - // Add bevel segments planes - - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { - - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); - - // contract shape - - for ( i = 0, il = contour.length; i < il; i ++ ) { - - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); - - } - - // expand holes - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( i = 0, il = ahole.length; i < il; i ++ ) { - - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, amount + z ); - - } else { - - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - - } - - } - - } - - } - - /* Faces */ - - // Top and bottom faces - - buildLidFaces(); - - // Sides faces - - buildSideFaces(); - - - ///// Internal functions - - function buildLidFaces() { - - var start = verticesArray.length/3; - - 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 ); - - } - - } - - scope.addGroup( start, verticesArray.length/3 -start, options.material !== undefined ? options.material : 0); - - } - - // Create faces for the z-sides of the shape - - function buildSideFaces() { - - var start = verticesArray.length/3; - 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; - - } - - - scope.addGroup( start, verticesArray.length/3 -start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1); - - - } - - 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 ) { - - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); - - } - - - function f3( a, b, c ) { - - addVertex( a ); - addVertex( b ); - addVertex( c ); - - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - - } - - function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { - - addVertex( a ); - addVertex( b ); - addVertex( d ); - - addVertex( b ); - addVertex( c ); - addVertex( d ); - - - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); - - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); - - } - - function addVertex( index ) { - - indicesArray.push( verticesArray.length / 3 ); - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); - - } - - - function addUV( vector2 ) { - - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); - - } - - if ( ! options.arrays ) { - - this.setIndex( indicesArray ); - this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) ); - - } - -}; - -ExtrudeGeometry.WorldUVGenerator = { - - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - - var a_x = vertices[ indexA * 3 ]; - var a_y = vertices[ indexA * 3 + 1 ]; - var b_x = vertices[ indexB * 3 ]; - var b_y = vertices[ indexB * 3 + 1 ]; - var c_x = vertices[ indexC * 3 ]; - var c_y = vertices[ indexC * 3 + 1 ]; - - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; - - }, - - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - - var a_x = vertices[ indexA * 3 ]; - var a_y = vertices[ indexA * 3 + 1 ]; - var a_z = vertices[ indexA * 3 + 2 ]; - var b_x = vertices[ indexB * 3 ]; - var b_y = vertices[ indexB * 3 + 1 ]; - var b_z = vertices[ indexB * 3 + 2 ]; - var c_x = vertices[ indexC * 3 ]; - var c_y = vertices[ indexC * 3 + 1 ]; - var c_z = vertices[ indexC * 3 + 2 ]; - var d_x = vertices[ indexD * 3 ]; - var d_y = vertices[ indexD * 3 + 1 ]; - var d_z = vertices[ indexD * 3 + 2 ]; - - if ( Math.abs( a_y - b_y ) < 0.01 ) { - - return [ - new Vector2( a_x, 1 - a_z ), - new Vector2( b_x, 1 - b_z ), - new Vector2( c_x, 1 - c_z ), - new Vector2( d_x, 1 - d_z ) - ]; - - } else { - - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; - - } - - } -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * Text = 3D Text - * - * parameters = { - * font: , // font - * - * size: , // size of the text - * height: , // thickness to extrude text - * curveSegments: , // number of points on the curves - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into text bevel goes - * bevelSize: // how far from text outline is bevel - * } - */ - -// TextGeometry - -function TextGeometry( text, parameters ) { - - Geometry.call( this ); - - this.type = 'TextGeometry'; - - this.parameters = { - text: text, - parameters: parameters - }; - - this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); - this.mergeVertices(); - -} - -TextGeometry.prototype = Object.create( Geometry.prototype ); -TextGeometry.prototype.constructor = TextGeometry; - -// TextBufferGeometry - -function TextBufferGeometry( text, parameters ) { - - parameters = parameters || {}; - - var font = parameters.font; - - if ( ! ( font && font.isFont ) ) { - - console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); - return new Geometry(); - - } - - var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments ); - - // translate parameters to ExtrudeGeometry API - - parameters.amount = parameters.height !== undefined ? parameters.height : 50; - - // defaults - - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - - ExtrudeBufferGeometry.call( this, shapes, parameters ); - - this.type = 'TextBufferGeometry'; - -} - -TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); -TextBufferGeometry.prototype.constructor = TextBufferGeometry; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - */ - -// SphereGeometry - -function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - - Geometry.call( this ); - - this.type = 'SphereGeometry'; - - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); - this.mergeVertices(); - -} - -SphereGeometry.prototype = Object.create( Geometry.prototype ); -SphereGeometry.prototype.constructor = SphereGeometry; - -// SphereBufferGeometry - -function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - - BufferGeometry.call( this ); - - this.type = 'SphereBufferGeometry'; - - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - radius = radius || 50; - - widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - - phiStart = phiStart !== undefined ? phiStart : 0; - phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - - var thetaEnd = thetaStart + thetaLength; - - var ix, iy; - - var index = 0; - var grid = []; - - var vertex = new Vector3(); - var normal = new Vector3(); - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // generate vertices, normals and uvs - - for ( iy = 0; iy <= heightSegments; iy ++ ) { - - var verticesRow = []; - - var v = iy / heightSegments; - - for ( ix = 0; ix <= widthSegments; ix ++ ) { - - var u = ix / widthSegments; - - // vertex - - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.set( vertex.x, vertex.y, vertex.z ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, 1 - v ); - - verticesRow.push( index ++ ); - - } - - grid.push( verticesRow ); - - } - - // indices - - for ( iy = 0; iy < heightSegments; iy ++ ) { - - for ( ix = 0; ix < widthSegments; ix ++ ) { - - var a = grid[ iy ][ ix + 1 ]; - var b = grid[ iy ][ ix ]; - var c = grid[ iy + 1 ][ ix ]; - var d = grid[ iy + 1 ][ ix + 1 ]; - - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; - -/** - * @author Kaleb Murphy - * @author Mugen87 / https://github.com/Mugen87 - */ - -// RingGeometry - -function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - - Geometry.call( this ); - - this.type = 'RingGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); - this.mergeVertices(); - -} - -RingGeometry.prototype = Object.create( Geometry.prototype ); -RingGeometry.prototype.constructor = RingGeometry; - -// RingBufferGeometry - -function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - - BufferGeometry.call( this ); - - this.type = 'RingBufferGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - innerRadius = innerRadius || 20; - outerRadius = outerRadius || 50; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // some helper variables - - var segment; - var radius = innerRadius; - var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - var vertex = new Vector3(); - var uv = new Vector2(); - var j, i; - - // generate vertices, normals and uvs - - for ( j = 0; j <= phiSegments; j ++ ) { - - for ( i = 0; i <= thetaSegments; i ++ ) { - - // values are generate from the inside of the ring to the outside - - segment = thetaStart + i / thetaSegments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uv - - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // increase the radius for next row of vertices - - radius += radiusStep; - - } - - // indices - - for ( j = 0; j < phiSegments; j ++ ) { - - var thetaSegmentLevel = j * ( thetaSegments + 1 ); - - for ( i = 0; i < thetaSegments; i ++ ) { - - segment = i + thetaSegmentLevel; - - var a = segment; - var b = segment + thetaSegments + 1; - var c = segment + thetaSegments + 2; - var d = segment + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -RingBufferGeometry.prototype.constructor = RingBufferGeometry; - -/** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://clara.io - * @author Mugen87 / https://github.com/Mugen87 - */ - -// LatheGeometry - -function LatheGeometry( points, segments, phiStart, phiLength ) { - - Geometry.call( this ); - - this.type = 'LatheGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); - this.mergeVertices(); - -} - -LatheGeometry.prototype = Object.create( Geometry.prototype ); -LatheGeometry.prototype.constructor = LatheGeometry; - -// LatheBufferGeometry - -function LatheBufferGeometry( points, segments, phiStart, phiLength ) { - - BufferGeometry.call( this ); - - this.type = 'LatheBufferGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - segments = Math.floor( segments ) || 12; - phiStart = phiStart || 0; - phiLength = phiLength || Math.PI * 2; - - // clamp phiLength so it's in range of [ 0, 2PI ] - - phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); - - - // buffers - - var indices = []; - var vertices = []; - var uvs = []; - - // helper variables - - var base; - var inverseSegments = 1.0 / segments; - var vertex = new Vector3(); - var uv = new Vector2(); - var i, j; - - // generate vertices and uvs - - for ( i = 0; i <= segments; i ++ ) { - - var phi = phiStart + i * inverseSegments * phiLength; - - var sin = Math.sin( phi ); - var cos = Math.cos( phi ); - - for ( j = 0; j <= ( points.length - 1 ); j ++ ) { - - // vertex - - vertex.x = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // uv - - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); - - uvs.push( uv.x, uv.y ); - - - } - - } - - // indices - - for ( i = 0; i < segments; i ++ ) { - - for ( j = 0; j < ( points.length - 1 ); j ++ ) { - - base = j + i * points.length; - - var a = base; - var b = base + points.length; - var c = base + points.length + 1; - var d = base + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // generate normals - - this.computeVertexNormals(); - - // if the geometry is closed, we need to average the normals along the seam. - // because the corresponding vertices are identical (but still have different UVs). - - if ( phiLength === Math.PI * 2 ) { - - var normals = this.attributes.normal.array; - var n1 = new Vector3(); - var n2 = new Vector3(); - var n = new Vector3(); - - // this is the buffer offset for the last line of vertices - - base = segments * points.length * 3; - - for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { - - // select the normal of the vertex in the first line - - n1.x = normals[ j + 0 ]; - n1.y = normals[ j + 1 ]; - n1.z = normals[ j + 2 ]; - - // select the normal of the vertex in the last line - - n2.x = normals[ base + j + 0 ]; - n2.y = normals[ base + j + 1 ]; - n2.z = normals[ base + j + 2 ]; - - // average normals - - n.addVectors( n1, n2 ).normalize(); - - // assign the new values to both normals - - normals[ j + 0 ] = normals[ base + j + 0 ] = n.x; - normals[ j + 1 ] = normals[ base + j + 1 ] = n.y; - normals[ j + 2 ] = normals[ base + j + 2 ] = n.z; - - } - - } - -} - -LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; - -/** - * @author jonobr1 / http://jonobr1.com - * @author Mugen87 / https://github.com/Mugen87 - */ - -// ShapeGeometry - -function ShapeGeometry( shapes, curveSegments ) { - - Geometry.call( this ); - - this.type = 'ShapeGeometry'; - - if ( typeof curveSegments === 'object' ) { - - console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); - - curveSegments = curveSegments.curveSegments; - - } - - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); - this.mergeVertices(); - -} - -ShapeGeometry.prototype = Object.create( Geometry.prototype ); -ShapeGeometry.prototype.constructor = ShapeGeometry; - -// ShapeBufferGeometry - -function ShapeBufferGeometry( shapes, curveSegments ) { - - BufferGeometry.call( this ); - - this.type = 'ShapeBufferGeometry'; - - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - curveSegments = curveSegments || 12; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var groupStart = 0; - var groupCount = 0; - - // allow single and array values for "shapes" parameter - - if ( Array.isArray( shapes ) === false ) { - - addShape( shapes ); - - } else { - - for ( var i = 0; i < shapes.length; i ++ ) { - - addShape( shapes[ i ] ); - - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - - groupStart += groupCount; - groupCount = 0; - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - - // helper functions - - function addShape( shape ) { - - var i, l, shapeHole; - - var indexOffset = vertices.length / 3; - var points = shape.extractPoints( curveSegments ); - - var shapeVertices = points.shape; - var shapeHoles = points.holes; - - // check direction of vertices - - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - - shapeVertices = shapeVertices.reverse(); - - // also check if holes are in the opposite direction - - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { - - shapeHole = shapeHoles[ i ]; - - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - - shapeHoles[ i ] = shapeHole.reverse(); - - } - - } - - } - - var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - - // join vertices of inner and outer paths to a single array - - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { - - shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); - - } - - // vertices, normals, uvs - - for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { - - var vertex = shapeVertices[ i ]; - - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs - - } - - // incides - - for ( i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - var a = face[ 0 ] + indexOffset; - var b = face[ 1 ] + indexOffset; - var c = face[ 2 ] + indexOffset; - - indices.push( a, b, c ); - groupCount += 3; - - } - - } - -} - -ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; - -/** - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ - -function EdgesGeometry( geometry, thresholdAngle ) { - - BufferGeometry.call( this ); - - this.type = 'EdgesGeometry'; - - this.parameters = { - thresholdAngle: thresholdAngle - }; - - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - - // buffer - - var vertices = []; - - // helper variables - - var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); - var edge = [ 0, 0 ], edges = {}, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; - - // prepare source geometry - - var geometry2; - - if ( geometry.isBufferGeometry ) { - - geometry2 = new Geometry(); - geometry2.fromBufferGeometry( geometry ); - - } else { - - geometry2 = geometry.clone(); - - } - - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); - - var sourceVertices = geometry2.vertices; - var faces = geometry2.faces; - - // now create a data structure where each entry represents an edge with its adjoining faces - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0; j < 3; j ++ ) { - - edge1 = face[ keys[ j ] ]; - edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; - edge[ 0 ] = Math.min( edge1, edge2 ); - edge[ 1 ] = Math.max( edge1, edge2 ); - - key = edge[ 0 ] + ',' + edge[ 1 ]; - - if ( edges[ key ] === undefined ) { - - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; - - } else { - - edges[ key ].face2 = i; - - } - - } - - } - - // generate vertices - - for ( key in edges ) { - - var e = edges[ key ]; - - // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree. - - if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { - - var vertex = sourceVertices[ e.index1 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); - - vertex = sourceVertices[ e.index2 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - // build geometry - - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - -} - -EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); -EdgesGeometry.prototype.constructor = EdgesGeometry; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// CylinderGeometry - -function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - - Geometry.call( this ); - - this.type = 'CylinderGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); - this.mergeVertices(); - -} - -CylinderGeometry.prototype = Object.create( Geometry.prototype ); -CylinderGeometry.prototype.constructor = CylinderGeometry; - -// CylinderBufferGeometry - -function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - - BufferGeometry.call( this ); - - this.type = 'CylinderBufferGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - var scope = this; - - radiusTop = radiusTop !== undefined ? radiusTop : 20; - radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; - height = height !== undefined ? height : 100; - - radialSegments = Math.floor( radialSegments ) || 8; - heightSegments = Math.floor( heightSegments ) || 1; - - openEnded = openEnded !== undefined ? openEnded : false; - thetaStart = thetaStart !== undefined ? thetaStart : 0.0; - thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var index = 0; - var indexArray = []; - var halfHeight = height / 2; - var groupStart = 0; - - // generate geometry - - generateTorso(); - - if ( openEnded === false ) { - - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function generateTorso() { - - var x, y; - var normal = new Vector3(); - var vertex = new Vector3(); - - var groupCount = 0; - - // this will be used to calculate the normal - var slope = ( radiusBottom - radiusTop ) / height; - - // generate vertices, normals and uvs - - for ( y = 0; y <= heightSegments; y ++ ) { - - var indexRow = []; - - var v = y / heightSegments; - - // calculate the radius of the current row - - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( x = 0; x <= radialSegments; x ++ ) { - - var u = x / radialSegments; - - var theta = u * thetaLength + thetaStart; - - var sinTheta = Math.sin( theta ); - var cosTheta = Math.cos( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, 1 - v ); - - // save index of vertex in respective row - - indexRow.push( index ++ ); - - } - - // now save vertices of the row in our index array - - indexArray.push( indexRow ); - - } - - // generate indices - - for ( x = 0; x < radialSegments; x ++ ) { - - for ( y = 0; y < heightSegments; y ++ ) { - - // we use the index array to access the correct indices - - var a = indexArray[ y ][ x ]; - var b = indexArray[ y + 1 ][ x ]; - var c = indexArray[ y + 1 ][ x + 1 ]; - var d = indexArray[ y ][ x + 1 ]; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // update group counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, 0 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - function generateCap( top ) { - - var x, centerIndexStart, centerIndexEnd; - - var uv = new Vector2(); - var vertex = new Vector3(); - - var groupCount = 0; - - var radius = ( top === true ) ? radiusTop : radiusBottom; - var sign = ( top === true ) ? 1 : - 1; - - // save the index of the first center vertex - centerIndexStart = index; - - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment - - for ( x = 1; x <= radialSegments; x ++ ) { - - // vertex - - vertices.push( 0, halfHeight * sign, 0 ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uvs.push( 0.5, 0.5 ); - - // increase index - - index ++; - - } - - // save the index of the last center vertex - - centerIndexEnd = index; - - // now we generate the surrounding vertices, normals and uvs - - for ( x = 0; x <= radialSegments; x ++ ) { - - var u = x / radialSegments; - var theta = u * thetaLength + thetaStart; - - var cosTheta = Math.cos( theta ); - var sinTheta = Math.sin( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); - - // increase index - - index ++; - - } - - // generate indices - - for ( x = 0; x < radialSegments; x ++ ) { - - var c = centerIndexStart + x; - var i = centerIndexEnd + x; - - if ( top === true ) { - - // face top - - indices.push( i, i + 1, c ); - - } else { - - // face bottom - - indices.push( i + 1, i, c ); - - } - - groupCount += 3; - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - -} - -CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; - -/** - * @author abelnation / http://github.com/abelnation - */ - -// ConeGeometry - -function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - - CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - - this.type = 'ConeGeometry'; - - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - -} - -ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); -ConeGeometry.prototype.constructor = ConeGeometry; - -// ConeBufferGeometry - -function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - - CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - - this.type = 'ConeBufferGeometry'; - - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - -} - -ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); -ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; - -/** - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - * @author hughes - */ - -// CircleGeometry - -function CircleGeometry( radius, segments, thetaStart, thetaLength ) { - - Geometry.call( this ); - - this.type = 'CircleGeometry'; - - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); - this.mergeVertices(); - -} - -CircleGeometry.prototype = Object.create( Geometry.prototype ); -CircleGeometry.prototype.constructor = CircleGeometry; - -// CircleBufferGeometry - -function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { - - BufferGeometry.call( this ); - - this.type = 'CircleBufferGeometry'; - - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - radius = radius || 50; - segments = segments !== undefined ? Math.max( 3, segments ) : 8; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; - - // helper variables - - var i, s; - var vertex = new Vector3(); - var uv = new Vector2(); - - // center point - - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); - - for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { - - var segment = thetaStart + s / segments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uvs - - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // indices - - for ( i = 1; i <= segments; i ++ ) { - - indices.push( i, i + 1, 0 ); - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -} - -CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; - - - -var Geometries = Object.freeze({ - WireframeGeometry: WireframeGeometry, - ParametricGeometry: ParametricGeometry, - ParametricBufferGeometry: ParametricBufferGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TetrahedronBufferGeometry: TetrahedronBufferGeometry, - OctahedronGeometry: OctahedronGeometry, - OctahedronBufferGeometry: OctahedronBufferGeometry, - IcosahedronGeometry: IcosahedronGeometry, - IcosahedronBufferGeometry: IcosahedronBufferGeometry, - DodecahedronGeometry: DodecahedronGeometry, - DodecahedronBufferGeometry: DodecahedronBufferGeometry, - PolyhedronGeometry: PolyhedronGeometry, - PolyhedronBufferGeometry: PolyhedronBufferGeometry, - TubeGeometry: TubeGeometry, - TubeBufferGeometry: TubeBufferGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TorusKnotBufferGeometry: TorusKnotBufferGeometry, - TorusGeometry: TorusGeometry, - TorusBufferGeometry: TorusBufferGeometry, - TextGeometry: TextGeometry, - TextBufferGeometry: TextBufferGeometry, - SphereGeometry: SphereGeometry, - SphereBufferGeometry: SphereBufferGeometry, - RingGeometry: RingGeometry, - RingBufferGeometry: RingBufferGeometry, - PlaneGeometry: PlaneGeometry, - PlaneBufferGeometry: PlaneBufferGeometry, - LatheGeometry: LatheGeometry, - LatheBufferGeometry: LatheBufferGeometry, - ShapeGeometry: ShapeGeometry, - ShapeBufferGeometry: ShapeBufferGeometry, - ExtrudeGeometry: ExtrudeGeometry, - ExtrudeBufferGeometry: ExtrudeBufferGeometry, - EdgesGeometry: EdgesGeometry, - ConeGeometry: ConeGeometry, - ConeBufferGeometry: ConeBufferGeometry, - CylinderGeometry: CylinderGeometry, - CylinderBufferGeometry: CylinderBufferGeometry, - CircleGeometry: CircleGeometry, - CircleBufferGeometry: CircleBufferGeometry, - BoxGeometry: BoxGeometry, - BoxBufferGeometry: BoxBufferGeometry -}); - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * opacity: - * } - */ - -function ShadowMaterial( parameters ) { - - ShaderMaterial.call( this, { - uniforms: UniformsUtils.merge( [ - UniformsLib.lights, - { - opacity: { value: 1.0 } - } - ] ), - vertexShader: ShaderChunk[ 'shadow_vert' ], - fragmentShader: ShaderChunk[ 'shadow_frag' ] - } ); - - this.lights = true; - this.transparent = true; - - Object.defineProperties( this, { - opacity: { - enumerable: true, - get: function () { - return this.uniforms.opacity.value; - }, - set: function ( value ) { - this.uniforms.opacity.value = value; - } - } - } ); - - this.setValues( parameters ); - -} - -ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype ); -ShadowMaterial.prototype.constructor = ShadowMaterial; - -ShadowMaterial.prototype.isShadowMaterial = true; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function RawShaderMaterial( parameters ) { - - ShaderMaterial.call( this, parameters ); - - this.type = 'RawShaderMaterial'; - -} - -RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); -RawShaderMaterial.prototype.constructor = RawShaderMaterial; - -RawShaderMaterial.prototype.isRawShaderMaterial = true; - -/** - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * color: , - * roughness: , - * metalness: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * roughnessMap: new THREE.Texture( ), - * - * metalnessMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), - * envMapIntensity: - * - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ - -function MeshStandardMaterial( parameters ) { - - Material.call( this ); - - this.defines = { 'STANDARD': '' }; - - this.type = 'MeshStandardMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 0.5; - this.metalness = 0.5; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.roughnessMap = null; - - this.metalnessMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.envMapIntensity = 1.0; - - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -} - -MeshStandardMaterial.prototype = Object.create( Material.prototype ); -MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; - -MeshStandardMaterial.prototype.isMeshStandardMaterial = true; - -MeshStandardMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.defines = { 'STANDARD': '' }; - - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.roughnessMap = source.roughnessMap; - - this.metalnessMap = source.metalnessMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; - - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; - - return this; - -}; - -/** - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * reflectivity: - * } - */ - -function MeshPhysicalMaterial( parameters ) { - - MeshStandardMaterial.call( this ); - - this.defines = { 'PHYSICAL': '' }; - - this.type = 'MeshPhysicalMaterial'; - - this.reflectivity = 0.5; // maps to F0 = 0.04 - - this.clearCoat = 0.0; - this.clearCoatRoughness = 0.0; - - this.setValues( parameters ); - -} - -MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); -MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; - -MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; - -MeshPhysicalMaterial.prototype.copy = function ( source ) { - - MeshStandardMaterial.prototype.copy.call( this, source ); - - this.defines = { 'PHYSICAL': '' }; - - this.reflectivity = source.reflectivity; - - this.clearCoat = source.clearCoat; - this.clearCoatRoughness = source.clearCoatRoughness; - - return this; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * specular: , - * shininess: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ - -function MeshPhongMaterial( parameters ) { - - Material.call( this ); - - this.type = 'MeshPhongMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -} - -MeshPhongMaterial.prototype = Object.create( Material.prototype ); -MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; - -MeshPhongMaterial.prototype.isMeshPhongMaterial = true; - -MeshPhongMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; - - return this; - -}; - -/** - * @author takahirox / http://github.com/takahirox - * - * parameters = { - * gradientMap: new THREE.Texture( ) - * } - */ - -function MeshToonMaterial( parameters ) { - - MeshPhongMaterial.call( this ); - - this.defines = { 'TOON': '' }; - - this.type = 'MeshToonMaterial'; - - this.gradientMap = null; - - this.setValues( parameters ); - -} - -MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); -MeshToonMaterial.prototype.constructor = MeshToonMaterial; - -MeshToonMaterial.prototype.isMeshToonMaterial = true; - -MeshToonMaterial.prototype.copy = function ( source ) { - - MeshPhongMaterial.prototype.copy.call( this, source ); - - this.gradientMap = source.gradientMap; - - return this; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * opacity: , - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ - -function MeshNormalMaterial( parameters ) { - - Material.call( this ); - - this.type = 'MeshNormalMaterial'; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; - this.lights = false; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -} - -MeshNormalMaterial.prototype = Object.create( Material.prototype ); -MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; - -MeshNormalMaterial.prototype.isMeshNormalMaterial = true; - -MeshNormalMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; - - return this; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ - -function MeshLambertMaterial( parameters ) { - - Material.call( this ); - - this.type = 'MeshLambertMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -} - -MeshLambertMaterial.prototype = Object.create( Material.prototype ); -MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; - -MeshLambertMaterial.prototype.isMeshLambertMaterial = true; - -MeshLambertMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; - - return this; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: - * } - */ - -function LineDashedMaterial( parameters ) { - - Material.call( this ); - - this.type = 'LineDashedMaterial'; - - this.color = new Color( 0xffffff ); - - this.linewidth = 1; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.lights = false; - - this.setValues( parameters ); - -} - -LineDashedMaterial.prototype = Object.create( Material.prototype ); -LineDashedMaterial.prototype.constructor = LineDashedMaterial; - -LineDashedMaterial.prototype.isLineDashedMaterial = true; - -LineDashedMaterial.prototype.copy = function ( source ) { - - Material.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - - this.linewidth = source.linewidth; - - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; - - return this; - -}; - - - -var Materials = Object.freeze({ - ShadowMaterial: ShadowMaterial, - SpriteMaterial: SpriteMaterial, - RawShaderMaterial: RawShaderMaterial, - ShaderMaterial: ShaderMaterial, - PointsMaterial: PointsMaterial, - MeshPhysicalMaterial: MeshPhysicalMaterial, - MeshStandardMaterial: MeshStandardMaterial, - MeshPhongMaterial: MeshPhongMaterial, - MeshToonMaterial: MeshToonMaterial, - MeshNormalMaterial: MeshNormalMaterial, - MeshLambertMaterial: MeshLambertMaterial, - MeshDepthMaterial: MeshDepthMaterial, - MeshBasicMaterial: MeshBasicMaterial, - LineDashedMaterial: LineDashedMaterial, - LineBasicMaterial: LineBasicMaterial, - Material: Material -}); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -var Cache = { - - enabled: false, - - files: {}, - - add: function ( key, file ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Adding key:', key ); - - this.files[ key ] = file; - - }, - - get: function ( key ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Checking key:', key ); - - return this.files[ key ]; - - }, - - remove: function ( key ) { - - delete this.files[ key ]; - - }, - - clear: function () { - - this.files = {}; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function LoadingManager( onLoad, onProgress, onError ) { - - var scope = this; - - var isLoading = false, itemsLoaded = 0, itemsTotal = 0; - - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - itemsTotal ++; - - if ( isLoading === false ) { - - if ( scope.onStart !== undefined ) { - - scope.onStart( url, itemsLoaded, itemsTotal ); - - } - - } - - isLoading = true; - - }; - - this.itemEnd = function ( url ) { - - itemsLoaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, itemsLoaded, itemsTotal ); - - } - - if ( itemsLoaded === itemsTotal ) { - - isLoading = false; - - if ( scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - } - - }; - - this.itemError = function ( url ) { - - if ( scope.onError !== undefined ) { - - scope.onError( url ); - - } - - }; - -} - -var DefaultLoadingManager = new LoadingManager(); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function FileLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( FileLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - var scope = this; - - var cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - // Check for data: URI - var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - var dataUriRegexResult = url.match( dataUriRegex ); - - // Safari can not handle Data URIs through XMLHttpRequest so process manually - if ( dataUriRegexResult ) { - - var mimeType = dataUriRegexResult[ 1 ]; - var isBase64 = !! dataUriRegexResult[ 2 ]; - var data = dataUriRegexResult[ 3 ]; - - data = window.decodeURIComponent( data ); - - if ( isBase64 ) data = window.atob( data ); - - try { - - var response; - var responseType = ( this.responseType || '' ).toLowerCase(); - - switch ( responseType ) { - - case 'arraybuffer': - case 'blob': - - response = new ArrayBuffer( data.length ); - - var view = new Uint8Array( response ); - - for ( var i = 0; i < data.length; i ++ ) { - - view[ i ] = data.charCodeAt( i ); - - } - - if ( responseType === 'blob' ) { - - response = new Blob( [ response ], { type: mimeType } ); - - } - - break; - - case 'document': - - var parser = new DOMParser(); - response = parser.parseFromString( data, mimeType ); - - break; - - case 'json': - - response = JSON.parse( data ); - - break; - - default: // 'text' or other - - response = data; - - break; - - } - - // Wait for next browser tick - window.setTimeout( function () { - - if ( onLoad ) onLoad( response ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - } catch ( error ) { - - // Wait for next browser tick - window.setTimeout( function () { - - if ( onError ) onError( error ); - - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); - - }, 0 ); - - } - - } else { - - var request = new XMLHttpRequest(); - request.open( 'GET', url, true ); - - request.addEventListener( 'load', function ( event ) { - - var response = event.target.response; - - Cache.add( url, response ); - - if ( this.status === 200 ) { - - if ( onLoad ) onLoad( response ); - - scope.manager.itemEnd( url ); - - } else if ( this.status === 0 ) { - - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - - if ( onLoad ) onLoad( response ); - - scope.manager.itemEnd( url ); - - } else { - - if ( onError ) onError( event ); - - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); - - } - - }, false ); - - if ( onProgress !== undefined ) { - - request.addEventListener( 'progress', function ( event ) { - - onProgress( event ); - - }, false ); - - } - - request.addEventListener( 'error', function ( event ) { - - if ( onError ) onError( event ); - - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); - - }, false ); - - if ( this.responseType !== undefined ) request.responseType = this.responseType; - if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; - - if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); - - for ( var header in this.requestHeader ) { - - request.setRequestHeader( header, this.requestHeader[ header ] ); - - } - - request.send( null ); - - } - - scope.manager.itemStart( url ); - - return request; - - }, - - setPath: function ( value ) { - - this.path = value; - return this; - - }, - - setResponseType: function ( value ) { - - this.responseType = value; - return this; - - }, - - setWithCredentials: function ( value ) { - - this.withCredentials = value; - return this; - - }, - - setMimeType: function ( value ) { - - this.mimeType = value; - return this; - - }, - - setRequestHeader: function ( value ) { - - this.requestHeader = value; - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * - * Abstract Base class to block based textures loader (dds, pvr, ...) - */ - -function CompressedTextureLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - // override in sub classes - this._parser = null; - -} - -Object.assign( CompressedTextureLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var images = []; - - var texture = new CompressedTexture(); - texture.image = images; - - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - - function loadTexture( i ) { - - loader.load( url[ i ], function ( buffer ) { - - var texDatas = scope._parser( buffer, true ); - - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; - - loaded += 1; - - if ( loaded === 6 ) { - - if ( texDatas.mipmapCount === 1 ) - texture.minFilter = LinearFilter; - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, onProgress, onError ); - - } - - if ( Array.isArray( url ) ) { - - var loaded = 0; - - for ( var i = 0, il = url.length; i < il; ++ i ) { - - loadTexture( i ); - - } - - } else { - - // compressed cubemap texture stored in a single DDS file - - loader.load( url, function ( buffer ) { - - var texDatas = scope._parser( buffer, true ); - - if ( texDatas.isCubemap ) { - - var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - - for ( var f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps : [] }; - - for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; - - } - - } - - } else { - - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; - - } - - if ( texDatas.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, onProgress, onError ); - - } - - return texture; - - }, - - setPath: function ( value ) { - - this.path = value; - return this; - - } - -} ); - -/** - * @author Nikos M. / https://github.com/foo123/ - * - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - */ - -function DataTextureLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - // override in sub classes - this._parser = null; - -} - -Object.assign( DataTextureLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var texture = new DataTexture(); - - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - - loader.load( url, function ( buffer ) { - - var texData = scope._parser( buffer ); - - if ( ! texData ) return; - - if ( undefined !== texData.image ) { - - texture.image = texData.image; - - } else if ( undefined !== texData.data ) { - - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; - - } - - texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping; - - texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter; - texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter; - - texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; - - if ( undefined !== texData.format ) { - - texture.format = texData.format; - - } - if ( undefined !== texData.type ) { - - texture.type = texData.type; - - } - - if ( undefined !== texData.mipmaps ) { - - texture.mipmaps = texData.mipmaps; - - } - - if ( 1 === texData.mipmapCount ) { - - texture.minFilter = LinearFilter; - - } - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture, texData ); - - }, onProgress, onError ); - - - return texture; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function ImageLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( ImageLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - var scope = this; - - var cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); - - image.addEventListener( 'load', function () { - - Cache.add( url, this ); - - if ( onLoad ) onLoad( this ); - - scope.manager.itemEnd( url ); - - }, false ); - - /* - image.addEventListener( 'progress', function ( event ) { - - if ( onProgress ) onProgress( event ); - - }, false ); - */ - - image.addEventListener( 'error', function ( event ) { - - if ( onError ) onError( event ); - - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); - - }, false ); - - if ( url.substr( 0, 5 ) !== 'data:' ) { - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - } - - scope.manager.itemStart( url ); - - image.src = url; - - return image; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - return this; - - }, - - setPath: function ( value ) { - - this.path = value; - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function CubeTextureLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( CubeTextureLoader.prototype, { - - load: function ( urls, onLoad, onProgress, onError ) { - - var texture = new CubeTexture(); - - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - var loaded = 0; - - function loadTexture( i ) { - - loader.load( urls[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded ++; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, undefined, onError ); - - } - - for ( var i = 0; i < urls.length; ++ i ) { - - loadTexture( i ); - - } - - return texture; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - return this; - - }, - - setPath: function ( value ) { - - this.path = value; - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function TextureLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( TextureLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - var texture = new Texture(); - texture.image = loader.load( url, function () { - - // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. - var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; - - texture.format = isJPEG ? RGBFormat : RGBAFormat; - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - }, onProgress, onError ); - - return texture; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - return this; - - }, - - setPath: function ( value ) { - - this.path = value; - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function Light( color, intensity ) { - - Object3D.call( this ); - - this.type = 'Light'; - - this.color = new Color( color ); - this.intensity = intensity !== undefined ? intensity : 1; - - this.receiveShadow = undefined; - -} - -Light.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Light, - - isLight: true, - - copy: function ( source ) { - - Object3D.prototype.copy.call( this, source ); - - this.color.copy( source.color ); - this.intensity = source.intensity; - - return this; - - }, - - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); - - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - - return data; - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function HemisphereLight( skyColor, groundColor, intensity ) { - - Light.call( this, skyColor, intensity ); - - this.type = 'HemisphereLight'; - - this.castShadow = undefined; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.groundColor = new Color( groundColor ); - -} - -HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: HemisphereLight, - - isHemisphereLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.groundColor.copy( source.groundColor ); - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function LightShadow( camera ) { - - this.camera = camera; - - this.bias = 0; - this.radius = 1; - - this.mapSize = new Vector2( 512, 512 ); - - this.map = null; - this.matrix = new Matrix4(); - -} - -Object.assign( LightShadow.prototype, { - - copy: function ( source ) { - - this.camera = source.camera.clone(); - - this.bias = source.bias; - this.radius = source.radius; - - this.mapSize.copy( source.mapSize ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - toJSON: function () { - - var object = {}; - - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; - - return object; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function SpotLightShadow() { - - LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - -} - -SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - - constructor: SpotLightShadow, - - isSpotLightShadow: true, - - update: function ( light ) { - - var camera = this.camera; - - var fov = _Math.RAD2DEG * 2 * light.angle; - var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || camera.far; - - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { - - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); - - } - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function SpotLight( color, intensity, distance, angle, penumbra, decay ) { - - Light.call( this, color, intensity ); - - this.type = 'SpotLight'; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.target = new Object3D(); - - Object.defineProperty( this, 'power', { - get: function () { - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * Math.PI; - }, - set: function ( power ) { - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / Math.PI; - } - } ); - - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - - this.shadow = new SpotLightShadow(); - -} - -SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: SpotLight, - - isSpotLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; - - this.target = source.target.clone(); - - this.shadow = source.shadow.clone(); - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - - -function PointLight( color, intensity, distance, decay ) { - - Light.call( this, color, intensity ); - - this.type = 'PointLight'; - - Object.defineProperty( this, 'power', { - get: function () { - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * 4 * Math.PI; - - }, - set: function ( power ) { - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / ( 4 * Math.PI ); - } - } ); - - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - - this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - -} - -PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: PointLight, - - isPointLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.distance = source.distance; - this.decay = source.decay; - - this.shadow = source.shadow.clone(); - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function DirectionalLightShadow( ) { - - LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - -} - -DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - - constructor: DirectionalLightShadow - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function DirectionalLight( color, intensity ) { - - Light.call( this, color, intensity ); - - this.type = 'DirectionalLight'; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.shadow = new DirectionalLightShadow(); - -} - -DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: DirectionalLight, - - isDirectionalLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.target = source.target.clone(); - - this.shadow = source.shadow.clone(); - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function AmbientLight( color, intensity ) { - - Light.call( this, color, intensity ); - - this.type = 'AmbientLight'; - - this.castShadow = undefined; - -} - -AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: AmbientLight, - - isAmbientLight: true - -} ); - -/** - * @author abelnation / http://github.com/abelnation - */ - -function RectAreaLight( color, intensity, width, height ) { - - Light.call( this, color, intensity ); - - this.type = 'RectAreaLight'; - - this.position.set( 0, 1, 0 ); - this.updateMatrix(); - - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; - - // TODO (abelnation): distance/decay - - // TODO (abelnation): update method for RectAreaLight to update transform to lookat target - - // TODO (abelnation): shadows - -} - -// TODO (abelnation): RectAreaLight update when light shape is changed -RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: RectAreaLight, - - isRectAreaLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.width = source.width; - this.height = source.height; - - return this; - - }, - - toJSON: function ( meta ) { - - var data = Light.prototype.toJSON.call( this, meta ); - - data.object.width = this.width; - data.object.height = this.height; - - return data; - - } - -} ); - -/** - * @author tschw - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ - -var AnimationUtils = { - - // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function ( array, from, to ) { - - if ( AnimationUtils.isTypedArray( array ) ) { - - // in ios9 array.subarray(from, undefined) will return empty array - // but array.subarray(from) or array.subarray(from, len) is correct - return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); - - } - - return array.slice( from, to ); - - }, - - // converts an array to a specific type - convertArray: function ( array, type, forceClone ) { - - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; - - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - - return new type( array ); // create typed array - - } - - return Array.prototype.slice.call( array ); // create Array - - }, - - isTypedArray: function ( object ) { - - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); - - }, - - // returns an array by which times and values can be sorted - getKeyframeOrder: function ( times ) { - - function compareTime( i, j ) { - - return times[ i ] - times[ j ]; - - } - - var n = times.length; - var result = new Array( n ); - for ( var i = 0; i !== n; ++ i ) result[ i ] = i; - - result.sort( compareTime ); - - return result; - - }, - - // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function ( values, stride, order ) { - - var nValues = values.length; - var result = new values.constructor( nValues ); - - for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - - var srcOffset = order[ i ] * stride; - - for ( var j = 0; j !== stride; ++ j ) { - - result[ dstOffset ++ ] = values[ srcOffset + j ]; - - } - - } - - return result; - - }, - - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { - - var i = 1, key = jsonKeys[ 0 ]; - - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - - key = jsonKeys[ i ++ ]; - - } - - if ( key === undefined ) return; // no data - - var value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data - - if ( Array.isArray( value ) ) { - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push.apply( values, value ); // push all elements - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else if ( value.toArray !== undefined ) { - - // ...assume THREE.Math-ish - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - value.toArray( values, values.length ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } else { - - // otherwise push as-is - - do { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push( value ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } - - } - -}; - -/** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - * @author tschw - */ - -function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; - - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; - -} - -Object.assign( Interpolant.prototype, { - - evaluate: function( t ) { - - var pp = this.parameterPositions, - i1 = this._cachedIndex, - - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; - - validate_interval: { - - seek: { - - var right; - - linear_scan: { - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { - - for ( var giveUpAt = i1 + 2; ;) { - - if ( t1 === undefined ) { - - if ( t < t0 ) break forward_scan; - - // after end - - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t, t0 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t0 = t1; - t1 = pp[ ++ i1 ]; - - if ( t < t1 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; - - } - - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { - - // looping? - - var t1global = pp[ 1 ]; - - if ( t < t1global ) { - - i1 = 2; // + 1, using the scan for the details - t0 = t1global; - - } - - // linear reverse scan - - for ( var giveUpAt = i1 - 2; ;) { - - if ( t0 === undefined ) { - - // before start - - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); - - } - - if ( i1 === giveUpAt ) break; // this loop - - t1 = t0; - t0 = pp[ -- i1 - 1 ]; - - if ( t >= t0 ) { - - // we have arrived at the sought interval - break seek; - - } - - } - - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; - - } - - // the interval is valid - - break validate_interval; - - } // linear scan - - // binary search - - while ( i1 < right ) { - - var mid = ( i1 + right ) >>> 1; - - if ( t < pp[ mid ] ) { - - right = mid; - - } else { - - i1 = mid + 1; - - } - - } - - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; - - // check boundary cases, again - - if ( t0 === undefined ) { - - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); - - } - - if ( t1 === undefined ) { - - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t0, t ); - - } - - } // seek - - this._cachedIndex = i1; - - this.intervalChanged_( i1, t0, t1 ); - - } // validate_interval - - return this.interpolate_( i1, t0, t, t1 ); - - }, - - settings: null, // optional, subclass-specific settings structure - // Note: The indirection allows central control of many interpolants. - - // --- Protected interface - - DefaultSettings_: {}, - - getSettings_: function() { - - return this.settings || this.DefaultSettings_; - - }, - - copySampleValue_: function( index ) { - - // copies a sample value to the result buffer - - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; - - for ( var i = 0; i !== stride; ++ i ) { - - result[ i ] = values[ offset + i ]; - - } - - return result; - - }, - - // Template methods for derived classes: - - interpolate_: function( i1, t0, t, t1 ) { - - throw new Error( "call to abstract method" ); - // implementations shall return this.resultBuffer - - }, - - intervalChanged_: function( i1, t0, t1 ) { - - // empty - - } - -} ); - -//!\ DECLARE ALIAS AFTER assign prototype ! -Object.assign( Interpolant.prototype, { - - //( 0, t, t0 ), returns this.resultBuffer - beforeStart_: Interpolant.prototype.copySampleValue_, - - //( N-1, tN-1, t ), returns this.resultBuffer - afterEnd_: Interpolant.prototype.copySampleValue_, - -} ); - -/** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - * - * @author tschw - */ - -function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - Interpolant.call( - this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - - this._weightPrev = -0; - this._offsetPrev = -0; - this._weightNext = -0; - this._offsetNext = -0; - -} - -CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: CubicInterpolant, - - DefaultSettings_: { - - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - - }, - - intervalChanged_: function( i1, t0, t1 ) { - - var pp = this.parameterPositions, - iPrev = i1 - 2, - iNext = i1 + 1, - - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; - - if ( tPrev === undefined ) { - - switch ( this.getSettings_().endingStart ) { - - case ZeroSlopeEnding: - - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; - - } - - } - - if ( tNext === undefined ) { - - switch ( this.getSettings_().endingEnd ) { - - case ZeroSlopeEnding: - - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; - - break; - - case WrapAroundEnding: - - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; - - break; - - default: // ZeroCurvatureEnding - - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; - - } - - } - - var halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; - - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; - - }, - - interpolate_: function( i1, t0, t, t1 ) { - - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, - - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; - - // evaluate polynomials - - var sP = - wP * ppp + 2 * wP * pp - wP * p; - var s0 = ( 1 + wP ) * ppp + (-1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1; - var s1 = (-1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - var sN = wN * ppp - wN * pp; - - // combine data linearly - - for ( var i = 0; i !== stride; ++ i ) { - - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; - - } - - return result; - - } - -} ); - -/** - * @author tschw - */ - -function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - -} - -LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: LinearInterpolant, - - interpolate_: function( i1, t0, t, t1 ) { - - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - offset1 = i1 * stride, - offset0 = offset1 - stride, - - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; - - for ( var i = 0; i !== stride; ++ i ) { - - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; - - } - - return result; - - } - -} ); - -/** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - * - * @author tschw - */ - -function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - -} - -DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: DiscreteInterpolant, - - interpolate_: function( i1, t0, t, t1 ) { - - return this.copySampleValue_( i1 - 1 ); - - } - -} ); - -var KeyframeTrackPrototype; - -KeyframeTrackPrototype = { - - TimeBufferType: Float32Array, - ValueBufferType: Float32Array, - - DefaultInterpolation: InterpolateLinear, - - InterpolantFactoryMethodDiscrete: function ( result ) { - - return new DiscreteInterpolant( - this.times, this.values, this.getValueSize(), result ); - - }, - - InterpolantFactoryMethodLinear: function ( result ) { - - return new LinearInterpolant( - this.times, this.values, this.getValueSize(), result ); - - }, - - InterpolantFactoryMethodSmooth: function ( result ) { - - return new CubicInterpolant( - this.times, this.values, this.getValueSize(), result ); - - }, - - setInterpolation: function ( interpolation ) { - - var factoryMethod; - - switch ( interpolation ) { - - case InterpolateDiscrete: - - factoryMethod = this.InterpolantFactoryMethodDiscrete; - - break; - - case InterpolateLinear: - - factoryMethod = this.InterpolantFactoryMethodLinear; - - break; - - case InterpolateSmooth: - - factoryMethod = this.InterpolantFactoryMethodSmooth; - - break; - - } - - if ( factoryMethod === undefined ) { - - var message = "unsupported interpolation for " + - this.ValueTypeName + " keyframe track named " + this.name; - - if ( this.createInterpolant === undefined ) { - - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { - - this.setInterpolation( this.DefaultInterpolation ); - - } else { - - throw new Error( message ); // fatal, in this case - - } - - } - - console.warn( 'THREE.KeyframeTrackPrototype:', message ); - return; - - } - - this.createInterpolant = factoryMethod; - - }, - - getInterpolation: function () { - - switch ( this.createInterpolant ) { - - case this.InterpolantFactoryMethodDiscrete: - - return InterpolateDiscrete; - - case this.InterpolantFactoryMethodLinear: - - return InterpolateLinear; - - case this.InterpolantFactoryMethodSmooth: - - return InterpolateSmooth; - - } - - }, - - getValueSize: function () { - - return this.values.length / this.times.length; - - }, - - // move all keyframes either forwards or backwards in time - shift: function ( timeOffset ) { - - if ( timeOffset !== 0.0 ) { - - var times = this.times; - - for ( var i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] += timeOffset; - - } - - } - - return this; - - }, - - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale: function ( timeScale ) { - - if ( timeScale !== 1.0 ) { - - var times = this.times; - - for ( var i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] *= timeScale; - - } - - } - - return this; - - }, - - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim: function ( startTime, endTime ) { - - var times = this.times, - nKeys = times.length, - from = 0, - to = nKeys - 1; - - while ( from !== nKeys && times[ from ] < startTime ) ++ from; - while ( to !== - 1 && times[ to ] > endTime ) -- to; - - ++ to; // inclusive -> exclusive bound - - if ( from !== 0 || to !== nKeys ) { - - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; - - var stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils. - arraySlice( this.values, from * stride, to * stride ); - - } - - return this; - - }, - - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate: function () { - - var valid = true; - - var valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { - - console.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this ); - valid = false; - - } - - var times = this.times, - values = this.values, - - nKeys = times.length; - - if ( nKeys === 0 ) { - - console.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this ); - valid = false; - - } - - var prevTime = null; - - for ( var i = 0; i !== nKeys; i ++ ) { - - var currTime = times[ i ]; - - if ( typeof currTime === 'number' && isNaN( currTime ) ) { - - console.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime ); - valid = false; - break; - - } - - if ( prevTime !== null && prevTime > currTime ) { - - console.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; - - } - - prevTime = currTime; - - } - - if ( values !== undefined ) { - - if ( AnimationUtils.isTypedArray( values ) ) { - - for ( var i = 0, n = values.length; i !== n; ++ i ) { - - var value = values[ i ]; - - if ( isNaN( value ) ) { - - console.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value ); - valid = false; - break; - - } - - } - - } - - } - - return valid; - - }, - - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize: function () { - - var times = this.times, - values = this.values, - stride = this.getValueSize(), - - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - - writeIndex = 1, - lastIndex = times.length - 1; - - for ( var i = 1; i < lastIndex; ++ i ) { - - var keep = false; - - var time = times[ i ]; - var timeNext = times[ i + 1 ]; - - // remove adjacent keyframes scheduled at the same time - - if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { - - if ( ! smoothInterpolation ) { - - // remove unnecessary keyframes same as their neighbors - - var offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; - - for ( var j = 0; j !== stride; ++ j ) { - - var value = values[ offset + j ]; - - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { - - keep = true; - break; - - } - - } - - } else keep = true; - - } - - // in-place compaction - - if ( keep ) { - - if ( i !== writeIndex ) { - - times[ writeIndex ] = times[ i ]; - - var readOffset = i * stride, - writeOffset = writeIndex * stride; - - for ( var j = 0; j !== stride; ++ j ) - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - ++ writeIndex; - - } - - } - - // flush last keyframe (compaction looks ahead) - - if ( lastIndex > 0 ) { - - times[ writeIndex ] = times[ lastIndex ]; - - for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) - - values[ writeOffset + j ] = values[ readOffset + j ]; - - ++ writeIndex; - - } - - if ( writeIndex !== times.length ) { - - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - - } - - return this; - - } - -}; - -function KeyframeTrackConstructor( name, times, values, interpolation ) { - - if ( name === undefined ) throw new Error( "track name is undefined" ); - - if ( times === undefined || times.length === 0 ) { - - throw new Error( "no keyframes in track named " + name ); - - } - - this.name = name; - - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - - this.setInterpolation( interpolation || this.DefaultInterpolation ); - - this.validate(); - this.optimize(); - -} - -/** - * - * A Track of vectored keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function VectorKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.call( this, name, times, values, interpolation ); - -} - -VectorKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: VectorKeyframeTrack, - - ValueTypeName: 'vector' - - // ValueBufferType is inherited - - // DefaultInterpolation is inherited - -} ); - -/** - * Spherical linear unit quaternion interpolant. - * - * @author tschw - */ - -function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - -} - -QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: QuaternionLinearInterpolant, - - interpolate_: function( i1, t0, t, t1 ) { - - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - offset = i1 * stride, - - alpha = ( t - t0 ) / ( t1 - t0 ); - - for ( var end = offset + stride; offset !== end; offset += 4 ) { - - Quaternion.slerpFlat( result, 0, - values, offset - stride, values, offset, alpha ); - - } - - return result; - - } - -} ); - -/** - * - * A Track of quaternion keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function QuaternionKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.call( this, name, times, values, interpolation ); - -} - -QuaternionKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: QuaternionKeyframeTrack, - - ValueTypeName: 'quaternion', - - // ValueBufferType is inherited - - DefaultInterpolation: InterpolateLinear, - - InterpolantFactoryMethodLinear: function( result ) { - - return new QuaternionLinearInterpolant( - this.times, this.values, this.getValueSize(), result ); - - }, - - InterpolantFactoryMethodSmooth: undefined // not yet implemented - -} ); - -/** - * - * A Track of numeric keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function NumberKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.call( this, name, times, values, interpolation ); - -} - -NumberKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: NumberKeyframeTrack, - - ValueTypeName: 'number' - - // ValueBufferType is inherited - - // DefaultInterpolation is inherited - -} ); - -/** - * - * A Track that interpolates Strings - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function StringKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.call( this, name, times, values, interpolation ); - -} - -StringKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: StringKeyframeTrack, - - ValueTypeName: 'string', - ValueBufferType: Array, - - DefaultInterpolation: InterpolateDiscrete, - - InterpolantFactoryMethodLinear: undefined, - - InterpolantFactoryMethodSmooth: undefined - -} ); - -/** - * - * A Track of Boolean keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function BooleanKeyframeTrack( name, times, values ) { - - KeyframeTrackConstructor.call( this, name, times, values ); - -} - -BooleanKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: BooleanKeyframeTrack, - - ValueTypeName: 'bool', - ValueBufferType: Array, - - DefaultInterpolation: InterpolateDiscrete, - - InterpolantFactoryMethodLinear: undefined, - InterpolantFactoryMethodSmooth: undefined - - // Note: Actually this track could have a optimized / compressed - // representation of a single value and a custom interpolant that - // computes "firstValue ^ isOdd( index )". - -} ); - -/** - * - * A Track of keyframe values that represent color. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function ColorKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.call( this, name, times, values, interpolation ); - -} - -ColorKeyframeTrack.prototype = - Object.assign( Object.create( KeyframeTrackPrototype ), { - - constructor: ColorKeyframeTrack, - - ValueTypeName: 'color' - - // ValueBufferType is inherited - - // DefaultInterpolation is inherited - - - // Note: Very basic implementation and nothing special yet. - // However, this is the place for color space parameterization. - -} ); - -/** - * - * A timed sequence of keyframes for a specific property. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function KeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrackConstructor.apply( this, arguments ); - -} - -KeyframeTrack.prototype = KeyframeTrackPrototype; -KeyframeTrackPrototype.constructor = KeyframeTrack; - -// Static methods: - -Object.assign( KeyframeTrack, { - - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): - - parse: function( json ) { - - if( json.type === undefined ) { - - throw new Error( "track type undefined, can not parse" ); - - } - - var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - var times = [], values = []; - - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - - json.times = times; - json.values = values; - - } - - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { - - return trackType.parse( json ); - - } else { - - // by default, we asssume a constructor compatible with the base - return new trackType( - json.name, json.times, json.values, json.interpolation ); - - } - - }, - - toJSON: function( track ) { - - var trackType = track.constructor; - - var json; - - // derived classes can define a static toJSON method - if ( trackType.toJSON !== undefined ) { - - json = trackType.toJSON( track ); - - } else { - - // by default, we assume the data can be serialized as-is - json = { - - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) - - }; - - var interpolation = track.getInterpolation(); - - if ( interpolation !== track.DefaultInterpolation ) { - - json.interpolation = interpolation; - - } - - } - - json.type = track.ValueTypeName; // mandatory - - return json; - - }, - - _getTrackTypeForValueTypeName: function( typeName ) { - - switch( typeName.toLowerCase() ) { - - case "scalar": - case "double": - case "float": - case "number": - case "integer": - - return NumberKeyframeTrack; - - case "vector": - case "vector2": - case "vector3": - case "vector4": - - return VectorKeyframeTrack; - - case "color": - - return ColorKeyframeTrack; - - case "quaternion": - - return QuaternionKeyframeTrack; - - case "bool": - case "boolean": - - return BooleanKeyframeTrack; - - case "string": - - return StringKeyframeTrack; - - } - - throw new Error( "Unsupported typeName: " + typeName ); - - } - -} ); - -/** - * - * Reusable set of Tracks that represent an animation. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ - -function AnimationClip( name, duration, tracks ) { - - this.name = name; - this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : - 1; - - this.uuid = _Math.generateUUID(); - - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { - - this.resetDuration(); - - } - - this.optimize(); - -} - -Object.assign( AnimationClip, { - - parse: function ( json ) { - - var tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); - - for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); - - } - - return new AnimationClip( json.name, json.duration, tracks ); - - }, - - toJSON: function ( clip ) { - - var tracks = [], - clipTracks = clip.tracks; - - var json = { - - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks - - }; - - for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - - } - - return json; - - }, - - CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { - - var numMorphTargets = morphTargetSequence.length; - var tracks = []; - - for ( var i = 0; i < numMorphTargets; i ++ ) { - - var times = []; - var values = []; - - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); - - values.push( 0, 1, 0 ); - - var order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); - - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { - - times.push( numMorphTargets ); - values.push( values[ 0 ] ); - - } - - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); - - } - - return new AnimationClip( name, - 1, tracks ); - - }, - - findByName: function ( objectOrClipArray, name ) { - - var clipArray = objectOrClipArray; - - if ( ! Array.isArray( objectOrClipArray ) ) { - - var o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; - - } - - for ( var i = 0; i < clipArray.length; i ++ ) { - - if ( clipArray[ i ].name === name ) { - - return clipArray[ i ]; - - } - - } - - return null; - - }, - - CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { - - var animationToMorphTargets = {}; - - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - var pattern = /^([\w-]*?)([\d]+)$/; - - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { - - var morphTarget = morphTargets[ i ]; - var parts = morphTarget.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - var name = parts[ 1 ]; - - var animationMorphTargets = animationToMorphTargets[ name ]; - if ( ! animationMorphTargets ) { - - animationToMorphTargets[ name ] = animationMorphTargets = []; - - } - - animationMorphTargets.push( morphTarget ); - - } - - } - - var clips = []; - - for ( var name in animationToMorphTargets ) { - - clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - - } - - return clips; - - }, - - // parse the animation.hierarchy format - parseAnimation: function ( animation, bones ) { - - if ( ! animation ) { - - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; - - } - - var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { - - var times = []; - var values = []; - - AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); - - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { - - destTracks.push( new trackType( trackName, times, values ) ); - - } - - } - - }; - - var tracks = []; - - var clipName = animation.name || 'default'; - // automatic length determination in AnimationClip. - var duration = animation.length || - 1; - var fps = animation.fps || 30; - - var hierarchyTracks = animation.hierarchy || []; - - for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - - var animationKeys = hierarchyTracks[ h ].keys; - - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; - - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { - - // figure out all morph targets used in this track - var morphTargetNames = {}; - - for ( var k = 0; k < animationKeys.length; k ++ ) { - - if ( animationKeys[ k ].morphTargets ) { - - for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - - } - - } - - } - - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( var morphTargetName in morphTargetNames ) { - - var times = []; - var values = []; - - for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - - var animationKey = animationKeys[ k ]; - - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - - } - - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - - } - - duration = morphTargetNames.length * ( fps || 1.0 ); - - } else { - - // ...assume skeletal animation - - var boneName = '.bones[' + bones[ h ].name + ']'; - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); - - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); - - } - - } - - if ( tracks.length === 0 ) { - - return null; - - } - - var clip = new AnimationClip( clipName, duration, tracks ); - - return clip; - - } - -} ); - -Object.assign( AnimationClip.prototype, { - - resetDuration: function () { - - var tracks = this.tracks, duration = 0; - - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - - var track = this.tracks[ i ]; - - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - - } - - this.duration = duration; - - }, - - trim: function () { - - for ( var i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].trim( 0, this.duration ); - - } - - return this; - - }, - - optimize: function () { - - for ( var i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].optimize(); - - } - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function MaterialLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.textures = {}; - -} - -Object.assign( MaterialLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - }, onProgress, onError ); - - }, - - setTextures: function ( value ) { - - this.textures = value; - - }, - - parse: function ( json ) { - - var textures = this.textures; - - function getTexture( name ) { - - if ( textures[ name ] === undefined ) { - - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - - } - - return textures[ name ]; - - } - - var material = new Materials[ json.type ](); - - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.shading !== undefined ) material.shading = json.shading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - if ( json.skinning !== undefined ) material.skinning = json.skinning; - if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; - - // for PointsMaterial - - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - - // maps - - if ( json.map !== undefined ) material.map = getTexture( json.map ); - - if ( json.alphaMap !== undefined ) { - - material.alphaMap = getTexture( json.alphaMap ); - material.transparent = true; - - } - - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalScale !== undefined ) { - - var normalScale = json.normalScale; - - if ( Array.isArray( normalScale ) === false ) { - - // Blender exporter used to export a scalar. See #7459 - - normalScale = [ normalScale, normalScale ]; - - } - - material.normalScale = new Vector2().fromArray( normalScale ); - - } - - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - - return material; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function BufferGeometryLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( BufferGeometryLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - }, onProgress, onError ); - - }, - - parse: function ( json ) { - - var geometry = new BufferGeometry(); - - var index = json.data.index; - - if ( index !== undefined ) { - - var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - - } - - var attributes = json.data.attributes; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); - - geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); - - } - - var groups = json.data.groups || json.data.drawcalls || json.data.offsets; - - if ( groups !== undefined ) { - - for ( var i = 0, n = groups.length; i !== n; ++ i ) { - - var group = groups[ i ]; - - geometry.addGroup( group.start, group.count, group.materialIndex ); - - } - - } - - var boundingSphere = json.data.boundingSphere; - - if ( boundingSphere !== undefined ) { - - var center = new Vector3(); - - if ( boundingSphere.center !== undefined ) { - - center.fromArray( boundingSphere.center ); - - } - - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - - } - - return geometry; - - } - -} ); - -var TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - // Workaround for IE11 pre KB2929437. See #11440 - Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function Loader() { - - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; - -} - -Loader.Handlers = { - - handlers: [], - - add: function ( regex, loader ) { - - this.handlers.push( regex, loader ); - - }, - - get: function ( file ) { - - var handlers = this.handlers; - - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - } - -}; - -Object.assign( Loader.prototype, { - - crossOrigin: undefined, - - extractUrlBase: function ( url ) { - - var parts = url.split( '/' ); - - if ( parts.length === 1 ) return './'; - - parts.pop(); - - return parts.join( '/' ) + '/'; - - }, - - initMaterials: function ( materials, texturePath, crossOrigin ) { - - var array = []; - - for ( var i = 0; i < materials.length; ++ i ) { - - array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); - - } - - return array; - - }, - - createMaterial: ( function () { - - var BlendingMode = { - NoBlending: NoBlending, - NormalBlending: NormalBlending, - AdditiveBlending: AdditiveBlending, - SubtractiveBlending: SubtractiveBlending, - MultiplyBlending: MultiplyBlending, - CustomBlending: CustomBlending - }; - - var color = new Color(); - var textureLoader = new TextureLoader(); - var materialLoader = new MaterialLoader(); - - return function createMaterial( m, texturePath, crossOrigin ) { - - // convert from old material format - - var textures = {}; - - function loadTexture( path, repeat, offset, wrap, anisotropy ) { - - var fullPath = texturePath + path; - var loader = Loader.Handlers.get( fullPath ); - - var texture; - - if ( loader !== null ) { - - texture = loader.load( fullPath ); - - } else { - - textureLoader.setCrossOrigin( crossOrigin ); - texture = textureLoader.load( fullPath ); - - } - - if ( repeat !== undefined ) { - - texture.repeat.fromArray( repeat ); - - if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; - - } - - if ( offset !== undefined ) { - - texture.offset.fromArray( offset ); - - } - - if ( wrap !== undefined ) { - - if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; - if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; - - if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; - if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; - - } - - if ( anisotropy !== undefined ) { - - texture.anisotropy = anisotropy; - - } - - var uuid = _Math.generateUUID(); - - textures[ uuid ] = texture; - - return uuid; - - } - - // - - var json = { - uuid: _Math.generateUUID(), - type: 'MeshLambertMaterial' - }; - - for ( var name in m ) { - - var value = m[ name ]; - - switch ( name ) { - - case 'DbgColor': - case 'DbgIndex': - case 'opticalDensity': - case 'illumination': - break; - case 'DbgName': - json.name = value; - break; - case 'blending': - json.blending = BlendingMode[ value ]; - break; - case 'colorAmbient': - case 'mapAmbient': - console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); - break; - case 'colorDiffuse': - json.color = color.fromArray( value ).getHex(); - break; - case 'colorSpecular': - json.specular = color.fromArray( value ).getHex(); - break; - case 'colorEmissive': - json.emissive = color.fromArray( value ).getHex(); - break; - case 'specularCoef': - json.shininess = value; - break; - case 'shading': - if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; - if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; - if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; - break; - case 'mapDiffuse': - json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - break; - case 'mapDiffuseRepeat': - case 'mapDiffuseOffset': - case 'mapDiffuseWrap': - case 'mapDiffuseAnisotropy': - break; - case 'mapEmissive': - json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); - break; - case 'mapEmissiveRepeat': - case 'mapEmissiveOffset': - case 'mapEmissiveWrap': - case 'mapEmissiveAnisotropy': - break; - case 'mapLight': - json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - break; - case 'mapLightRepeat': - case 'mapLightOffset': - case 'mapLightWrap': - case 'mapLightAnisotropy': - break; - case 'mapAO': - json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - break; - case 'mapAORepeat': - case 'mapAOOffset': - case 'mapAOWrap': - case 'mapAOAnisotropy': - break; - case 'mapBump': - json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - break; - case 'mapBumpScale': - json.bumpScale = value; - break; - case 'mapBumpRepeat': - case 'mapBumpOffset': - case 'mapBumpWrap': - case 'mapBumpAnisotropy': - break; - case 'mapNormal': - json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - break; - case 'mapNormalFactor': - json.normalScale = [ value, value ]; - break; - case 'mapNormalRepeat': - case 'mapNormalOffset': - case 'mapNormalWrap': - case 'mapNormalAnisotropy': - break; - case 'mapSpecular': - json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - break; - case 'mapSpecularRepeat': - case 'mapSpecularOffset': - case 'mapSpecularWrap': - case 'mapSpecularAnisotropy': - break; - case 'mapMetalness': - json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); - break; - case 'mapMetalnessRepeat': - case 'mapMetalnessOffset': - case 'mapMetalnessWrap': - case 'mapMetalnessAnisotropy': - break; - case 'mapRoughness': - json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); - break; - case 'mapRoughnessRepeat': - case 'mapRoughnessOffset': - case 'mapRoughnessWrap': - case 'mapRoughnessAnisotropy': - break; - case 'mapAlpha': - json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - break; - case 'mapAlphaRepeat': - case 'mapAlphaOffset': - case 'mapAlphaWrap': - case 'mapAlphaAnisotropy': - break; - case 'flipSided': - json.side = BackSide; - break; - case 'doubleSided': - json.side = DoubleSide; - break; - case 'transparency': - console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); - json.opacity = value; - break; - case 'depthTest': - case 'depthWrite': - case 'colorWrite': - case 'opacity': - case 'reflectivity': - case 'transparent': - case 'visible': - case 'wireframe': - json[ name ] = value; - break; - case 'vertexColors': - if ( value === true ) json.vertexColors = VertexColors; - if ( value === 'face' ) json.vertexColors = FaceColors; - break; - default: - console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); - break; - - } - - } - - if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; - if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; - - if ( json.opacity < 1 ) json.transparent = true; - - materialLoader.setTextures( textures ); - - return materialLoader.parse( json ); - - }; - - } )() - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function JSONLoader( manager ) { - - if ( typeof manager === 'boolean' ) { - - console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); - manager = undefined; - - } - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - this.withCredentials = false; - -} - -Object.assign( JSONLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url ); - - var loader = new FileLoader( this.manager ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - var json = JSON.parse( text ); - var metadata = json.metadata; - - if ( metadata !== undefined ) { - - var type = metadata.type; - - if ( type !== undefined ) { - - if ( type.toLowerCase() === 'object' ) { - - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; - - } - - if ( type.toLowerCase() === 'scene' ) { - - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); - return; - - } - - } - - } - - var object = scope.parse( json, texturePath ); - onLoad( object.geometry, object.materials ); - - }, onProgress, onError ); - - }, - - setTexturePath: function ( value ) { - - this.texturePath = value; - - }, - - parse: ( function () { - - function parseModel( json, geometry ) { - - 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, - - scale = json.scale, - - nUvLayers = 0; - - - if ( json.uvs !== undefined ) { - - // disregard empty arrays - - for ( i = 0; i < json.uvs.length; i ++ ) { - - if ( json.uvs[ i ].length ) nUvLayers ++; - - } - - for ( i = 0; i < nUvLayers; i ++ ) { - - geometry.faceVertexUvs[ i ] = []; - - } - - } - - offset = 0; - zLength = vertices.length; - - while ( offset < zLength ) { - - vertex = new Vector3(); - - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; - - geometry.vertices.push( vertex ); - - } - - offset = 0; - zLength = faces.length; - - while ( offset < zLength ) { - - type = faces[ offset ++ ]; - - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); - - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); - - if ( isQuad ) { - - faceA = new Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; - - faceB = new Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; - - offset += 4; - - if ( hasMaterial ) { - - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; - - } - - // to get face <=> uv index correspondence - - fi = geometry.faces.length; - - if ( hasFaceVertexUv ) { - - for ( i = 0; i < nUvLayers; i ++ ) { - - uvLayer = json.uvs[ i ]; - - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = []; - - for ( j = 0; j < 4; j ++ ) { - - uvIndex = faces[ offset ++ ]; - - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; - - uv = new Vector2( u, v ); - - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - - } - - } - - } - - if ( hasFaceNormal ) { - - normalIndex = faces[ offset ++ ] * 3; - - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - faceB.normal.copy( faceA.normal ); - - } - - if ( hasFaceVertexNormal ) { - - for ( i = 0; i < 4; i ++ ) { - - normalIndex = faces[ offset ++ ] * 3; - - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); - - } - - } - - - if ( hasFaceColor ) { - - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; - - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); - - } - - - if ( hasFaceVertexColor ) { - - for ( i = 0; i < 4; i ++ ) { - - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; - - if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); - - } - - } - - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); - - } else { - - face = new Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; - - if ( hasMaterial ) { - - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; - - } - - // to get face <=> uv index correspondence - - fi = geometry.faces.length; - - if ( hasFaceVertexUv ) { - - for ( i = 0; i < nUvLayers; i ++ ) { - - uvLayer = json.uvs[ i ]; - - geometry.faceVertexUvs[ i ][ fi ] = []; - - for ( j = 0; j < 3; j ++ ) { - - uvIndex = faces[ offset ++ ]; - - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; - - uv = new Vector2( u, v ); - - geometry.faceVertexUvs[ i ][ fi ].push( uv ); - - } - - } - - } - - if ( hasFaceNormal ) { - - normalIndex = faces[ offset ++ ] * 3; - - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - } - - if ( hasFaceVertexNormal ) { - - for ( i = 0; i < 3; i ++ ) { - - normalIndex = faces[ offset ++ ] * 3; - - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - face.vertexNormals.push( normal ); - - } - - } - - - if ( hasFaceColor ) { - - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); - - } - - - if ( hasFaceVertexColor ) { - - for ( i = 0; i < 3; i ++ ) { - - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new Color( colors[ colorIndex ] ) ); - - } - - } - - geometry.faces.push( face ); - - } - - } - - } - - function parseSkin( json, geometry ) { - - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; - - if ( json.skinWeights ) { - - for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - - var x = json.skinWeights[ i ]; - var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; - var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; - var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; - - geometry.skinWeights.push( new Vector4( x, y, z, w ) ); - - } - - } - - if ( json.skinIndices ) { - - for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - - var a = json.skinIndices[ i ]; - var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; - var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; - var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; - - geometry.skinIndices.push( new Vector4( a, b, c, d ) ); - - } - - } - - geometry.bones = json.bones; - - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - - } - - } - - function parseMorphing( json, geometry ) { - - var scale = json.scale; - - if ( json.morphTargets !== undefined ) { - - for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { - - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; - - var dstVertices = geometry.morphTargets[ i ].vertices; - var srcVertices = json.morphTargets[ i ].vertices; - - for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - - var vertex = new Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; - - dstVertices.push( vertex ); - - } - - } - - } - - if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { - - console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); - - var faces = geometry.faces; - var morphColors = json.morphColors[ 0 ].colors; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - faces[ i ].color.fromArray( morphColors, i * 3 ); - - } - - } - - } - - function parseAnimations( json, geometry ) { - - var outputAnimations = []; - - // parse old style Bone/Hierarchy animations - var animations = []; - - if ( json.animation !== undefined ) { - - animations.push( json.animation ); - - } - - if ( json.animations !== undefined ) { - - if ( json.animations.length ) { - - animations = animations.concat( json.animations ); - - } else { - - animations.push( json.animations ); - - } - - } - - for ( var i = 0; i < animations.length; i ++ ) { - - var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); - if ( clip ) outputAnimations.push( clip ); - - } - - // parse implicit morph animations - if ( geometry.morphTargets ) { - - // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. - var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); - outputAnimations = outputAnimations.concat( morphAnimationClips ); - - } - - if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; - - } - - return function ( json, texturePath ) { - - if ( json.data !== undefined ) { - - // Geometry 4.0 spec - json = json.data; - - } - - if ( json.scale !== undefined ) { - - json.scale = 1.0 / json.scale; - - } else { - - json.scale = 1.0; - - } - - var geometry = new Geometry(); - - parseModel( json, geometry ); - parseSkin( json, geometry ); - parseMorphing( json, geometry ); - parseAnimations( json, geometry ); - - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); - - if ( json.materials === undefined || json.materials.length === 0 ) { - - return { geometry: geometry }; - - } else { - - var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); - - return { geometry: geometry, materials: materials }; - - } - - }; - - } )() - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function ObjectLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.texturePath = ''; - -} - -Object.assign( ObjectLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - if ( this.texturePath === '' ) { - - this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - - } - - var scope = this; - - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { - - var json = null; - - try { - - json = JSON.parse( text ); - - } catch ( error ) { - - if ( onError !== undefined ) onError( error ); - - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - - return; - - } - - var metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); - return; - - } - - scope.parse( json, onLoad ); - - }, onProgress, onError ); - - }, - - setTexturePath: function ( value ) { - - this.texturePath = value; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json, onLoad ) { - - var geometries = this.parseGeometries( json.geometries ); - - var images = this.parseImages( json.images, function () { - - if ( onLoad !== undefined ) onLoad( object ); - - } ); - - var textures = this.parseTextures( json.textures, images ); - var materials = this.parseMaterials( json.materials, textures ); - - var object = this.parseObject( json.object, geometries, materials ); - - if ( json.animations ) { - - object.animations = this.parseAnimations( json.animations ); - - } - - if ( json.images === undefined || json.images.length === 0 ) { - - if ( onLoad !== undefined ) onLoad( object ); - - } - - return object; - - }, - - parseGeometries: function ( json ) { - - var geometries = {}; - - if ( json !== undefined ) { - - var geometryLoader = new JSONLoader(); - var bufferGeometryLoader = new BufferGeometryLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var geometry; - var data = json[ i ]; - - switch ( data.type ) { - - case 'PlaneGeometry': - case 'PlaneBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); - - break; - - case 'BoxGeometry': - case 'BoxBufferGeometry': - case 'CubeGeometry': // backwards compatible - - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); - - break; - - case 'CircleGeometry': - case 'CircleBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.segments, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'CylinderGeometry': - case 'CylinderBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'ConeGeometry': - case 'ConeBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'SphereGeometry': - case 'SphereBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'DodecahedronGeometry': - case 'IcosahedronGeometry': - case 'OctahedronGeometry': - case 'TetrahedronGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.detail - ); - - break; - - case 'RingGeometry': - case 'RingBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.innerRadius, - data.outerRadius, - data.thetaSegments, - data.phiSegments, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'TorusGeometry': - case 'TorusBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); - - break; - - case 'TorusKnotGeometry': - case 'TorusKnotBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.tubularSegments, - data.radialSegments, - data.p, - data.q - ); - - break; - - case 'LatheGeometry': - case 'LatheBufferGeometry': - - geometry = new Geometries[ data.type ]( - data.points, - data.segments, - data.phiStart, - data.phiLength - ); - - break; - - case 'BufferGeometry': - - geometry = bufferGeometryLoader.parse( data ); - - break; - - case 'Geometry': - - geometry = geometryLoader.parse( data, this.texturePath ).geometry; - - break; - - default: - - console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - - continue; - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - }, - - parseMaterials: function ( json, textures ) { - - var materials = {}; - - if ( json !== undefined ) { - - var loader = new MaterialLoader(); - loader.setTextures( textures ); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - - if ( data.type === 'MultiMaterial' ) { - - // Deprecated - - var array = []; - - for ( var j = 0; j < data.materials.length; j ++ ) { - - array.push( loader.parse( data.materials[ j ] ) ); - - } - - materials[ data.uuid ] = array; - - } else { - - materials[ data.uuid ] = loader.parse( data ); - - } - - } - - } - - return materials; - - }, - - parseAnimations: function ( json ) { - - var animations = []; - - for ( var i = 0; i < json.length; i ++ ) { - - var clip = AnimationClip.parse( json[ i ] ); - - animations.push( clip ); - - } - - return animations; - - }, - - parseImages: function ( json, onLoad ) { - - var scope = this; - var images = {}; - - function loadImage( url ) { - - scope.manager.itemStart( url ); - - return loader.load( url, function () { - - scope.manager.itemEnd( url ); - - }, undefined, function () { - - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); - - } ); - - } - - if ( json !== undefined && json.length > 0 ) { - - var manager = new LoadingManager( onLoad ); - - var loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var image = json[ i ]; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; - - images[ image.uuid ] = loadImage( path ); - - } - - } - - return images; - - }, - - parseTextures: function ( json, images ) { - - function parseConstant( value, type ) { - - if ( typeof( value ) === 'number' ) return value; - - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - - return type[ value ]; - - } - - var textures = {}; - - if ( json !== undefined ) { - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - - if ( data.image === undefined ) { - - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - - } - - if ( images[ data.image ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - - } - - var texture = new Texture( images[ data.image ] ); - texture.needsUpdate = true; - - texture.uuid = data.uuid; - - if ( data.name !== undefined ) texture.name = data.name; - - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.wrap !== undefined ) { - - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - - } - - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - - if ( data.flipY !== undefined ) texture.flipY = data.flipY; - - textures[ data.uuid ] = texture; - - } - - } - - return textures; - - }, - - parseObject: function () { - - var matrix = new Matrix4(); - - return function parseObject( data, geometries, materials ) { - - var object; - - function getGeometry( name ) { - - if ( geometries[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - - } - - return geometries[ name ]; - - } - - function getMaterial( name ) { - - if ( name === undefined ) return undefined; - - if ( Array.isArray( name ) ) { - - var array = []; - - for ( var i = 0, l = name.length; i < l; i ++ ) { - - var uuid = name[ i ]; - - if ( materials[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - - } - - array.push( materials[ uuid ] ); - - } - - return array; - - } - - if ( materials[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', name ); - - } - - return materials[ name ]; - - } - - switch ( data.type ) { - - case 'Scene': - - object = new Scene(); - - if ( data.background !== undefined ) { - - if ( Number.isInteger( data.background ) ) { - - object.background = new Color( data.background ); - - } - - } - - if ( data.fog !== undefined ) { - - if ( data.fog.type === 'Fog' ) { - - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - - } else if ( data.fog.type === 'FogExp2' ) { - - object.fog = new FogExp2( data.fog.color, data.fog.density ); - - } - - } - - break; - - case 'PerspectiveCamera': - - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'OrthographicCamera': - - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - break; - - case 'AmbientLight': - - object = new AmbientLight( data.color, data.intensity ); - - break; - - case 'DirectionalLight': - - object = new DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - - break; - - case 'RectAreaLight': - - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - - break; - - case 'SpotLight': - - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - - break; - - case 'HemisphereLight': - - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'SkinnedMesh': - - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); - - case 'Mesh': - - var geometry = getGeometry( data.geometry ); - var material = getMaterial( data.material ); - - if ( geometry.bones && geometry.bones.length > 0 ) { - - object = new SkinnedMesh( geometry, material ); - - } else { - - object = new Mesh( geometry, material ); - - } - - break; - - case 'LOD': - - object = new LOD(); - - break; - - case 'Line': - - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - - break; - - case 'LineLoop': - - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineSegments': - - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'PointCloud': - case 'Points': - - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Sprite': - - object = new Sprite( getMaterial( data.material ) ); - - break; - - case 'Group': - - object = new Group(); - - break; - - default: - - object = new Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { - - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - - if ( data.shadow ) { - - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; - - if ( data.children !== undefined ) { - - for ( var child in data.children ) { - - object.add( this.parseObject( data.children[ child ], geometries, materials ) ); - - } - - } - - if ( data.type === 'LOD' ) { - - var levels = data.levels; - - for ( var l = 0; l < levels.length; l ++ ) { - - var level = levels[ l ]; - var child = object.getObjectByProperty( 'uuid', level.object ); - - if ( child !== undefined ) { - - object.addLevel( child, level.distance ); - - } - - } - - } - - return object; - - }; - - }() - -} ); - -var TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping -}; - -var TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; - -var TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ - -function CatmullRom( t, p0, p1, p2, p3 ) { - - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - -} - -// - -function QuadraticBezierP0( t, p ) { - - var k = 1 - t; - return k * k * p; - -} - -function QuadraticBezierP1( t, p ) { - - return 2 * ( 1 - t ) * t * p; - -} - -function QuadraticBezierP2( t, p ) { - - return t * t * p; - -} - -function QuadraticBezier( t, p0, p1, p2 ) { - - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); - -} - -// - -function CubicBezierP0( t, p ) { - - var k = 1 - t; - return k * k * k * p; - -} - -function CubicBezierP1( t, p ) { - - var k = 1 - t; - return 3 * k * k * t * p; - -} - -function CubicBezierP2( t, p ) { - - return 3 * ( 1 - t ) * t * t * p; - -} - -function CubicBezierP3( t, p ) { - - return t * t * t * p; - -} - -function CubicBezier( t, p0, p1, p2, p3 ) { - - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); - -} - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of curve methods: - * .getPoint(t), getTangent(t) - * .getPointAt(u), getTangentAt(u) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ - -/************************************************************** - * Abstract Curve base class - **************************************************************/ - -function Curve() { - - this.arcLengthDivisions = 200; - -} - -Object.assign( Curve.prototype, { - - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] - - getPoint: function () { - - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; - - }, - - // Get point at relative position in curve according to arc length - // - u [0 .. 1] - - getPointAt: function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getPoint( t ); - - }, - - // Get sequence of points using getPoint( t ) - - getPoints: function ( divisions ) { - - if ( divisions === undefined ) divisions = 5; - - var points = []; - - for ( var d = 0; d <= divisions; d ++ ) { - - points.push( this.getPoint( d / divisions ) ); - - } - - return points; - - }, - - // Get sequence of points using getPointAt( u ) - - getSpacedPoints: function ( divisions ) { - - if ( divisions === undefined ) divisions = 5; - - var points = []; - - for ( var d = 0; d <= divisions; d ++ ) { - - points.push( this.getPointAt( d / divisions ) ); - - } - - return points; - - }, - - // Get total curve arc length - - getLength: function () { - - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - - }, - - // Get list of cumulative segment lengths - - getLengths: function ( divisions ) { - - if ( divisions === undefined ) divisions = this.arcLengthDivisions; - - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { - - return this.cacheArcLengths; - - } - - this.needsUpdate = false; - - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; - - cache.push( 0 ); - - for ( p = 1; p <= divisions; p ++ ) { - - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; - - } - - this.cacheArcLengths = cache; - - return cache; // { sums: cache, sum: sum }; Sum is in the last element. - - }, - - updateArcLengths: function () { - - this.needsUpdate = true; - this.getLengths(); - - }, - - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - - getUtoTmapping: function ( u, distance ) { - - var arcLengths = this.getLengths(); - - var i = 0, il = arcLengths.length; - - var targetArcLength; // The targeted u distance value to get - - if ( distance ) { - - targetArcLength = distance; - - } else { - - targetArcLength = u * arcLengths[ il - 1 ]; - - } - - // 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; - - if ( arcLengths[ i ] === targetArcLength ) { - - return i / ( il - 1 ); - - } - - // we could get finer grain at lengths, or use simple interpolation between two points - - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; - - var segmentLength = lengthAfter - lengthBefore; - - // determine where we are between the 'before' and 'after' points - - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - - // add that fractional amount to t - - var t = ( i + segmentFraction ) / ( il - 1 ); - - return t; - - }, - - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation - - getTangent: function ( t ) { - - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; - - // Capping in case of danger - - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; - - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); - - var vec = pt2.clone().sub( pt1 ); - return vec.normalize(); - - }, - - getTangentAt: function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); - - }, - - computeFrenetFrames: function ( segments, closed ) { - - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - - var normal = new Vector3(); - - var tangents = []; - var normals = []; - var binormals = []; - - var vec = new Vector3(); - var mat = new Matrix4(); - - var i, u, theta; - - // compute the tangent vectors for each segment on the curve - - for ( i = 0; i <= segments; i ++ ) { - - u = i / segments; - - tangents[ i ] = this.getTangentAt( u ); - tangents[ i ].normalize(); - - } - - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component - - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - var min = Number.MAX_VALUE; - var tx = Math.abs( tangents[ 0 ].x ); - var ty = Math.abs( tangents[ 0 ].y ); - var tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= min ) { - - min = tx; - normal.set( 1, 0, 0 ); - - } - - if ( ty <= min ) { - - min = ty; - normal.set( 0, 1, 0 ); - - } - - if ( tz <= min ) { - - normal.set( 0, 0, 1 ); - - } - - vec.crossVectors( tangents[ 0 ], normal ).normalize(); - - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - - - // compute the slowly-varying normal and binormal vectors for each segment on the curve - - for ( i = 1; i <= segments; i ++ ) { - - normals[ i ] = normals[ i - 1 ].clone(); - - binormals[ i ] = binormals[ i - 1 ].clone(); - - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - - if ( vec.length() > Number.EPSILON ) { - - vec.normalize(); - - theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - - } - - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - - if ( closed === true ) { - - theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - - theta = - theta; - - } - - for ( i = 1; i <= segments; i ++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } - - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; - - } - -} ); - -function LineCurve( v1, v2 ) { - - Curve.call( this ); - - this.v1 = v1; - this.v2 = v2; - -} - -LineCurve.prototype = Object.create( Curve.prototype ); -LineCurve.prototype.constructor = LineCurve; - -LineCurve.prototype.isLineCurve = true; - -LineCurve.prototype.getPoint = function ( t ) { - - if ( t === 1 ) { - - return this.v2.clone(); - - } - - var point = this.v2.clone().sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - return point; - -}; - -// Line curve is linear, so we can overwrite default getPointAt - -LineCurve.prototype.getPointAt = function ( u ) { - - return this.getPoint( u ); - -}; - -LineCurve.prototype.getTangent = function ( t ) { - - var tangent = this.v2.clone().sub( this.v1 ); - - return tangent.normalize(); - -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ - -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - -function CurvePath() { - - Curve.call( this ); - - this.curves = []; - - this.autoClose = false; // Automatically closes the path - -} - -CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { - - constructor: CurvePath, - - add: function ( curve ) { - - this.curves.push( curve ); - - }, - - closePath: function () { - - // Add a line curve if start and end of lines are not connected - var startPoint = this.curves[ 0 ].getPoint( 0 ); - var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - - if ( ! startPoint.equals( endPoint ) ) { - - this.curves.push( new LineCurve( endPoint, startPoint ) ); - - } - - }, - - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: - - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') - - getPoint: function ( t ) { - - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - var diff = curveLengths[ i ] - d; - var curve = this.curves[ i ]; - - var segmentLength = curve.getLength(); - var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - - return curve.getPointAt( u ); - - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) { - - points.push( points[ 0 ] ); - - } - - return points; - - }, - - /************************************************************** - * Create Geometries Helpers - **************************************************************/ - - /// Generate geometry from path points (for Line or Points objects) - - createPointsGeometry: function ( divisions ) { - - var pts = this.getPoints( divisions ); - return this.createGeometry( pts ); - - }, - - // Generate geometry from equidistant sampling along the path - - createSpacedPointsGeometry: function ( divisions ) { - - var pts = this.getSpacedPoints( divisions ); - return this.createGeometry( pts ); - - }, - - createGeometry: function ( points ) { - - var geometry = new Geometry(); - - for ( var i = 0, l = points.length; i < l; i ++ ) { - - var point = points[ i ]; - geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); - - } - - return geometry; - - } - -} ); - -function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - Curve.call( this ); - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - - this.aRotation = aRotation || 0; - -} - -EllipseCurve.prototype = Object.create( Curve.prototype ); -EllipseCurve.prototype.constructor = EllipseCurve; - -EllipseCurve.prototype.isEllipseCurve = true; - -EllipseCurve.prototype.getPoint = function ( t ) { - - var twoPi = Math.PI * 2; - var deltaAngle = this.aEndAngle - this.aStartAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - - if ( deltaAngle < Number.EPSILON ) { - - if ( samePoints ) { - - deltaAngle = 0; - - } else { - - deltaAngle = twoPi; - - } - - } - - if ( this.aClockwise === true && ! samePoints ) { - - if ( deltaAngle === twoPi ) { - - deltaAngle = - twoPi; - - } else { - - deltaAngle = deltaAngle - twoPi; - - } - - } - - var angle = this.aStartAngle + t * deltaAngle; - var x = this.aX + this.xRadius * Math.cos( angle ); - var y = this.aY + this.yRadius * Math.sin( angle ); - - if ( this.aRotation !== 0 ) { - - var cos = Math.cos( this.aRotation ); - var sin = Math.sin( this.aRotation ); - - var tx = x - this.aX; - var ty = y - this.aY; - - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; - - } - - return new Vector2( x, y ); - -}; - -function SplineCurve( points /* array of Vector2 */ ) { - - Curve.call( this ); - - this.points = ( points === undefined ) ? [] : points; - -} - -SplineCurve.prototype = Object.create( Curve.prototype ); -SplineCurve.prototype.constructor = SplineCurve; - -SplineCurve.prototype.isSplineCurve = true; - -SplineCurve.prototype.getPoint = function ( t ) { - - var points = this.points; - var point = ( points.length - 1 ) * t; - - var intPoint = Math.floor( point ); - var weight = point - intPoint; - - var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - var point1 = points[ intPoint ]; - var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - - return new Vector2( - CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ), - CatmullRom( weight, point0.y, point1.y, point2.y, point3.y ) - ); - -}; - -function CubicBezierCurve( v0, v1, v2, v3 ) { - - Curve.call( this ); - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - -} - -CubicBezierCurve.prototype = Object.create( Curve.prototype ); -CubicBezierCurve.prototype.constructor = CubicBezierCurve; - -CubicBezierCurve.prototype.getPoint = function ( t ) { - - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - return new Vector2( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); - -}; - -function QuadraticBezierCurve( v0, v1, v2 ) { - - Curve.call( this ); - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - -} - -QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); -QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; - -QuadraticBezierCurve.prototype.getPoint = function ( t ) { - - var v0 = this.v0, v1 = this.v1, v2 = this.v2; - - return new Vector2( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); - -}; - -var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), { - - fromPoints: function ( vectors ) { - - this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - - for ( var i = 1, l = vectors.length; i < l; i ++ ) { - - this.lineTo( vectors[ i ].x, vectors[ i ].y ); - - } - - }, - - moveTo: function ( x, y ) { - - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - - }, - - lineTo: function ( x, y ) { - - var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); - - this.currentPoint.set( x, y ); - - }, - - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - - var curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - }, - - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - var curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - }, - - splineThru: function ( pts /*Array of Vector*/ ) { - - var npts = [ this.currentPoint.clone() ].concat( pts ); - - var curve = new SplineCurve( npts ); - this.curves.push( curve ); - - this.currentPoint.copy( pts[ pts.length - 1 ] ); - - }, - - arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; - - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - }, - - absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - }, - - ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; - - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - }, - - absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - if ( this.curves.length > 0 ) { - - // if a previous curve is present, attempt to join - var firstPoint = curve.getPoint( 0 ); - - if ( ! firstPoint.equals( this.currentPoint ) ) { - - this.lineTo( firstPoint.x, firstPoint.y ); - - } - - } - - this.curves.push( curve ); - - var lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); - - } - -} ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - **/ - -function Path( points ) { - - CurvePath.call( this ); - this.currentPoint = new Vector2(); - - if ( points ) { - - this.fromPoints( points ); - - } - -} - -Path.prototype = PathPrototype; -PathPrototype.constructor = Path; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ - -// STEP 1 Create a path. -// STEP 2 Turn path into shape. -// STEP 3 ExtrudeGeometry takes in Shape/Shapes -// STEP 3a - Extract points from each shape, turn to vertices -// STEP 3b - Triangulate each shape, add faces. - -function Shape() { - - Path.apply( this, arguments ); - - this.holes = []; - -} - -Shape.prototype = Object.assign( Object.create( PathPrototype ), { - - constructor: Shape, - - getPointsHoles: function ( divisions ) { - - var holesPts = []; - - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - - } - - return holesPts; - - }, - - // Get points of shape and holes (keypoints based on segments parameter) - - extractAllPoints: function ( divisions ) { - - return { - - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - - }, - - extractPoints: function ( divisions ) { - - return this.extractAllPoints( divisions ); - - } - -} ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" - **/ - -function ShapePath() { - - this.subPaths = []; - this.currentPath = null; - -} - -Object.assign( ShapePath.prototype, { - - moveTo: function ( x, y ) { - - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); - - }, - - lineTo: function ( x, y ) { - - this.currentPath.lineTo( x, y ); - - }, - - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - - }, - - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); - - }, - - splineThru: function ( pts ) { - - this.currentPath.splineThru( pts ); - - }, - - toShapes: function ( isCCW, noHoles ) { - - function toShapesNoHoles( inSubpaths ) { - - var shapes = []; - - for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { - - var tmpPath = inSubpaths[ i ]; - - var tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - - shapes.push( tmpShape ); - - } - - return shapes; - - } - - function isPointInsidePolygon( inPt, inPolygon ) { - - var polyLen = inPolygon.length; - - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - var inside = false; - for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - - var edgeLowPt = inPolygon[ p ]; - var edgeHighPt = inPolygon[ q ]; - - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; - - if ( Math.abs( edgeDy ) > Number.EPSILON ) { - - // not parallel - if ( edgeDy < 0 ) { - - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - - } - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - - if ( inPt.y === edgeLowPt.y ) { - - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! - - } else { - - var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt - - } - - } else { - - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; - - } - - } - - return inside; - - } - - var isClockWise = ShapeUtils.isClockWise; - - var subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; - - if ( noHoles === true ) return toShapesNoHoles( subPaths ); - - - var solid, tmpPath, tmpShape, shapes = []; - - if ( subPaths.length === 1 ) { - - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; - - // console.log("Holes first", holesFirst); - - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; - - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; - - for ( var i = 0, l = subPaths.length; i < l; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; - - if ( solid ) { - - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; - - //console.log('cw', i); - - } else { - - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - - //console.log('ccw', i); - - } - - } - - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - - - if ( newShapes.length > 1 ) { - - var ambiguous = false; - var toChange = []; - - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - betterShapeHoles[ sIdx ] = []; - - } - - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - var sho = newShapeHoles[ sIdx ]; - - for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { - - var ho = sho[ hIdx ]; - var hole_unassigned = true; - - for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - - if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); - if ( hole_unassigned ) { - - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); - - } else { - - ambiguous = true; - - } - - } - - } - if ( hole_unassigned ) { - - betterShapeHoles[ sIdx ].push( ho ); - - } - - } - - } - // console.log("ambiguous: ", ambiguous); - if ( toChange.length > 0 ) { - - // console.log("to change: ", toChange); - if ( ! ambiguous ) newShapeHoles = betterShapeHoles; - - } - - } - - var tmpHoles; - - for ( var i = 0, il = newShapes.length; i < il; i ++ ) { - - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; - - for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - - tmpShape.holes.push( tmpHoles[ j ].h ); - - } - - } - - //console.log("shape", shapes); - - return shapes; - - } - -} ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author mrdoob / http://mrdoob.com/ - */ - -function Font( data ) { - - this.data = data; - -} - -Object.assign( Font.prototype, { - - isFont: true, - - generateShapes: function ( text, size, divisions ) { - - function createPaths( text ) { - - var chars = String( text ).split( '' ); - var scale = size / data.resolution; - var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; - - var offsetX = 0, offsetY = 0; - - var paths = []; - - for ( var i = 0; i < chars.length; i ++ ) { - - var char = chars[ i ]; - - if ( char === '\n' ) { - - offsetX = 0; - offsetY -= line_height; - - } else { - - var ret = createPath( char, scale, offsetX, offsetY ); - offsetX += ret.offsetX; - paths.push( ret.path ); - - } - - } - - return paths; - - } - - function createPath( c, scale, offsetX, offsetY ) { - - var glyph = data.glyphs[ c ] || data.glyphs[ '?' ]; - - if ( ! glyph ) return; - - var path = new ShapePath(); - - var pts = []; - var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste; - - if ( glyph.o ) { - - var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - - for ( var i = 0, l = outline.length; i < l; ) { - - var action = outline[ i ++ ]; - - switch ( action ) { - - case 'm': // moveTo - - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; - - path.moveTo( x, y ); - - break; - - case 'l': // lineTo - - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; - - path.lineTo( x, y ); - - break; - - case 'q': // quadraticCurveTo - - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; - - path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( var i2 = 1; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - QuadraticBezier( t, cpx0, cpx1, cpx ); - QuadraticBezier( t, cpy0, cpy1, cpy ); - - } - - } - - break; - - case 'b': // bezierCurveTo - - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; - cpx2 = outline[ i ++ ] * scale + offsetX; - cpy2 = outline[ i ++ ] * scale + offsetY; - - path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( var i2 = 1; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - CubicBezier( t, cpx0, cpx1, cpx2, cpx ); - CubicBezier( t, cpy0, cpy1, cpy2, cpy ); - - } - - } - - break; - - } - - } - - } - - return { offsetX: glyph.ha * scale, path: path }; - - } - - // - - if ( size === undefined ) size = 100; - if ( divisions === undefined ) divisions = 4; - - var data = this.data; - - var paths = createPaths( text ); - var shapes = []; - - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - - } - - return shapes; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function FontLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( FontLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new FileLoader( this.manager ); - loader.load( url, function ( text ) { - - var json; - - try { - - json = JSON.parse( text ); - - } catch ( e ) { - - console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); - json = JSON.parse( text.substring( 65, text.length - 2 ) ); - - } - - var font = scope.parse( json ); - - if ( onLoad ) onLoad( font ); - - }, onProgress, onError ); - - }, - - parse: function ( json ) { - - return new Font( json ); - - } - -} ); - -var context; - -var AudioContext = { - - getContext: function () { - - if ( context === undefined ) { - - context = new ( window.AudioContext || window.webkitAudioContext )(); - - } - - return context; - - }, - - setContext: function ( value ) { - - context = value; - - } - -}; - -/** - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ - -function AudioLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( AudioLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.load( url, function ( buffer ) { - - var context = AudioContext.getContext(); - - context.decodeAudioData( buffer, function ( audioBuffer ) { - - onLoad( audioBuffer ); - - } ); - - }, onProgress, onError ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function StereoCamera() { - - this.type = 'StereoCamera'; - - this.aspect = 1; - - this.eyeSep = 0.064; - - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; - - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; - -} - -Object.assign( StereoCamera.prototype, { - - update: ( function () { - - var instance, focus, fov, aspect, near, far, zoom, eyeSep; - - var eyeRight = new Matrix4(); - var eyeLeft = new Matrix4(); - - return function update( camera ) { - - var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov || - aspect !== camera.aspect * this.aspect || near !== camera.near || - far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep; - - if ( needsUpdate ) { - - instance = this; - focus = camera.focus; - fov = camera.fov; - aspect = camera.aspect * this.aspect; - near = camera.near; - far = camera.far; - zoom = camera.zoom; - - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ - - var projectionMatrix = camera.projectionMatrix.clone(); - eyeSep = this.eyeSep / 2; - var eyeSepOnProjection = eyeSep * near / focus; - var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom; - var xmin, xmax; - - // translate xOffset - - eyeLeft.elements[ 12 ] = - eyeSep; - eyeRight.elements[ 12 ] = eyeSep; - - // for left eye - - xmin = - ymax * aspect + eyeSepOnProjection; - xmax = ymax * aspect + eyeSepOnProjection; - - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraL.projectionMatrix.copy( projectionMatrix ); - - // for right eye - - xmin = - ymax * aspect - eyeSepOnProjection; - xmax = ymax * aspect - eyeSepOnProjection; - - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraR.projectionMatrix.copy( projectionMatrix ); - - } - - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); - - }; - - } )() - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function AudioListener() { - - Object3D.call( this ); - - this.type = 'AudioListener'; - - this.context = AudioContext.getContext(); - - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); - - this.filter = null; - -} - -AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: AudioListener, - - getInput: function () { - - return this.gain; - - }, - - removeFilter: function ( ) { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; - - } - - }, - - getFilter: function () { - - return this.filter; - - }, - - setFilter: function ( value ) { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - - } else { - - this.gain.disconnect( this.context.destination ); - - } - - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); - - }, - - getMasterVolume: function () { - - return this.gain.gain.value; - - }, - - setMasterVolume: function ( value ) { - - this.gain.gain.value = value; - - }, - - updateMatrixWorld: ( function () { - - var position = new Vector3(); - var quaternion = new Quaternion(); - var scale = new Vector3(); - - var orientation = new Vector3(); - - return function updateMatrixWorld( force ) { - - Object3D.prototype.updateMatrixWorld.call( this, force ); - - var listener = this.context.listener; - var up = this.up; - - this.matrixWorld.decompose( position, quaternion, scale ); - - orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - - if ( listener.positionX ) { - - listener.positionX.setValueAtTime( position.x, this.context.currentTime ); - listener.positionY.setValueAtTime( position.y, this.context.currentTime ); - listener.positionZ.setValueAtTime( position.z, this.context.currentTime ); - listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime ); - listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime ); - listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime ); - listener.upX.setValueAtTime( up.x, this.context.currentTime ); - listener.upY.setValueAtTime( up.y, this.context.currentTime ); - listener.upZ.setValueAtTime( up.z, this.context.currentTime ); - - } else { - - listener.setPosition( position.x, position.y, position.z ); - listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); - - } - - }; - - } )() - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ - -function Audio( listener ) { - - Object3D.call( this ); - - this.type = 'Audio'; - - this.context = listener.context; - - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); - - this.autoplay = false; - - this.buffer = null; - this.loop = false; - this.startTime = 0; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.sourceType = 'empty'; - - this.filters = []; - -} - -Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: Audio, - - getOutput: function () { - - return this.gain; - - }, - - setNodeSource: function ( audioNode ) { - - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); - - return this; - - }, - - setBuffer: function ( audioBuffer ) { - - this.buffer = audioBuffer; - this.sourceType = 'buffer'; - - if ( this.autoplay ) this.play(); - - return this; - - }, - - play: function () { - - if ( this.isPlaying === true ) { - - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; - - } - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - var source = this.context.createBufferSource(); - - source.buffer = this.buffer; - source.loop = this.loop; - source.onended = this.onEnded.bind( this ); - source.playbackRate.setValueAtTime( this.playbackRate, this.startTime ); - source.start( 0, this.startTime ); - - this.isPlaying = true; - - this.source = source; - - return this.connect(); - - }, - - pause: function () { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.source.stop(); - this.startTime = this.context.currentTime; - this.isPlaying = false; - - return this; - - }, - - stop: function () { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.source.stop(); - this.startTime = 0; - this.isPlaying = false; - - return this; - - }, - - connect: function () { - - if ( this.filters.length > 0 ) { - - this.source.connect( this.filters[ 0 ] ); - - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].connect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - - } else { - - this.source.connect( this.getOutput() ); - - } - - return this; - - }, - - disconnect: function () { - - if ( this.filters.length > 0 ) { - - this.source.disconnect( this.filters[ 0 ] ); - - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - - } else { - - this.source.disconnect( this.getOutput() ); - - } - - return this; - - }, - - getFilters: function () { - - return this.filters; - - }, - - setFilters: function ( value ) { - - if ( ! value ) value = []; - - if ( this.isPlaying === true ) { - - this.disconnect(); - this.filters = value; - this.connect(); - - } else { - - this.filters = value; - - } - - return this; - - }, - - getFilter: function () { - - return this.getFilters()[ 0 ]; - - }, - - setFilter: function ( filter ) { - - return this.setFilters( filter ? [ filter ] : [] ); - - }, - - setPlaybackRate: function ( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.playbackRate = value; - - if ( this.isPlaying === true ) { - - this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime ); - - } - - return this; - - }, - - getPlaybackRate: function () { - - return this.playbackRate; - - }, - - onEnded: function () { - - this.isPlaying = false; - - }, - - getLoop: function () { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; - - } - - return this.loop; - - }, - - setLoop: function ( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.loop = value; - - if ( this.isPlaying === true ) { - - this.source.loop = this.loop; - - } - - return this; - - }, - - getVolume: function () { - - return this.gain.gain.value; - - }, - - setVolume: function ( value ) { - - this.gain.gain.value = value; - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function PositionalAudio( listener ) { - - Audio.call( this, listener ); - - this.panner = this.context.createPanner(); - this.panner.connect( this.gain ); - -} - -PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { - - constructor: PositionalAudio, - - getOutput: function () { - - return this.panner; - - }, - - getRefDistance: function () { - - return this.panner.refDistance; - - }, - - setRefDistance: function ( value ) { - - this.panner.refDistance = value; - - }, - - getRolloffFactor: function () { - - return this.panner.rolloffFactor; - - }, - - setRolloffFactor: function ( value ) { - - this.panner.rolloffFactor = value; - - }, - - getDistanceModel: function () { - - return this.panner.distanceModel; - - }, - - setDistanceModel: function ( value ) { - - this.panner.distanceModel = value; - - }, - - getMaxDistance: function () { - - return this.panner.maxDistance; - - }, - - setMaxDistance: function ( value ) { - - this.panner.maxDistance = value; - - }, - - updateMatrixWorld: ( function () { - - var position = new Vector3(); - - return function updateMatrixWorld( force ) { - - Object3D.prototype.updateMatrixWorld.call( this, force ); - - position.setFromMatrixPosition( this.matrixWorld ); - - this.panner.setPosition( position.x, position.y, position.z ); - - }; - - } )() - - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function AudioAnalyser( audio, fftSize ) { - - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; - - this.data = new Uint8Array( this.analyser.frequencyBinCount ); - - audio.getOutput().connect( this.analyser ); - -} - -Object.assign( AudioAnalyser.prototype, { - - getFrequencyData: function () { - - this.analyser.getByteFrequencyData( this.data ); - - return this.data; - - }, - - getAverageFrequency: function () { - - var value = 0, data = this.getFrequencyData(); - - for ( var i = 0; i < data.length; i ++ ) { - - value += data[ i ]; - - } - - return value / data.length; - - } - -} ); - -/** - * - * Buffered scene graph property that allows weighted accumulation. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function PropertyMixer( binding, typeName, valueSize ) { - - this.binding = binding; - this.valueSize = valueSize; - - var bufferType = Float64Array, - mixFunction; - - switch ( typeName ) { - - case 'quaternion': - mixFunction = this._slerp; - break; - - case 'string': - case 'bool': - bufferType = Array; - mixFunction = this._select; - break; - - default: - mixFunction = this._lerp; - - } - - this.buffer = new bufferType( valueSize * 4 ); - // layout: [ incoming | accu0 | accu1 | orig ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - - this._mixBufferRegion = mixFunction; - - this.cumulativeWeight = 0; - - this.useCount = 0; - this.referenceCount = 0; - -} - -Object.assign( PropertyMixer.prototype, { - - // accumulate data in the 'incoming' region into 'accu' - accumulate: function ( accuIndex, weight ) { - - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place - - var buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride, - - currentWeight = this.cumulativeWeight; - - if ( currentWeight === 0 ) { - - // accuN := incoming * weight - - for ( var i = 0; i !== stride; ++ i ) { - - buffer[ offset + i ] = buffer[ i ]; - - } - - currentWeight = weight; - - } else { - - // accuN := accuN + incoming * weight - - currentWeight += weight; - var mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); - - } - - this.cumulativeWeight = currentWeight; - - }, - - // apply the state of 'accu' to the binding when accus differ - apply: function ( accuIndex ) { - - var stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, - - weight = this.cumulativeWeight, - - binding = this.binding; - - this.cumulativeWeight = 0; - - if ( weight < 1 ) { - - // accuN := accuN + original * ( 1 - cumulativeWeight ) - - var originalValueOffset = stride * 3; - - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); - - } - - for ( var i = stride, e = stride + stride; i !== e; ++ i ) { - - if ( buffer[ i ] !== buffer[ i + stride ] ) { - - // value has changed -> update scene graph - - binding.setValue( buffer, offset ); - break; - - } - - } - - }, - - // remember the state of the bound property and copy it to both accus - saveOriginalState: function () { - - var binding = this.binding; - - var buffer = this.buffer, - stride = this.valueSize, - - originalValueOffset = stride * 3; - - binding.getValue( buffer, originalValueOffset ); - - // accu[0..1] := orig -- initially detect changes against the original - for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { - - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - - } - - this.cumulativeWeight = 0; - - }, - - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState: function () { - - var originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); - - }, - - - // mix functions - - _select: function ( buffer, dstOffset, srcOffset, t, stride ) { - - if ( t >= 0.5 ) { - - for ( var i = 0; i !== stride; ++ i ) { - - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - - } - - } - - }, - - _slerp: function ( buffer, dstOffset, srcOffset, t ) { - - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - - }, - - _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { - - var s = 1 - t; - - for ( var i = 0; i !== stride; ++ i ) { - - var j = dstOffset + i; - - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - - } - - } - -} ); - -/** - * - * A reference to a real property in the scene graph. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function Composite( targetGroup, path, optionalParsedPath ) { - - var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); - -} - -Object.assign( Composite.prototype, { - - getValue: function ( array, offset ) { - - this.bind(); // bind all binding - - var firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; - - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); - - }, - - setValue: function ( array, offset ) { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].setValue( array, offset ); - - } - - }, - - bind: function () { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].bind(); - - } - - }, - - unbind: function () { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].unbind(); - - } - - } - -} ); - - -function PropertyBinding( rootNode, path, parsedPath ) { - - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - - this.rootNode = rootNode; - -} - -Object.assign( PropertyBinding, { - - Composite: Composite, - - create: function ( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { - - return new PropertyBinding( root, path, parsedPath ); - - } else { - - return new PropertyBinding.Composite( root, path, parsedPath ); - - } - - }, - - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - sanitizeNodeName: function ( name ) { - - return name.replace( /\s/g, '_' ).replace( /[^\w-]/g, '' ); - - }, - - parseTrackName: function () { - - // Parent directories, delimited by '/' or ':'. Currently unused, but must - // be matched to parse the rest of the track name. - var directoryRe = /((?:[\w-]+[\/:])*)/; - - // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. - var nodeRe = /([\w-\.]+)?/; - - // Object on target node, and accessor. Name may contain only word - // characters. Accessor may contain any character except closing bracket. - var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/; - - // Property and accessor. May contain only word characters. Accessor may - // contain any non-bracket characters. - var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/; - - var trackRe = new RegExp('' - + '^' - + directoryRe.source - + nodeRe.source - + objectRe.source - + propertyRe.source - + '$' - ); - - var supportedObjectNames = [ 'material', 'materials', 'bones' ]; - - return function ( trackName ) { - - var matches = trackRe.exec( trackName ); - - if ( ! matches ) { - - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - - } - - var results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; - - var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - - if ( lastDot !== undefined && lastDot !== -1 ) { - - var objectName = results.nodeName.substring( lastDot + 1 ); - - // Object names must be checked against a whitelist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( supportedObjectNames.indexOf( objectName ) !== -1 ) { - - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; - - } - - } - - if ( results.propertyName === null || results.propertyName.length === 0 ) { - - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - - } - - return results; - - }; - - }(), - - findNode: function ( root, nodeName ) { - - if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - - return root; - - } - - // search into skeleton bones. - if ( root.skeleton ) { - - var searchSkeleton = function ( skeleton ) { - - for ( var i = 0; i < skeleton.bones.length; i ++ ) { - - var bone = skeleton.bones[ i ]; - - if ( bone.name === nodeName ) { - - return bone; - - } - - } - - return null; - - }; - - var bone = searchSkeleton( root.skeleton ); - - if ( bone ) { - - return bone; - - } - - } - - // search into node subtree. - if ( root.children ) { - - var searchNodeSubtree = function ( children ) { - - for ( var i = 0; i < children.length; i ++ ) { - - var childNode = children[ i ]; - - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - - return childNode; - - } - - var result = searchNodeSubtree( childNode.children ); - - if ( result ) return result; - - } - - return null; - - }; - - var subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } - - } - - return null; - - } - -} ); - -Object.assign( PropertyBinding.prototype, { // prototype, continued - - // these are used to "bind" a nonexistent property - _getValue_unavailable: function () {}, - _setValue_unavailable: function () {}, - - BindingType: { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 - }, - - Versioning: { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 - }, - - GetterByBindingType: [ - - function getValue_direct( buffer, offset ) { - - buffer[ offset ] = this.node[ this.propertyName ]; - - }, - - function getValue_array( buffer, offset ) { - - var source = this.resolvedProperty; - - for ( var i = 0, n = source.length; i !== n; ++ i ) { - - buffer[ offset ++ ] = source[ i ]; - - } - - }, - - function getValue_arrayElement( buffer, offset ) { - - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - - }, - - function getValue_toArray( buffer, offset ) { - - this.resolvedProperty.toArray( buffer, offset ); - - } - - ], - - SetterByBindingTypeAndVersioning: [ - - [ - // Direct - - function setValue_direct( buffer, offset ) { - - this.node[ this.propertyName ] = buffer[ offset ]; - - }, - - function setValue_direct_setNeedsUpdate( buffer, offset ) { - - this.node[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - }, - - function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.node[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - ], [ - - // EntireArray - - function setValue_array( buffer, offset ) { - - var dest = this.resolvedProperty; - - for ( var i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - }, - - function setValue_array_setNeedsUpdate( buffer, offset ) { - - var dest = this.resolvedProperty; - - for ( var i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.needsUpdate = true; - - }, - - function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - - var dest = this.resolvedProperty; - - for ( var i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - ], [ - - // ArrayElement - - function setValue_arrayElement( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - - }, - - function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - }, - - function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - ], [ - - // HasToFromArray - - function setValue_fromArray( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - - }, - - function setValue_fromArray_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; - - }, - - function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - ] - - ], - - getValue: function getValue_unbound( targetArray, offset ) { - - this.bind(); - this.getValue( targetArray, offset ); - - // Note: This class uses a State pattern on a per-method basis: - // 'bind' sets 'this.getValue' / 'setValue' and shadows the - // prototype version of these methods with one that represents - // the bound state. When the property is not found, the methods - // become no-ops. - - }, - - setValue: function getValue_unbound( sourceArray, offset ) { - - this.bind(); - this.setValue( sourceArray, offset ); - - }, - - // create getter / setter pair for a property in the scene graph - bind: function () { - - var targetObject = this.node, - parsedPath = this.parsedPath, - - objectName = parsedPath.objectName, - propertyName = parsedPath.propertyName, - propertyIndex = parsedPath.propertyIndex; - - if ( ! targetObject ) { - - targetObject = PropertyBinding.findNode( - this.rootNode, parsedPath.nodeName ) || this.rootNode; - - this.node = targetObject; - - } - - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; - - // ensure there is a value node - if ( ! targetObject ) { - - console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); - return; - - } - - if ( objectName ) { - - var objectIndex = parsedPath.objectIndex; - - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { - - case 'materials': - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.materials ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; - - } - - targetObject = targetObject.material.materials; - - break; - - case 'bones': - - if ( ! targetObject.skeleton ) { - - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; - - } - - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. - - targetObject = targetObject.skeleton.bones; - - // support resolving morphTarget names into indices. - for ( var i = 0; i < targetObject.length; i ++ ) { - - if ( targetObject[ i ].name === objectIndex ) { - - objectIndex = i; - break; - - } - - } - - break; - - default: - - if ( targetObject[ objectName ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; - - } - - targetObject = targetObject[ objectName ]; - - } - - - if ( objectIndex !== undefined ) { - - if ( targetObject[ objectIndex ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; - - } - - targetObject = targetObject[ objectIndex ]; - - } - - } - - // resolve property - var nodeProperty = targetObject[ propertyName ]; - - if ( nodeProperty === undefined ) { - - var nodeName = parsedPath.nodeName; - - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; - - } - - // determine versioning scheme - var versioning = this.Versioning.None; - - if ( targetObject.needsUpdate !== undefined ) { // material - - versioning = this.Versioning.NeedsUpdate; - this.targetObject = targetObject; - - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - - versioning = this.Versioning.MatrixWorldNeedsUpdate; - this.targetObject = targetObject; - - } - - // determine how the property gets bound - var bindingType = this.BindingType.Direct; - - if ( propertyIndex !== undefined ) { - - // access a sub element of the property array (only primitives are supported right now) - - if ( propertyName === "morphTargetInfluences" ) { - - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; - - } - - if ( targetObject.geometry.isBufferGeometry ) { - - if ( ! targetObject.geometry.morphAttributes ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; - - } - - for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) { - - if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) { - - propertyIndex = i; - break; - - } - - } - - - } else { - - if ( ! targetObject.geometry.morphTargets ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this ); - return; - - } - - for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { - - if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { - - propertyIndex = i; - break; - - } - - } - - } - - } - - bindingType = this.BindingType.ArrayElement; - - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; - - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - - // must use copy for Object3D.Euler/Quaternion - - bindingType = this.BindingType.HasFromToArray; - - this.resolvedProperty = nodeProperty; - - } else if ( Array.isArray( nodeProperty ) ) { - - bindingType = this.BindingType.EntireArray; - - this.resolvedProperty = nodeProperty; - - } else { - - this.propertyName = propertyName; - - } - - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - - }, - - unbind: function () { - - this.node = null; - - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - -} ); - -//!\ DECLARE ALIAS AFTER assign prototype ! -Object.assign( PropertyBinding.prototype, { - - // initial state of these methods that calls 'bind' - _getValue_unbound: PropertyBinding.prototype.getValue, - _setValue_unbound: PropertyBinding.prototype.setValue, - -} ); - -/** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - * - * @author tschw - */ - -function AnimationObjectGroup( var_args ) { - - this.uuid = _Math.generateUUID(); - - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); - - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite - - var indices = {}; - this._indicesByUUID = indices; // for bookkeeping - - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - - indices[ arguments[ i ].uuid ] = i; - - } - - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays - - var scope = this; - - this.stats = { - - objects: { - get total() { return scope._objects.length; }, - get inUse() { return this.total - scope.nCachedObjects_; } - }, - - get bindingsPerObject() { return scope._bindings.length; } - - }; - -} - -Object.assign( AnimationObjectGroup.prototype, { - - isAnimationObjectGroup: true, - - add: function( var_args ) { - - var objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; - - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ], - knownObject = undefined; - - if ( index === undefined ) { - - // unknown object -> add it to the ACTIVE region - - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); - - // accounting is done, now do the same for all bindings - - for ( var j = 0, m = nBindings; j !== m; ++ j ) { - - bindings[ j ].push( - new PropertyBinding( - object, paths[ j ], parsedPaths[ j ] ) ); - - } - - } else if ( index < nCachedObjects ) { - - knownObject = objects[ index ]; - - // move existing object to the ACTIVE region - - var firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; - - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( var j = 0, m = nBindings; j !== m; ++ j ) { - - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = lastCached; - - if ( binding === undefined ) { - - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist - - binding = new PropertyBinding( - object, paths[ j ], parsedPaths[ j ] ); - - } - - bindingsForPath[ firstActiveIndex ] = binding; - - } - - } else if ( objects[ index ] !== knownObject ) { - - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - - } // else the object is already where we want it to be - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - }, - - remove: function( var_args ) { - - var objects = this._objects, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined && index >= nCachedObjects ) { - - // move existing object into the CACHED region - - var lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; - - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; - - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( var j = 0, m = nBindings; j !== m; ++ j ) { - - var bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; - - } - - } - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - }, - - // remove & forget - uncache: function( var_args ) { - - var objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined ) { - - delete indicesByUUID[ uuid ]; - - if ( index < nCachedObjects ) { - - // object is cached, shrink the CACHED region - - var firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( var j = 0, m = nBindings; j !== m; ++ j ) { - - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; - - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); - - } - - } else { - - // object is active, just swap with the last and pop - - var lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - indicesByUUID[ lastObject.uuid ] = index; - objects[ index ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( var j = 0, m = nBindings; j !== m; ++ j ) { - - var bindingsForPath = bindings[ j ]; - - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); - - } - - } // cached or active - - } // if object is known - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - }, - - // Internal interface used by befriended PropertyBinding.Composite: - - subscribe_: function ( path, parsedPath ) { - - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group - - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ], - bindings = this._bindings; - - if ( index !== undefined ) return bindings[ index ]; - - var paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); - - index = bindings.length; - - indicesByPath[ path ] = index; - - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); - - for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - - var object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - - } - - return bindingsForPath; - - }, - - unsubscribe_: function ( path ) { - - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' - - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; - - if ( index !== undefined ) { - - var paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; - - indicesByPath[ lastBindingsPath ] = index; - - bindings[ index ] = lastBindings; - bindings.pop(); - - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); - - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); - - } - - } - -} ); - -/** - * - * Action provided by AnimationMixer for scheduling clip playback on specific - * objects. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - * - */ - -function AnimationAction( mixer, clip, localRoot ) { - - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot || null; - - var tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); - - var interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; - - for ( var i = 0; i !== nTracks; ++ i ) { - - var interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; - - } - - this._interpolantSettings = interpolantSettings; - - this._interpolants = interpolants; // bound by the mixer - - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); - - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager - - this._timeScaleInterpolant = null; - this._weightInterpolant = null; - - this.loop = LoopRepeat; - this._loopCount = -1; - - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; - - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; - - this.timeScale = 1; - this._effectiveTimeScale = 1; - - this.weight = 1; - this._effectiveWeight = 1; - - this.repetitions = Infinity; // no. of repetitions when looping - - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight - - this.clampWhenFinished = false; // keep feeding the last frame? - - this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true; // clips for start, loop and end - -} - -Object.assign( AnimationAction.prototype, { - - // State & Scheduling - - play: function() { - - this._mixer._activateAction( this ); - - return this; - - }, - - stop: function() { - - this._mixer._deactivateAction( this ); - - return this.reset(); - - }, - - reset: function() { - - this.paused = false; - this.enabled = true; - - this.time = 0; // restart clip - this._loopCount = -1; // forget previous loops - this._startTime = null; // forget scheduling - - return this.stopFading().stopWarping(); - - }, - - isRunning: function() { - - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); - - }, - - // return true when play has been called - isScheduled: function() { - - return this._mixer._isActiveAction( this ); - - }, - - startAt: function( time ) { - - this._startTime = time; - - return this; - - }, - - setLoop: function( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; - - }, - - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight: function( weight ) { - - this.weight = weight; - - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; - - return this.stopFading(); - - }, - - // return the weight considering fading and .enabled - getEffectiveWeight: function() { - - return this._effectiveWeight; - - }, - - fadeIn: function( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - }, - - fadeOut: function( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - }, - - crossFadeFrom: function( fadeOutAction, duration, warp ) { - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if( warp ) { - - var fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, - - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; - - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); - - } - - return this; - - }, - - crossFadeTo: function( fadeInAction, duration, warp ) { - - return fadeInAction.crossFadeFrom( this, duration, warp ); - - }, - - stopFading: function() { - - var weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); - - } - - return this; - - }, - - // Time Scale Control - - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale: function( timeScale ) { - - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 :timeScale; - - return this.stopWarping(); - - }, - - // return the time scale considering warping and .paused - getEffectiveTimeScale: function() { - - return this._effectiveTimeScale; - - }, - - setDuration: function( duration ) { - - this.timeScale = this._clip.duration / duration; - - return this.stopWarping(); - - }, - - syncWith: function( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; - - return this.stopWarping(); - - }, - - halt: function( duration ) { - - return this.warp( this._effectiveTimeScale, 0, duration ); - - }, - - warp: function( startTimeScale, endTimeScale, duration ) { - - var mixer = this._mixer, now = mixer.time, - interpolant = this._timeScaleInterpolant, - - timeScale = this.timeScale; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; - - } - - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; - - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; - - return this; - - }, - - stopWarping: function() { - - var timeScaleInterpolant = this._timeScaleInterpolant; - - if ( timeScaleInterpolant !== null ) { - - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - - } - - return this; - - }, - - // Object Accessors - - getMixer: function() { - - return this._mixer; - - }, - - getClip: function() { - - return this._clip; - - }, - - getRoot: function() { - - return this._localRoot || this._mixer._root; - - }, - - // Interna - - _update: function( time, deltaTime, timeDirection, accuIndex ) { - - // called by the mixer - - if ( ! this.enabled ) { - - // call ._updateWeight() to update ._effectiveWeight - - this._updateWeight( time ); - return; - - } - - var startTime = this._startTime; - - if ( startTime !== null ) { - - // check for scheduled start of action - - var timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { - - return; // yet to come / don't decide when delta = 0 - - } - - // start - - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; - - } - - // apply time scale and advance time - - deltaTime *= this._updateTimeScale( time ); - var clipTime = this._updateTime( deltaTime ); - - // note: _updateTime may disable the action resulting in - // an effective weight of 0 - - var weight = this._updateWeight( time ); - - if ( weight > 0 ) { - - var interpolants = this._interpolants; - var propertyMixers = this._propertyBindings; - - for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); - - } - - } - - }, - - _updateWeight: function( time ) { - - var weight = 0; - - if ( this.enabled ) { - - weight = this.weight; - var interpolant = this._weightInterpolant; - - if ( interpolant !== null ) { - - var interpolantValue = interpolant.evaluate( time )[ 0 ]; - - weight *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopFading(); - - if ( interpolantValue === 0 ) { - - // faded out, disable - this.enabled = false; - - } - - } - - } - - } - - this._effectiveWeight = weight; - return weight; - - }, - - _updateTimeScale: function( time ) { - - var timeScale = 0; - - if ( ! this.paused ) { - - timeScale = this.timeScale; - - var interpolant = this._timeScaleInterpolant; - - if ( interpolant !== null ) { - - var interpolantValue = interpolant.evaluate( time )[ 0 ]; - - timeScale *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopWarping(); - - if ( timeScale === 0 ) { - - // motion has halted, pause - this.paused = true; - - } else { - - // warp done - apply final time scale - this.timeScale = timeScale; - - } - - } - - } - - } - - this._effectiveTimeScale = timeScale; - return timeScale; - - }, - - _updateTime: function( deltaTime ) { - - var time = this.time + deltaTime; - - if ( deltaTime === 0 ) return time; - - var duration = this._clip.duration, - - loop = this.loop, - loopCount = this._loopCount; - - if ( loop === LoopOnce ) { - - if ( loopCount === -1 ) { - // just started - - this._loopCount = 0; - this._setEndings( true, true, false ); - - } - - handle_stop: { - - if ( time >= duration ) { - - time = duration; - - } else if ( time < 0 ) { - - time = 0; - - } else break handle_stop; - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? -1 : 1 - } ); - - } - - } else { // repetitive Repeat or PingPong - - var pingPong = ( loop === LoopPingPong ); - - if ( loopCount === -1 ) { - // just started - - if ( deltaTime >= 0 ) { - - loopCount = 0; - - this._setEndings( - true, this.repetitions === 0, pingPong ); - - } else { - - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( - this.repetitions === 0, true, pingPong ); - - } - - } - - if ( time >= duration || time < 0 ) { - // wrap around - - var loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; - - loopCount += Math.abs( loopDelta ); - - var pending = this.repetitions - loopCount; - - if ( pending < 0 ) { - // have to stop (switch state, clamp time, fire event) - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - time = deltaTime > 0 ? duration : 0; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : -1 - } ); - - } else { - // keep running - - if ( pending === 0 ) { - // entering the last round - - var atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); - - } else { - - this._setEndings( false, false, pingPong ); - - } - - this._loopCount = loopCount; - - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); - - } - - } - - if ( pingPong && ( loopCount & 1 ) === 1 ) { - // invert time for the "pong round" - - this.time = time; - return duration - time; - - } - - } - - this.time = time; - return time; - - }, - - _setEndings: function( atStart, atEnd, pingPong ) { - - var settings = this._interpolantSettings; - - if ( pingPong ) { - - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; - - } else { - - // assuming for LoopOnce atStart == atEnd == true - - if ( atStart ) { - - settings.endingStart = this.zeroSlopeAtStart ? - ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingStart = WrapAroundEnding; - - } - - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? - ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingEnd = WrapAroundEnding; - - } - - } - - }, - - _scheduleFading: function( duration, weightNow, weightThen ) { - - var mixer = this._mixer, now = mixer.time, - interpolant = this._weightInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; - - } - - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; values[ 0 ] = weightNow; - times[ 1 ] = now + duration; values[ 1 ] = weightThen; - - return this; - - } - -} ); - -/** - * - * Player for AnimationClips. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function AnimationMixer( root ) { - - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - - this.time = 0; - - this.timeScale = 1.0; - -} - -Object.assign( AnimationMixer.prototype, EventDispatcher.prototype, { - - _bindAction: function ( action, prototypeAction ) { - - var root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName, - bindingsByName = bindingsByRoot[ rootUuid ]; - - if ( bindingsByName === undefined ) { - - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; - - } - - for ( var i = 0; i !== nTracks; ++ i ) { - - var track = tracks[ i ], - trackName = track.name, - binding = bindingsByName[ trackName ]; - - if ( binding !== undefined ) { - - bindings[ i ] = binding; - - } else { - - binding = bindings[ i ]; - - if ( binding !== undefined ) { - - // existing binding, make sure the cache knows - - if ( binding._cacheIndex === null ) { - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - } - - continue; - - } - - var path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; - - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - bindings[ i ] = binding; - - } - - interpolants[ i ].resultBuffer = binding.buffer; - - } - - }, - - _activateAction: function ( action ) { - - if ( ! this._isActiveAction( action ) ) { - - if ( action._cacheIndex === null ) { - - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind - - var rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; - - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); - - this._addInactiveAction( action, clipUuid, rootUuid ); - - } - - var bindings = action._propertyBindings; - - // increment reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - - var binding = bindings[ i ]; - - if ( binding.useCount ++ === 0 ) { - - this._lendBinding( binding ); - binding.saveOriginalState(); - - } - - } - - this._lendAction( action ); - - } - - }, - - _deactivateAction: function ( action ) { - - if ( this._isActiveAction( action ) ) { - - var bindings = action._propertyBindings; - - // decrement reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - - var binding = bindings[ i ]; - - if ( -- binding.useCount === 0 ) { - - binding.restoreOriginalState(); - this._takeBackBinding( binding ); - - } - - } - - this._takeBackAction( action ); - - } - - }, - - // Memory manager - - _initMemoryManager: function () { - - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; - - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } - - - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; - - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - - - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; - - var scope = this; - - this.stats = { - - actions: { - get total() { return scope._actions.length; }, - get inUse() { return scope._nActiveActions; } - }, - bindings: { - get total() { return scope._bindings.length; }, - get inUse() { return scope._nActiveBindings; } - }, - controlInterpolants: { - get total() { return scope._controlInterpolants.length; }, - get inUse() { return scope._nActiveControlInterpolants; } - } - - }; - - }, - - // Memory management for AnimationAction objects - - _isActiveAction: function ( action ) { - - var index = action._cacheIndex; - return index !== null && index < this._nActiveActions; - - }, - - _addInactiveAction: function ( action, clipUuid, rootUuid ) { - - var actions = this._actions, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip === undefined ) { - - actionsForClip = { - - knownActions: [ action ], - actionByRoot: {} - - }; - - action._byClipCacheIndex = 0; - - actionsByClip[ clipUuid ] = actionsForClip; - - } else { - - var knownActions = actionsForClip.knownActions; - - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); - - } - - action._cacheIndex = actions.length; - actions.push( action ); - - actionsForClip.actionByRoot[ rootUuid ] = action; - - }, - - _removeInactiveAction: function ( action ) { - - var actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - action._cacheIndex = null; - - - var clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, - - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], - - byClipCacheIndex = action._byClipCacheIndex; - - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); - - action._byClipCacheIndex = null; - - - var actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; - - delete actionByRoot[ rootUuid ]; - - if ( knownActionsForClip.length === 0 ) { - - delete actionsByClip[ clipUuid ]; - - } - - this._removeInactiveBindingsForAction( action ); - - }, - - _removeInactiveBindingsForAction: function ( action ) { - - var bindings = action._propertyBindings; - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - - var binding = bindings[ i ]; - - if ( -- binding.referenceCount === 0 ) { - - this._removeInactiveBinding( binding ); - - } - - } - - }, - - _lendAction: function ( action ) { - - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s - - var actions = this._actions, - prevIndex = action._cacheIndex, - - lastActiveIndex = this._nActiveActions ++, - - firstInactiveAction = actions[ lastActiveIndex ]; - - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; - - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; - - }, - - _takeBackAction: function ( action ) { - - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a - - var actions = this._actions, - prevIndex = action._cacheIndex, - - firstInactiveIndex = -- this._nActiveActions, - - lastActiveAction = actions[ firstInactiveIndex ]; - - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; - - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; - - }, - - // Memory management for PropertyMixer objects - - _addInactiveBinding: function ( binding, rootUuid, trackName ) { - - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], - - bindings = this._bindings; - - if ( bindingByName === undefined ) { - - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; - - } - - bindingByName[ trackName ] = binding; - - binding._cacheIndex = bindings.length; - bindings.push( binding ); - - }, - - _removeInactiveBinding: function ( binding ) { - - var bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], - - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; - - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); - - delete bindingByName[ trackName ]; - - remove_empty_map: { - - for ( var _ in bindingByName ) break remove_empty_map; - - delete bindingsByRoot[ rootUuid ]; - - } - - }, - - _lendBinding: function ( binding ) { - - var bindings = this._bindings, - prevIndex = binding._cacheIndex, - - lastActiveIndex = this._nActiveBindings ++, - - firstInactiveBinding = bindings[ lastActiveIndex ]; - - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; - - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; - - }, - - _takeBackBinding: function ( binding ) { - - var bindings = this._bindings, - prevIndex = binding._cacheIndex, - - firstInactiveIndex = -- this._nActiveBindings, - - lastActiveBinding = bindings[ firstInactiveIndex ]; - - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; - - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; - - }, - - - // Memory management of Interpolants for weight and time scale - - _lendControlInterpolant: function () { - - var interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++, - interpolant = interpolants[ lastActiveIndex ]; - - if ( interpolant === undefined ) { - - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, this._controlInterpolantsResultBuffer ); - - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; - - } - - return interpolant; - - }, - - _takeBackControlInterpolant: function ( interpolant ) { - - var interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, - - firstInactiveIndex = -- this._nActiveControlInterpolants, - - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; - - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; - - }, - - _controlInterpolantsResultBuffer: new Float32Array( 1 ), - - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction: function ( clip, optionalRoot ) { - - var root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject !== null ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ], - prototypeAction = null; - - if ( actionsForClip !== undefined ) { - - var existingAction = - actionsForClip.actionByRoot[ rootUuid ]; - - if ( existingAction !== undefined ) { - - return existingAction; - - } - - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - var newAction = new AnimationAction( this, clipObject, optionalRoot ); - - this._bindAction( newAction, prototypeAction ); - - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); - - return newAction; - - }, - - // get an existing action - existingAction: function ( clip, optionalRoot ) { - - var root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - return actionsForClip.actionByRoot[ rootUuid ] || null; - - } - - return null; - - }, - - // deactivates all previously scheduled actions - stopAllAction: function () { - - var actions = this._actions, - nActions = this._nActiveActions, - bindings = this._bindings, - nBindings = this._nActiveBindings; - - this._nActiveActions = 0; - this._nActiveBindings = 0; - - for ( var i = 0; i !== nActions; ++ i ) { - - actions[ i ].reset(); - - } - - for ( var i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].useCount = 0; - - } - - return this; - - }, - - // advance the time and update apply the animation - update: function ( deltaTime ) { - - deltaTime *= this.timeScale; - - var actions = this._actions, - nActions = this._nActiveActions, - - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), - - accuIndex = this._accuIndex ^= 1; - - // run active actions - - for ( var i = 0; i !== nActions; ++ i ) { - - var action = actions[ i ]; - - action._update( time, deltaTime, timeDirection, accuIndex ); - - } - - // update scene graph - - var bindings = this._bindings, - nBindings = this._nActiveBindings; - - for ( var i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].apply( accuIndex ); - - } - - return this; - - }, - - // return this mixer's root target object - getRoot: function () { - - return this._root; - - }, - - // free all resources specific to a particular clip - uncacheClip: function ( clip ) { - - var actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away - - var actionsToRemove = actionsForClip.knownActions; - - for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - - var action = actionsToRemove[ i ]; - - this._deactivateAction( action ); - - var cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; - - action._cacheIndex = null; - action._byClipCacheIndex = null; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - this._removeInactiveBindingsForAction( action ); - - } - - delete actionsByClip[ clipUuid ]; - - } - - }, - - // free all resources specific to a particular root target object - uncacheRoot: function ( root ) { - - var rootUuid = root.uuid, - actionsByClip = this._actionsByClip; - - for ( var clipUuid in actionsByClip ) { - - var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; - - if ( action !== undefined ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName !== undefined ) { - - for ( var trackName in bindingByName ) { - - var binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); - - } - - } - - }, - - // remove a targeted clip from the cache - uncacheAction: function ( clip, optionalRoot ) { - - var action = this.existingAction( clip, optionalRoot ); - - if ( action !== null ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function Uniform( value ) { - - if ( typeof value === 'string' ) { - - console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); - value = arguments[ 1 ]; - - } - - this.value = value; - -} - -Uniform.prototype.clone = function () { - - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - -}; - -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ - -function InstancedBufferGeometry() { - - BufferGeometry.call( this ); - - this.type = 'InstancedBufferGeometry'; - this.maxInstancedCount = undefined; - -} - -InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { - - constructor: InstancedBufferGeometry, - - isInstancedBufferGeometry: true, - - addGroup: function ( start, count, materialIndex ) { - - this.groups.push( { - - start: start, - count: count, - materialIndex: materialIndex - - } ); - - }, - - copy: function ( source ) { - - var index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone() ); - - } - - var attributes = source.attributes; - - for ( var name in attributes ) { - - var attribute = attributes[ name ]; - this.addAttribute( name, attribute.clone() ); - - } - - var groups = source.groups; - - for ( var i = 0, l = groups.length; i < l; i ++ ) { - - var group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - return this; - - } - -} ); - -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ - -function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { - - this.uuid = _Math.generateUUID(); - - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; - - this.normalized = normalized === true; - -} - -Object.defineProperties( InterleavedBufferAttribute.prototype, { - - count: { - - get: function () { - - return this.data.count; - - } - - }, - - array: { - - get: function () { - - return this.data.array; - - } - - } - -} ); - -Object.assign( InterleavedBufferAttribute.prototype, { - - isInterleavedBufferAttribute: true, - - setX: function ( index, x ) { - - this.data.array[ index * this.data.stride + this.offset ] = x; - - return this; - - }, - - setY: function ( index, y ) { - - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - - return this; - - }, - - setZ: function ( index, z ) { - - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - - return this; - - }, - - setW: function ( index, w ) { - - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - - return this; - - }, - - getX: function ( index ) { - - return this.data.array[ index * this.data.stride + this.offset ]; - - }, - - getY: function ( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 1 ]; - - }, - - getZ: function ( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 2 ]; - - }, - - getW: function ( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 3 ]; - - }, - - setXY: function ( index, x, y ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - - return this; - - }, - - setXYZ: function ( index, x, y, z ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - - return this; - - }, - - setXYZW: function ( index, x, y, z, w ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - this.data.array[ index + 3 ] = w; - - return this; - - } - -} ); - -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ - -function InterleavedBuffer( array, stride ) { - - this.uuid = _Math.generateUUID(); - - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; - - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; - - this.onUploadCallback = function () {}; - - this.version = 0; - -} - -Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { - - set: function ( value ) { - - if ( value === true ) this.version ++; - - } - -} ); - -Object.assign( InterleavedBuffer.prototype, { - - isInterleavedBuffer: true, - - setArray: function ( array ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.count = array !== undefined ? array.length / this.stride : 0; - this.array = array; - - }, - - setDynamic: function ( value ) { - - this.dynamic = value; - - return this; - - }, - - copy: function ( source ) { - - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.dynamic = source.dynamic; - - return this; - - }, - - copyAt: function ( index1, attribute, index2 ) { - - index1 *= this.stride; - index2 *= attribute.stride; - - for ( var i = 0, l = this.stride; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - }, - - set: function ( value, offset ) { - - if ( offset === undefined ) offset = 0; - - this.array.set( value, offset ); - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - onUpload: function ( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - -} ); - -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ - -function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { - - InterleavedBuffer.call( this, array, stride ); - - this.meshPerAttribute = meshPerAttribute || 1; - -} - -InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { - - constructor: InstancedInterleavedBuffer, - - isInstancedInterleavedBuffer: true, - - copy: function ( source ) { - - InterleavedBuffer.prototype.copy.call( this, source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - -} ); - -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ - -function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) { - - BufferAttribute.call( this, array, itemSize ); - - this.meshPerAttribute = meshPerAttribute || 1; - -} - -InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { - - constructor: InstancedBufferAttribute, - - isInstancedBufferAttribute: true, - - copy: function ( source ) { - - BufferAttribute.prototype.copy.call( this, source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://clara.io/ - * @author stephomi / http://stephaneginier.com/ - */ - -function Raycaster( origin, direction, near, far ) { - - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near || 0; - this.far = far || Infinity; - - this.params = { - Mesh: {}, - Line: {}, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; - - Object.defineProperties( this.params, { - PointCloud: { - get: function () { - console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); - return this.Points; - } - } - } ); - -} - -function ascSort( a, b ) { - - return a.distance - b.distance; - -} - -function intersectObject( object, raycaster, intersects, recursive ) { - - if ( object.visible === false ) return; - - object.raycast( raycaster, intersects ); - - if ( recursive === true ) { - - var children = object.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { - - intersectObject( children[ i ], raycaster, intersects, true ); - - } - - } - -} - -Object.assign( Raycaster.prototype, { - - linePrecision: 1, - - set: function ( origin, direction ) { - - // direction is assumed to be normalized (for accurate distance calculations) - - this.ray.set( origin, direction ); - - }, - - setFromCamera: function ( coords, camera ) { - - if ( ( camera && camera.isPerspectiveCamera ) ) { - - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - - } else if ( ( camera && camera.isOrthographicCamera ) ) { - - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - - } else { - - console.error( 'THREE.Raycaster: Unsupported camera type.' ); - - } - - }, - - intersectObject: function ( object, recursive ) { - - var intersects = []; - - intersectObject( object, this, intersects, recursive ); - - intersects.sort( ascSort ); - - return intersects; - - }, - - intersectObjects: function ( objects, recursive ) { - - var intersects = []; - - if ( Array.isArray( objects ) === false ) { - - console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); - return intersects; - - } - - for ( var i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects, recursive ); - - } - - intersects.sort( ascSort ); - - return intersects; - - } - -} ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -function Clock( autoStart ) { - - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - -} - -Object.assign( Clock.prototype, { - - start: function () { - - this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; - - }, - - stop: function () { - - this.getElapsedTime(); - this.running = false; - this.autoStart = false; - - }, - - getElapsedTime: function () { - - this.getDelta(); - return this.elapsedTime; - - }, - - getDelta: function () { - - var diff = 0; - - if ( this.autoStart && ! this.running ) { - - this.start(); - return 0; - - } - - if ( this.running ) { - - var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); - - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - -} ); - -/** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - * - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The poles (phi) are at the positive and negative y axis. - * The equator starts at positive z. - */ - -function Spherical( radius, phi, theta ) { - - this.radius = ( radius !== undefined ) ? radius : 1.0; - this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole - this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere - - return this; - -} - -Object.assign( Spherical.prototype, { - - set: function ( radius, phi, theta ) { - - this.radius = radius; - this.phi = phi; - this.theta = theta; - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( other ) { - - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; - - return this; - - }, - - // restrict phi to be betwee EPS and PI-EPS - makeSafe: function() { - - var EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - - return this; - - }, - - setFromVector3: function( vec3 ) { - - this.radius = vec3.length(); - - if ( this.radius === 0 ) { - - this.theta = 0; - this.phi = 0; - - } else { - - this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis - this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle - - } - - return this; - - } - -} ); - -/** - * @author Mugen87 / https://github.com/Mugen87 - * - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - * - */ - -function Cylindrical( radius, theta, y ) { - - this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane - this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane - - return this; - -} - -Object.assign( Cylindrical.prototype, { - - set: function ( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; - - return this; - - }, - - clone: function () { - - return new this.constructor().copy( this ); - - }, - - copy: function ( other ) { - - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; - - return this; - - }, - - setFromVector3: function( vec3 ) { - - this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z ); - this.theta = Math.atan2( vec3.x, vec3.z ); - this.y = vec3.y; - - return this; - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -function VertexNormalsHelper( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xff0000; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - // - - var nNormals = 0; - - var objGeometry = this.object.geometry; - - if ( objGeometry && objGeometry.isGeometry ) { - - nNormals = objGeometry.faces.length * 3; - - } else if ( objGeometry && objGeometry.isBufferGeometry ) { - - nNormals = objGeometry.attributes.normal.count; - - } - - // - - var geometry = new BufferGeometry(); - - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); - - geometry.addAttribute( 'position', positions ); - - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); - - // - - this.matrixAutoUpdate = false; - - this.update(); - -} - -VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); -VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; - -VertexNormalsHelper.prototype.update = ( function () { - - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); - - return function update() { - - var keys = [ 'a', 'b', 'c' ]; - - this.object.updateMatrixWorld( true ); - - normalMatrix.getNormalMatrix( this.object.matrixWorld ); - - var matrixWorld = this.object.matrixWorld; - - var position = this.geometry.attributes.position; - - // - - var objGeometry = this.object.geometry; - - if ( objGeometry && objGeometry.isGeometry ) { - - var vertices = objGeometry.vertices; - - var faces = objGeometry.faces; - - var idx = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - - var vertex = vertices[ face[ keys[ j ] ] ]; - - var normal = face.vertexNormals[ j ]; - - v1.copy( vertex ).applyMatrix4( matrixWorld ); - - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); - - position.setXYZ( idx, v1.x, v1.y, v1.z ); - - idx = idx + 1; - - position.setXYZ( idx, v2.x, v2.y, v2.z ); - - idx = idx + 1; - - } - - } - - } else if ( objGeometry && objGeometry.isBufferGeometry ) { - - var objPos = objGeometry.attributes.position; - - var objNorm = objGeometry.attributes.normal; - - var idx = 0; - - // for simplicity, ignore index and drawcalls, and render every normal - - for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { - - v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); - - v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); - - v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); - - position.setXYZ( idx, v1.x, v1.y, v1.z ); - - idx = idx + 1; - - position.setXYZ( idx, v2.x, v2.y, v2.z ); - - idx = idx + 1; - - } - - } - - position.needsUpdate = true; - - }; - -}() ); - -/** - * @author Sean Griffin / http://twitter.com/sgrif - * @author Michael Guerrero / http://realitymeltdown.com - * @author mrdoob / http://mrdoob.com/ - * @author ikerr / http://verold.com - * @author Mugen87 / https://github.com/Mugen87 - */ - -function getBoneList( object ) { - - var boneList = []; - - if ( object && object.isBone ) { - - boneList.push( object ); - - } - - for ( var i = 0; i < object.children.length; i ++ ) { - - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - - } - - return boneList; - -} - -function SkeletonHelper( object ) { - - var bones = getBoneList( object ); - - var geometry = new BufferGeometry(); - - var vertices = []; - var colors = []; - - var color1 = new Color( 0, 0, 1 ); - var color2 = new Color( 0, 1, 0 ); - - for ( var i = 0; i < bones.length; i ++ ) { - - var bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); - - } - - } - - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); - - LineSegments.call( this, geometry, material ); - - this.root = object; - this.bones = bones; - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - - this.onBeforeRender(); - -} - -SkeletonHelper.prototype = Object.create( LineSegments.prototype ); -SkeletonHelper.prototype.constructor = SkeletonHelper; - -SkeletonHelper.prototype.onBeforeRender = function () { - - var vector = new Vector3(); - - var boneMatrix = new Matrix4(); - var matrixWorldInv = new Matrix4(); - - return function onBeforeRender() { - - var bones = this.bones; - - var geometry = this.geometry; - var position = geometry.getAttribute( 'position' ); - - matrixWorldInv.getInverse( this.root.matrixWorld ); - - for ( var i = 0, j = 0; i < bones.length; i ++ ) { - - var bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j, vector.x, vector.y, vector.z ); - - boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j + 1, vector.x, vector.y, vector.z ); - - j += 2; - - } - - } - - geometry.getAttribute( 'position' ).needsUpdate = true; - - }; - -}(); - -/** - * @author abelnation / http://github.com/abelnation - * @author Mugen87 / http://github.com/Mugen87 - * @author WestLangley / http://github.com/WestLangley - */ - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -function HemisphereLightHelper( light, size ) { - - Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - var geometry = new OctahedronBufferGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); - - var material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } ); - - var position = geometry.getAttribute( 'position' ); - var colors = new Float32Array( position.count * 3 ); - - geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); - - this.add( new Mesh( geometry, material ) ); - - this.update(); - -} - -HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); -HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; - -HemisphereLightHelper.prototype.dispose = function () { - - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - -}; - -HemisphereLightHelper.prototype.update = function () { - - var vector = new Vector3(); - - var color1 = new Color(); - var color2 = new Color(); - - return function update() { - - var mesh = this.children[ 0 ]; - - var colors = mesh.geometry.getAttribute( 'color' ); - - color1.copy( this.light.color ); - color2.copy( this.light.groundColor ); - - for ( var i = 0, l = colors.count; i < l; i ++ ) { - - var color = ( i < ( l / 2 ) ) ? color1 : color2; - - colors.setXYZ( i, color.r, color.g, color.b ); - - } - - mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - - colors.needsUpdate = true; - - }; - -}(); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -function FaceNormalsHelper( object, size, hex, linewidth ) { - - // FaceNormalsHelper only supports THREE.Geometry - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xffff00; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - // - - var nNormals = 0; - - var objGeometry = this.object.geometry; - - if ( objGeometry && objGeometry.isGeometry ) { - - nNormals = objGeometry.faces.length; - - } else { - - console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); - - } - - // - - var geometry = new BufferGeometry(); - - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); - - geometry.addAttribute( 'position', positions ); - - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); - - // - - this.matrixAutoUpdate = false; - this.update(); - -} - -FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); -FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; - -FaceNormalsHelper.prototype.update = ( function () { - - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); - - return function update() { - - this.object.updateMatrixWorld( true ); - - normalMatrix.getNormalMatrix( this.object.matrixWorld ); - - var matrixWorld = this.object.matrixWorld; - - var position = this.geometry.attributes.position; - - // - - var objGeometry = this.object.geometry; - - var vertices = objGeometry.vertices; - - var faces = objGeometry.faces; - - var idx = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - var normal = face.normal; - - v1.copy( vertices[ face.a ] ) - .add( vertices[ face.b ] ) - .add( vertices[ face.c ] ) - .divideScalar( 3 ) - .applyMatrix4( matrixWorld ); - - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); - - position.setXYZ( idx, v1.x, v1.y, v1.z ); - - idx = idx + 1; - - position.setXYZ( idx, v2.x, v2.y, v2.z ); - - idx = idx + 1; - - } - - position.needsUpdate = true; - - }; - -}() ); - -/** - * @author alteredq / http://alteredqualia.com/ - * @author Mugen87 / https://github.com/Mugen87 - * - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * http://evanw.github.com/lightgl.js/tests/shadowmap.html - */ - -function CameraHelper( camera ) { - - var geometry = new BufferGeometry(); - var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); - - var vertices = []; - var colors = []; - - var pointMap = {}; - - // colors - - var colorFrustum = new Color( 0xffaa00 ); - var colorCone = new Color( 0xff0000 ); - var colorUp = new Color( 0x00aaff ); - var colorTarget = new Color( 0xffffff ); - var colorCross = new Color( 0x333333 ); - - // near - - addLine( "n1", "n2", colorFrustum ); - addLine( "n2", "n4", colorFrustum ); - addLine( "n4", "n3", colorFrustum ); - addLine( "n3", "n1", colorFrustum ); - - // far - - addLine( "f1", "f2", colorFrustum ); - addLine( "f2", "f4", colorFrustum ); - addLine( "f4", "f3", colorFrustum ); - addLine( "f3", "f1", colorFrustum ); - - // sides - - addLine( "n1", "f1", colorFrustum ); - addLine( "n2", "f2", colorFrustum ); - addLine( "n3", "f3", colorFrustum ); - addLine( "n4", "f4", colorFrustum ); - - // cone - - addLine( "p", "n1", colorCone ); - addLine( "p", "n2", colorCone ); - addLine( "p", "n3", colorCone ); - addLine( "p", "n4", colorCone ); - - // up - - addLine( "u1", "u2", colorUp ); - addLine( "u2", "u3", colorUp ); - addLine( "u3", "u1", colorUp ); - - // target - - addLine( "c", "t", colorTarget ); - addLine( "p", "c", colorCross ); - - // cross - - addLine( "cn1", "cn2", colorCross ); - addLine( "cn3", "cn4", colorCross ); - - addLine( "cf1", "cf2", colorCross ); - addLine( "cf3", "cf4", colorCross ); - - function addLine( a, b, color ) { - - addPoint( a, color ); - addPoint( b, color ); - - } - - function addPoint( id, color ) { - - vertices.push( 0, 0, 0 ); - colors.push( color.r, color.g, color.b ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - - } - - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - LineSegments.call( this, geometry, material ); - - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - -} - -CameraHelper.prototype = Object.create( LineSegments.prototype ); -CameraHelper.prototype.constructor = CameraHelper; - -CameraHelper.prototype.update = function () { - - var geometry, pointMap; - - var vector = new Vector3(); - var camera = new Camera(); - - function setPoint( point, x, y, z ) { - - vector.set( x, y, z ).unproject( camera ); - - var points = pointMap[ point ]; - - if ( points !== undefined ) { - - var position = geometry.getAttribute( 'position' ); - - for ( var i = 0, l = points.length; i < l; i ++ ) { - - position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); - - } - - } - - } - - return function update() { - - geometry = this.geometry; - pointMap = this.pointMap; - - var w = 1, h = 1; - - // we need just camera projection matrix - // world matrix must be identity - - camera.projectionMatrix.copy( this.camera.projectionMatrix ); - - // center / target - - setPoint( "c", 0, 0, - 1 ); - setPoint( "t", 0, 0, 1 ); - - // near - - setPoint( "n1", - w, - h, - 1 ); - setPoint( "n2", w, - h, - 1 ); - setPoint( "n3", - w, h, - 1 ); - setPoint( "n4", w, h, - 1 ); - - // far - - setPoint( "f1", - w, - h, 1 ); - setPoint( "f2", w, - h, 1 ); - setPoint( "f3", - w, h, 1 ); - setPoint( "f4", w, h, 1 ); - - // up - - setPoint( "u1", w * 0.7, h * 1.1, - 1 ); - setPoint( "u2", - w * 0.7, h * 1.1, - 1 ); - setPoint( "u3", 0, h * 2, - 1 ); - - // cross - - setPoint( "cf1", - w, 0, 1 ); - setPoint( "cf2", w, 0, 1 ); - setPoint( "cf3", 0, - h, 1 ); - setPoint( "cf4", 0, h, 1 ); - - setPoint( "cn1", - w, 0, - 1 ); - setPoint( "cn2", w, 0, - 1 ); - setPoint( "cn3", 0, - h, - 1 ); - setPoint( "cn4", 0, h, - 1 ); - - geometry.getAttribute( 'position' ).needsUpdate = true; - - }; - -}(); - -/** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 - * @author bhouston / http://clara.io - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * color - color in hex value - * headLength - Number - * headWidth - Number - */ - -/** - * @author zz85 https://github.com/zz85 - * - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ - - -/* -Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM - -This CubicPoly class could be used for reusing some variables and calculations, -but for three.js curve use, it could be possible inlined and flatten into a single function call -which can be placed in CurveUtils. -*/ - -function CubicPoly() { - - var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { - - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; - - } - - return { - - initCatmullRom: function ( x0, x1, x2, x3, tension ) { - - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - - }, - - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - - // compute tangents when parameterized in [t1,t2] - var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; - - init( x1, x2, t1, t2 ); - - }, - - calc: function ( t ) { - - var t2 = t * t; - var t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - -} - -// - -var tmp = new Vector3(); -var px = new CubicPoly(); -var py = new CubicPoly(); -var pz = new CubicPoly(); - -function CatmullRomCurve3( points ) { - - Curve.call( this ); - - if ( points.length < 2 ) console.warn( 'THREE.CatmullRomCurve3: Points array needs at least two entries.' ); - - this.points = points || []; - this.closed = false; - -} - -CatmullRomCurve3.prototype = Object.create( Curve.prototype ); -CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - -CatmullRomCurve3.prototype.getPoint = function ( t ) { - - var points = this.points; - var l = points.length; - - var point = ( l - ( this.closed ? 0 : 1 ) ) * t; - var intPoint = Math.floor( point ); - var weight = point - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - var p0, p1, p2, p3; // 4 points - - if ( this.closed || intPoint > 0 ) { - - p0 = points[ ( intPoint - 1 ) % l ]; - - } else { - - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; - - } - - p1 = points[ intPoint % l ]; - p2 = points[ ( intPoint + 1 ) % l ]; - - if ( this.closed || intPoint + 2 < l ) { - - p3 = points[ ( intPoint + 2 ) % l ]; - - } else { - - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; - - } - - if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) { - - // init Centripetal / Chordal Catmull-Rom - var pow = this.type === 'chordal' ? 0.5 : 0.25; - var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; - - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - - } else if ( this.type === 'catmullrom' ) { - - var tension = this.tension !== undefined ? this.tension : 0.5; - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension ); - - } - - return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) ); - -}; - -function CubicBezierCurve3( v0, v1, v2, v3 ) { - - Curve.call( this ); - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - -} - -CubicBezierCurve3.prototype = Object.create( Curve.prototype ); -CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - -CubicBezierCurve3.prototype.getPoint = function ( t ) { - - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - return new Vector3( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - - - - - - - - - - - - - - - - - - - - - - - - - -// - - - - - - - - - - - - - - - - - - - - - -// - -Curve.create = function ( construct, getPoint ) { - - console.log( 'THREE.Curve.create() has been deprecated' ); - - construct.prototype = Object.create( Curve.prototype ); - construct.prototype.constructor = construct; - construct.prototype.getPoint = getPoint; - - return construct; - -}; - -// - - - -// - - - -// - -function Spline( points ) { - - console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); - - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; - -} - -Spline.prototype = Object.create( CatmullRomCurve3.prototype ); - -Object.assign( Spline.prototype, { - - initFromArray: function ( a ) { - - console.error( 'THREE.Spline: .initFromArray() has been removed.' ); - - }, - getControlPointsArray: function ( optionalTarget ) { - - console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); - - }, - reparametrizeByArcLength: function ( samplingCoef ) { - - console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); - - } - -} ); - -// - - - - -SkeletonHelper.prototype.update = function () { - - console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' ); - -}; - - - -// - - - - - -// - -Object.assign( Box2.prototype, { - - center: function ( optionalTarget ) { - - console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - - }, - empty: function () { - - console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); - - }, - isIntersectionBox: function ( box ) { - - console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }, - size: function ( optionalTarget ) { - - console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); - - } -} ); - -Object.assign( Box3.prototype, { - - center: function ( optionalTarget ) { - - console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - - }, - empty: function () { - - console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); - - }, - isIntersectionBox: function ( box ) { - - console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }, - isIntersectionSphere: function ( sphere ) { - - console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); - - }, - size: function ( optionalTarget ) { - - console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); - - } -} ); - -Line3.prototype.center = function ( optionalTarget ) { - - console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - -}; - -_Math.random16 = function () { - - console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' ); - return Math.random(); - -}; - -Object.assign( Matrix3.prototype, { - - flattenToArrayOffset: function ( array, offset ) { - - console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); - - }, - multiplyVector3: function ( vector ) { - - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); - - }, - multiplyVector3Array: function ( a ) { - - console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); - - }, - applyToBuffer: function( buffer, offset, length ) { - - console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); - - }, - applyToVector3Array: function( array, offset, length ) { - - console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); - - } - -} ); - -Object.assign( Matrix4.prototype, { - - extractPosition: function ( m ) { - - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); - - }, - flattenToArrayOffset: function ( array, offset ) { - - console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); - - }, - getPosition: function () { - - var v1; - - return function getPosition() { - - if ( v1 === undefined ) v1 = new Vector3(); - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - return v1.setFromMatrixColumn( this, 3 ); - - }; - - }(), - setRotationFromQuaternion: function ( q ) { - - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - return this.makeRotationFromQuaternion( q ); - - }, - multiplyToArray: function () { - - console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); - - }, - multiplyVector3: function ( vector ) { - - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - multiplyVector4: function ( vector ) { - - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - multiplyVector3Array: function ( a ) { - - console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' ); - - }, - rotateAxis: function ( v ) { - - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - v.transformDirection( this ); - - }, - crossVector: function ( vector ) { - - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - translate: function () { - - console.error( 'THREE.Matrix4: .translate() has been removed.' ); - - }, - rotateX: function () { - - console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - - }, - rotateY: function () { - - console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - - }, - rotateZ: function () { - - console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - - }, - rotateByAxis: function () { - - console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - - }, - applyToBuffer: function( buffer, offset, length ) { - - console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); - - }, - applyToVector3Array: function( array, offset, length ) { - - console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); - - }, - makeFrustum: function( left, right, bottom, top, near, far ) { - - console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' ); - return this.makePerspective( left, right, top, bottom, near, far ); - - } - -} ); - -Plane.prototype.isIntersectionLine = function ( line ) { - - console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); - return this.intersectsLine( line ); - -}; - -Quaternion.prototype.multiplyVector3 = function ( vector ) { - - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); - -}; - -Object.assign( Ray.prototype, { - - isIntersectionBox: function ( box ) { - - console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }, - isIntersectionPlane: function ( plane ) { - - console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); - return this.intersectsPlane( plane ); - - }, - isIntersectionSphere: function ( sphere ) { - - console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); - - } - -} ); - -Object.assign( Shape.prototype, { - - extrude: function ( options ) { - - console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); - return new ExtrudeGeometry( this, options ); - - }, - makeGeometry: function ( options ) { - - console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); - return new ShapeGeometry( this, options ); - - } - -} ); - -Object.assign( Vector2.prototype, { - - fromAttribute: function ( attribute, index, offset ) { - - console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - } - -} ); - -Object.assign( Vector3.prototype, { - - setEulerFromRotationMatrix: function () { - - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - - }, - setEulerFromQuaternion: function () { - - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - - }, - getPositionFromMatrix: function ( m ) { - - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - return this.setFromMatrixPosition( m ); - - }, - getScaleFromMatrix: function ( m ) { - - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - return this.setFromMatrixScale( m ); - - }, - getColumnFromMatrix: function ( index, matrix ) { - - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return this.setFromMatrixColumn( matrix, index ); - - }, - applyProjection: function ( m ) { - - console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); - return this.applyMatrix4( m ); - - }, - fromAttribute: function ( attribute, index, offset ) { - - console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - } - -} ); - -Object.assign( Vector4.prototype, { - - fromAttribute: function ( attribute, index, offset ) { - - console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - } - -} ); - -// - -Geometry.prototype.computeTangents = function () { - - console.warn( 'THREE.Geometry: .computeTangents() has been removed.' ); - -}; - -Object.assign( Object3D.prototype, { - - getChildByName: function ( name ) { - - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name ); - - }, - renderDepth: function () { - - console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); - - }, - translate: function ( distance, axis ) { - - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); - return this.translateOnAxis( axis, distance ); - - } - -} ); - -Object.defineProperties( Object3D.prototype, { - - eulerOrder: { - get: function () { - - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - return this.rotation.order; - - }, - set: function ( value ) { - - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - this.rotation.order = value; - - } - }, - useQuaternion: { - get: function () { - - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - set: function () { - - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - } - } - -} ); - -Object.defineProperties( LOD.prototype, { - - objects: { - get: function () { - - console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); - return this.levels; - - } - } - -} ); - -Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { - - get: function () { - - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); - - }, - set: function () { - - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); - - } - -} ); - -Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { - - get: function () { - - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - return this.arcLengthDivisions; - - }, - set: function ( value ) { - - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - this.arcLengthDivisions = value; - - } - -} ); - -// - -PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { - - console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + - "Use .setFocalLength and .filmGauge for a photographic setup." ); - - if ( filmGauge !== undefined ) this.filmGauge = filmGauge; - this.setFocalLength( focalLength ); - -}; - -// - -Object.defineProperties( Light.prototype, { - onlyShadow: { - set: function () { - - console.warn( 'THREE.Light: .onlyShadow has been removed.' ); - - } - }, - shadowCameraFov: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); - this.shadow.camera.fov = value; - - } - }, - shadowCameraLeft: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); - this.shadow.camera.left = value; - - } - }, - shadowCameraRight: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); - this.shadow.camera.right = value; - - } - }, - shadowCameraTop: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); - this.shadow.camera.top = value; - - } - }, - shadowCameraBottom: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); - this.shadow.camera.bottom = value; - - } - }, - shadowCameraNear: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); - this.shadow.camera.near = value; - - } - }, - shadowCameraFar: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); - this.shadow.camera.far = value; - - } - }, - shadowCameraVisible: { - set: function () { - - console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); - - } - }, - shadowBias: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); - this.shadow.bias = value; - - } - }, - shadowDarkness: { - set: function () { - - console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); - - } - }, - shadowMapWidth: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); - this.shadow.mapSize.width = value; - - } - }, - shadowMapHeight: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); - this.shadow.mapSize.height = value; - - } - } -} ); - -// - -Object.defineProperties( BufferAttribute.prototype, { - - length: { - get: function () { - - console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); - return this.array.length; - - } - } - -} ); - -Object.assign( BufferGeometry.prototype, { - - addIndex: function ( index ) { - - console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); - this.setIndex( index ); - - }, - addDrawCall: function ( start, count, indexOffset ) { - - if ( indexOffset !== undefined ) { - - console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); - - } - console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); - this.addGroup( start, count ); - - }, - clearDrawCalls: function () { - - console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); - this.clearGroups(); - - }, - computeTangents: function () { - - console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); - - }, - computeOffsets: function () { - - console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); - - } - -} ); - -Object.defineProperties( BufferGeometry.prototype, { - - drawcalls: { - get: function () { - - console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); - return this.groups; - - } - }, - offsets: { - get: function () { - - console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); - return this.groups; - - } - } - -} ); - -// - -Object.defineProperties( Uniform.prototype, { - - dynamic: { - set: function () { - - console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); - - } - }, - onUpdate: { - value: function () { - - console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); - return this; - - } - } - -} ); - -// - -Object.defineProperties( Material.prototype, { - - wrapAround: { - get: function () { - - console.warn( 'THREE.Material: .wrapAround has been removed.' ); - - }, - set: function () { - - console.warn( 'THREE.Material: .wrapAround has been removed.' ); - - } - }, - wrapRGB: { - get: function () { - - console.warn( 'THREE.Material: .wrapRGB has been removed.' ); - return new Color(); - - } - } - -} ); - -Object.defineProperties( MeshPhongMaterial.prototype, { - - metal: { - get: function () { - - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); - return false; - - }, - set: function () { - - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); - - } - } - -} ); - -Object.defineProperties( ShaderMaterial.prototype, { - - derivatives: { - get: function () { - - console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - return this.extensions.derivatives; - - }, - set: function ( value ) { - - console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - this.extensions.derivatives = value; - - } - } - -} ); - -// - -Object.assign( WebGLRenderer.prototype, { - - getCurrentRenderTarget: function () { - - console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); - return this.getRenderTarget(); - - }, - - supportsFloatTextures: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); - return this.extensions.get( 'OES_texture_float' ); - - }, - supportsHalfFloatTextures: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); - return this.extensions.get( 'OES_texture_half_float' ); - - }, - supportsStandardDerivatives: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); - return this.extensions.get( 'OES_standard_derivatives' ); - - }, - supportsCompressedTextureS3TC: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - }, - supportsCompressedTexturePVRTC: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - }, - supportsBlendMinMax: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); - return this.extensions.get( 'EXT_blend_minmax' ); - - }, - supportsVertexTextures: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); - return this.capabilities.vertexTextures; - - }, - supportsInstancedArrays: function () { - - console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); - return this.extensions.get( 'ANGLE_instanced_arrays' ); - - }, - enableScissorTest: function ( boolean ) { - - console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); - this.setScissorTest( boolean ); - - }, - initMaterial: function () { - - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); - - }, - addPrePlugin: function () { - - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - - }, - addPostPlugin: function () { - - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); - - }, - updateShadowMap: function () { - - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - - } - -} ); - -Object.defineProperties( WebGLRenderer.prototype, { - - shadowMapEnabled: { - get: function () { - - return this.shadowMap.enabled; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); - this.shadowMap.enabled = value; - - } - }, - shadowMapType: { - get: function () { - - return this.shadowMap.type; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); - this.shadowMap.type = value; - - } - }, - shadowMapCullFace: { - get: function () { - - return this.shadowMap.cullFace; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' ); - this.shadowMap.cullFace = value; - - } - } -} ); - -Object.defineProperties( WebGLShadowMap.prototype, { - - cullFace: { - get: function () { - - return this.renderReverseSided ? CullFaceFront : CullFaceBack; - - }, - set: function ( cullFace ) { - - var value = ( cullFace !== CullFaceBack ); - console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." ); - this.renderReverseSided = value; - - } - } - -} ); - -// - -Object.defineProperties( WebGLRenderTarget.prototype, { - - wrapS: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - return this.texture.wrapS; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - this.texture.wrapS = value; - - } - }, - wrapT: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - return this.texture.wrapT; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - this.texture.wrapT = value; - - } - }, - magFilter: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - return this.texture.magFilter; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - this.texture.magFilter = value; - - } - }, - minFilter: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - return this.texture.minFilter; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - this.texture.minFilter = value; - - } - }, - anisotropy: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - return this.texture.anisotropy; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - this.texture.anisotropy = value; - - } - }, - offset: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - return this.texture.offset; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - this.texture.offset = value; - - } - }, - repeat: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - return this.texture.repeat; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - this.texture.repeat = value; - - } - }, - format: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - return this.texture.format; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - this.texture.format = value; - - } - }, - type: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - return this.texture.type; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - this.texture.type = value; - - } - }, - generateMipmaps: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - return this.texture.generateMipmaps; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - this.texture.generateMipmaps = value; - - } - } - -} ); - -// - -Audio.prototype.load = function ( file ) { - - console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); - var scope = this; - var audioLoader = new AudioLoader(); - audioLoader.load( file, function ( buffer ) { - - scope.setBuffer( buffer ); - - } ); - return this; - -}; - -AudioAnalyser.prototype.getData = function () { - - console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); - return this.getFrequencyData(); - -}; - -// - - - - - -// - - - -// - -function AHI ( container ) { - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - Group.call( this ); - - this.name = 'CV.AHI'; - this.domObjects = []; - - this.lastPitch = 0; - - // artificial horizon instrument - var globe = new Group(); - - var ring = new CylinderBufferGeometry( stdWidth * 0.90, stdWidth, 3, 32, 1, true ); - ring.rotateX( Math.PI / 2 ); - - var sphere = new SphereBufferGeometry( stdWidth - 10, 31, 31 ); - var bar = new Geometry(); - var marks = new Geometry(); - - var sv = sphere.getAttribute( 'position' ).count; - - var sphereColors = new BufferAttribute( new Float32Array( sv * 3 ), 3 ); - - var colours = []; - - var c1 = ColourCache.hudBlue; - var c2 = ColourCache.hudRed; - - var i; - - for ( i = 0; i < sv; i++ ) { - - colours.push( ( i < sv / 2 ) ? c1 : c2 ); - - } - - sphere.addAttribute( 'color', sphereColors.copyColorsArray( colours ) ); - - // view orinetation line - bar.vertices.push( new Vector3( 4 - stdWidth, 0, stdWidth ) ); - bar.vertices.push( new Vector3( stdWidth - 4, 0, stdWidth ) ); - - // pitch interval marks - var m1 = new Vector3( 4, 0, stdWidth - 10 ); - var m2 = new Vector3( -4, 0, stdWidth - 10 ); - - var xAxis = new Vector3( 1, 0, 0 ); - - for ( i = 0; i < 12; i++ ) { - - var mn1 = m1.clone(); - var mn2 = m2.clone(); - - if ( i % 3 === 0 ) { - - mn1.x = 7; - mn2.x = -7; - - } - - mn1.applyAxisAngle( xAxis, i * Math.PI / 6 ); - mn2.applyAxisAngle( xAxis, i * Math.PI / 6 ); - - marks.vertices.push( mn1 ); - marks.vertices.push( mn2 ); - - } - - var mRing = new Mesh( ring, new MeshPhongMaterial( { color: 0x888888, specular: 0x888888 } ) ); - var mSphere = new Mesh( sphere, new MeshPhongMaterial( { vertexColors: VertexColors, specular: 0x666666, shininess: 20 } ) ); - var mBar = new LineSegments( bar, new LineBasicMaterial( { color: 0xcccc00 } ) ); - var mMarks = new LineSegments( marks, new LineBasicMaterial( { color: 0xffffff } ) ); - - mSphere.rotateOnAxis( new Vector3( 0, 1, 0 ), Math.PI / 2 ); - mMarks.rotateOnAxis( new Vector3( 1, 0, 0 ), Math.PI / 2 ); - mRing.rotateOnAxis( new Vector3( 0, 0, 1 ), Math.PI / 8 ); - - globe.add( mSphere ); - globe.add( mMarks ); - - this.add( mRing ); - this.add( globe ); - this.add( mBar ); - - var offset = stdWidth + stdMargin; - - this.translateX( -3 * offset ); - this.translateY( offset ); - - var panel = document.createElement( 'div' ); - - panel.classList.add( 'cv-ahi' ); - panel.textContent = ''; - - container.appendChild( panel ); - - this.globe = globe; - this.txt = panel; - - this.domObjects.push( panel ); - - this.addEventListener( 'removed', this.removeDomObjects ); - this.txt.textContent = '-90\u00B0'; - - return this; - -} - -AHI.prototype = Object.create( Group.prototype ); - -Object.assign( AHI.prototype, HudObject.prototype ); - -AHI.prototype.constructor = AHI; - -AHI.prototype.set = function () { - - var direction = new Vector3(); - var xAxis = new Vector3( 1, 0, 0 ); - - return function set ( vCamera ) { - - vCamera.getWorldDirection( direction ); - - var pitch = Math.PI / 2 - direction.angleTo( upAxis ); - - if ( pitch === this.lastPitch ) return; - - this.globe.rotateOnAxis( xAxis, pitch - this.lastPitch ); - this.lastPitch = pitch; - - this.txt.textContent = Math.round( _Math.radToDeg( pitch ) ) + '\u00B0'; - - }; - -} (); - - - -// EOF - -function AngleScale ( container ) { - - var width = container.clientWidth; - var height = container.clientHeight; - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - var i, l; - - var geometry = new RingGeometry( 1, 40, 36, 1, Math.PI, Math.PI ); - var c = []; - - var pNormal = new Vector3( 1, 0, 0 ); - var hues = ColourCache.getColors( 'inclination' ); - - var vertices = geometry.vertices; - var legNormal = new Vector3(); - - for ( i = 0, l = vertices.length; i < l; i++ ) { - - legNormal.copy( vertices[ i ] ).normalize(); - - var dotProduct = legNormal.dot( pNormal ); - var hueIndex = Math.floor( 127 * 2 * Math.asin( Math.abs( dotProduct ) ) / Math.PI ); - - c[ i ] = hues[ hueIndex ]; - - } - - var faces = geometry.faces, f; - - for ( i = 0, l = faces.length; i < l; i++ ) { - - f = faces[ i ]; - - f.vertexColors = [ c[ f.a ], c[ f.b ], c[ f.c ] ]; - - } - - geometry.colorsNeedUpdate = true; - - Mesh.call( this, geometry, new MeshBasicMaterial( { color: 0xffffff, vertexColors: VertexColors, side: FrontSide } ) ); - - this.translateY( -height / 2 + 3 * ( stdWidth + stdMargin ) + stdMargin + 30 ); - this.translateX( width / 2 - 40 - 5 ); - - this.name = 'CV.AngleScale'; - this.domObjects = []; - - var legend = document.createElement( 'div' ); - - legend.id = 'angle-legend'; - legend.textContent = 'Inclination'; - - container.appendChild( legend ); - - this.txt = legend; - this.domObjects.push( legend ); - - this.addEventListener( 'removed', this.removeDomObjects ); - - return this; - -} - -AngleScale.prototype = Object.create( Mesh.prototype ); - -Object.assign( AngleScale.prototype, HudObject.prototype ); - -AngleScale.prototype.constructor = AngleScale; - - - -// EOF - -function Compass ( container ) { - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - Group.call( this ); - - this.name = 'CV.Compass'; - this.domObjects = []; - - var cg1 = new CylinderBufferGeometry( stdWidth * 0.90, stdWidth, 3, 32, 1, true ); - cg1.rotateX( Math.PI / 2 ); - - var c1 = new Mesh( cg1, new MeshPhongMaterial( { color: 0x888888, specular: 0x888888 } ) ); - - var cg2 = new RingGeometry( stdWidth * 0.9, stdWidth, 4, 1, -Math.PI / 32 + Math.PI / 2, Math.PI / 16 ); - cg2.translate( 0, 0, 5 ); - - var c2 = new Mesh( cg2, new MeshBasicMaterial( { color: 0xb03a14 } ) ); - - var r1 = _makeRose( stdWidth * 0.8, 0.141, 0x581d0a, 0x0c536a ); - var r2 = _makeRose( stdWidth * 0.9, 0.141, 0xb03a14, 0x1ab4e5 ); - - r1.rotateZ( Math.PI / 4 ); - r1.merge( r2 ); - - var rMesh = new Mesh( r1, new MeshLambertMaterial( { vertexColors: VertexColors, side: FrontSide, shading: FlatShading } ) ); - - this.add( c1 ); - this.add( c2 ); - this.add( rMesh ); - - var offset = stdWidth + stdMargin; - - this.translateX( -offset ); - this.translateY( offset ); - - this.lastRotation = 0; - - var panel = document.createElement( 'div' ); - - panel.classList.add( 'cv-compass' ); - panel.textContent = ''; - - container.appendChild( panel ); - - this.txt = panel; - this.domObjects.push( panel ); - - this.addEventListener( 'removed', this.removeDomObjects ); - this.txt.textContent = '000\u00B0'; - - return this; - - // make 'petal' for compass rose - function _makePetal ( radius, scale, color1, color2 ) { - - var innerR = radius * scale; - var g = new Geometry(); - - g.vertices.push( new Vector3( 0, radius, 0 ) ); - g.vertices.push( new Vector3( innerR ,innerR, 0 ) ); - g.vertices.push( new Vector3( 0, 0, 14 * scale ) ); - g.vertices.push( new Vector3( -innerR, innerR, 0 ) ); - - var f1 = new Face3( 0, 2, 1, new Vector3( 0, 0, 1 ), color1, 0 ); - var f2 = new Face3( 0, 3, 2, new Vector3( 0, 0, 1 ), color2, 0 ); - - g.faces.push( f1 ); - g.faces.push( f2 ); - - return g; - - } - - function _makeRose ( radius, scale, color1, color2 ) { - - var p1 = _makePetal( radius, scale, new Color( color1 ), new Color( color2 ) ); - var p2 = p1.clone(); - var p3 = p1.clone(); - var p4 = p1.clone(); - - p2.rotateZ( Math.PI / 2 ); - p3.rotateZ( Math.PI ); - p4.rotateZ( Math.PI / 2 * 3 ); - - p1.merge( p2 ); - p1.merge( p3 ); - p1.merge( p4 ); - - p1.computeFaceNormals(); - - return p1; - - } - -} - -Compass.prototype = Object.create( Group.prototype ); - -Object.assign( Compass.prototype, HudObject.prototype ); - -Compass.prototype.constructor = Compass; - -Compass.prototype.set = function () { - - var direction = new Vector3(); - var yAxis = new Vector3( 0, 1, 0 ); - var negativeZAxis = new Vector3( 0, 0, -1 ); - - return function set ( vCamera ) { - - vCamera.getWorldDirection( direction ); - - if ( direction.x === 0 && direction.y === 0 ) { - - // FIXME get camera rotation.... - return; - - } - - // we are only interested in angle to horizontal plane. - direction.z = 0; - - var a = direction.angleTo( yAxis ); - - if ( direction.x >= 0 ) a = 2 * Math.PI - a; - - if ( a === this.lastRotation ) return; - - var degrees = 360 - Math.round( _Math.radToDeg( a ) ); - - this.txt.textContent = degrees.toString().padStart( 3, '0' ) + '\u00B0'; // unicode degree symbol - - this.rotateOnAxis( negativeZAxis, a - this.lastRotation ); - - this.lastRotation = a; - - }; - -} (); - - - -// EOF - -var cursorVertexShader = "\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\t\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float height;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\theight = position.z;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n"; - -var cursorFragmentShader = "\r\nuniform float cursor;\r\nuniform float cursorWidth;\r\n\r\nuniform vec3 baseColor;\r\nuniform vec3 cursorColor;\r\n\r\nvarying float height;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n#else\r\n\r\n\tfloat light = 1.0;\r\n\r\n#endif\r\n\r\n\tfloat delta = abs( height - cursor );\r\n\tfloat ss = smoothstep( 0.0, cursorWidth, cursorWidth - delta );\r\n\r\n\r\n#ifdef SURFACE\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light;\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 );\r\n\r\n\t}\r\n\r\n#else\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light * vec4( vColor, 1.0 );\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 ) * vec4( vColor, 1.0 );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n}\r\n"; - -var depthMapVertexShader = "\r\nuniform float minZ;\r\nuniform float scaleZ;\r\n\r\nvarying float vHeight;\r\n\r\nvoid main() {\r\n\r\n\tvHeight = ( position.z - minZ ) * scaleZ;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n"; - -var depthMapFragmentShader = "\r\nconst float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\n\r\nconst float ShiftRight8 = 1. / 256.;\r\n\r\nvec4 packFloatToRGBA( const in float v ) {\r\n\r\n\tvec4 r = vec4( fract( v * PackFactors ), v );\r\n\r\n\tr.yzw -= r.xyz * ShiftRight8; // tidy overflow\r\n\r\n\treturn r * PackUpscale;\r\n\r\n}\r\n\r\nvarying float vHeight;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = packFloatToRGBA( vHeight );\r\n\r\n}\r\n"; - -var depthVertexShader = "const float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nfloat unpackRGBAToFloat( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\nuniform float minX;\r\nuniform float minY;\r\nuniform float minZ;\r\n\r\nuniform float scaleX;\r\nuniform float scaleY;\r\nuniform float rangeZ;\r\n\r\nuniform float depthScale;\r\n\r\nuniform sampler2D depthMap;\r\nuniform float datumShift;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float vDepth;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\t// get terrain height in model space\r\n\r\n\tvec2 terrainCoords = vec2( ( position.x - minX ) * scaleX, ( position.y - minY ) * scaleY );\r\n\tfloat terrainHeight = unpackRGBAToFloat( texture2D( depthMap, terrainCoords ) );\r\n\r\n\tterrainHeight = terrainHeight * rangeZ + minZ + datumShift;\r\n\r\n\t// depth below terrain for this vertex, scaled in 0.0 - 1.0 range\r\n\r\n\tvDepth = ( terrainHeight - position.z ) * depthScale;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n"; - -var depthFragmentShader = "\r\nuniform sampler2D cmap;\r\nvarying float vDepth;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( vDepth, 1.0 ) ) * light;\r\n\r\n#else\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( vDepth, 1.0 ) ) * vec4( vColor, 1.0 );\r\n\r\n#endif\r\n\r\n}\r\n"; - -var depthCursorVertexShader = "\r\nconst float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)\r\n\r\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\r\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\r\n\r\nfloat unpackRGBAToFloat( const in vec4 v ) {\r\n\treturn dot( v, UnpackFactors );\r\n}\r\n\r\nuniform float minX;\r\nuniform float minY;\r\nuniform float minZ;\r\n\r\nuniform float scaleX;\r\nuniform float scaleY;\r\nuniform float rangeZ;\r\n\r\nuniform sampler2D depthMap;\r\nuniform float datumShift;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\t\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float vDepth;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\tvec2 terrainCoords = vec2( ( position.x - minX ) * scaleX, ( position.y - minY ) * scaleY );\r\n\tfloat terrainHeight = unpackRGBAToFloat( texture2D( depthMap, terrainCoords ) );\r\n\r\n\tvDepth = terrainHeight * rangeZ + datumShift + minZ - position.z;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n\r\n\r\n\r\n\r\n\r\n"; - -var depthCursorFragmentShader = "\r\nuniform float cursor;\r\nuniform float cursorWidth;\r\n\r\nuniform vec3 baseColor;\r\nuniform vec3 cursorColor;\r\n\r\nvarying float vDepth;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n\tfloat light;\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n#else\r\n\r\n\tlight = 1.0;\r\n\r\n#endif\r\n\r\n\tfloat delta = abs( vDepth - cursor );\r\n\tfloat ss = smoothstep( 0.0, cursorWidth, cursorWidth - delta );\r\n\r\n#ifdef SURFACE\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light;\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 );\r\n\r\n\t}\r\n\r\n#else\r\n\r\n\tif ( delta < cursorWidth * 0.05 ) {\r\n\r\n\t\tgl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * light * vec4( vColor, 1.0 );\r\n\r\n\t} else {\r\n\r\n\t\tgl_FragColor = vec4( mix( baseColor, cursorColor, ss ) * light, 1.0 ) * vec4( vColor, 1.0 );\r\n\r\n\t}\r\n\r\n#endif\r\n\r\n}"; - -var extendedPointsVertexShader = "uniform float size;\r\nuniform float scale;\r\nuniform float pScale;\r\n\r\nattribute float pSize;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\t#ifdef USE_SIZEATTENUATION\r\n\t\tgl_PointSize = pScale * pSize * ( scale / - mvPosition.z );\r\n\t#else\r\n\t\tgl_PointSize = pScale * pSize;\r\n\t#endif\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var extendedPointsFragmentShader = "uniform vec3 diffuse;\r\nuniform float opacity;\r\n\r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n#include \r\n\r\nvoid main() {\r\n\r\n\t#include \r\n\r\n\tvec3 outgoingLight = vec3( 0.0 );\r\n\tvec4 diffuseColor = vec4( diffuse, opacity );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n\toutgoingLight = diffuseColor.rgb;\r\n\r\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n\t#include \r\n\t#include \r\n\t#include \r\n\t#include \r\n\r\n}\r\n"; - -var glyphVertexShader = "\r\n\r\n// glyph shader, each instance represents one glyph.\r\n\r\nuniform float cellScale;\r\nuniform mat2 rotate;\r\nuniform float scale;\r\n\r\nattribute vec2 instanceUvs;\r\nattribute float instanceOffsets;\r\nattribute float instanceWidths;\r\n\r\nvarying vec2 vUv;\r\nvarying vec3 vColor;\r\n\r\nvoid main() {\r\n\r\n\tvColor = color;\r\n\r\n\t// select glyph from atlas ( with proportional spacing ).\r\n\r\n\tvUv = instanceUvs + vec2( position.x * cellScale * instanceWidths, position.y * cellScale );\r\n\r\n\t// scale by glyph width ( vertices form unit square with (0,0) origin )\r\n\r\n\tvec2 newPosition = vec2( position.x * instanceWidths, position.y );\r\n\r\n\t// move to correct offset in string\r\n\r\n\tnewPosition.x += instanceOffsets;\r\n\r\n\t// rotate as required\r\n\r\n\tnewPosition = rotate * newPosition;\r\n\r\n\t// position of GlyphString object on screeno\r\n\r\n\tvec4 offset = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\r\n\r\n\t// scale glyphs\r\n\r\n\tnewPosition.xy *= 0.0625;\r\n\r\n\t// correct for aspect ratio\r\n\r\n\tnewPosition.x *= scale;\r\n\r\n\t// move to clip space\r\n\r\n\tnewPosition.xy *= offset.w;\r\n\r\n\tgl_Position = vec4( newPosition, 0.0, 0.0 ) + offset;\r\n\r\n}\r\n"; - -var glyphFragmentShader = "\r\nuniform sampler2D atlas;\r\n\r\nvarying vec2 vUv;\r\nvarying vec3 vColor;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = texture2D( atlas, vUv ) * vec4( vColor, 1.0 );\r\n\r\n}"; - -var heightVertexShader = "\r\nuniform sampler2D cmap;\r\n\r\nuniform float minZ;\r\nuniform float scaleZ;\r\n\r\n#ifdef SURFACE\r\n\r\nuniform vec3 uLight;\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvarying float zMap;\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tvNormal = normalMatrix * normal;\r\n\tlNormal = uLight;\r\n\r\n#else\r\n\r\n\tvColor = color;\r\n\r\n#endif\r\n\r\n\tzMap = ( position.z - minZ ) * scaleZ;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n"; - -var heightFragmentShader = "\r\nuniform sampler2D cmap;\r\n\r\nvarying float zMap;\r\n\r\n#ifdef SURFACE\r\n\r\nvarying vec3 vNormal;\r\nvarying vec3 lNormal;\r\n\r\n#else\r\n\r\nvarying vec3 vColor;\r\n\r\n#endif\r\n\r\nvoid main() {\r\n\r\n#ifdef SURFACE\r\n\r\n\tfloat nDot = dot( normalize( vNormal ), normalize( lNormal ) );\r\n\tfloat light;\r\n\tlight = 0.5 * ( nDot + 1.0 );\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( 1.0 - zMap, 1.0 ) ) * vec4( light, light, light, 1.0 );\r\n\r\n#else\r\n\r\n\tgl_FragColor = texture2D( cmap, vec2( 1.0 - zMap, 1.0 ) ) * vec4( vColor, 1.0 );\r\n\r\n#endif\r\n\r\n}\r\n"; - -var waterVertexShader = "\r\nattribute vec3 sinks;\r\n\r\nvarying vec3 vPosition;\r\nvarying vec3 vSink;\r\n\r\nvoid main() {\r\n\r\n\tvPosition = position;\r\n\tvSink = sinks;\r\n\r\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\r\n\r\n}\r\n"; - -var waterFragmentShader = "\r\nuniform float offset;\r\n\r\nvarying vec3 vPosition;\r\nvarying vec3 vSink;\r\n\r\nvoid main() {\r\n\r\n\tgl_FragColor = vec4( 0.1, 0.1, sin( offset + distance( vPosition, vSink ) ) * 0.4 + 0.6, 0.0 );\r\n\r\n}\r\n"; - -var Shaders = { - cursorVertexShader: cursorVertexShader, - cursorFragmentShader: cursorFragmentShader, - depthMapVertexShader: depthMapVertexShader, - depthMapFragmentShader: depthMapFragmentShader, - depthVertexShader: depthVertexShader, - depthFragmentShader: depthFragmentShader, - depthCursorVertexShader: depthCursorVertexShader, - depthCursorFragmentShader: depthCursorFragmentShader, - extendedPointsVertexShader: extendedPointsVertexShader, - extendedPointsFragmentShader: extendedPointsFragmentShader, - glyphVertexShader: glyphVertexShader, - glyphFragmentShader: glyphFragmentShader, - heightVertexShader: heightVertexShader, - heightFragmentShader: heightFragmentShader, - waterVertexShader: waterVertexShader, - waterFragmentShader: waterFragmentShader -}; - - -// EOF - -function CursorMaterial ( type, limits ) { - - ShaderMaterial.call( this ); - - this.halfRange = ( limits.max.z - limits.min.z ) / 2; - - this.defines = ( type === MATERIAL_LINE ) ? { USE_COLOR: true } : { SURFACE: true }; - - this.uniforms = { - uLight: { value: new Vector3( -1, -1, 2 ) }, - cursor: { value: 0 }, - cursorWidth: { value: 5.0 }, - baseColor: { value: ColourCache.lightGrey }, - cursorColor: { value: ColourCache.green } - }; - - this.vertexShader = Shaders.cursorVertexShader; - this.fragmentShader = Shaders.cursorFragmentShader; - - this.type = 'CV.CursorMaterial'; - - this.addEventListener( 'update', _update ); - - return this; - - function _update() { - - this.uniforms.surfaceOpacity.value = this.opacity; - - } - -} - -CursorMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -CursorMaterial.prototype.constructor = CursorMaterial; - -CursorMaterial.prototype.setCursor = function ( value ) { - - var newValue = Math.max( Math.min( value, this.halfRange ), -this.halfRange ); - - this.uniforms.cursor.value = newValue; - - return newValue; // return value clamped to material range - -}; - -CursorMaterial.prototype.getCursor = function () { - - return this.uniforms.cursor.value; - -}; - - - -// EOF - -function DepthMaterial ( type, surveyLimits, terrain ) { - - var limits = terrain.boundingBox; - var range = limits.getSize(); - - var defines = ( type === MATERIAL_LINE ) ? { USE_COLOR: true } : { SURFACE: true }; - - ShaderMaterial.call( this, { - - uniforms: { - // pseudo light source somewhere over viewer's left shoulder. - uLight: { value: new Vector3( -1, -1, 2 ) }, - minX: { value: limits.min.x }, - minY: { value: limits.min.y }, - minZ: { value: limits.min.z }, - scaleX: { value: 1 / range.x }, - scaleY: { value: 1 / range.y }, - rangeZ: { value: range.z }, - depthScale: { value: 1 / ( surveyLimits.max.z - surveyLimits.min.z ) }, - cmap: { value: ColourCache.getTexture( 'gradient' ) }, - depthMap: { value: terrain.depthTexture }, - datumShift: { value: 0.0 } - }, - - defines: defines, - vertexShader: Shaders.depthVertexShader, - fragmentShader: Shaders.depthFragmentShader - } ); - - this.type = 'CV.DepthMaterial'; - - return this; - -} - -DepthMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -DepthMaterial.prototype.constructor = DepthMaterial; - -DepthMaterial.prototype.setDatumShift = function ( shift ) { - - this.uniforms.datumShift.value = shift; - -}; - - - -// EOF - -function DepthCursorMaterial ( type, surveyLimits, terrain ) { - - var limits = terrain.boundingBox; - var range = limits.getSize(); - - // max range of depth values - this.max = surveyLimits.max.z - surveyLimits.min.z; - - ShaderMaterial.call( this, { - - uniforms: { - uLight: { value: new Vector3( -1, -1, 2 ) }, - minX: { value: limits.min.x }, - minY: { value: limits.min.y }, - minZ: { value: limits.min.z }, - scaleX: { value: 1 / range.x }, - scaleY: { value: 1 / range.y }, - rangeZ: { value: range.z }, - depthMap: { value: terrain.depthTexture }, - datumShift: { value: 0.0 }, - cursor: { value: this.max / 2 }, - cursorWidth: { value: 5.0 }, - baseColor: { value: ColourCache.lightGrey }, - cursorColor: { value: ColourCache.green } - }, - vertexShader: Shaders.depthCursorVertexShader, - fragmentShader: Shaders.depthCursorFragmentShader - } ); - - this.defines = {}; - - if ( type === MATERIAL_LINE ) { - - this.defines.USE_COLOR = true; - - } else { - - this.defines.SURFACE = true; - - } - - this.type = 'CV.DepthCursorMaterial'; - - return this; - -} - -DepthCursorMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -DepthCursorMaterial.prototype.constructor = DepthCursorMaterial; - -DepthCursorMaterial.prototype.setCursor = function ( value ) { - - var newValue = Math.max( Math.min( value, this.max ), 0 ); - - this.uniforms.cursor.value = newValue; - - return newValue; // return value clamped to material range - -}; - -DepthCursorMaterial.prototype.getCursor = function () { - - return this.uniforms.cursor.value; - -}; - -DepthCursorMaterial.prototype.setDatumShift = function ( shift ) { - - this.uniforms.datumShift.value = shift; - -}; - - - -// EOF - -function DepthMapMaterial ( terrain ) { - - if ( terrain.boundingBox === undefined ) terrain.computeBoundingBox(); - - var boundingBox = terrain.boundingBox; - - var minHeight = boundingBox.min.z; - var maxHeight = boundingBox.max.z; - - ShaderMaterial.call( this, { - - uniforms: { - - minZ: { value: minHeight }, - scaleZ: { value: 1 / ( maxHeight - minHeight ) } - - }, - - vertexShader: Shaders.depthMapVertexShader, - fragmentShader: Shaders.depthMapFragmentShader, - depthWrite: false, - type: 'CV.DepthMapMaterial' - - } ); - - return this; - -} - -DepthMapMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -DepthMapMaterial.prototype.constructor = DepthMapMaterial; - - - -// EOF - -function HeightMaterial ( type, limits ) { - - ShaderMaterial.call( this ); - - this.defines = ( type === MATERIAL_LINE ) ? { USE_COLOR: true } : { SURFACE: true }; - - this.uniforms = { - uLight: { value: new Vector3( -1, -1, 2 ) }, // pseudo light source somewhere over viewer's left shoulder. - minZ: { value: limits.min.z }, - scaleZ: { value: 1 / ( limits.max.z - limits.min.z ) }, - cmap: { value: ColourCache.getTexture( 'gradient' ) }, - }; - - this.vertexShader = Shaders.heightVertexShader; - this.fragmentShader = Shaders.heightFragmentShader; - - this.type = 'CV.HeightMaterial'; - - return this; - -} - -HeightMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -HeightMaterial.prototype.constructor = HeightMaterial; - - - -// EOF - -function GlyphAtlas ( glyphAtlasSpec ) { - - var atlasSize = 512; - var cellSize = 32; - - var canvas = document.createElement( 'canvas' ); - var map = {}; - - if ( ! canvas ) console.error( 'creating canvas for glyph atlas failed' ); - - canvas.width = atlasSize; - canvas.height = atlasSize; - - var ctx = canvas.getContext( '2d' ); - - if ( ! ctx ) console.error( 'cannot obtain 2D canvas' ); - - // set background - - ctx.fillStyle = 'rgba( 0, 0, 0, 1 )'; - ctx.fillRect( 0, 0, atlasSize, atlasSize ); - - // populate with glyphs - - var glyphs = '\u2610 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_'; - - var divisions = atlasSize / cellSize; - - var glyphCount = glyphs.length; - - if ( glyphCount > divisions * divisions ) { - - console.error( 'too many glyphs for atlas' ); - return; - - } - - var glyph; - var fontSize = 20; - - ctx.textAlign = 'left'; - ctx.font = fontSize + 'px ' + glyphAtlasSpec; - ctx.fillStyle = '#ffffff'; - - var row, column; - - for ( var i = 0; i < glyphCount; i++ ) { - - glyph = glyphs.charAt( i ); - - var glyphWidth = ctx.measureText( glyph ).width / cellSize; - - row = Math.floor( i / divisions ) + 1; - column = i % divisions; - - map[ glyph ] = { row: ( divisions - row ) / divisions, column: column / divisions, width: glyphWidth }; - - ctx.fillText( glyph, cellSize * column, cellSize * row - 6 ); - - } - - this.texture = new CanvasTexture( canvas ); - this.map = map; - this.cellScale = cellSize / atlasSize; - -} - -GlyphAtlas.prototype.constructor = GlyphAtlas; - -GlyphAtlas.prototype.getTexture = function () { - - return this.texture; - -}; - -GlyphAtlas.prototype.getCellScale = function () { - - return this.cellScale; - -}; - -GlyphAtlas.prototype.getGlyph = function ( glyph ) { - - var glyphData = this.map[ glyph ]; - - if ( glyphData === undefined ) { - - console.warn( 'unavailable glyph [' + glyph + ']', glyph.codePointAt() ); - glyphData = this.map[ '\u2610' ]; // substitute empty box - - } - - return glyphData; - -}; - - -var atlasCache = {}; -var AtlasFactory = {}; - -AtlasFactory.getAtlas = function ( glyphAtlasSpec ) { - - var atlas = atlasCache[ glyphAtlasSpec ]; - - if ( atlas === undefined ) { - - atlas = new GlyphAtlas( glyphAtlasSpec ); - atlasCache[ glyphAtlasSpec ] = atlas; - - } - - return atlas; - -}; - - - -// EOF - -function GlyphMaterial ( glyphAtlasSpec, container, rotation, colour ) { - - var glyphAtlas = AtlasFactory.getAtlas( glyphAtlasSpec ); - - var cellScale = glyphAtlas.getCellScale(); - - var cos = Math.cos( rotation ); - var sin = Math.sin( rotation ); - - var rotationMatrix = new Float32Array( [ cos, sin, -sin, cos ] ); - - colour = colour || [ 1, 1, 1 ]; - - ShaderMaterial.call( this, { - uniforms: { - cellScale: { value: cellScale }, - atlas: { value: glyphAtlas.getTexture() }, - rotate: { value: rotationMatrix }, - scale: { value: container.clientHeight / container.clientWidth } - }, - vertexShader: Shaders.glyphVertexShader, - fragmentShader: Shaders.glyphFragmentShader, - } ); - - this.opacity = 1.0; - this.alphaTest = 0.8; - this.depthTest = false; - this.transparent = true; - this.defines = { USE_COLOR: true }; - - this.defaultAttributeValues.color = colour; - this.type = 'CV.GlyphMaterial'; - this.atlas = glyphAtlas; - - - // event handler - window.addEventListener( 'resize', _resize ); - - var self = this; - - return this; - - function _resize() { - - self.uniforms.scale.value = container.clientHeight / container.clientWidth; - - } - -} - -GlyphMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -GlyphMaterial.prototype.constructor = GlyphMaterial; - -GlyphMaterial.prototype.getAtlas = function () { - - return this.atlas; - -}; - - - -// EOF - -var cache = new Map(); -var viewer; - -var cursorMaterials = []; -var depthMaterials = []; -var perSurveyMaterials = {}; - -function updateMaterialCursor ( material ) { - - viewer.initCursorHeight = material.setCursor( viewer.cursorHeight ); - -} - -function updateCursors( /* event */ ) { - - cursorMaterials.forEach( updateMaterialCursor ); - -} - -function updateDatumShifts( event ) { - - var datumShift = event.value; - - depthMaterials.forEach( _updateMaterialDepth ); - - function _updateMaterialDepth ( material ) { - - material.setDatumShift( datumShift ); - - } - -} - - -function getHeightMaterial ( type, limits ) { - - var name = 'height' + type; - - if ( cache.has( name ) ) return cache.get( name ); - - var material = new HeightMaterial( type, limits ); - - cache.set( name, material ); - - perSurveyMaterials[ name ] = material; - - return material; - -} - -function getDepthMapMaterial ( terrain ) { - - return new DepthMapMaterial( terrain ); - -} - -function getDepthMaterial ( type, limits, terrain ) { - - var name = 'depth' + type; - var material = cache.get( name ); - - if ( material === undefined ) { - - material = new DepthMaterial( type, limits, terrain ); - - cache.set( name, material ); - - perSurveyMaterials[ name ] = material; - depthMaterials.push( material ); - - } - - return material; - -} - -function getCursorMaterial ( type, limits ) { - - var name = 'cursor' + type; - - var material = cache.get( name ); - - if ( material === undefined ) { - - material = new CursorMaterial( type, limits ); - - perSurveyMaterials[ name ] = material; - - cache.set( name, material ); - - } - - // restore current cursor - - viewer.initCursorHeight = material.getCursor(); - - // set active cursor material for updating - - cursorMaterials[ type ] = material; - - return material; - -} - -function getDepthCursorMaterial( type, limits, terrain ) { - - var name = 'depthCursor' + type; - - var material = cache.get( name ); - - if ( material === undefined ) { - - material = new DepthCursorMaterial( type, limits, terrain ); - - perSurveyMaterials[ name ] = material; - depthMaterials.push( material ); - - cache.set( name, material ); - - } - - // restore current cursor - - viewer.initCursorHeight = material.getCursor(); - - // set active cursor material for updating - - cursorMaterials[ type ] = material; - - return material; - -} - -function getSurfaceMaterial () { - - if ( cache.has( 'surface' ) ) return cache.get( 'surface' ); - - var material = new MeshLambertMaterial( { color: 0xFFFFFF, vertexColors: NoColors } ); - - cache.set( 'surface', material ); - - return material; - -} - -function getLineMaterial () { - - if ( cache.has( 'line' ) ) return cache.get( 'line' ); - - var material = new LineBasicMaterial( { color: 0xFFFFFF, vertexColors: VertexColors } ); - - cache.set( 'line', material ); - - return material; - -} - -function getGlyphMaterial ( glyphAtlasSpec, rotation, colour ) { - - var name = glyphAtlasSpec + ':' + rotation.toString() + ':' + ( colour ? colour.toString() : 'default' ); - - if ( cache.has( name ) ) return cache.get( name ); - - var material = new GlyphMaterial( glyphAtlasSpec, viewer.container, rotation, colour ); - - cache.set( name, material ); - - return material; - -} - -function setTerrain( terrain ) { - - - terrain.addEventListener( 'datumShiftChange', updateDatumShifts ); - -} - -function initCache ( Viewer ) { - - cache.clear(); - - viewer = Viewer; - - viewer.addEventListener( 'cursorChange', updateCursors ); - -} - -function flushCache() { - - var name; - - for ( name in perSurveyMaterials ) { - - var material = perSurveyMaterials[ name ]; - - material.dispose(); - cache.delete( name ); - - } - - depthMaterials = []; - perSurveyMaterials = {}; - -} - -var Materials$1 = { - getHeightMaterial: getHeightMaterial, - getDepthMapMaterial: getDepthMapMaterial, - getDepthMaterial: getDepthMaterial, - getDepthCursorMaterial: getDepthCursorMaterial, - getCursorMaterial: getCursorMaterial, - getSurfaceMaterial: getSurfaceMaterial, - getLineMaterial: getLineMaterial, - getGlyphMaterial: getGlyphMaterial, - setTerrain: setTerrain, - initCache: initCache, - flushCache: flushCache -}; - -// EOF - -function LinearScale ( container, Viewer ) { - - var width = container.clientWidth; - var height = container.clientHeight; - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - this.name = 'CV.LinearScale'; - this.domObjects = []; - - var barOffset = 3 * ( stdWidth + stdMargin ); - var barHeight = ( height - barOffset ) / 2; - var barWidth = stdWidth / 2; - - var range = Viewer.maxHeight - Viewer.minHeight; - - var geometry = new PlaneBufferGeometry( barWidth, range ); - - // rotate the model to put the plane in the xz plane, covering the range of view height values - the gradient shader works on z values. - - geometry.rotateX( Math.PI / 2 ); - geometry.translate( -barWidth / 2, 0, 0 ); - - Mesh.call( this, geometry, Materials$1.getHeightMaterial( MATERIAL_LINE ) ); - - var ms = new Matrix4().makeScale( 1, 1, barHeight / range ); - - ms.multiply( new Matrix4().makeTranslation( width / 2 - stdMargin, -height / 2 + barOffset + barHeight / 2, 0 ) ); - - this.applyMatrix( ms ); - - // rotate the model in the world view. - this.rotateOnAxis( new Vector3( 1, 0, 0 ), -Math.PI / 2 ); - - // add labels - var maxdiv = document.createElement( 'div' ); - var mindiv = document.createElement( 'div' ); - - var caption = document.createElement( 'div' ); - - maxdiv.classList.add( 'linear-scale' ); - mindiv.classList.add( 'linear-scale' ); - - caption.classList.add( 'linear-scale-caption' ); - - maxdiv.id = 'max-div'; - mindiv.id = 'min-div'; - - caption.id = 'linear-caption'; - - maxdiv.style.top = barHeight + 'px'; - mindiv.style.bottom = barOffset + 'px'; - - caption.style.bottom = height - barHeight + 'px'; - - container.appendChild( maxdiv ); - container.appendChild( mindiv ); - - container.appendChild( caption ); - - maxdiv.textContent = '---'; - mindiv.textContent = '---'; - - caption.textContent = 'xxxx'; - - this.maxDiv = maxdiv; - this.minDiv = mindiv; - - this.caption = caption; - - this.domObjects.push( mindiv ); - this.domObjects.push( maxdiv ); - - this.domObjects.push( caption ); - - this.addEventListener( 'removed', this.removeDomObjects ); - - return this; - -} - -LinearScale.prototype = Object.create( Mesh.prototype ); - -Object.assign( LinearScale.prototype, HudObject.prototype ); - -LinearScale.prototype.constructor = LinearScale; - -LinearScale.prototype.setRange = function ( min, max, caption ) { - - this.maxDiv.textContent = Math.round( max ) + 'm'; - this.minDiv.textContent = Math.round( min ) + 'm'; - - this.setCaption( caption ); - - return this; - -}; - - -LinearScale.prototype.setCaption = function ( caption ) { - - this.caption.textContent = caption; - - return this; - -}; - -LinearScale.prototype.setMaterial = function ( material ) { - - this.material = material; - - return this; - -}; - - - -// EOF - -function CursorScale ( container ) { - - var width = container.clientWidth; - var height = container.clientHeight; - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - this.name = 'CV.CursorScale'; - this.domObjects = []; - - var barOffset = 3 * ( stdWidth + stdMargin ); - var barHeight = ( height - barOffset ) / 2; - var barWidth = stdWidth / 2; - - var geometry = new PlaneBufferGeometry( barWidth, barHeight ); - - Mesh.call( this, geometry, new MeshBasicMaterial( { color: 0x777777 } ) ); - - this.translateX( width / 2 - barWidth / 2 - stdMargin ); - this.translateY( -height / 2 + barHeight / 2 + barOffset ); - - this.barHeight = barHeight; - - // make cursor line - - var cursorGeometry = new Geometry(); - - cursorGeometry.vertices.push( new Vector3( barWidth / 2, -barHeight / 2, 0 ) ); - cursorGeometry.vertices.push( new Vector3( -barWidth / 2, -barHeight / 2, 0 ) ); - - var cursor = new Line( cursorGeometry, new LineBasicMaterial( { color: 0xffffff } ) ); - - this.add( cursor ); - - this.cursor = cursor; - - // add labels - var maxdiv = document.createElement( 'div' ); - var mindiv = document.createElement( 'div' ); - - var caption = document.createElement( 'div' ); - - maxdiv.classList.add( 'linear-scale' ); - mindiv.classList.add( 'linear-scale' ); - - caption.classList.add( 'linear-scale-caption' ); - - maxdiv.id = 'max-div'; - mindiv.id = 'min-div'; - - caption.id = 'linear-caption'; - - maxdiv.style.top = barHeight + 'px'; - mindiv.style.bottom = barOffset + 'px'; - - caption.style.bottom = height - barHeight + 'px'; - - container.appendChild( maxdiv ); - container.appendChild( mindiv ); - - container.appendChild( caption ); - - maxdiv.textContent = '---'; - mindiv.textContent = '---'; - - caption.textContent = 'xxxx'; - - this.maxDiv = maxdiv; - this.minDiv = mindiv; - - this.caption = caption; - - this.domObjects.push( mindiv ); - this.domObjects.push( maxdiv ); - - this.domObjects.push( caption ); - - this.addEventListener( 'removed', this.removeDomObjects ); - - return this; - -} - -CursorScale.prototype = Object.create( Mesh.prototype ); - -Object.assign( CursorScale.prototype, HudObject.prototype ); - -CursorScale.prototype.constructor = CursorScale; - -CursorScale.prototype.setRange = function ( min, max, caption ) { - - this.maxDiv.textContent = Math.round( max ) + 'm'; - this.minDiv.textContent = Math.round( min ) + 'm'; - - this.caption.textContent = caption; - - return this; - -}; - - -CursorScale.prototype.setCursor = function ( scaledValue /*, displayValue */ ) { - - this.cursor.position.setY( this.barHeight * scaledValue ); - - return this; - -}; - - - -// EOF - -function ProgressDial () { - - var stdWidth = HudObject.stdWidth; - var stdMargin = HudObject.stdMargin; - - var geometry = new RingGeometry( stdWidth * 0.9, stdWidth, 50 ); - - Mesh.call( this, geometry, new MeshBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ) ); - - this.name = 'CV.ProgressDial'; - this.domObjects = []; - - var offset = stdWidth + stdMargin; - - this.translateX( -offset * 5 ); - this.translateY( offset ); - - this.rotateOnAxis( upAxis, Math.PI / 2 ); - - this.visible = false; - this.isVisible = true; - - this.addEventListener( 'removed', this.removeDomObjects ); - - return this; - -} - -ProgressDial.prototype = Object.create( Mesh.prototype ); - -Object.assign( ProgressDial.prototype, HudObject.prototype ); - -ProgressDial.prototype.constructor = ProgressDial; - -ProgressDial.prototype.set = function ( progress ) { - - this.progress = progress; - - var l = Math.floor( Math.min( 100, Math.round( progress ) ) / 2 ) * 2; - var faces = this.geometry.faces; - - for ( var i = 0; i < l; i++ ) { - - faces[ 99 - i ].color.set( 0x00ff00 ); - - } - - this.geometry.colorsNeedUpdate = true; - -}; - -ProgressDial.prototype.add = function ( progress ) { - - this.set( this.progress + progress ); - -}; - -ProgressDial.prototype.start = function () { - - var faces = this.geometry.faces; - - for ( var i = 0; i < 100; i++ ) { - - faces[ i ].color.set( 0x333333 ); - - } - - this.geometry.colorsNeedUpdate = true; - this.progress = 0; - this.visible = this.isVisible; - -}; - -ProgressDial.prototype.end = function () { - - var self = this; - - setTimeout( function () { self.visible = false; Viewer.renderView(); }, 500 ); - -}; - -ProgressDial.prototype.setVisibility = function ( visibility ) { - - this.isVisible = visibility; - this.visible = ( this.visible && visibility ); - -}; - - - -// EOF - -function ScaleBar ( container, hScale, rightMargin ) { - - var leftMargin = 10; - - Group.call( this ); - - this.name = 'CV.ScaleBar'; - this.domObjects = []; - - this.hScale = hScale; - this.scaleBars = []; - this.currentLength = 0; - - this.position.set( -container.clientWidth / 2 + 5, -container.clientHeight / 2 + leftMargin, 0 ); - this.scaleMax = container.clientWidth - ( leftMargin + rightMargin ); - - var legend = document.createElement( 'div' ); - - legend.classList.add( 'scale-legend' ); - legend.textContent = ''; - - container.appendChild( legend ); - - this.legend = legend; - this.domObjects.push( legend ); - - this.addEventListener( 'removed', this.removeDomObjects ); - - return this; - -} - -ScaleBar.prototype = Object.create( Group.prototype ); - -Object.assign( ScaleBar.prototype, HudObject.prototype ); - -ScaleBar.prototype.constructor = ScaleBar; - -ScaleBar.prototype.setVisibility = function ( visible ) { - - HudObject.prototype.setVisibility.call( this, visible ); - - if ( this.currentLength !== 0 ) this.scaleBars[ this.currentLength ].mesh.visible = visible; - -}; - -ScaleBar.prototype.setScale = function ( scale ) { - - var scaleBars = this.scaleBars; - var length = 0; - var self = this; - - var maxVisible = this.scaleMax / ( scale * this.hScale ); - var exponent = Math.ceil( Math.log( maxVisible ) / Math.LN10 ) - 1; - var rMax = Math.pow( 10, exponent ); - var maxInc = maxVisible / rMax; - var legendText; - - if ( maxInc < 2 ) { - - length = 10; - exponent = exponent - 1; - - } else if ( maxInc < 5 ) { - - length = 2; - - } else { - - length = 5; - - } - - if ( exponent >= 3 ) { - - legendText = length * Math.pow( 10, exponent - 3) + 'km'; - - } else { - - legendText = length * Math.pow( 10, exponent ) + 'm'; - - } - - scale = scale * Math.pow( 10, exponent ); - - if ( this.currentLength !== length ) { - - if ( ! scaleBars[ length ] ) { - - var bar = _makeScaleBar( length ); - - scaleBars[ length ] = bar; - this.add( bar.mesh ); - - } - - if ( this.currentLength > 0 ) { - - scaleBars[ this.currentLength ].mesh.visible = false; - - } - - scaleBars[ length ].mesh.visible = this.visible; - this.currentLength = length; - - } - - scaleBars[ length ].mesh.scale.x = scale; - - var legend = this.legend; - - legend.style.display = this.visible ? 'block' : 'none'; - legend.style.left = ( scale * scaleBars[ length ].topRight - legend.clientWidth ) + 'px'; - - legend.textContent = legendText; - - return this; - - function _makeScaleBar ( length ) { - - var height = 4; - var rLength = length * self.hScale; - var i, l; - - var bar = new PlaneGeometry( rLength, height, length ); - var bar2 = new PlaneGeometry( rLength, height, length * 10 ); - var line = new Geometry(); - - line.vertices.push( new Vector3( -rLength / 2, 0, 1 ) ); - line.vertices.push( new Vector3( rLength / 2, 0, 1 ) ); - - var mBar = new Mesh( bar, new MeshBasicMaterial( { color: 0xffffff, vertexColors: FaceColors, side: FrontSide } ) ); - var mBar2 = new Mesh( bar2, new MeshBasicMaterial( { color: 0xffffff, vertexColors: FaceColors, side: FrontSide } ) ); - var mLine = new LineSegments( line, new LineBasicMaterial( { color: 0xff0000 } ) ); - - for ( i = 0, l = bar.faces.length; i < l; i = i + 4 ) { - - bar.faces[ i ].color = ColourCache.red; - bar.faces[ i + 1 ].color = ColourCache.red; - - } - - for ( i = 0, l = bar2.faces.length; i < l; i = i + 4 ) { - - bar2.faces[ i ].color = ColourCache.red; - bar2.faces[ i + 1 ].color = ColourCache.red; - - } - - bar.translate( rLength / 2, height + height / 2 + 1, 0 ); - bar2.translate( rLength / 2, height / 2, 0 ); - line.translate( rLength / 2, height, 0 ); - - bar.computeBoundingBox(); - - var group = new Group(); - - group.add( mBar ); - group.add( mBar2 ); - group.add( mLine ); - - return { mesh: group, topRight: bar.boundingBox.max.x }; - - } - -}; - - - -// EOF - -// THREE objects - -var renderer$1; -var camera$1; -var scene$1; - -var hScale = 0; - -var attitudeGroup; - -var linearScale = null; -var angleScale = null; -var cursorScale = null; -var scaleBar = null; - -var compass; -var ahi; -var progressDial; - -// DOM objects - -var container$1; - -// viewer state - -var controls$1; -var isVisible = true; - -function init$1 ( domId, viewRenderer ) { - - container$1 = document.getElementById( domId ); - renderer$1 = viewRenderer; - - var hHeight = container$1.clientHeight / 2; - var hWidth = container$1.clientWidth / 2; - - // create GL scene and camera for overlay - camera$1 = new OrthographicCamera( -hWidth, hWidth, hHeight, -hHeight, 1, 1000 ); - camera$1.position.z = 600; - - scene$1 = new Scene(); - - // group to simplyfy resize handling - attitudeGroup = new Group(); - attitudeGroup.position.set( hWidth, -hHeight, 0 ); - - scene$1.add( attitudeGroup ); - - var aLight = new AmbientLight( 0x888888 ); - var dLight = new DirectionalLight( 0xFFFFFF ); - - dLight.position.set( -1, 1, 1 ); - - scene$1.add( aLight ); - scene$1.add( dLight ); - - compass = new Compass( container$1 ); - ahi = new AHI( container$1 ); - progressDial = new ProgressDial(); - - attitudeGroup.add( compass ); - attitudeGroup.add( ahi ); - attitudeGroup.add( progressDial ); - - window.addEventListener( 'resize', resize$1 ); - - Viewer.addEventListener( 'newCave', caveChanged ); - Viewer.addEventListener( 'change', viewChanged ); - - controls$1 = Viewer.getControls(); - - controls$1.addEventListener( 'change', update ); - -} - -function setVisibility ( visible ) { - - compass.setVisibility( visible ); - ahi.setVisibility( visible ); - progressDial.setVisibility( visible ); - - if ( scaleBar ) scaleBar.setVisibility( visible ); - - isVisible = visible; - - // reset correct disposition of colour keys etc. - if ( linearScale ) { - - if ( visible ) { - - viewChanged ( { type: 'change', name: 'shadingMode' } ); - - } else { - - linearScale.setVisibility( false ); - cursorScale.setVisibility( false ); - angleScale.setVisibility( false ); - - } - - } - - Viewer.renderView(); - -} - -function getVisibility() { - - return isVisible; - -} - -function getProgressDial() { - - return progressDial; - -} - -function setScale$1( scale ) { - - hScale = scale; - -} - -function resize$1 () { - - var hWidth = container$1.clientWidth / 2; - var hHeight = container$1.clientHeight / 2; - - // adjust cameras to new aspect ratio etc. - camera$1.left = -hWidth; - camera$1.right = hWidth; - camera$1.top = hHeight; - camera$1.bottom = -hHeight; - - camera$1.updateProjectionMatrix(); - - attitudeGroup.position.set( hWidth, -hHeight, 0 ); - - newScales(); - - setVisibility ( isVisible ); // set correct visibility of elements - -} - -function update () { - - // update HUD components - - var currentCamera = controls$1.object; - - compass.set( currentCamera ); - ahi.set( currentCamera ); - updateScaleBar( currentCamera ); - -} - -function renderHUD () { - - // render on screen - renderer$1.clearDepth(); - renderer$1.render( scene$1, camera$1 ); - -} - -function caveChanged ( /* event */ ) { - - newScales(); - - viewChanged ( { type: 'change', name: 'shadingMode' } ); - -} - - -function newScales () { - - if ( linearScale ) scene$1.remove( linearScale ); - - linearScale = new LinearScale( container$1, Viewer ); - - scene$1.add( linearScale ); - - - if ( cursorScale ) scene$1.remove( cursorScale ); - - cursorScale = new CursorScale( container$1 ); - - scene$1.add( cursorScale ); - - - if ( angleScale ) scene$1.remove( angleScale ); - - angleScale = new AngleScale( container$1 ); - - scene$1.add( angleScale ); - - if ( scaleBar ) { - - scene$1.remove( scaleBar ); - scaleBar = null; - - } - - updateScaleBar( controls$1.object ); - -} - -function viewChanged ( event ) { - - if ( event.name !== 'shadingMode' || ! isVisible ) return; - - // hide all - and only make required elements visible - - var useAngleScale = false; - var useLinearScale = false; - var useCursorScale = false; - - switch ( Viewer.shadingMode ) { - - case SHADING_HEIGHT: - - useLinearScale = true; - - linearScale.setRange( Viewer.minHeight, Viewer.maxHeight, 'Height above Datum' ).setMaterial( Materials$1.getHeightMaterial( MATERIAL_LINE ) ); - - break; - - case SHADING_DEPTH: - - useLinearScale = true; - - linearScale.setRange( Viewer.maxHeight - Viewer.minHeight, 0, 'Depth below surface' ).setMaterial( Materials$1.getHeightMaterial( MATERIAL_LINE ) ); - - break; - - case SHADING_CURSOR: - - useCursorScale = true; - - cursorScale.setRange( Viewer.minHeight, Viewer.maxHeight, 'Height' ); - - cursorChanged(); - - break; - - case SHADING_DEPTH_CURSOR: - - useCursorScale = true; - - cursorScale.setRange( Viewer.maxHeight - Viewer.minHeight, 0, 'Depth' ); - - cursorChanged(); - - break; - - case SHADING_LENGTH: - - useLinearScale = true; - - linearScale.setRange( Viewer.minLegLength, Viewer.maxLegLength, 'Leg length' ).setMaterial( Materials$1.getHeightMaterial( MATERIAL_LINE, true ) ).setVisibility( true ); - - break; - - case SHADING_INCLINATION: - - useAngleScale = true; - - break; - - } - - angleScale.setVisibility( useAngleScale ); - linearScale.setVisibility( useLinearScale ); - cursorScale.setVisibility( useCursorScale ); - - if ( useCursorScale ) { - - Viewer.addEventListener( 'cursorChange', cursorChanged ); - - } else { - - Viewer.removeEventListener( 'cursorChange', cursorChanged ); - - } - - Viewer.renderView(); - -} - -function cursorChanged ( /* event */ ) { - - var cursorHeight = Viewer.cursorHeight; - var range = Viewer.maxHeight - Viewer.minHeight; - var scaledHeight = 0; - - if ( Viewer.shadingMode === SHADING_CURSOR ) { - - scaledHeight = ( Viewer.cursorHeight + range / 2 ) / range; - - } else { - - scaledHeight = 1 - cursorHeight / range; - - } - - scaledHeight = Math.max( Math.min( scaledHeight, 1 ), 0 ); - - cursorScale.setCursor( scaledHeight, Math.round( cursorHeight ) ); - -} - -function updateScaleBar ( camera ) { - - if ( camera instanceof OrthographicCamera ) { - - if ( scaleBar === null ) { - - scaleBar = new ScaleBar( container$1, hScale, ( HudObject.stdWidth + HudObject.stdMargin ) * 4 ); - scene$1.add( scaleBar ); - - } - - if ( isVisible !== scaleBar.visible ) scaleBar.setVisibility( isVisible ); - - scaleBar.setScale( camera.zoom ); - - } else { - - if ( scaleBar !== null && scaleBar.visible ) scaleBar.setVisibility( false ); - - } - -} - -var HUD = { - init: init$1, - renderHUD: renderHUD, - update: update, - setVisibility: setVisibility, - getVisibility: getVisibility, - getProgressDial: getProgressDial, - setScale: setScale$1 -}; - -// EOF - -function CameraMove ( controls, renderFunction, endCallback ) { - - this.cameraTarget = null; - this.targetPOI = null; - - this.controls = controls; - this.renderFunction = renderFunction; - this.endCallback = endCallback; - this.frameCount = 0; - this.frames = 0; - this.targetZoom = 1; - this.curve = null; - this.skipNext = false; - - this.moveRequired = false; - -} - -CameraMove.prototype.constructor = CameraMove; - -CameraMove.prototype.prepare = function ( cameraTarget, targetPOI ) { - - if ( this.frameCount !== 0 ) return; - - this.skipNext = false; - - if ( targetPOI && targetPOI.isBox3 ) { - - // target can be a Box3 in world space - - var size = targetPOI.getSize(); - var camera = this.controls.object; - var elevation; - - targetPOI = targetPOI.getCenter(); - - if ( camera.isPerspectiveCamera ) { - - var tan = Math.tan( _Math.DEG2RAD * 0.5 * camera.getEffectiveFOV() ); - - var e1 = 1.5 * tan * size.y / 2 + size.z; - var e2 = tan * camera.aspect * size.x / 2 + size.z; - - elevation = Math.max( e1, e2 ); - - this.targetZoom = 1; - - if ( elevation === 0 ) elevation = 100; - - } else { - - var hRatio = ( camera.right - camera.left ) / size.x; - var vRatio = ( camera.top - camera.bottom ) / size.y; - - this.targetZoom = Math.min( hRatio, vRatio ); - elevation = 600; - - } - - cameraTarget = targetPOI.clone(); - cameraTarget.z = cameraTarget.z + elevation; - - } - - this.cameraTarget = cameraTarget; - this.targetPOI = targetPOI; - - this.moveRequired = ( this.cameraTarget !== null || this.targetPOI !== null ); - - var startPOI = this.controls.target; - var cameraStart = this.controls.object.position; - - if ( cameraTarget !== null ) { - - if ( cameraTarget.equals( cameraStart ) ) { - - // start and end camera positions are identical. - - this.moveRequired = false; - - if ( targetPOI === null ) this.skipNext = true; - - } else { - - if ( targetPOI === null ) targetPOI = startPOI; - - var distance = cameraStart.distanceTo( cameraTarget ); - - var cp1 = this.getControlPoint( startPOI, cameraStart, cameraTarget, distance ); - var cp2 = this.getControlPoint( targetPOI, cameraTarget, cameraStart, distance ); - - this.curve = new CubicBezierCurve3( cameraStart, cp1, cp2, cameraTarget ); - - } - - } - -}; - -CameraMove.prototype.getControlPoint = function ( common, p1, p2, distance ) { - - var v1 = new Vector3(); - var v2 = new Vector3(); - - var normal = new Vector3(); - var l = 0; - - while ( l === 0 ) { - - v1.copy( p1 ).sub( common ); - v2.copy( p2 ).sub( common ); - - normal.crossVectors( v1, v2 ); - - l = normal.length(); - - if ( l === 0 ) { - - // adjust the targetPOI to avoid degenerate triangles. - - common.addScalar( -1 ); - - } - - } - - var adjust = new Vector3().crossVectors( normal, v1 ).setLength( Math.min( distance, v1.length() ) / 3 ); - - var candidate1 = new Vector3().copy( adjust ).add( v1 ); - var candidate2 = new Vector3().copy( adjust ).negate().add( v1 ); - - return ( v2.distanceTo( candidate1 ) < v2.distanceTo( candidate2 ) ) ? candidate1 : candidate2; - -}; - -CameraMove.prototype.start = function ( time ) { - - if ( this.frameCount === 0 && ! this.skipNext ) { - - this.frameCount = time + 1; - this.frames = this.frameCount; - this.controls.enabled = ! this.moveRequired; - - this.animate(); - - } - -}; - -CameraMove.prototype.animate = function () { - - var tRemaining = --this.frameCount; - var controls = this.controls; - var curve = this.curve; - - if ( tRemaining < 0 ) { - - this.frameCount = 0; - this.endAnimation(); - - return; - - } - - if ( this.moveRequired ) { - - // update camera position and controls.target - - var camera = controls.object; - - var t = 1 - tRemaining / this.frames; - - controls.target.lerp( this.targetPOI, t ); - - if ( curve !== null ) { - - camera.position.copy( this.curve.getPoint( t ) ); - - } - - camera.zoom = camera.zoom + ( this.targetZoom - camera.zoom ) * t; - - // if ( targetPOI.quaternion ) camera.quaternion.slerp( targetPOI.quaternion, t ); - - camera.updateProjectionMatrix(); - - } - - controls.update(); - - if ( tRemaining === 0 ) { - - // end of animation - - this.endAnimation(); - - return; - - } - - var self = this; - - requestAnimationFrame( function () { self.animate(); } ); - - this.renderFunction(); - -}; - -CameraMove.prototype.endAnimation = function () { - - this.controls.enabled = true; - this.moveRequired = false; - - this.cameraTarget = null; - this.targetPOI = null; - - this.renderFunction(); - this.endCallback(); - -}; - -CameraMove.prototype.stop = function () { - - this.frameCount = 1; - -}; - -CameraMove.prototype.cancel = function () { - - this.frameCount = 0; - this.skipNext = false; - -}; - -CameraMove.prototype.isActive = function () { - - return ( this.frameCount > 0 ); - -}; - -function Tree( name, id, root, parent ) { // root parameter only used internally - - if ( root === undefined ) { - - this.id = 0; - this.maxId = 0; - this.root = this; - this.parent = null; - - } else { - - this.root = root; - this.parent = parent; - this.id = ( id === null ) ? ++root.maxId : id; - - } - - this.name = name || ''; - this.children = []; - -} - -Tree.prototype.constructor = Tree; - -Tree.prototype.traverse = function ( func ) { - - var children = this.children; - - func ( this ); - - for ( var i = 0; i < children.length; i++ ) { - - children[ i ].traverse( func ); - - } - -}; - -Tree.prototype.traverseDepthFirst = function ( func ) { - - var children = this.children; - - - for ( var i = 0; i < children.length; i++ ) { - - children[ i ].traverseDepthFirst( func ); - - } - - func ( this ); - -}; - -Tree.prototype.forEachChild = function ( func, recurse ) { - - var children = this.children; - var child; - - for ( var i = 0; i < children.length; i++ ) { - - child = children[ i ]; - - func( child ); - - if ( recurse === true ) child.forEachChild( func, true ); - - } - -}; - -Tree.prototype.addById = function ( name, id, parentId, properties ) { - - var parentNode = this.findById( parentId ); - - if ( parentNode ) { - - var node = new Tree( name, id, this.root, parentNode ); - - if ( properties !== undefined ) Object.assign( node, properties ); - - parentNode.children.push( node ); - - var root = this.root; - root.maxId = Math.max( root.maxId, id ); - - return node.id; - - } - - return null; - -}; - -Tree.prototype.findById = function ( id ) { - - if ( this.id == id ) return this; - - for ( var i = 0, l = this.children.length; i < l; i++ ) { - - var child = this.children[ i ]; - - var found = child.findById( id ); - - if ( found ) return found; - - } - - return undefined; - -}; - -Tree.prototype.getByPath = function ( path ) { - - var pathArray = path.split( '.' ); - var node = this.getByPathArray( pathArray ); - - return pathArray.length === 0 ? node : undefined; - -}; - -Tree.prototype.getByPathArray = function ( path ) { - - var node = this; - var search = true; - - while ( search && path.length > 0 ) { - - search = false; - - for ( var i = 0, l = node.children.length; i < l; i++ ) { - - var child = node.children[ i ]; - - if ( child.name === path[ 0 ] ) { - - node = child; - path.shift(); - search = true; - - break; - - } - - } - - } - - return node; - -}; - -Tree.prototype.addPath = function ( path, properties ) { - - var node; - var newNode; - - // find part of path that exists already - - node = this.getByPathArray( path ); - - if ( path.length === 0 ) return node; - - // add remainder of path to node - - while ( path.length > 0 ) { - - newNode = new Tree( path.shift(), null, this.root, node ); - - node.children.push( newNode ); - node = newNode; - - } - - if ( properties !== undefined ) Object.assign( node, properties ); - - return node; - -}; - -Tree.prototype.getPath = function ( endNode ) { - - var node = this; - var path = []; - - if ( endNode === undefined ) endNode = this.root; - - do { - - path.push( node.name ); - node = node.parent; - - } while ( node !== endNode ); - - return path.reverse().join( '.' ); - -}; - -Tree.prototype.getSubtreeIds = function ( id, idSet ) { - - var node = this.findById( id ); - - node.traverse( _getId ); - - function _getId( node ) { - - idSet.add( node.id ); - - } - -}; - -Tree.prototype.getIdByPath = function ( path ) { - - var node = this.getByPathArray( path ); - - if ( path.length === 0 ) { - - return node.id; - - } else { - - return undefined; - - } - -}; - - - -// EOF - -/** - * based on BoxHelper - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / http://github.com/Mugen87 - */ - -function Box3Helper( box3, color ) { - - this.box3 = box3; - - if ( color === undefined ) color = 0xffff00; - - var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - var positions = new Float32Array( 8 * 3 ); - - var geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); - - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); - - this.matrixAutoUpdate = false; - - this.update( box3 ); - -} - -Box3Helper.prototype.type = 'Box3Helper'; - -Box3Helper.prototype = Object.create( LineSegments.prototype ); -Box3Helper.prototype.constructor = Box3Helper; - -Box3Helper.prototype.update = function ( box3 ) { - - this.box3 = box3; - - if ( box3.isEmpty() ) return; - - var min = box3.min; - var max = box3.max; - - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ - - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - - */ - - var position = this.geometry.attributes.position; - var array = position.array; - - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; - - position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - -}; - -Box3Helper.prototype.removed = function () { - - if ( this.geometry ) this.geometry.dispose(); - -}; - -function GlyphStringGeometry ( text, glyphAtlas ) { - - InstancedBufferGeometry.call( this ); - - this.type = 'GlyphStringGeometry'; - this.name = text; - this.width = 0; - - var indexAttribute = new Uint16BufferAttribute( [ 0, 2, 1, 0, 3, 2 ], 1 ); - - // unit square - var positions = [ - 0, 0, 0, - 0, 1, 0, - 1, 1, 0, - 1, 0, 0 - ]; - - var positionAttribute = new Float32BufferAttribute( positions, 3 ); - - this.setIndex( indexAttribute ); - this.addAttribute( 'position', positionAttribute ); - - var i, l, glyphData; - var offset = 0; - - l = text.length; - - var uvs = new Float32Array( l * 2 ); - var widths = new Float32Array( l ); - var offsets = new Float32Array( l ); - - for ( i = 0; i < l; i++ ) { - - if ( text.charCodeAt() === 0 ) continue; // skip null characters - - glyphData = glyphAtlas.getGlyph( text[ i ] ); - - uvs[ i * 2 ] = glyphData.column; - uvs[ i * 2 + 1 ] = glyphData.row; - - widths[ i ] = glyphData.width; - - offsets[ i ] = offset; - - offset += glyphData.width; - - } - - this.width = offset; - - this.addAttribute( 'instanceUvs', new InstancedBufferAttribute( uvs, 2, 1 ) ); - this.addAttribute( 'instanceOffsets', new InstancedBufferAttribute( offsets, 1, 1 ) ); - this.addAttribute( 'instanceWidths', new InstancedBufferAttribute( widths, 1, 1 ) ); - -} - -GlyphStringGeometry.indexAttribute = null; -GlyphStringGeometry.positionAttribute = null; - -GlyphStringGeometry.prototype = Object.assign( Object.create( InstancedBufferGeometry.prototype ), { - - constructor: GlyphStringGeometry - -} ); - - -function GlyphString ( text, glyphMaterial ) { - - var geometry = new GlyphStringGeometry( text, glyphMaterial.getAtlas() ); - - Mesh.call( this, geometry, glyphMaterial ); - - this.type = 'GlyphString'; - this.name = text; - this.frustumCulled = false; - -} - -GlyphString.prototype = Object.assign( Object.create( Mesh.prototype ), { - - constructor: GlyphString, - - isGlyphString: true, - - getWidth: function () { - - return this.geometry.width; - - } - -} ); - - - -// EOF - -function Point ( material ) { - - var geometry = new BufferGeometry(); - - material = material || new PointsMaterial( { color: 0xffffff } ); - - geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0 ], 3 ) ); - - Points.call( this, geometry, material ); - - this.type = 'Point'; - - return this; - -} - -Point.prototype = Object.create( Points.prototype ); - -Point.prototype.constructor = Point; - -// preallocated objects for projected area calculation - -var A = new Vector3(); -var B = new Vector3(); -var C = new Vector3(); -var D = new Vector3(); - -var T1 = new Triangle( A, B, C ); -var T2 = new Triangle( A, C, D ); - -var clusterMaterialCache = []; - -function getClusterMaterial ( count ) { - - var material = clusterMaterialCache[ count ]; - - if ( material !== undefined ) return material; - - var markerSize = 64; - var halfSize = markerSize / 2; - - var canvas = document.createElement( 'canvas' ); - - if ( ! canvas ) console.error( 'creating canvas for glyph atlas failed' ); - - canvas.width = markerSize; - canvas.height = markerSize; - - var ctx = canvas.getContext( '2d' ); - - if ( ! ctx ) console.error( 'cannot obtain 2D canvas' ); - - // set transparent background - - ctx.fillStyle = 'rgba( 0, 0, 0, 0 )'; - ctx.fillRect( 0, 0, markerSize, markerSize ); - - var fontSize = 40; - - ctx.textAlign = 'center'; - ctx.font = 'bold ' + fontSize + 'px helvetica,sans-serif'; - ctx.fillStyle = '#ffffff'; - - var gradient = ctx.createRadialGradient( halfSize, halfSize, 30, halfSize, halfSize, 0 ); - - gradient.addColorStop( 0.0, 'rgba( 255, 128, 0, 64 )' ); - gradient.addColorStop( 0.3, 'rgba( 255, 200, 0, 255 )' ); - gradient.addColorStop( 1.0, 'rgba( 255, 255, 0, 255 )' ); - - ctx.fillStyle = gradient; - - ctx.beginPath(); - ctx.arc( halfSize, halfSize, 30, 0, Math.PI * 2 ); - ctx.fill(); - - ctx.fillStyle = 'rgba( 0, 0, 0, 255 )'; - - ctx.fillText( count, halfSize, halfSize + 15 ); - - material = new PointsMaterial( { map: new CanvasTexture( canvas ), size: 32, depthTest: false, transparent: true, alphaTest: 0.8, sizeAttenuation: false } ); - - clusterMaterialCache[ count ] = material; - - return material; - -} - -function makeClusterMarker ( count ) { - - return new Point( getClusterMaterial( count ) ); - -} - - -function QuadTree ( xMin, xMax, yMin, yMax ) { - - this.nodes = new Array( 4 ); - this.count = 0; - this.markers = []; - this.quadMarker = null; - this.centroid = new Vector3(); - - this.xMin = xMin; - this.xMax = xMax; - - this.yMin = yMin; - this.yMax = yMax; - -} - -QuadTree.prototype.addNode = function ( marker, depth ) { - - // add marker into this quad and recurse to inner quads - - var index = 0; - var position = marker.position; - - this.markers.push( marker ); - this.centroid.add( marker.position ); - - this.count++; - - if ( depth-- === 0 ) return; - - var xMid = ( this.xMin + this.xMax ) / 2; - var yMid = ( this.yMin + this.yMax ) / 2; - - if ( position.x > xMid ) index += 1; - if ( position.y > yMid ) index += 2; - - var subQuad = this.nodes[ index ]; - - if ( subQuad === undefined ) { - - switch ( index ) { - - case 0: - - subQuad = new QuadTree( this.xMin, xMid, this.yMin, yMid ); - break; - - case 1: - - subQuad = new QuadTree( xMid, this.xMax, this.yMin, yMid ); - break; - - case 2: - - subQuad = new QuadTree( this.xMin, xMid, yMid, this.yMax ); - break; - - case 3: - - subQuad = new QuadTree( xMid, this.xMax, yMid, this.yMax ); - break; - - } - - this.nodes[ index ] = subQuad; - - } - - subQuad.addNode( marker, depth ); - -}; - -QuadTree.prototype.check = function ( cluster ) { - - var subQuad; - - for ( var i = 0; i < 4; i++ ) { - - subQuad = this.nodes[ i ]; - - if ( subQuad !== undefined ) { - - // prune quads that will never be clustered. will not be checked after first pass - - if ( subQuad.count < 2 ) { - - this.nodes[ i ] = undefined; - - continue; - - } - - // test for projected area for quad containing multiple markers - - var area = subQuad.projectedArea( cluster ); - - if ( area < 0.80 ) { // FIXME calibrate by screen size ??? - - subQuad.clusterMarkers( cluster ); - - } else { - - subQuad.showMarkers(); - subQuad.check( cluster ); - - } - - } - - } - -}; - -QuadTree.prototype.showMarkers = function () { - - var markers = this.markers; - - // hide the indiviual markers in this quad - - for ( var i = 0, l = markers.length; i < l; i++ ) { - - markers[ i ].visible = true; - - } - - if ( this.quadMarker !== null ) this.quadMarker.visible = false; - -}; - -QuadTree.prototype.clusterMarkers = function ( cluster ) { - - var i, l, subQuad; - var markers = this.markers; - - // hide the indiviual markers in this quad - - for ( i = 0, l = markers.length; i < l; i++ ) { - - markers[ i ].visible = false; - - } - - // hide quadMarkers for contained quads - - for ( i = 0; i < 4; i++ ) { - - subQuad = this.nodes[ i ]; - - if ( subQuad !== undefined ) subQuad.hideQuadMarkers(); - - } - - if ( this.quadMarker === null ) { - - var quadMarker = makeClusterMarker( this.count ); - - // set to center of distribution of markers in this quad. - - quadMarker.position.copy( this.centroid ).divideScalar( this.count ); - quadMarker.layers.set( FEATURE_ENTRANCES ); - - cluster.add( quadMarker ); - - this.quadMarker = quadMarker; - - } - - this.quadMarker.visible = true; - -}; - -QuadTree.prototype.hideQuadMarkers = function () { - - var subQuad; - - if ( this.quadMarker ) this.quadMarker.visible = false; - - for ( var i = 0; i < 4; i++ ) { - - subQuad = this.nodes[ i ]; - - if ( subQuad !== undefined ) subQuad.hideQuadMarkers(); - - } - -}; - -QuadTree.prototype.projectedArea = function ( cluster ) { - - var camera = cluster.camera; - var matrixWorld = cluster.matrixWorld; - var zAverage = this.centroid.z / this.count; - - A.set( this.xMin, this.yMin, zAverage ).applyMatrix4( matrixWorld ).project( camera ); - B.set( this.xMin, this.yMax, zAverage ).applyMatrix4( matrixWorld ).project( camera ); - C.set( this.xMax, this.yMax, zAverage ).applyMatrix4( matrixWorld ).project( camera ); - D.set( this.xMax, this.yMin, zAverage ).applyMatrix4( matrixWorld ).project( camera ); - - return T1.area() + T2.area(); - -}; - -function ClusterMarkers ( limits, maxDepth ) { - - Object3D.call( this ); - - var min = limits.min; - var max = limits.max; - - this.maxDepth = maxDepth; - - this.type = 'CV.ClusterMarker'; - - this.quadTree = new QuadTree( min.x, max.x, min.y, max.y ); - - this.addEventListener( 'removed', this.onRemoved ); - - return this; - -} - -ClusterMarkers.prototype = Object.create( Object3D.prototype ); - -ClusterMarkers.prototype.constructor = ClusterMarkers; - -ClusterMarkers.prototype.onRemoved = function () { - - this.traverse( - - function _traverse ( obj ) { - - if ( obj.type === 'GlyphString' ) { obj.geometry.dispose(); } - - } - - ); - -}; - -ClusterMarkers.prototype.addMarker = function ( position, label ) { - - // create marker - var material = Materials$1.getGlyphMaterial( 'normal helvetica,sans-serif', Math.PI / 4 ); - var marker = new GlyphString( label, material ); - - marker.layers.set( FEATURE_ENTRANCES ); - marker.position.copy( position ); - - this.quadTree.addNode( marker, this.maxDepth ); - - this.add( marker ); - - return marker; - -}; - -ClusterMarkers.prototype.cluster = function ( camera ) { - - // determine which labels are too close together to be usefully displayed as separate objects. - - // immediate exit if only a single label or none. - - if ( this.children.length < 2 ) return; - - this.camera = camera; - - this.quadTree.check( this ) ; - - return; - -}; - - - -// EOF - -function ExtendedPointsMaterial () { - - ShaderMaterial.call( this, { - uniforms: { - diffuse: { value: ColourCache.white }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - pScale: { value: 1.0 }, - offsetRepeat: { value: new Vector4() }, - map: { value: null } - }, - vertexShader: Shaders.extendedPointsVertexShader, - fragmentShader: Shaders.extendedPointsFragmentShader, - vertexColors: VertexColors - } ); - - this.map = new TextureLoader().load( getEnvironmentValue( 'home', '' ) + 'images/disc.png' ); - - this.color = ColourCache.white; - this.opacity = 1.0; - this.alphaTest = 0.8; - - this.size = 1; - this.scale = 1; - this.sizeAttenuation = true; - this.transparent = true; - - this.type = 'CV.ExtendedPointsMaterial'; - - this.isPointsMaterial = true; - - return this; - -} - -ExtendedPointsMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -ExtendedPointsMaterial.prototype.constructor = ExtendedPointsMaterial; - - - -// EOF - -function Stations () { - - Points.call( this, new BufferGeometry, new ExtendedPointsMaterial() ); - - this.type = 'CV.Stations'; - this.map = new Map(); - this.stationCount = 0; - - this.baseColor = ColourCache.red; - this.junctionColor = ColourCache.yellow; - - this.layers.set( FEATURE_STATIONS ); - - this.pointSizes = []; - this.vertices = []; - this.colors = []; - - this.stations = []; - - this.selected = null; - this.selectedSize = 0; - - var self = this; - - Viewer.addEventListener( 'change', _viewChanged ); - - this.addEventListener( 'removed', _removed ); - - Object.defineProperty( this, 'count', { - - get: function () { return this.stations.length; } - - } ); - - function _viewChanged( event ) { - - if ( event.name === 'splays' ) { - - var splaySize = Viewer.splays ? 1.0 : 0.0; - - var stations = self.stations; - var pSize = self.geometry.getAttribute( 'pSize' ); - var i; - var l = stations.length; - - for ( i = 0; i < l; i++ ) { - - if ( stations[ i ].hitCount === 0 ) { - - pSize.setX( i, splaySize ); - - } - - } - - pSize.needsUpdate = true; - Viewer.renderView(); - - } - - } - - function _removed ( ) { - - Viewer.removeEventListener( 'change', _viewChanged ); - - } - -} - -Stations.prototype = Object.create ( Points.prototype ); - -Stations.prototype.constructor = Stations; - -Stations.prototype.addStation = function ( node ) { - - var point = node.p; - - this.vertices.push( point ); - this.colors.push( this.baseColor ); - this.pointSizes.push( point.type === STATION_ENTRANCE ? 8.0 : 0.0 ); - - this.map.set( point.x.toString() + ':' + point.y.toString() + ':' + point.z.toString(), node ); - this.stations.push( node ); - - node.hitCount = 0; - node.stationVertexIndex = this.stationCount++; - node.linkedSegments = []; - -}; - -Stations.prototype.getStation = function ( vertex ) { - - return this.map.get( vertex.x.toString() + ':' + vertex.y.toString() + ':' + vertex.z.toString() ); - -}; - - -Stations.prototype.getStationByIndex = function ( index ) { - - return this.stations[ index ]; - -}; - -Stations.prototype.clearSelected = function () { - - if ( this.selected !== null ) { - - var pSize = this.geometry.getAttribute( 'pSize' ); - - pSize.setX( this.selected, this.selectedSize ); - pSize.needsUpdate = true; - - this.selected = null; - - } - -}; - -Stations.prototype.selectStation = function ( node ) { - - this.selectStationByIndex( node.stationVertexIndex ); - -}; - -Stations.prototype.selectStationByIndex = function ( index ) { - - var pSize = this.geometry.getAttribute( 'pSize' ); - - if ( this.selected !== null ) { - - pSize.setX( this.selected, this.selectedSize ); - - } - - this.selectedSize = pSize.getX( index ); - - pSize.setX( index, this.selectedSize * 2 ); - -// pSize.updateRange.offset = index; -// pSize.updateRange.count = 1; - - pSize.needsUpdate = true; - - this.selected = index; - -}; - -Stations.prototype.updateStation = function ( vertex ) { - - var station = this.getStation( vertex ); - - if ( station !== undefined ) { - - station.hitCount++; - - if ( station.hitCount > 2 ) { - - this.colors[ station.stationVertexIndex ] = this.junctionColor; - this.pointSizes[ station.stationVertexIndex ] = 4.0; - - } else if ( station.hitCount > 0 ) { - - this.pointSizes[ station.stationVertexIndex ] = 2.0; - - } - - } - -}; - -Stations.prototype.finalise = function () { - - var bufferGeometry = this.geometry; - - var positions = new Float32BufferAttribute(this.vertices.length * 3, 3 ); - var colors = new Float32BufferAttribute( this.colors.length * 3, 3 ); - - bufferGeometry.addAttribute( 'pSize', new Float32BufferAttribute( this.pointSizes, 1 ) ); - bufferGeometry.addAttribute( 'position', positions.copyVector3sArray( this.vertices ) ); - bufferGeometry.addAttribute( 'color', colors.copyColorsArray( this.colors ) ); - - this.pointSizes = null; - this.vertices = null; - this.colors = null; - -}; - -Stations.prototype.setScale = function ( scale ) { - - this.material.uniforms.pScale.value = scale; - this.material.needsUpdate = true; - -}; - -var _tmpVector3 = new Vector3(); - -function StationLabels () { - - Group.call( this ); - - this.type = 'CV.StationLabels'; - this.layers.set( LABEL_STATION ); - - this.junctionLabelMaterial = Materials$1.getGlyphMaterial( 'normal helvetica,sans-serif', 0, [ 1, 1, 0 ] ); - this.defaultLabelMaterial = Materials$1.getGlyphMaterial( 'normal helvetica,sans-serif', 0 ); - this.splayLabelMaterial = Materials$1.getGlyphMaterial( 'normal helvetica,sans-serif', 0, [ 0.6, 0.6, 0.6 ] ); - -} - -StationLabels.prototype = Object.create ( Group.prototype ); - -StationLabels.prototype.constructor = StationLabels; - -StationLabels.prototype.addStation = function ( station ) { - - var material; - - if ( station.hitCount === 0 ) { - - material = this.splayLabelMaterial; - - } else if ( station.hitCount < 3 ) { - - material = this.defaultLabelMaterial; - - } else { - - material = this.junctionLabelMaterial; - - } - - var label = new GlyphString( station.name, material ); - - label.layers.set( LABEL_STATION ); - - label.position.copy( station.p ); - - label.hitCount = station.hitCount; - label.visible = false; - - this.add( label ); - -}; - -StationLabels.prototype.update = function ( camera, target, inverseWorld ) { - - var cameraPosition = _tmpVector3.copy( camera.position ); - - if ( camera.isOrthographicCamera ) { - - // if orthographic, calculate 'virtual' camera position - - cameraPosition.sub( target ); // now vector from target - - cameraPosition.setLength( CAMERA_OFFSET / camera.zoom ); // scale for zoom factor - cameraPosition.add( target ); // relocate in world space - - } - - // transform camera position into model coordinate system - - cameraPosition.applyMatrix4( inverseWorld ); - - var label, limit; - var splaysVisible = camera.layers.mask & 1 << LEG_SPLAY; - var children = this.children; - - for ( var i = 0, l = children.length; i < l; i++ ) { - - label = children[ i ]; - - // only show labels for splay end stations if splays visible - if ( label.hitCount === 0 && ! splaysVisible ) { - - label.visible = false; - - } else { - - // show labels for network vertices at greater distance than intermediate stations - limit = ( label.hitCount < 3 ) ? 5000 : 40000; - label.visible = ( label.position.distanceToSquared( cameraPosition) < limit ); - - } - - } - -}; - -function Routes ( metadataSource ) { - - // determine segments between junctions and entrances/passage ends and create mapping array. - - this.metadataSource = metadataSource; - this.surveyTree = null; - this.vertexPairToSegment = []; // maps vertex index to segment membership - this.segmentMap = new Map(); // maps segments of survey between ends of passages and junctions. - this.segmentToInfo = {}; - - this.routes = new Map(); - this.routeNames = []; - - this.currentRoute = new Set(); - this.currentRouteName = null; - this.adjacentSegments = new Set(); - - Object.defineProperty( this, 'setRoute', { - set: function ( x ) { this.loadRoute( x ); }, - get: function () { return this.currentRouteName; } - } ); - - var routes = metadataSource.getRoutes(); - var routeName; - var routeNames = this.routeNames; - - for ( routeName in routes ) { - - var route = routes[ routeName ]; - - routeNames.push( routeName ); - this.routes.set( routeName, route.segments ); - - } - - routeNames.sort(); - - this.dispatchEvent( { type: 'changed', name: 'download' } ); - -} - -Routes.prototype.constructor = Routes; - -Object.assign( Routes.prototype, EventDispatcher.prototype ); - -Routes.prototype.mapSurvey = function ( stations, legs, surveyTree ) { - - // determine segments between junctions and entrances/passage ends and create mapping array. - this.surveyTree = surveyTree; - - var segmentMap = this.segmentMap; - var newSegment = true; - - var station; - - var segment = 0; - var vertexPairToSegment = this.vertexPairToSegment; - var segmentToInfo = this.segmentToInfo; - - var v1, v2; - - var i, l = legs.length; - - var segmentInfo; - - for ( i = 0; i < l; i = i + 2 ) { - - v1 = legs[ i ]; - v2 = legs[ i + 1 ]; - - vertexPairToSegment.push( segment ); - - if ( newSegment ) { - - station = stations.getStation( v1 ); - if ( station === undefined ) continue; // possible use of separator in station name. - - segmentInfo = { - segment: segment, - startStation: station, - endStation: null - }; - - station.linkedSegments.push( segment ); - - newSegment = false; - - } - - station = stations.getStation( v2 ); - if ( station === undefined ) continue; // possible use of separator in station name. - if ( ( station && station.hitCount > 2 ) || ( i + 2 < l && ! v2.equals( legs[ i + 2 ] ) ) ) { - - // we have found a junction or a passage end - segmentInfo.endStation = station; - - segmentMap.set( segmentInfo.startStation.id + ':' + station.id, segmentInfo ); - segmentToInfo[ segment ] = segmentInfo; - - station.linkedSegments.push( segment ); - - segment++; - - newSegment = true; - - } - - } - - if ( ! newSegment ) { - - segmentInfo.endStation = station; - - segmentMap.set( segmentInfo.startStation.id + ':' + station.id, segmentInfo ); - - station.linkedSegments.push( segment ); - - } - - return this; - -}; - -Routes.prototype.createWireframe = function () { - - var geometry = new Geometry(); - var vertices = geometry.vertices; - - this.segmentMap.forEach( _addSegment ); - - return new LineSegments( geometry, new LineBasicMaterial( { color: 0x00ff00 } ) ); - - function _addSegment( value /*, key */ ) { - - vertices.push( value.startStation.p ); - vertices.push( value.endStation.p ); - - } - -}; - -Routes.prototype.addRoute = function ( routeName ) { - - if ( routeName === this.currentRouteName || routeName === undefined ) return; - - if ( this.routeNames.indexOf( routeName ) < 0 ) { - - // create entry for empty route if a new name - - this.routeNames.push( routeName ); - this.routes.set( routeName, [] ); - - } - - this.loadRoute( routeName ); - -}; - -Routes.prototype.loadRoute = function ( routeName ) { - - var self = this; - - var surveyTree = this.surveyTree; - var currentRoute = this.currentRoute; - var segmentMap = this.segmentMap; - - var map; - var segment; - - var routeSegments = this.routes.get( routeName ); - - if ( ! routeSegments ) { - - alert( 'route ' + routeName + ' does not exist' ); - return false; - - } - - currentRoute.clear(); - - for ( var i = 0; i < routeSegments.length; i++ ) { - - segment = routeSegments[ i ]; - - map = segmentMap.get( surveyTree.getIdByPath( segment.start.split( '.' ) ) + ':' + surveyTree.getIdByPath( segment.end.split( '.' ) ) ); - - if ( map !== undefined ) currentRoute.add( map.segment ); - - } - - this.currentRouteName = routeName; - - self.dispatchEvent( { type: 'changed', name: '' } ); - - return true; - -}; - -Routes.prototype.getCurrentRoute = function () { - - return this.currentRoute; - -}; - -Routes.prototype.saveCurrent = function () { - - var routeName = this.currentRouteName; - - if ( ! routeName ) return; - - var segmentMap = this.segmentMap; - var route = this.currentRoute; - - var routeSegments = []; - - segmentMap.forEach( _addRoute ); - - // update in memory route - - this.routes.set( routeName, routeSegments ); - - // update persistant browser storage - - this.metadataSource.saveRoute( routeName, { segments: routeSegments } ); - - function _addRoute ( value /*, key */ ) { - - if ( route.has( value.segment ) ) { - - routeSegments.push( { - start: value.startStation.getPath(), - end: value.endStation.getPath() - } ); - - } - - } - -}; - -Routes.prototype.getRouteNames = function () { - - return this.routeNames; - -}; - -Routes.prototype.toggleSegment = function ( index ) { - - var self = this; - var route = this.currentRoute; - var segment = this.vertexPairToSegment[ index / 2 ]; - - this.adjacentSegments.clear(); - - if ( route.has( segment ) ) { - - route.delete( segment ); - - } else { - - route.add( segment ); - - // handle adjacent segments to the latest segment toggled 'on' - - var segmentInfo = this.segmentToInfo[ segment ]; - - if ( segmentInfo !== undefined ) { - - segmentInfo.startStation.linkedSegments.forEach( _setAdjacentSegments ); - segmentInfo.endStation.linkedSegments.forEach( _setAdjacentSegments ); - - } - - } - - return; - - function _setAdjacentSegments ( segment ) { - - if ( ! route.has( segment ) ) self.adjacentSegments.add( segment ); - - } - -}; - -Routes.prototype.inCurrentRoute = function ( index ) { - - return this.currentRoute.has( this.vertexPairToSegment[ index / 2 ] ); - -}; - -Routes.prototype.adjacentToRoute = function ( index ) { - - return this.adjacentSegments.has( this.vertexPairToSegment[ index / 2 ] ); - -}; - -var unselectedMaterial = new LineBasicMaterial( { color: 0x444444, vertexColors: VertexColors } ); - -function onBeforeRender( renderer ) { - - var stencil = renderer.state.buffers.stencil; - var gl = renderer.context; - - stencil.setTest( true ); - - stencil.setOp( gl.KEEP, gl.KEEP, gl.INCR ); - -} - -function onAfterRender( renderer ) { - - var stencil = renderer.state.buffers.stencil; - - stencil.setTest( false ); - - -} - -function Legs ( layer ) { - - var geometry = new Geometry(); - - LineSegments.call( this, geometry, unselectedMaterial ); - - this.layers.set( layer ); - this.type = 'Legs'; - - this.onBeforeRender = onBeforeRender; - this.onAfterRender = onAfterRender; - - return this; - -} - -Legs.prototype = Object.create( LineSegments.prototype ); - -Legs.prototype.constructor = Legs; - -Legs.prototype.addLegs = function ( vertices, colors, legRuns ) { - - var geometry = this.geometry; - - if ( geometry.vertices.length === 0 ) { - - geometry.vertices = vertices; - geometry.colors = colors; - - } else { - - // FIXME: alllocate new buffer of old + new length, adjust indexs and append old data after new data. - - console.error( 'Walls: appending not yet implemented' ); - - } - - geometry.computeBoundingBox(); - - this.legRuns = legRuns; - - this.computeStats(); - - return this; - -}; - -Legs.prototype.cutRuns = function ( selectedRuns ) { - - var legRuns = this.legRuns; - - if ( ! legRuns ) return; - - var geometry = this.geometry; - - var vertices = geometry.vertices; - var colors = geometry.colors; - - var newGeometry = new Geometry(); - - var newVertices = newGeometry.vertices; - var newColors = newGeometry.colors; - var newLegRuns = []; - - var vp = 0; - - for ( var run = 0, l = legRuns.length; run < l; run++ ) { - - var legRun = legRuns[ run ]; - - var survey = legRun.survey; - var start = legRun.start; - var end = legRun.end; - - if ( selectedRuns.has( survey ) ) { - - for ( var v = start; v < end; v++ ) { - - newVertices.push( vertices[ v ] ); - newColors.push( colors[ v ] ); - - } - - // adjust vertex run for new vertices and color arrays - - legRun.start = vp; - - vp += end - start; - - legRun.end = vp; - - newLegRuns.push( legRun ); - - } - - } - - if ( newGeometry.vertices.length === 0 ) return false; - - newGeometry.computeBoundingBox(); - newGeometry.name = geometry.name; - - this.geometry = newGeometry; - this.legRuns = newLegRuns; - - geometry.dispose(); - - this.computeStats(); - - return true; - -}; - -Legs.prototype.computeStats = function () { - - var stats = { maxLegLength: -Infinity, minLegLength: Infinity, legCount: 0, legLength: 0 }; - var vertices = this.geometry.vertices; - - var vertex1, vertex2, legLength; - - var l = vertices.length; - - for ( var i = 0; i < l; i += 2 ) { - - vertex1 = vertices[ i ]; - vertex2 = vertices[ i + 1 ]; - - legLength = Math.abs( vertex1.distanceTo( vertex2 ) ); - - stats.legLength = stats.legLength + legLength; - - stats.maxLegLength = Math.max( stats.maxLegLength, legLength ); - stats.minLegLength = Math.min( stats.minLegLength, legLength ); - - } - - stats.legLengthRange = stats.maxLegLength - stats.minLegLength; - stats.legCount = l / 2; - - this.stats = stats; - -}; - -Legs.prototype.setShading = function ( selectedRuns, colourSegment, material ) { - - this.material = material; - - var geometry = this.geometry; - var legRuns = this.legRuns; - - var colors = geometry.colors; - - var l, run, v; - - if ( selectedRuns.size && legRuns ) { - - for ( run = 0, l = legRuns.length; run < l; run++ ) { - - var legRun = legRuns[ run ]; - - var survey = legRun.survey; - var start = legRun.start; - var end = legRun.end; - - if ( selectedRuns.has( survey ) ) { - - for ( v = start; v < end; v += 2 ) { - - colourSegment( geometry, v, v + 1, survey ); - - } - - } else { - - for ( v = start; v < end; v += 2 ) { - - colors[ v ] = ColourCache.grey; - colors[ v + 1 ] = ColourCache.grey; - - } - - } - - } - - } else { - - for ( v = 0, l = geometry.vertices.length; v < l; v += 2 ) { - - colourSegment( geometry, v, v + 1 ); - - } - - } - - geometry.colorsNeedUpdate = true; - -}; - -var unselectedMaterial$1 = new MeshLambertMaterial( { color: 0x444444, vertexColors: FaceColors } ); - -function Walls ( layer ) { - - var geometry = new BufferGeometry(); - - Mesh.call( this, geometry, unselectedMaterial$1 ); - - this.layers.set( layer ); - this.type = 'Walls'; - - return this; - -} - -Walls.prototype = Object.create( Mesh.prototype ); - -Walls.prototype.constructor = Walls; - -Walls.prototype.addWalls = function ( vertices, indices, indexRuns ) { - - var geometry = this.geometry; - - var position = geometry.getAttribute( 'position' ); - - if ( position === undefined ) { - - var positions = new Float32BufferAttribute( vertices.length * 3, 3 ); - - geometry.addAttribute( 'position', positions.copyVector3sArray( vertices ) ); - - geometry.setIndex( indices ); - - } else { - - // FIXME: alllocate new buffer of old + new length, adjust indexs and append old data after new data. - - console.error( 'Walls: appending not yet implemented' ); - - } - - geometry.computeVertexNormals(); - geometry.computeBoundingBox(); - - this.indexRuns = indexRuns; - - return this; - -}; - -Walls.prototype.setShading = function ( selectedRuns, selectedMaterial ) { - - var geometry = this.geometry; - - geometry.clearGroups(); - - var indexRuns = this.indexRuns; - - if ( selectedRuns.size && indexRuns ) { - - this.material = [ selectedMaterial, unselectedMaterial$1 ]; - - var indexRun = indexRuns[ 0 ]; - - var start = indexRun.start; - var count = indexRun.count; - - var currentMaterial; - var lastMaterial = selectedRuns.has( indexRun.survey ) ? 0 : 1; - - - // merge adjacent runs with shared material. - - for ( var run = 1, l = indexRuns.length; run < l; run++ ) { - - indexRun = indexRuns[ run ]; - - currentMaterial = selectedRuns.has( indexRun.survey ) ? 0 : 1; - - if ( currentMaterial === lastMaterial && indexRun.start === start + count ) { - - count += indexRun.count; - - } else { - - geometry.addGroup( start, count, lastMaterial ); - - start = indexRun.start; - count = indexRun.count; - - lastMaterial = currentMaterial; - - } - - } - - geometry.addGroup( start, count, lastMaterial ); - - } else { - - this.material = selectedMaterial; - - } - -}; - -Walls.prototype.cutRuns = function ( selectedRuns ) { - - var indexRuns = this.indexRuns; - - var geometry = this.geometry; - - var vertices = geometry.getAttribute( 'position' ); - var indices = geometry.index; - - var newIndices = []; - var newVertices = []; - - var newIndexRuns = []; - - var fp = 0; - - var vMap = new Map(); - var index, newIndex; - var newVertexIndex = 0; - var offset; - - for ( var run = 0, l = indexRuns.length; run < l; run++ ) { - - var indexRun = indexRuns[ run ]; - - if ( selectedRuns.has( indexRun.survey ) ) { - - var start = indexRun.start; - var count = indexRun.count; - - var end = start + count; - - var itemSize = vertices.itemSize; - var oldVertices = vertices.array; - - for ( var i = start; i < end; i++ ) { - - index = indices.getX( i ); - - newIndex = vMap.get( index ); - - if ( newIndex === undefined ) { - - newIndex = newVertexIndex++; - - vMap.set( index, newIndex ); - - offset = index * itemSize; - - newVertices.push( oldVertices[ offset ], oldVertices[ offset + 1 ], oldVertices[ offset + 2 ] ); - - } - - newIndices.push( newIndex ); - - } - - indexRun.start = fp; - - fp += count; - - newIndexRuns.push( indexRun ); - - } - - } - - if ( newIndices.length === 0 ) return false; - - // replace position and index attributes - dispose of old attributes - geometry.index.setArray( new indices.array.constructor( newIndices ) ); - geometry.index.needsUpdate = true; - - vertices.setArray( new Float32Array( newVertices ) ); - vertices.needsUpdate = true; - - geometry.computeVertexNormals(); - geometry.computeBoundingBox(); - - this.indexRuns = newIndexRuns; - - return true; - -}; - -function WaterMaterial () { - - ShaderMaterial.call( this, { - uniforms: { - offset: { value: 0 } - }, - vertexShader: Shaders.waterVertexShader, - fragmentShader: Shaders.waterFragmentShader, - depthWrite: false, - type: 'CV.WaterMaterial', - side: DoubleSide - } ); - - return this; - -} - -WaterMaterial.prototype = Object.create( ShaderMaterial.prototype ); - -WaterMaterial.prototype.constructor = WaterMaterial; - - - -// EOF - -function beforeRender ( renderer, scene, camera, geometry, material ) { - - material.uniforms.offset.value += 0.1; - -} - -function DyeTraces () { - - var geometry = new BufferGeometry(); - - Mesh.call( this, geometry, new WaterMaterial() ); - - this.vertices = []; - this.ends = []; - - this.onBeforeRender = beforeRender; - this.layers.set( FEATURE_TRACES ); - - return this; - -} - -DyeTraces.prototype = Object.create( Mesh.prototype ); - -DyeTraces.prototype.constructor = DyeTraces; - -DyeTraces.prototype.finish = function () { - - var geometry = this.geometry; - - var vertices = this.vertices; - var ends = this.ends; - - var positions = new Float32BufferAttribute( vertices.length * 3, 3 ); - var sinks = new Float32BufferAttribute( ends.length * 3, 3 ); - - geometry.addAttribute( 'position', positions.copyVector3sArray( vertices ) ); - geometry.addAttribute( 'sinks', sinks.copyVector3sArray( ends ) ); - - return this; - -}; - -DyeTraces.prototype.addTrace = function ( startStation, endStation ) { - - var vertices = this.vertices; - var ends = this.ends; - - var end = new Vector3().copy( endStation ); - - var v = new Vector3().subVectors( endStation, startStation ).cross( upAxis ).setLength( 2 ); - - var v1 = new Vector3().add( startStation ).add( v ); - var v2 = new Vector3().add( startStation ).sub( v ); - - vertices.push( v1 ); - vertices.push( v2 ); - vertices.push( end ); - - ends.push ( end ); - ends.push ( end ); - ends.push ( end ); - -}; - -function SurveyMetadata( name, metadata ) { - - this.name = name; - - var routes = {}; - var traces = []; - - if ( metadata !== null ) { - - if ( metadata.routes ) routes = metadata.routes; - if ( metadata.traces ) traces = metadata.traces; - - } - - var localMetadata = localStorage.getItem( name ); - - if ( localMetadata !== null ) { - - localMetadata = JSON.parse( localMetadata ); - - var localRoutes = localMetadata.routes; - var routeName, route; - - // add local routes to any routes in metadata (if any) - - for ( routeName in localRoutes ) { - - route = localRoutes[ routeName ]; - route.local = true; - - routes[ routeName ] = route; - - } - - } - - this.routes = routes; - this.traces = traces; - -} - -SurveyMetadata.prototype.constructor = SurveyMetadata; - -SurveyMetadata.prototype.getTraces = function () { - - return this.traces; - -}; - -SurveyMetadata.prototype.getRoutes = function () { - - return this.routes; - -}; - -SurveyMetadata.prototype.saveRoute = function ( routeName, route ) { - - this.routes[ routeName ] = route; - - this.saveLocal(); - -}; - -SurveyMetadata.prototype.saveLocal = function () { - - var localMetadata = { routes: this.routes, traces: this.traces }; - - localStorage.setItem( this.name, JSON.stringify( localMetadata ) ); - -}; - -SurveyMetadata.prototype.getURL = function () { - - // dump of json top window for cut and paste capture - - var routesJSON = { - name: 'test', - version: 1.0, - routes: this.routes, - traces: this.traces - }; - - return 'data:text/json;charset=utf8,' + encodeURIComponent( JSON.stringify( routesJSON ) ); - -}; - -var map = []; -var selectedSection$1 = 0; - -var SurveyColours = {}; - -SurveyColours.clearMap = function () { - - map = []; - selectedSection$1 = 0; - -}; - -SurveyColours.getSurveyColour = function ( surveyId ) { - - var surveyColours = ColourCache.getColors( 'survey' ); - - return surveyColours[ surveyId % surveyColours.length ]; - -}; - -SurveyColours.getSurveyColourMap = function ( surveyTree, newSelectedSection ) { - - if ( selectedSection$1 === newSelectedSection && map.length > 0 ) { - - // use cached mapping - return map; - - } - - map = []; - selectedSection$1 = newSelectedSection; - - var survey = ( selectedSection$1 === 0 ) ? surveyTree.id : selectedSection$1; - - // create mapping of survey id to colour - // map each child id _and_ all its lower level survey ids to the same colour - - var subTree = surveyTree.findById( survey ); - - var colour = this.getSurveyColour( survey ); - - _addMapping( subTree ); - - var children = subTree.children; - - while ( children.length === 1 ) { - - subTree = children[ 0 ]; - _addMapping( subTree ); - children = subTree.children; - - } - - for ( var i = 0, l = children.length; i < l; i++ ) { - - var childId = children[ i ].id; - - subTree = surveyTree.findById( childId ); - - colour = this.getSurveyColour( childId ); - - subTree.traverse( _addMapping ); - - } - - return map; - - function _addMapping ( node ) { - - // only add values for sections - not stations - if ( node.p === undefined ) map[ node.id ] = colour; - - } - -}; - -// unpack GLSL created RGBA packed float values - -var unpackDownscale = 255 / ( 256 * 256 ); - -var unpackFactor0 = unpackDownscale / ( 256 * 256 * 256 ); -var unpackFactor1 = unpackDownscale / ( 256 * 256 ); -var unpackFactor2 = unpackDownscale / 256; -var unpackFactor3 = unpackDownscale / 1; - -function unpackRGBA( buffer ) { - - return unpackFactor0 * buffer[ 0 ] + - unpackFactor1 * buffer[ 1 ] + - unpackFactor2 * buffer[ 2 ] + - unpackFactor3 * buffer[ 3 ]; - -} - -function CommonTerrain () { - - Group.call( this ); - - this.hasOverlay = false; - this.defaultOverlay = null; - this.activeOverlay = null; - this.depthTexture = null; - this.renderer = null; - this.renderTarget = null; - this.datumShift = 0; - this.activeDatumShift = 0; - this.terrainBase = null; - this.terrainRange = null; - - this.addEventListener( 'removed', function removeTerrain() { this.removed(); } ); - -} - -CommonTerrain.prototype = Object.create( Group.prototype ); - -CommonTerrain.prototype.constructor = CommonTerrain; - -CommonTerrain.prototype.shadingMode = SHADING_SHADED; -CommonTerrain.prototype.opacity = 0.5; - -CommonTerrain.prototype.removed = function () {}; - -CommonTerrain.prototype.getOpacity = function () { - - return this.opacity; - -}; - -CommonTerrain.prototype.commonRemoved = function () { - - var activeOverlay = this.activeOverlay; - - if ( activeOverlay !== null ) { - - activeOverlay.flushCache(); - activeOverlay.hideAttribution(); - - } - - if ( this.renderTarget !== null ) this.renderTarget.dispose(); - -}; - -CommonTerrain.prototype.setShadingMode = function ( mode, renderCallback ) { - - var material; - var hideAttribution = true; - var activeOverlay = this.activeOverlay; - - switch ( mode ) { - - case SHADING_HEIGHT: - - material = Materials$1.getHeightMaterial( MATERIAL_SURFACE ); - - break; - - case SHADING_OVERLAY: - - this.setOverlay( ( activeOverlay === null ? this.defaultOverlay : activeOverlay ), renderCallback ); - hideAttribution = false; - - break; - - case SHADING_SHADED: - - material = new MeshLambertMaterial( { - color: 0xffffff, - vertexColors: VertexColors, - side: FrontSide, - transparent: true, - opacity: this.opacity } - ); - - break; - - default: - - console.warn( 'unknown mode', mode ); - return false; - - } - - if ( hideAttribution && activeOverlay !== null ) { - - activeOverlay.flushCache(); - activeOverlay.hideAttribution(); - - this.activeOverlay = null; - - } - - if ( material !== undefined ) this.setMaterial( material ); - - this.shadingMode = mode; - - return true; - -}; - -CommonTerrain.prototype.setVisibility = function ( mode ) { - - if ( this.activeOverlay === null ) return; - - if ( mode ) { - - this.activeOverlay.showAttribution(); - - } else { - - this.activeOverlay.hideAttribution(); - - } - -}; - -CommonTerrain.prototype.applyDatumShift = function ( mode ) { - - if ( mode && this.activeDatumShift === 0 ) { - - this.translateZ( this.datumShift ); - this.activeDatumShift = this.datumShift; - - } else if ( ! mode && this.activeDatumShift !== 0 ) { - - this.translateZ( - this.datumShift ); - this.activeDatumShift = 0; - - } - - this.dispatchEvent( { type: 'datumShiftChange', value: this.activeDatumShift } ); - -}; - -CommonTerrain.prototype.computeBoundingBox = function () { - - var bb = new Box3(); - - this.traverse( _getBoundingBox ); - - this.boundingBox = bb; - - function _getBoundingBox( obj ) { - - if ( obj.isTile ) bb.union( obj.geometry.boundingBox ); - - } - - return bb; - -}; - -CommonTerrain.prototype.addHeightMap = function ( renderer, renderTarget ) { - - this.depthTexture = renderTarget.texture; - this.renderer = renderer; - this.renderTarget = renderTarget; - -}; - -CommonTerrain.prototype.getHeight = function () { - - var pixelCoords = new Vector3(); - var adjust = new Vector3(); - - var result = new Uint8Array( 4 ); - - return function getHeight( point ) { - - var renderTarget = this.renderTarget; - - if ( this.terrainBase === null ) { - - if ( this.boundingBox === undefined ) this.computeBoundingBox(); - - this.terrainBase = this.boundingBox.min; - this.terrainRange = this.boundingBox.getSize(); - - // setup value cached in closure - - adjust.set( renderTarget.width, renderTarget.height, 1 ).divide( this.terrainRange ); - - } - - var terrainBase = this.terrainBase; - - pixelCoords.copy( point ).sub( terrainBase ).multiply( adjust ).round(); - - this.renderer.readRenderTargetPixels( renderTarget, pixelCoords.x, pixelCoords.y, 1, 1, result ); - - // convert to survey units and return - - return unpackRGBA( result ) * this.terrainRange.z + terrainBase.z; - - }; - -} (); - - - -// EOF - -/** - * @author Angus Sawyer - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - * - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -function LoxTerrainGeometry( dtm, offsets ) { - - BufferGeometry.call( this ); - - this.type = 'LoxTerrainGeometry'; - - var heightData = dtm.data; - - var ix, iy, i, l, x, y, z; - - // buffers - - var indices = []; - var vertices = []; - - var minZ = Infinity; - var maxZ = -Infinity; - - // generate vertices - - var zIndex = 0; - - var lines = dtm.lines; - var samples = dtm.samples; - - var vertexCount = lines * samples; - - // 2 x 2 scale & rotate callibration matrix - - var xx = dtm.xx; - var xy = dtm.xy; - var yx = dtm.yx; - var yy = dtm.yy; - - // offsets from dtm -> survey -> model - - var xOffset = dtm.xOrigin - offsets.x; - var yOffset = dtm.yOrigin - offsets.y; - var zOffset = - offsets.z; - -// var x, y, z; - - var lx = samples - 1; - var ly = lines - 1; - - for ( iy = 0; iy < lines; iy++ ) { - - for ( ix = 0; ix < samples; ix++ ) { - - z = heightData[ zIndex++ ]; - - x = ix * xx + ( ly - iy ) * xy + xOffset; - y = ix * yx + ( ly - iy ) * yy + yOffset; - z += zOffset; - - vertices.push( x, y, z ); - - if ( z < minZ ) minZ = z; - if ( z > maxZ ) maxZ = z; - - } - - } - - var maxX = lx * xx + ly * xy + xOffset; - var maxY = lx * yx + ly * yy + yOffset; - - this.boundingBox = new Box3( new Vector3( xOffset, yOffset, minZ ), new Vector3( maxX, maxY, maxZ ) ); - - // indices - - for ( iy = 0; iy < ly; iy ++ ) { - - for ( ix = 0; ix < lx; ix ++ ) { - - var a = ix + samples * iy; - var b = ix + samples * ( iy + 1 ); - var c = ( ix + 1 ) + samples * ( iy + 1 ); - var d = ( ix + 1 ) + samples * iy; - - // faces - render each quad such that the shared diagonal edge has the minimum length - gives a smother terrain surface - // diagonals b - d, a - c - - var d1 = Math.abs( vertices[ a * 3 + 2 ] - vertices[ d * 3 + 2 ] ); // diff in Z values between diagonal vertices - var d2 = Math.abs( vertices[ b * 3 + 2 ] - vertices[ c * 3 + 2 ] ); // diff in Z values between diagonal vertices - - if ( d1 < d2 ) { - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } else { - - indices.push( a, b, c ); - indices.push( c, d, a ); - - } - - } - - } - - // build geometry - - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - // calibration data from terrain and local survey -> model - offsets - - this.computeVertexNormals(); - - var colourScale = Colours.terrain; - var colourRange = colourScale.length - 1; - - var colourIndex; - var dotProduct; - - var normal = this.getAttribute( 'normal' ); - var vNormal = new Vector3(); - - var buffer = new Float32Array( vertexCount * 3 ); - var colours = []; - var colour; - - // convert scale to float values - - for ( i = 0, l = colourScale.length; i < l; i++ ) { - - colour = colourScale[ i ]; - colours.push( [ colour[ 0 ] / 255, colour[ 1 ] / 255, colour[ 2 ] / 255 ] ); - - } - - for ( i = 0; i < vertexCount; i++ ) { - - vNormal.fromArray( normal.array, i * 3 ); - - dotProduct = vNormal.dot( upAxis ); - colourIndex = Math.floor( colourRange * 2 * Math.acos( Math.abs( dotProduct ) ) / Math.PI ); - - colour = colours[ colourIndex ]; - - var offset = i * 3; - - buffer[ offset ] = colour[ 0 ]; - buffer[ offset + 1 ] = colour[ 1 ]; - buffer[ offset + 2 ] = colour[ 2 ]; - - } - - this.addAttribute( 'color', new Float32BufferAttribute( buffer, 3 ) ); - -} - -LoxTerrainGeometry.prototype = Object.create( BufferGeometry.prototype ); -LoxTerrainGeometry.prototype.constructor = LoxTerrainGeometry; - -LoxTerrainGeometry.prototype.setupUVs = function ( bitmap, image, offsets ) { - - var det = bitmap.xx * bitmap.yy - bitmap.xy * bitmap.yx; - - if ( det === 0 ) return false; - - var xx = bitmap.yy / det; - var xy = - bitmap.xy / det; - var yx = - bitmap.yx / det; - var yy = bitmap.xx / det; - - var vertices = this.getAttribute( 'position' ).array; - - var width = image.naturalWidth; - var height = image.naturalHeight; - - var x, y, u, v; - - var xOffset = - ( xx * bitmap.xOrigin + xy * bitmap.yOrigin ); - var yOffset = - ( yx * bitmap.xOrigin + yy * bitmap.yOrigin ); - - var uvs = []; - - for ( var i = 0; i < vertices.length; i += 3 ) { - - x = vertices[ i ] + offsets.x; - y = vertices[ i + 1 ] + offsets.y; - - u = ( x * xx + y * xy + xOffset ) / width; - v = ( x * yx + y * yy + yOffset ) / height; - - uvs.push( u, v ); - - } - - var uvAttribute = this.getAttribute( 'uv' ); - - if ( uvAttribute !== undefined ) { - - console.alert( 'replacing attribute uv' ); - - } - - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - -}; - -var terrainLib = { - - onBeforeRender: function ( renderer ) { - - var stencil = renderer.state.buffers.stencil; - var gl = renderer.context; - - stencil.setTest( true ); - - stencil.setOp( gl.KEEP, gl.KEEP, gl.KEEP ); - stencil.setFunc( gl.EQUAL, 0, 0xFFFF ); - - }, - - onAfterRender: function ( renderer ) { - - var stencil = renderer.state.buffers.stencil; - - stencil.setTest( false ); - - } - -}; - -function LoxTerrain ( terrainData, offsets ) { - - CommonTerrain.call( this ); - - this.type = 'CV.Terrain'; - this.offsets = offsets; - this.bitmap = terrainData.bitmap; - this.overlayMaterial = null; - - var tile = new Mesh( new LoxTerrainGeometry( terrainData.dtm, offsets ), Materials$1.getSurfaceMaterial() ); - - tile.layers.set( FEATURE_TERRAIN ); - tile.isTile = true; - tile.onBeforeRender = terrainLib.onBeforeRender; - tile.onAfterRender = terrainLib.onAfterRender; - - this.tile = tile; - - this.add( tile ); - - this.hasOverlay = ( terrainData.bitmap ) ? true : false; - -} - -LoxTerrain.prototype = Object.create( CommonTerrain.prototype ); - -LoxTerrain.prototype.constructor = LoxTerrain; - -LoxTerrain.prototype.isTiled = false; - -LoxTerrain.prototype.isLoaded = function () { - - return true; - -}; - -LoxTerrain.prototype.setOverlay = function ( overlay, overlayLoadedCallback ) { - - if ( this.overlayMaterial !== null ) { - - this.setMaterial( this.overlayMaterial ); - - overlayLoadedCallback(); - - return; - - } - - var texture = new TextureLoader().load( this.bitmap.image, _overlayLoaded ); - - var self = this; - - function _overlayLoaded( ) { - - var bitmap = self.bitmap; - - self.tile.geometry.setupUVs( bitmap, texture.image, self.offsets ); - - self.overlayMaterial = new MeshLambertMaterial( - { - map: texture, - transparent: true, - opacity: self.opacity - } - ); - - bitmap.data = null; - - self.setMaterial( self.overlayMaterial ); - - overlayLoadedCallback(); - - } - -}; - -LoxTerrain.prototype.removed = function () { - - var overlayMaterial = this.overlayMaterial; - - if ( overlayMaterial !== null ) { - - // dispose of overlay texture and material - - overlayMaterial.map.dispose(); - overlayMaterial.dispose(); - - } - - this.commonRemoved(); - -}; - -LoxTerrain.prototype.setMaterial = function ( material ) { - - this.tile.material = material; - -}; - -LoxTerrain.prototype.setOpacity = function ( opacity ) { - - var material = this.tile.material; - - material.opacity = opacity; - material.needsUpdate = true; - - this.opacity = opacity; - -}; - - - -// EOF - -function WorkerPool ( script ) { - - this.script = getEnvironmentValue( 'home', '' ) + 'js/workers/' + script; - - if ( WorkerPool.workers[ script ] === undefined ) { - - // no existing workers running - WorkerPool.workers[ script ] = []; - - } - - this.workers = WorkerPool.workers[ script ]; - -} - - -WorkerPool.workers = {}; - -WorkerPool.prototype.constructor = WorkerPool; - -WorkerPool.prototype.getWorker = function () { - - if ( this.workers.length === 0 ) { - - return new Worker( this.script ); - - } else { - - return this.workers.pop(); - - } - -}; - -WorkerPool.prototype.putWorker = function ( worker ) { - - if ( this.workers.length < 4 ) { - - this.workers.push( worker ); - - } else { - - worker.terminate(); - - } - -}; - -WorkerPool.prototype.dispose = function () { - - for ( var i = 0; i < this.workers.length; i++ ) { - - this.workers[ i ].terminate(); - - } - -}; - -var zeroVector = new Vector3(); - -function Survey ( cave ) { - - if ( ! cave ) { - - alert( 'failed loading cave information' ); - return; - - } - - Object3D.call( this ); - - this.selectedSectionIds = new Set(); - this.selectedSection = 0; - this.selectedBox = null; - this.highlightBox = null; - this.featureBox = null; - this.surveyTree = null; - this.projection = null; - - // objects targetted by raycasters and objects with variable LOD - - this.pointTargets = []; - this.legTargets = []; - - this.type = 'CV.Survey'; - this.cutInProgress = false; - this.terrain = null; - this.isRegion = cave.isRegion; - this.features = []; - this.routes = null; - this.stations = null; - this.workerPool = new WorkerPool( 'caveWorker.js' ); - this.inverseWorld = null; - - // highlit point marker - - var pointerTexture = new TextureLoader().load( getEnvironmentValue( 'home', '' ) + 'images/ic_location.png' ); - var pointerMaterial = new PointsMaterial( { size: 32, map: pointerTexture, transparent : true, sizeAttenuation: false, alphaTest: 0.8 } ); - - var point = new Point( pointerMaterial ); - - point.visible = false; - - this.add( point ); - - this.stationHighlight = point; - - var self = this; - - SurveyColours.clearMap(); // clear cache of survey section to colour - - var survey = cave.getSurvey(); - - this.name = survey.title; - this.CRS = ( survey.sourceCRS === null ) ? getEnvironmentValue( 'CRS', 'fred' ) : survey.sourceCRS; - - if ( this.isRegion === true ) { - - this.surveyTree = survey.surveyTree; - this.limits = cave.getLimits(); - - } else { - - var surveyLimits = survey.limits; - - this.limits = new Box3( new Vector3().copy( surveyLimits.min ), new Vector3().copy( surveyLimits.max ) ); - this.offsets = survey.offsets; - - var modelLimits = new Box3().copy( this.limits ); - - modelLimits.min.sub( this.offsets ); - modelLimits.max.sub( this.offsets ); - - this.modelLimits = modelLimits; - - this.loadCave( survey ); - - this.legTargets = [ this.features[ LEG_CAVE ] ]; - - } - - this.loadEntrances(); - - this.setFeatureBox(); - - _setProjectionScale(); - - this.addEventListener( 'removed', this.onRemoved ); - - return; - - function _setProjectionScale () { - - // calculate scaling distortion if we have required CRS definitions - - if ( survey.sourceCRS === null || survey.targetCRS === null ) { - - self.scaleFactor = 1; - - return; - - } - - var limits = self.limits; - - var p1 = limits.min.clone(); - var p2 = limits.max.clone(); - - p1.z = 0; - p2.z = 0; - - var l1 = p1.distanceTo( p2 ); - - var transform = proj4( survey.targetCRS, survey.sourceCRS ); // eslint-disable-line no-undef - - p1.copy( transform.forward( p1 ) ); - p2.copy( transform.forward( p2 ) ); - - self.projection = transform; - - var l2 = p1.distanceTo( p2 ); - - self.scaleFactor = l1 / l2; - - } - -} - -Survey.prototype = Object.create( Object3D.prototype ); - -Survey.prototype.constructor = Survey; - -Survey.prototype.onRemoved = function ( /* event */ ) { - - if ( this.cutInProgress ) { - - // avoid disposal phase when a cut operation is taking place. - // this survey is being redisplayed. - - this.cutInProgress = false; - - return; - - } - - // needs explicit removal to call removed handlers atm - this.remove( this.stations ); - - this.traverse( _dispose ); - - return; - - function _dispose ( object ) { - - if ( object.geometry ) object.geometry.dispose(); - - } - -}; - -Survey.prototype.loadEntrances = function () { - - var surveyTree = this.surveyTree; - var self = this; - - var clusterMarkers = new ClusterMarkers( this.modelLimits, 4 ); - - // remove common elements from station names - - var endNode = surveyTree; - - while ( endNode.children.length === 1 ) endNode = endNode.children [ 0 ]; - - - // find entrances and add Markers - - surveyTree.traverse( _addEntrance ); - - this.addFeature( clusterMarkers, FEATURE_ENTRANCES, 'CV.Survey:entrances' ); - - return; - - function _addEntrance( node ) { - - var marker; - - if ( node.type !== STATION_ENTRANCE ) return; - - marker = clusterMarkers.addMarker( node.p, node.getPath( endNode ) ); - - self.pointTargets.push( marker ); - - } - -}; - -Survey.prototype.calibrateTerrain = function ( terrain ) { - - var s1 = 0, s2 = 0; - var n = 0; - - // find height difference between all entrance locations and terrain - // find average differences and use to alter height of terrain - - this.surveyTree.traverse( _testHeight ); - - if ( n > 0 ) { - - // standard deviation - - var sd = Math.sqrt( s2 / n - Math.pow( s1 / n, 2 ) ); - - // simple average - - terrain.datumShift = s1 / n; - - console.log( 'Adjustmenting terrain height by ', terrain.datumShift, sd ); - - } - - if ( this.terrain === null ) this.terrain = terrain; - - return; - - function _testHeight( node ) { - - // FIXME to extend to surface points - if ( node.type !== STATION_ENTRANCE) return; - - var v = node.p.z - terrain.getHeight( node.p ); - - s1 += v; - s2 += v * v; - n++; - - } - -}; - -Survey.prototype.loadCave = function ( cave ) { - - var self = this; - - _restoreSurveyTree( cave.surveyTree ); - - _loadSegments( cave.lineSegments ); - - this.loadStations( cave.surveyTree ); - - _loadScraps( cave.scraps ); - _loadCrossSections( cave.crossSections ); - _loadTerrain( cave ); - - this.computeBoundingBoxes( cave.surveyTree ); - - this.pointTargets.push( this.stations ); - - var metadata = new SurveyMetadata( this.name, cave.metadata ); - - this.metadata = metadata; - - this.loadDyeTraces(); - - this.routes = new Routes( metadata ).mapSurvey( this.stations, this.getLegs(), this.surveyTree ); - - return; - - function _restoreSurveyTree ( surveyTree ) { - - if ( surveyTree.forEachChild === undefined ) { - - // surveyTree from worker loading - add Tree methods to all objects in tree. - - _restore( surveyTree ); - - surveyTree.forEachChild( _restore, true ); - - } - - if ( self.surveyTree === null ) { - - self.surveyTree = surveyTree; - - } else { - - self.surveyTree.children.push( surveyTree ); - - } - - return; - - function _restore ( child ) { - - Object.assign( child, Tree.prototype ); - - } - - } - - function _loadScraps ( scrapList ) { - - var l = scrapList.length; - - if ( l === 0 ) return null; - - var mesh = self.getFeature( FACE_SCRAPS, Walls ); - - var indices = []; - var vertices = []; - - var indexRuns = []; - - var vertexOffset = 0; - var lastEnd = 0; - - for ( var i = 0; i < l; i++ ) { - - _loadScrap( scrapList[ i ] ); - - } - - mesh.addWalls( vertices, indices, indexRuns ); - - self.addFeature( mesh, FACE_SCRAPS, 'CV.Survey:faces:scraps' ); - - return; - - function _loadScrap ( scrap ) { - - var i, l; - - for ( i = 0, l = scrap.vertices.length; i < l; i++ ) { - - var vertex = scrap.vertices[ i ]; - - vertices.push( new Vector3( vertex.x, vertex.y, vertex.z ) ); - - } - - for ( i = 0, l = scrap.faces.length; i < l; i++ ) { - - var face = scrap.faces[ i ]; - - indices.push( face[ 0 ] + vertexOffset, face[ 2 ] + vertexOffset, face[ 1 ] + vertexOffset ); - - } - - var end = indices.length; - - indexRuns.push( { start: lastEnd, count: end - lastEnd, survey: scrap.survey } ); - lastEnd = end; - - vertexOffset += scrap.vertices.length; - - } - - } - - function _loadCrossSections ( crossSectionGroups ) { - - var mesh = self.getFeature( FACE_WALLS, Walls ); - - var indices = []; - var vertices = []; - - var v = 0; - var l = crossSectionGroups.length; - - // survey to face index mapping - var currentSurvey; - var indexRuns = []; - - var lastEnd = 0; - var l1, r1, u1, d1, l2, r2, u2, d2, lrud; - var i, j; - - var cross = new Vector3(); - var lastCross = new Vector3(); - - var run = null; - - if ( l === 0 ) return; - - for ( i = 0; i < l; i++ ) { - - var crossSectionGroup = crossSectionGroups[ i ]; - var m = crossSectionGroup.length; - - if ( m < 2 ) continue; - - // enter first station vertices - FIXME use fudged approach vector for this (points wrong way). - lrud = _getLRUD( crossSectionGroup[ 0 ] ); - - vertices.push( lrud.l ); - vertices.push( lrud.r ); - vertices.push( lrud.u ); - vertices.push( lrud.d ); - - for ( j = 0; j < m; j++ ) { - - var survey = crossSectionGroup[ j ].survey; - - lrud = _getLRUD( crossSectionGroup[ j ] ); - - if ( survey !== currentSurvey ) { - - currentSurvey = survey; - - if ( run !== null ) { - - // close section with two triangles to form cap. - indices.push( u2, r2, d2 ); - indices.push( u2, d2, l2 ); - - lastEnd = indices.length; - - run.count = lastEnd - run.start; - - indexRuns.push( run ); - - run = null; - - } - - } - - // next station vertices - vertices.push( lrud.l ); - vertices.push( lrud.r ); - vertices.push( lrud.u ); - vertices.push( lrud.d ); - - // triangles to form passage box - l1 = v++; - r1 = v++; - u1 = v++; - d1 = v++; - - l2 = v++; - r2 = v++; - u2 = v++; - d2 = v++; - - // all face vertices specified in CCW winding order to define front side. - - // top faces - indices.push( u1, r1, r2 ); - indices.push( u1, r2, u2 ); - indices.push( u1, u2, l2 ); - indices.push( u1, l2, l1 ); - - // bottom faces - indices.push( d1, r2, r1 ); - indices.push( d1, d2, r2 ); - indices.push( d1, l2, d2 ); - indices.push( d1, l1, l2 ); - - v = v - 4; // rewind to allow current vertices to be start of next box section. - - if ( run === null ) { - - // handle first section of run - - run = { start: lastEnd, survey: survey }; - - // start tube with two triangles to form cap - indices.push( u1, r1, d1 ); - indices.push( u1, d1, l1 ); - - } - - } - - currentSurvey = null; - v = v + 4; // advance because we are starting a new set of independant x-sections. - - } - - if ( run !== null ) { - - // close tube with two triangles - indices.push( u2, r2, d2 ); - indices.push( u2, d2, l2 ); - - run.count = indices.length - run.start; - - indexRuns.push( run ); - - } - - l = indices.length; - - if ( l === 0 ) return; - - mesh.addWalls( vertices, indices, indexRuns ); - - self.addFeature( mesh, FACE_WALLS, 'CV.Survey:faces:walls' ); - - return; - - function _getLRUD ( crossSection ) { - - var station = crossSection.end; - var lrud = crossSection.lrud; - var stationV = new Vector3( station.x, station.y, station.z ); - - // cross product of leg and up AXIS to give direction of LR vector - cross.subVectors( crossSection.start, crossSection.end ).cross( upAxis ); - - var L, R, U, D; - - if ( cross.equals( zeroVector ) ) { - - // leg is vertical - - if ( lastCross.equals( zeroVector ) ) { - - // previous leg was vertical - - L = stationV; - R = stationV; - - } else { - - // use previous leg to determine passage orientation for L and R for vertical legs - - L = lastCross.clone().setLength( lrud.l ).add( stationV ); - R = lastCross.clone().setLength( -lrud.r ).add( stationV ); - - } - - } else { - - L = cross.clone().setLength( lrud.l ).add( stationV ); - R = cross.clone().setLength( -lrud.r ).add( stationV ); - - } - - U = new Vector3( station.x, station.y, station.z + lrud.u ); - D = new Vector3( station.x, station.y, station.z - lrud.d ); - - lastCross.copy( cross ); - - return { l: L, r: R, u: U, d: D }; - - } - - } - - function _loadSegments ( srcSegments ) { - - var typeLegs = []; - - typeLegs[ LEG_CAVE ] = { vertices: [], colors: [], runs: [] }; - typeLegs[ LEG_SURFACE ] = { vertices: [], colors: [], runs: [] }; - typeLegs[ LEG_SPLAY ] = { vertices: [], colors: [], runs: [] }; - - var legs; - - var currentType; - var currentSurvey; - - var run; - var l = srcSegments.length; - - if ( l === 0 ) return null; - - var vertex1, vertex2; - - var lastVertex = new Vector3(); - - for ( var i = 0; i < l; i++ ) { - - var leg = srcSegments[ i ]; - - var type = leg.type; - var survey = leg.survey; - - // most line segments will share vertices - avoid allocating new Vector3() in this case. - - vertex1 = lastVertex.equals( leg.from ) ? lastVertex : new Vector3( leg.from.x, leg.from.y, leg.from.z ); - vertex2 = new Vector3( leg.to.x, leg.to.y, leg.to.z ); - - lastVertex = vertex2; - - legs = typeLegs[ type ]; - - if ( leg === undefined ) { - - console.warn( 'unknown segment type: ', type ); - break; - - } - - if ( survey !== currentSurvey || type !== currentType ) { - - // complete last run data - - if ( run !== undefined ) { - - var lastLegs = typeLegs[ currentType ]; - - run.end = lastLegs.vertices.length; - lastLegs.runs.push( run ); - - } - - // start new run - - run = {}; - - run.survey = survey; - run.start = legs.vertices.length; - - currentSurvey = survey; - currentType = type; - - } - - - legs.vertices.push( vertex1 ); - legs.vertices.push( vertex2 ); - - legs.colors.push( ColourCache.white ); - legs.colors.push( ColourCache.white ); - - } - - // add vertices run for last survey section encountered - - if ( run.end === undefined ) { - - run.end = legs.vertices.length; - legs.runs.push( run ); - - } - - _addModelSegments( LEG_CAVE, 'CV.Survey:cave:cave' ); - _addModelSegments( LEG_SURFACE, 'CV.Survey:surface:surface' ); - _addModelSegments( LEG_SPLAY, 'CV.Survey:cave:splay' ); - - return; - - function _addModelSegments ( tag, name ) { - - var legs = typeLegs[ tag ]; - - if ( legs.vertices.length === 0 ) return; - - var legObject = self.getFeature( tag, Legs ); - - legObject.addLegs( legs.vertices, legs.colors, legs.runs ); - - self.addFeature( legObject, tag, name + ':g' ); - - } - - } - - function _loadTerrain ( cave ) { - - if ( cave.hasTerrain === false ) return; - - var terrain = new LoxTerrain( cave.terrain, self.offsets ); - - // get limits of terrain - ignoring maximum which distorts height shading etc - var terrainLimits = new Box3().copy( terrain.tile.geometry.boundingBox ); - - var modelLimits = self.modelLimits; - - terrainLimits.min.z = modelLimits.min.z; - terrainLimits.max.z = modelLimits.max.z; - - modelLimits.union( terrainLimits ); - - self.terrain = terrain; - - return; - - } - -}; - -Survey.prototype.getFeature = function ( tag, obj ) { - - var o = this.features[ tag ]; - - if ( o === undefined && obj ) { - - o = new obj ( tag ); - - } - - return o; - -}; - -Survey.prototype.update = function ( camera, target ) { - - var cameraLayers = camera.layers; - - if ( this.features[ FEATURE_ENTRANCES ] && cameraLayers.mask & 1 << FEATURE_ENTRANCES ) { - - this.getFeature( FEATURE_ENTRANCES ).cluster( camera ); - - } - - if ( this.features[ LABEL_STATION ] && cameraLayers.mask & 1 << LABEL_STATION ) { - - if ( this.inverseWorld === null ) { - - this.inverseWorld = new Matrix4().getInverse( this.matrixWorld ); - - } - - this.getFeature( LABEL_STATION ).update( camera, target, this.inverseWorld ); - - } - -}; - -Survey.prototype.addFeature = function ( obj, tag, name ) { - - obj.name = name; - - this.features[ tag ] = obj; - - this.add( obj ); - -}; - -Survey.prototype.removeFeature = function ( obj ) { - - this.layers.mask &= ~ obj.layers.mask; - - var features = this.features; - - for ( var i = 0, l = features.length; i < l; i++ ) { - - if ( features[ i ] === obj ) delete features[ i ]; - - } - -}; - -Survey.prototype.hasFeature = function ( tag ) { - - return ! ( this.features[ tag ] === undefined ); - -}; - -Survey.prototype.loadStations = function ( surveyTree ) { - - var i, l; - - var stations = new Stations(); - var stationLabels = new StationLabels(); - - surveyTree.traverse( _addStation ); - - var legs = this.getLegs(); - - // count number of legs linked to each station - - for ( i = 0; i < legs.length; i++ ) { - - stations.updateStation( legs[ i ] ); - - } - - // we have finished adding stations. - stations.finalise(); - - - // add labels for stations - - for ( i = 0, l = stations.count; i < l; i++ ) { - - stationLabels.addStation( stations.getStationByIndex( i ) ); - - } - - this.addFeature( stations, FEATURE_STATIONS, 'CV.Stations' ); - this.addFeature( stationLabels, LABEL_STATION, 'CV.StationLabels' ); - - this.stations = stations; - - return; - - function _addStation ( node ) { - - if ( node.p === undefined ) return; - - stations.addStation( node ); - - } - -}; - -Survey.prototype.computeBoundingBoxes = function ( surveyTree ) { - - surveyTree.traverseDepthFirst( _computeBoundingBox ); - - return; - - function _computeBoundingBox ( node ) { - - var parent = node.parent; - - if ( parent && parent.boundingBox === undefined ) parent.boundingBox = new Box3(); - - if ( node.p !== undefined ) { - - parent.boundingBox.expandByPoint( node.p ); - - } else if ( parent ) { - - if ( node.children.length === 0 || ( node.boundingBox !== undefined && node.boundingBox.isEmpty() ) ) return; - - parent.boundingBox.expandByPoint( node.boundingBox.min ); - parent.boundingBox.expandByPoint( node.boundingBox.max ); - - } - - } - -}; - -Survey.prototype.loadDyeTraces = function () { - - var traces = this.metadata.getTraces(); - - if ( traces.length === 0 ) return; - - var surveyTree = this.surveyTree; - var dyeTraces = new DyeTraces(); - - for ( var i = 0, l = traces.length; i < l; i++ ) { - - var trace = traces[ i ]; - - var startStation = surveyTree.getByPath( trace.start ); - var endStation = surveyTree.getByPath( trace.end ); - - if ( endStation === undefined || startStation === undefined ) continue; - - dyeTraces.addTrace( startStation.p, endStation.p ); - - } - - dyeTraces.finish(); - - this.addFeature( dyeTraces, FEATURE_TRACES, 'CV.DyeTraces' ); - -}; - -Survey.prototype.loadFromEntrance = function ( entrance, loadedCallback ) { - - var self = this; - var name = replaceExtension( entrance.name, '3d' ); - var prefix = getEnvironmentValue( 'surveyDirectory', '' ); - - if ( entrance.loaded ) return; - - entrance.loaded = true; - - console.log( 'load: ', name ); - - var worker = this.workerPool.getWorker(); - - worker.onmessage = _surveyLoaded; - - worker.postMessage( prefix + name ); - - return; - - function _surveyLoaded ( event ) { - - var surveyData = event.data; // FIXME check for ok; - - self.workerPool.putWorker( worker ); - - self.loadCave( surveyData.survey ); - - loadedCallback(); - - } - -}; - -Survey.prototype.getMetadataURL = function () { - - return this.metadata.getURL(); - -}; - -Survey.prototype.getLegs = function () { - - return this.getFeature( LEG_CAVE ).geometry.vertices; - -}; - -Survey.prototype.getRoutes = function () { - - return this.routes; - -}; - -Survey.prototype.setScale = function ( scale ) { - - this.stations.setScale( scale ); - -}; - -Survey.prototype.getWorldPosition = function ( position ) { - - return new Vector3().copy( position ).applyMatrix4( this.matrixWorld ); - -}; - -Survey.prototype.getGeographicalPosition = function ( position ) { - - var offsets = this.offsets; - var projection = this.projection; - - var originalPosition = { x: position.x + offsets.x, y: position.y + offsets.y, z: 0 }; - - // convert to original survey CRS - - if ( projection !== null ) originalPosition = projection.forward( originalPosition ); - - originalPosition.z = position.z + offsets.z; - - return originalPosition; - -}; - -Survey.prototype.selectStation = function ( index ) { - - var stations = this.stations; - var station = stations.getStationByIndex( index ); - - stations.selectStation( station ); - - return station; - -}; - -Survey.prototype.clearSelection = function () { - - this.selectedSection = 0; - this.selectedSectionIds.clear(); - - this.stations.clearSelected(); - - var box = this.selectedBox; - - if ( box !== null ) box.visible = false; - -}; - -Survey.prototype.boxSection = function ( node, box, colour ) { - - if ( box === null ) { - - box = new Box3Helper( node.boundingBox, colour ); - - box.layers.set( FEATURE_SELECTED_BOX ); - - this.add( box ); - - } else { - - box.visible = true; - box.update( node.boundingBox ); - - } - - return box; - -}; - -Survey.prototype.highlightSelection = function ( id ) { - - var surveyTree = this.surveyTree; - var node; - var box = this.highlightBox; - - if ( id ) { - - node = surveyTree.findById( id ); - - if ( node.p === undefined && node.boundingBox !== undefined ) { - - this.highlightBox = this.boxSection( node, box, 0xffff00 ); - - } else if ( node.p ) { - - var highlight = this.stationHighlight; - - highlight.position.copy( node.p ); - highlight.visible = true; - - } - - } else { - - if ( box !== null ) box.visible = false; - - } - -}; - -Survey.prototype.selectSection = function ( id ) { - - var selectedSectionIds = this.selectedSectionIds; - var surveyTree = this.surveyTree; - var node; - - this.clearSelection(); - - if ( id ) { - - node = surveyTree.findById( id ); - - if ( node.p === undefined && node.boundingBox !== undefined ) { - - this.selectedBox = this.boxSection( node, this.selectedBox, 0x00ff00 ); - surveyTree.getSubtreeIds( id, selectedSectionIds ); - - } else { - - if ( node.p !== undefined ) this.stations.selectStation( node ); - - } - - } - - this.selectedSection = id; - - return node; - -}; - -Survey.prototype.setFeatureBox = function () { - - if ( this.featureBox === null ) { - - var box = new Box3Helper( this.modelLimits, 0xffffff ); - - box.layers.set( FEATURE_BOX ); - box.name = 'survey-boundingbox'; - - this.featureBox = box; - this.add( box ); - - } else { - - this.featureBox.update( this.modelLimits ); - - } - -}; - -Survey.prototype.cutSection = function ( id ) { - - var selectedSectionIds = this.selectedSectionIds; - var self = this; - - if ( selectedSectionIds.size === 0 ) return; - - // clear target lists - - this.PointTargets = []; - this.legTargets = []; - - this.terrain = null; - - // iterate through objects replace geometries and remove bounding boxes; - - var cutList = []; // list of Object3D's to remove from survey - workaround for lack of traverseReverse - - this.traverse( _cutObject ); - - for ( var i = 0, l = cutList.length; i < l; i++ ) { - - var obj = cutList[ i ]; - var parent = obj.parent; - - if ( parent ) parent.remove( obj ); - - // dispose of all geometry of this object and descendants - - if ( obj.geometry ) obj.geometry.dispose(); - - this.removeFeature( obj ); - - } - - this.surveyTree = this.surveyTree.findById( id ); - this.surveyTree.parent = null; - - this.loadStations( this.surveyTree ); - - // ordering is important here - - this.clearSelection(); - this.highlightSelection( 0 ); - - this.modelLimits = this.getBounds(); - this.limits.copy( this.modelLimits ); - - this.limits.min.add( this.offsets ); - this.limits.max.add( this.offsets ); - - this.setFeatureBox(); - - this.loadEntrances(); - - this.cutInProgress = true; - - return; - - function _cutObject ( obj ) { - - switch ( obj.type ) { - - case 'Legs': - case 'Walls': - - if ( ! obj.cutRuns( self.selectedSectionIds ) ) cutList.push( obj ); - - break; - - case 'Box3Helper': - case 'CV.Stations': - case 'CV.StationLabels': - case 'CV.ClusterMarker': - - cutList.push( obj ); - - break; - - case 'Group': - - break; - - } - - } - -}; - -Survey.prototype.getBounds = function () { - - var box = new Box3(); - - var min = box.min; - var max = box.max; - - this.traverse( _addObjectBounds ); - - return box; - - function _addObjectBounds ( obj ) { - - if ( obj.type === 'CV.Survey' ) return; // skip survey which is positioned/scaled into world space - - var geometry = obj.geometry; - - if ( geometry && geometry.boundingBox ) { - - min.min( geometry.boundingBox.min ); - max.max( geometry.boundingBox.max ); - - } - - } - -}; - -Survey.prototype.setShadingMode = function ( mode ) { - - var material; - - switch ( mode ) { - - case SHADING_HEIGHT: - - material = Materials$1.getHeightMaterial( MATERIAL_SURFACE, this.modelLimits ); - - break; - - case SHADING_CURSOR: - - material = Materials$1.getCursorMaterial( MATERIAL_SURFACE, this.modelLimits ); - - break; - - case SHADING_SINGLE: - - material = Materials$1.getSurfaceMaterial(); - - break; - - case SHADING_SURVEY: - - // FIXME make multiple material for survey - > color and pass to Walls(). - - break; - - case SHADING_DEPTH: - - material = Materials$1.getDepthMaterial( MATERIAL_SURFACE, this.modelLimits, this.terrain ); - - if ( ! material ) return false; - - break; - - case SHADING_DEPTH_CURSOR: - - material = Materials$1.getDepthCursorMaterial( MATERIAL_SURFACE, this.modelLimits, this.terrain ); - - if ( ! material ) return false; - - break; - - } - - if ( this.setLegShading( LEG_CAVE, mode ) ) { - - this.setWallShading( this.features[ FACE_WALLS ], mode, material ); - this.setWallShading( this.features[ FACE_SCRAPS ], mode, material ); - - return true; - - } - - return false; - -}; - -Survey.prototype.setWallShading = function ( mesh, node, selectedMaterial ) { - - if ( ! mesh ) return; - - if ( selectedMaterial ) { - - mesh.setShading( this.selectedSectionIds, selectedMaterial ); - mesh.visible = true; - - } else { - - mesh.visible = false; - - } - - // FIXME - ressurect SHADING_SURVEY ??? - -}; - -Survey.prototype.setLegShading = function ( legType, legShadingMode ) { - - var mesh = this.features[ legType ]; - - if ( mesh === undefined ) return; - - switch ( legShadingMode ) { - - case SHADING_HEIGHT: - - this.setLegColourByHeight( mesh ); - - break; - - case SHADING_LENGTH: - - this.setLegColourByLength( mesh ); - - break; - - case SHADING_INCLINATION: - - this.setLegColourByInclination( mesh, upAxis ); - - break; - - case SHADING_CURSOR: - - this.setLegColourByCursor( mesh ); - - break; - - case SHADING_DEPTH_CURSOR: - - this.setLegColourByDepthCursor( mesh ); - - break; - - case SHADING_SINGLE: - - this.setLegColourByColour( mesh, ColourCache.white ); - - break; - - case SHADING_SURVEY: - - this.setLegColourBySurvey( mesh ); - - break; - - case SHADING_PATH: - - this.setLegColourByPath( mesh ); - - break; - - case SHADING_OVERLAY: - - break; - - case SHADING_SHADED: - - break; - - case SHADING_DEPTH: - - this.setLegColourByDepth( mesh ); - - break; - - default: - - console.warn( 'invalid leg shading mode' ); - - return false; - - } - - return true; - -}; - -Survey.prototype.setLegColourByMaterial = function ( mesh, material ) { - - material.needsUpdate = true; - - mesh.setShading( this.selectedSectionIds, _colourSegment, material ); - - function _colourSegment ( geometry, v1, v2 ) { - - geometry.colors[ v1 ] = ColourCache.white; - geometry.colors[ v2 ] = ColourCache.white; - - } - -}; - -Survey.prototype.setLegColourByDepth = function ( mesh ) { - - this.setLegColourByMaterial( mesh, Materials$1.getDepthMaterial( MATERIAL_LINE, this.modelLimits, this.terrain ) ); - -}; - -Survey.prototype.setLegColourByDepthCursor = function ( mesh ) { - - this.setLegColourByMaterial( mesh, Materials$1.getDepthCursorMaterial( MATERIAL_LINE, this.modelLimits, this.terrain ) ); - -}; - -Survey.prototype.setLegColourByHeight = function ( mesh ) { - - this.setLegColourByMaterial( mesh, Materials$1.getHeightMaterial( MATERIAL_LINE, this.modelLimits ) ); - -}; - -Survey.prototype.setLegColourByCursor = function ( mesh ) { - - this.setLegColourByMaterial( mesh, Materials$1.getCursorMaterial( MATERIAL_LINE, this.modelLimits ) ); - -}; - -Survey.prototype.setLegColourByColour = function ( mesh, colour ) { - - mesh.setShading( this.selectedSectionIds, _colourSegment, Materials$1.getLineMaterial() ); - - function _colourSegment ( geometry, v1, v2 ) { - - geometry.colors[ v1 ] = colour; - geometry.colors[ v2 ] = colour; - - } - -}; - -Survey.prototype.setLegColourByLength = function ( mesh ) { - - var colours = ColourCache.getColors( 'gradient' ); - var colourRange = colours.length - 1; - var stats = mesh.stats; - - mesh.setShading( this.selectedSectionIds, _colourSegment, Materials$1.getLineMaterial() ); - - function _colourSegment ( geometry, v1, v2 ) { - - var vertex1 = geometry.vertices[ v1 ]; - var vertex2 = geometry.vertices[ v2 ]; - - var relLength = ( Math.abs( vertex1.distanceTo( vertex2 ) ) - stats.minLegLength ) / stats.legLengthRange; - var colour = colours[ Math.floor( ( 1 - relLength ) * colourRange ) ]; - - geometry.colors[ v1 ] = colour; - geometry.colors[ v2 ] = colour; - - } - -}; - -Survey.prototype.setLegColourBySurvey = function ( mesh ) { - - var surveyTree = this.surveyTree; - var selectedSection = this.selectedSection; - - if ( selectedSection === 0) selectedSection = surveyTree.id; - - var surveyToColourMap = SurveyColours.getSurveyColourMap( surveyTree, selectedSection ); - - if ( this.selectedSectionIds.size === 0 ) this.surveyTree.getSubtreeIds( selectedSection, this.selectedSectionIds ); - - mesh.setShading( this.selectedSectionIds, _colourSegment, Materials$1.getLineMaterial() ); - - function _colourSegment ( geometry, v1, v2, survey ) { - - var colour = surveyToColourMap[ survey ]; - - geometry.colors[ v1 ] = colour; - geometry.colors[ v2 ] = colour; - - } - -}; - -Survey.prototype.setLegColourByPath = function ( mesh ) { - - var routes = this.getRoutes(); - - var c1 = ColourCache.yellow; - var c2 = ColourCache.red; - var c3 = ColourCache.white; - - var colour; - - mesh.setShading( this.selectedSectionIds, _colourSegment, Materials$1.getLineMaterial() ); - - function _colourSegment ( geometry, v1, v2 /*, survey */ ) { - - if ( routes.inCurrentRoute( v1 ) ) { - - colour = c1; - - } else if ( routes.adjacentToRoute( v1 ) ) { - - colour = c2; - - } else { - - colour = c3; - } - - geometry.colors[ v1 ] = colour; - geometry.colors[ v2 ] = colour; - - } - -}; - -Survey.prototype.setLegColourByInclination = function ( mesh, pNormal ) { - - var colours = ColourCache.getColors( 'inclination' ); - - var colourRange = colours.length - 1; - var hueFactor = colourRange * 2 / Math.PI; - var legNormal = new Vector3(); - - // pNormal = normal of reference plane in model space - - mesh.setShading( this.selectedSectionIds, _colourSegment, Materials$1.getLineMaterial() ); - - function _colourSegment ( geometry, v1, v2 ) { - - var vertex1 = geometry.vertices[ v1 ]; - var vertex2 = geometry.vertices[ v2 ]; - - legNormal.subVectors( vertex1, vertex2 ).normalize(); - var dotProduct = legNormal.dot( pNormal ); - - var hueIndex = Math.floor( hueFactor * Math.acos( Math.abs( dotProduct ) ) ); - var colour = colours[ hueIndex ]; - - geometry.colors[ v1 ] = colour; - geometry.colors[ v2 ] = colour; - - } - -}; - - - -// EOF - -function Popup( cssClass ) { - - this.div = document.createElement( 'div' ); - this.div.classList.add( cssClass ); - -} - -Popup.prototype.constructor = Popup; - -Popup.prototype.display = function ( container, x, y, camera, p ) { - - var div = this.div; - var screenPosition = new Vector3(); - - div.style.left = x + 'px'; - div.style.top = y + 'px'; - - container.appendChild ( div ); - - container.addEventListener( 'mouseup', _mouseUp ); - container.addEventListener( 'mousemove', _mouseMove ); - - function _mouseMove ( /* event */ ) { - - camera.updateMatrixWorld(); - - screenPosition.copy( p ); - screenPosition.project( camera ); - - var X = container.clientWidth * ( screenPosition.x + 1 ) / 2; - var Y = container.clientHeight * ( -screenPosition.y + 1 ) / 2; - - - if ( X + div.clientWidth > container.clientWidth || Y + div.clientHeight > container.clientHeight ) { - - // moving off screen, delete now. - _mouseUp(); - - } else { - - div.style.left = X + 'px'; - div.style.top = Y + 'px'; - - } - - } - - function _mouseUp ( /* event */ ) { - - container.removeChild( div ); - - container.removeEventListener( 'mousemove', _mouseMove ); - container.removeEventListener( 'mouseup', _mouseUp ); - - } - -}; - -Popup.prototype.addLine = function ( line ) { - - var newLine = document.createElement( 'div' ); - - newLine.textContent = line; - - this.div.appendChild ( newLine ); - - return this; - -}; - -function StationPopup ( station, position, depth ) { - - Popup.call( this, 'station-info' ); - - var name = station.getPath(); - var long = false; - var tmp; - - // reduce name length if too long - - while ( name.length > 20 ) { - - tmp = name.split( '.' ); - tmp.shift(); - - name = tmp.join( '.' ); - long = true; - - } - - if ( long ) name = '...' + name; - - this.addLine( name ); - this.addLine( 'x: ' + position.x + ' m' ).addLine( 'y: ' + position.y + ' m' ).addLine( 'z: ' + position.z + ' m' ); - - if ( depth !== null ) this.addLine( 'depth from surface: ' + Math.round( depth ) + ' m' ); - -} - -StationPopup.prototype = Object.create( Popup.prototype ); - -StationPopup.prototype.constructor = StationPopup; - -// preallocated for projected area calculations - -var A$1 = new Vector3(); -var B$1 = new Vector3(); -var C$1 = new Vector3(); -var D$1 = new Vector3(); - -var T1$1 = new Triangle( A$1, B$1, C$1 ); -var T2$1 = new Triangle( A$1, C$1, D$1 ); - -function onUploadDropBuffer() { - - // call back from BufferAttribute to drop JS buffers after data has been transfered to GPU - this.array = null; - -} - -function Tile ( x, y, zoom, tileSet, clip ) { - - this.x = x; - this.y = y; - - this.zoom = zoom; - this.tileSet = tileSet; - this.clip = clip; - - this.canZoom = true; - this.evicted = false; - this.replaced = false; - this.evictionCount = 1; - this.resurrectionPending = false; - this.childrenLoading = 0; - this.childErrors = 0; - - this.boundingBox = null; - this.worldBoundingBox = null; - - Mesh.call( this, new BufferGeometry(), Materials$1.getSurfaceMaterial() ); - - this.onBeforeRender = terrainLib.onBeforeRender; - this.onAfterRender = terrainLib.onAfterRender; - - return this; - -} - -Tile.liveTiles = 0; - -Tile.prototype = Object.create( Mesh.prototype ); - -Tile.prototype.constructor = Tile; - -Tile.prototype.type = 'Tile'; -Tile.prototype.isTile = true; - -Tile.prototype.createFromBufferAttributes = function ( index, attributes, boundingBox, material ) { - - var attributeName; - var attribute; - var bufferGeometry = this.geometry; - - // assemble BufferGeometry from binary buffer objects transfered from worker - - for ( attributeName in attributes ) { - - attribute = attributes[ attributeName ]; - bufferGeometry.addAttribute( attributeName, new Float32BufferAttribute( attribute.array, attribute.itemSize ) ); - - } - - bufferGeometry.setIndex( new Uint16BufferAttribute( index, 1 ) ); - - // use precalculated bounding box rather than recalculating it here. - - bufferGeometry.boundingBox = new Box3( - new Vector3( boundingBox.min.x, boundingBox.min.y, boundingBox.min.z ), - new Vector3( boundingBox.max.x, boundingBox.max.y, boundingBox.max.z ) - ); - - attributes = bufferGeometry.attributes; - - // discard javascript attribute buffers after upload to GPU - - for ( var name in attributes ) attributes[ name ].onUpload( onUploadDropBuffer ); - - this.geometry.index.onUpload( onUploadDropBuffer ); - - this.layers.set( FEATURE_TERRAIN ); - - this.material = material; - - return this; - -}; - -Tile.prototype.getWorldBoundingBox = function () { - - var boundingBox; - - if ( this.worldBoundingBox === null ) { - - this.updateMatrixWorld(); - - boundingBox = this.getBoundingBox().clone(); - boundingBox.applyMatrix4( this.matrixWorld ); - - this.worldBoundingBox = boundingBox; - - } - - return this.worldBoundingBox; - -}; - -Tile.prototype.getBoundingBox = function () { - - var boundingBox; - - if ( this.boundingBox === null ) { - - boundingBox = this.geometry.boundingBox.clone(); - - var adj = 5; // adjust to cope with overlaps // FIXME - was resolution - - boundingBox.min.x += adj; - boundingBox.min.y += adj; - boundingBox.max.x -= adj; - boundingBox.max.y -= adj; - - this.boundingBox = boundingBox; - - } - - return this.boundingBox; - -}; - -Tile.prototype.empty = function () { - - this.isMesh = false; - - if ( ! this.boundingBox ) { - - console.warn( 'FIXUP :', this.x, this.y ); - this.getWorldBoundingBox(); - - } - - if ( this.geometry ) { - - this.geometry.dispose(); - this.geometry = new BufferGeometry(); - - } - - --Tile.liveTiles; - -}; - -Tile.prototype.evict = function () { - - this.evictionCount++; - this.evicted = true; - this.replaced = false; - - this.empty(); - -}; - -Tile.prototype.setReplaced = function () { - - this.evicted = false; - this.replaced = true; - - this.empty(); - -}; - - -Tile.prototype.setPending = function ( parentTile ) { - - if ( parentTile && this.parent === null ) { - - parentTile.add( this ); - - } - - this.parent.childrenLoading++; - - this.isMesh = false; - this.evicted = false; - -}; - -Tile.prototype.setFailed = function () { - - var parent = this.parent; - - parent.childErrors++; - parent.childrenLoading--; - parent.canZoom = false; - - parent.remove( this ); - -}; - -Tile.prototype.setLoaded = function ( overlay, opacity, renderCallback ) { - - var parent = this.parent; - var tilesWaiting = 0; - - if ( --parent.childrenLoading === 0 ) { // this tile and all siblings loaded - - if ( parent.childErrors === 0 ) { // all loaded without error - - if ( parent.isTile ) parent.setReplaced(); - - var siblings = parent.children; - - for ( var i = 0, l = siblings.length; i < l; i++ ) { - - var sibling = siblings[ i ]; - - if ( sibling.replaced || sibling.evicted ) continue; - - if ( overlay === null ) { - - sibling.isMesh = true; - Tile.liveTiles++; - - } else { - - // delay finalising until overlays loaded - avoids flash of raw surface - sibling.setOverlay( overlay, opacity, _completed ); - tilesWaiting++; - - } - - } - - if ( tilesWaiting === 0 ) renderCallback(); - - return true; - - } else { - - parent.remove( this ); - - } - - } - - return false; - - function _completed( tile ) { - - tile.isMesh = true; - Tile.liveTiles++; - - if ( --tilesWaiting === 0 ) renderCallback(); - - } - -}; - -Tile.prototype.removed = function () { - - if ( this.geometry ) this.geometry.dispose(); - -}; - -Tile.prototype.setMaterial = function ( material ) { - - this.material = material; - -}; - -Tile.prototype.setOpacity = function ( opacity ) { - - var material = this.material; - - material.opacity = opacity; - material.needsUpdate = true; - -}; - -Tile.prototype.setOverlay = function ( overlay, opacity, imageLoadedCallback ) { - - var self = this; - - overlay.getTile( this.x, this.y, this.zoom, opacity, _overlayLoaded ); - - return; - - function _overlayLoaded ( material ) { - - self.material = material; - imageLoadedCallback( self ); - - } - -}; - -Tile.prototype.projectedArea = function ( camera ) { - - var boundingBox = this.getWorldBoundingBox(); - - var z = boundingBox.max.z; - - A$1.copy( boundingBox.min ).setZ( z ); - C$1.copy( boundingBox.max ); - - B$1.set( A$1.x, C$1.y, z ); - D$1.set( C$1.x, A$1.y, z ); - -// clamping reduces accuracy of area but stops offscreen area contributing to zoom pressure -// .clampScalar( -1, 1 ); - - A$1.project( camera ); - B$1.project( camera ); - C$1.project( camera ); - D$1.project( camera ); - - - return T1$1.area() + T2$1.area(); - -}; - - - -// EOF - -//import { Box3Helper } from '../core/Box3'; -var halfMapExtent = 6378137 * Math.PI; // from EPSG:3875 definition - -function WebTerrain ( survey, onReady, onLoaded ) { - - CommonTerrain.call( this ); - - this.name = 'WebTerrain'; - this.type = 'CV.WebTerrain'; - - var limits = survey.limits; - - this.limits = new Box2( - new Vector2( limits.min.x, limits.min.y ), - new Vector2( limits.max.x, limits.max.y ) - ); - - this.offsets = survey.offsets; - - this.onLoaded = onLoaded; - this.childrenLoading = 0; - this.childErrors = 0; - this.terrainLoaded = false; - this.material = null; - this.initialZoom = null; - this.currentZoom = null; - this.currentLimits = null; - this.dying = false; - this.overlaysLoading = 0; - this.debug = true; - - this.workerPool = new WorkerPool( 'webTileWorker.js' ); - - if ( HUD !== undefined ) { - - this.progressDial = HUD.getProgressDial(); - - } - - var self = this; - - new FileLoader().setResponseType( 'text' ).load( getEnvironmentValue( 'terrainDirectory', '' ) + '/' + 'tileSets.json', _tileSetLoaded, function () {}, _tileSetMissing ); - - function _tileSetLoaded( text ) { - - self.tileSets = JSON.parse( text ); - - onReady(); // call handler - - } - - function _tileSetMissing( ) { - - onReady(); // call handler - - } - -} - -WebTerrain.prototype = Object.create( CommonTerrain.prototype ); - -WebTerrain.prototype.constructor = WebTerrain; - -WebTerrain.prototype.isTiled = true; - -WebTerrain.prototype.isLoaded = function () { - - return this.terrainLoaded; - -}; - -WebTerrain.prototype.hasCoverage = function () { - - var limits = this.limits; - var tileSets = this.tileSets; - var tileSet; - var coverage; - - if ( tileSets === undefined ) return false; - - // iterate through available tileSets and pick the first match - var baseDirectory = getEnvironmentValue( 'terrainDirectory', '' ); - - for ( var i = 0, l = tileSets.length; i < l; i++ ) { - - tileSet = tileSets[ i ]; - - coverage = this.getCoverage( limits, tileSet.minZoom ); - - if ( ( coverage.min_x >= tileSet.minX && coverage.max_x <= tileSet.maxX ) - && ( - ( coverage.min_y >= tileSet.minY && coverage.max_y <= tileSet.maxY ) ) ) { - - tileSet.directory = baseDirectory + tileSet.subdirectory; - this.tileSet = tileSet; - return true; - - } - - } - - return false; - -}; - -WebTerrain.prototype.getCoverage = function ( limits, zoom ) { - - var coverage = { zoom: zoom }; - - var N = halfMapExtent; - var W = -halfMapExtent; - - var tileCount = Math.pow( 2, zoom - 1 ) / halfMapExtent; // tile count per metre - - coverage.min_x = Math.floor( ( limits.min.x - W ) * tileCount ); - coverage.max_x = Math.floor( ( limits.max.x - W ) * tileCount ); - - coverage.max_y = Math.floor( ( N - limits.min.y ) * tileCount ); - coverage.min_y = Math.floor( ( N - limits.max.y ) * tileCount ); - - coverage.count = ( coverage.max_x - coverage.min_x + 1 ) * ( coverage.max_y - coverage.min_y + 1 ); - - return coverage; - -}; - -WebTerrain.prototype.pickCoverage = function ( limits ) { - - var tileSet = this.tileSet; - var zoom = tileSet.maxZoom + 1; - var coverage; - - do { - - --zoom; - coverage = this.getCoverage( limits, zoom ); - - } while ( coverage.count > 4 && zoom > tileSet.minZoom ); - - return coverage; - -}; - -WebTerrain.prototype.loadTile = function ( x, y, z, existingTile, parentTile ) { - - // account for limits of DTM resolution - - var tileSet = this.tileSet; - var scale = ( z > tileSet.dtmMaxZoom ) ? Math.pow( 2, tileSet.dtmMaxZoom - z ) : 1; - - // don't zoom in with no overlay - no improvement of terrain rendering in this case - - if ( scale !== 1 && this.activeOverlay === null && this.currentZoom !== null ) return; - - console.log( 'load: [ ', z +'/' + x + '/' + y, ']' ); - - var self = this; - - var limits = this.limits; - var tileWidth = halfMapExtent / Math.pow( 2, z - 1 ); - var clip = { top: 0, bottom: 0, left: 0, right: 0 }; - - var tileMinX = tileWidth * x - halfMapExtent; - var tileMaxX = tileMinX + tileWidth; - - var tileMaxY = halfMapExtent - tileWidth * y; - var tileMinY = tileMaxY - tileWidth; - - var divisions = ( tileSet.divisions ) * scale; - var resolution = tileWidth / divisions; - - ++this.tilesLoading; - - // trim excess off sides of tile where overlapping with region - - if ( tileMaxY > limits.max.y ) clip.top = Math.floor( ( tileMaxY - limits.max.y ) / resolution ); - - if ( tileMinY < limits.min.y ) clip.bottom = Math.floor( ( limits.min.y - tileMinY ) / resolution ); - - if ( tileMinX < limits.min.x ) clip.left = Math.floor( ( limits.min.x - tileMinX ) / resolution ); - - if ( tileMaxX > limits.max.x ) clip.right = Math.floor( ( tileMaxX - limits.max.x ) / resolution ); - - // get Tile instance. - - var tile = existingTile ? existingTile : new Tile( x, y, z, self.tileSet, clip ); - var parent = parentTile ? parentTile : this; - - tile.setPending( parent ); // tile load/reload pending - - // get a web worker from the pool and create new geometry in it - - var tileLoader = this.workerPool.getWorker(); - - tileLoader.onmessage = _mapLoaded; - - tileLoader.postMessage( { - tileSet: tileSet, - divisions: divisions, - resolution: resolution, - x: x, - y: y, - z: z, - clip: clip, - offsets: this.offsets - } ); - - return; - - function _mapLoaded ( event ) { - - var tileData = event.data; - - // return worker to pool - - self.workerPool.putWorker( tileLoader ); - - --self.tilesLoading; - - // the survey/region in the viewer may have changed while the height maps are being loaded. - // bail out in this case to avoid errors - - if ( self.dying ) { - - self.progressDial.end(); - return; - - } - - // error out early if we or other tiles have failed to load. - - if ( tileData.status !== 'ok' || tile.parent.childErrors !== 0 ) { - - tile.setFailed(); - - if ( self.progressDial ) self.progressDial.end(); - - return; - - } - - if ( self.progressDial ) self.progressDial.add( self.progressInc ); - - tile.createFromBufferAttributes( tileData.index, tileData.attributes, tileData.boundingBox, self.material ); - - if ( self.progressDial ) self.progressDial.add( self.progressInc ); - - if ( tile.setLoaded( self.activeOverlay, self.opacity, self.onLoaded ) ) { - - if ( self.progressDial ) self.progressDial.end(); - - } - - self.terrainLoaded = true; - - } - -}; - -WebTerrain.prototype.resurrectTile = function ( tile ) { - - if ( tile.isMesh ) { - - console.warn( 'resurrecting the undead!' ); - return; - - } - - // reload tile (use exiting tile object to preserve canZoom). - this.loadTile( tile.x, tile.y, tile.zoom, tile ); - -}; - -WebTerrain.prototype.tileArea = function ( limits, tile ) { - - var coverage = this.pickCoverage( limits ); - var zoom = coverage.zoom; - - if ( tile && tile.zoom == zoom ) { - - console.error( 'ERROR - looping on tile replacement' ); - return; - - } - - this.currentLimits = limits; - - if ( this.initialZoom === null ) { - - this.initialZoom = zoom; - - } - - for ( var x = coverage.min_x; x < coverage.max_x + 1; x++ ) { - - for ( var y = coverage.min_y; y < coverage.max_y + 1; y++ ) { - - this.loadTile( x, y, zoom, null, tile ); - - } - - } - - if ( this.tilesLoading > 0 && this.progressDial !== undefined ) { - - this.progressDial.start( 'Loading ' + this.tilesLoading + ' terrain tiles' ); - this.progressInc = 100 / ( this.tilesLoading * 2 ); - - } - - this.currentZoom = zoom; - - return; - -}; - -WebTerrain.prototype.setDefaultOverlay = function ( overlay ) { - - this.defaultOverlay = overlay; - -}; - -WebTerrain.prototype.setOverlay = function ( overlay, overlayLoadedCallback ) { - - if ( this.tilesLoading > 0 ) return; - - var self = this; - - var currentOverlay = this.activeOverlay; - - if ( currentOverlay !== null ) { - - if ( currentOverlay === overlay ) { - - return; - - } else { - - currentOverlay.flushCache(); - currentOverlay.hideAttribution(); - - } - - } - - this.activeOverlay = overlay; - this.defaultOverlay = overlay; - - overlay.showAttribution(); - - this.traverse( _setTileOverlays ); - - return; - - function _setTileOverlays ( obj ) { - - if ( ! obj.isTile ) return; - - obj.setOverlay( overlay, self.opacity, _overlayLoaded ); - self.overlaysLoading++; - - } - - function _overlayLoaded () { - - if ( --self.overlaysLoading === 0 ) overlayLoadedCallback(); - - } - -}; - -WebTerrain.prototype.removed = function () { - - this.dying = true; - - if ( this.tilesLoading > 0 ) return; - - var self = this; - - this.traverse( _disposeTileMesh ); - - this.commonRemoved(); - - return; - - function _disposeTileMesh ( obj ) { - - if ( obj !== self ) obj.removed( obj ); - - } - -}; - -WebTerrain.prototype.setMaterial = function ( material ) { - - if ( this.tilesLoading > 0 ) return; - - this.traverse( _setTileMeshMaterial ); - - this.activeOverlay = null; - - // use for commmon material access for opacity - - material.opacity = this.opacity; - material.needsUpdate = true; - - this.material = material; - - return; - - function _setTileMeshMaterial ( obj ) { - - if ( ! obj.isTile ) return; - - obj.setMaterial( material ); - - } - -}; - -WebTerrain.prototype.setOpacity = function ( opacity ) { - - if ( this.shadingMode === SHADING_OVERLAY ) { - - // each tile has its own material, therefore need setting separately - this.traverse( _setTileOpacity ); - - } else { - - if ( this.material ) { - - this.material.opacity = opacity; - this.material.needsUpdate = true; - - } - - } - - this.opacity = opacity; - - return; - - function _setTileOpacity ( obj ) { - - if ( obj.isTile ) obj.setOpacity( opacity ); - - } - -}; - -WebTerrain.prototype.zoomCheck = function ( camera ) { - - var maxZoom = this.tileSet.maxZoom; - var initialZoom = this.initialZoom; - var self = this; - - var frustum = new Frustum(); - - var candidateTiles = []; - var candidateEvictTiles = []; - var resurrectTiles = []; - var retry = false; - - var total, tile, i; - - if ( this.tilesLoading > 0 ) return true; - - camera.updateMatrix(); // make sure camera's local matrix is updated - camera.updateMatrixWorld(); // make sure camera's world matrix is updated - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - - frustum.setFromMatrix( new Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) ); - - // scan scene graph of terrain - - this.traverse( _scanTiles ); - - var resurrectCount = resurrectTiles.length; - var candidateCount = candidateTiles.length; - - _evictTiles(); - - if ( resurrectCount !== 0 ) { - - if ( this.progressDial ) this.progressDial.start( 'Resurrecting tiles' ); - - for ( i = 0; i < resurrectCount; i++ ) { - - this.resurrectTile( resurrectTiles[ i ] ); - retry = true; - - } - - this.progressInc = 100 / ( 2 * resurrectCount ); - - } else if ( candidateCount !== 0 ) { - - total = candidateTiles.reduce( function ( a, b ) { return { area: a.area + b.area }; } ); - - for ( i = 0; i < candidateCount; i++ ) { - - if ( candidateTiles[ i ].area / total.area > 0.3 ) { // FIXME - weight by tile resolution to balance view across all visible areas first. - - tile = candidateTiles[ i ].tile; - - if ( tile.zoom < maxZoom ) { - - var bb = tile.getBoundingBox().clone(); - - bb.min.add( this.offsets ); - bb.max.add( this.offsets ); - - this.tileArea( bb, tile ); - retry = true; - - } - - } - - } - - } - - return retry; - - function _scanTiles( tile ) { - - if ( tile === self || ! tile.isTile ) return; - - if ( frustum.intersectsBox( tile.getWorldBoundingBox() ) ) { - - // this tile intersects the screen - - if ( tile.children.length === 0 ) { - - if ( ! tile.isMesh ) { - - // this tile is not loaded, but has been previously - resurrectTiles.push( tile ); - - } else { - - // this tile is loaded, maybe increase resolution? - if ( tile.canZoom ) candidateTiles.push( { tile: tile, area: tile.projectedArea( camera ) } ); - - } - - } else { - - if ( ! tile.isMesh && tile.evicted && ! this.parent.resurrectionPending ) { - - tile.resurrectionPending = true; - resurrectTiles.push( tile ); - - } - - if ( tile.parent.ResurrectionPending && this.isMesh ) { - - // remove tile - will be replaced with parent - console.warn( ' should not get here' ); - - } - - } - - } else { - - // off screen tile - if ( tile.isMesh ) candidateEvictTiles.push( tile ); - - } - - } - - function _evictTiles() { - - var EVICT_PRESSURE = 5; - var evictCount = candidateEvictTiles.length; - var i; - - if ( evictCount !== 0 ) { - - candidateEvictTiles.sort( _sortByPressure ); - - for ( i = 0; i < evictCount; i++ ) { - - var tile = candidateEvictTiles[ i ]; - - // heuristics for evicting tiles - needs refinement - - var pressure = Tile.liveTiles / EVICT_PRESSURE; - var tilePressure = tile.evictionCount * Math.pow( 2, initialZoom - tile.zoom ); - - //console.log( 'ir', initialZoom, 'p: ', pressure, ' tp: ', tilePressure, ( pressure > tilePressure ? '*** EVICTING ***' : 'KEEP' ) ); - - if ( pressure > tilePressure ) tile.evict(); - - } - - } - - function _sortByPressure( tileA, tileB ) { - - return tileA.evictionCount / tileA.zoom - tileB.evictionCount / tileB.zoom; - - } - - } - -}; - - - -// EOF - -// FIXME fix lifecycle of materials and textures - ensure disposal/caching as required -// GPU resource leak etc. - -function Overlay ( overlayProvider, container ) { - - this.provider = overlayProvider; - this.container = container; - - var attribution = overlayProvider.getAttribution(); - - if ( attribution ) { - - attribution.classList.add( 'overlay-branding' ); - this.attribution = attribution; - - } - - this.materialCache = {}; - -} - -Overlay.prototype.showAttribution = function () { - - var attribution = this.attribution; - - if ( attribution !== undefined ) this.container.appendChild( attribution ); - -}; - -Overlay.prototype.hideAttribution = function () { - - var attribution = this.attribution; - var parent = attribution.parentNode; - - if ( parent !== null ) parent.removeChild( attribution ); - -}; - -Overlay.prototype.getTile = function ( x, y, z, opacity, overlayLoaded ) { - - var self = this; - var key = x + ':' + y + ':' + z; - - var material = this.materialCache[ key ]; - - if ( material !== undefined ) { - - overlayLoaded( material ); - - return; - - } - - var url = this.provider.getUrl( x, y, z ); - - if ( url === null ) return; - - new TextureLoader().setCrossOrigin( 'anonymous' ).load( url, _textureLoaded ); - - return; - - function _textureLoaded( texture ) { - - var material = new MeshLambertMaterial( { transparent: true, opacity: opacity, color: 0xffffff } ); - - material.map = texture; - material.needsUpdate = true; - - self.materialCache[ key ] = material; - - overlayLoaded( material ); - - } - -}; - -Overlay.prototype.flushCache = function () { - - var materialCache = this.materialCache; - var material; - - for ( var name in materialCache ) { - - material = materialCache[ name ]; - - material.map.dispose(); - material.dispose(); - - } - - this.materialCache = {}; - -}; - -Overlay.prototype.constructor = Overlay; - -/** - * @author qiao / https://github.com/qiao - * @author mrdoob / http://mrdoob.com - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author erich666 / http://erichaines.com - */ - -// This set of controls performs orbiting, dollying (zooming), and panning. -// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). -// -// Orbit - left mouse / touch: one finger move -// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish -// Pan - right mouse, or arrow keys / touch: three finter swipe - -/* eslint-disable */ - -function OrbitControls ( object, domElement ) { - - this.object = object; - - this.domElement = ( domElement !== undefined ) ? domElement : document; - - // Set to false to disable this control - this.enabled = true; - - // "target" sets the location of focus, where the object orbits around - this.target = new Vector3(); - - // How far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0; - this.maxDistance = Infinity; - - // How far you can zoom in and out ( OrthographicCamera only ) - this.minZoom = 0; - this.maxZoom = Infinity; - - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0; // radians - this.maxPolarAngle = Math.PI; // radians - - // How far you can orbit horizontally, upper and lower limits. - // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. - this.minAzimuthAngle = - Infinity; // radians - this.maxAzimuthAngle = Infinity; // radians - - // Set to true to enable damping (inertia) - // If damping is enabled, you must call controls.update() in your animation loop - this.enableDamping = false; - this.dampingFactor = 0.25; - - // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. - // Set to false to disable zooming - this.enableZoom = true; - this.zoomSpeed = 1.0; - - // Set to false to disable rotating - this.enableRotate = true; - this.rotateSpeed = 1.0; - - // Set to false to disable panning - this.enablePan = true; - this.keyPanSpeed = 7.0; // pixels moved per arrow key push - - // Set to true to automatically rotate around the target - // If auto-rotate is enabled, you must call controls.update() in your animation loop - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 - - // Set to false to disable use of the keys - this.enableKeys = true; - - // The four arrow keys - this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; - - // Mouse buttons - this.mouseButtons = { ORBIT: MOUSE.LEFT, ZOOM: MOUSE.MIDDLE, PAN: MOUSE.RIGHT }; - - // for reset - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.zoom0 = this.object.zoom; - - // - // public methods - // - - this.getPolarAngle = function () { - - return spherical.phi; - - }; - - this.getAzimuthalAngle = function () { - - return spherical.theta; - - }; - - this.reset = function () { - - scope.target.copy( scope.target0 ); - scope.object.position.copy( scope.position0 ); - scope.object.zoom = scope.zoom0; - - scope.object.updateProjectionMatrix(); - scope.dispatchEvent( changeEvent ); - - scope.update(); - - state = STATE.NONE; - - }; - - // this method is exposed, but perhaps it would be better if we can make it private... - this.update = function() { - - var offset = new Vector3(); - - // so camera.up is the orbit axis - var quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); - - var lastPosition = new Vector3(); - var lastQuaternion = new Quaternion(); - - return function update () { - - var position = scope.object.position; - - offset.copy( position ).sub( scope.target ); - - // rotate offset to "y-axis-is-up" space - offset.applyQuaternion( quat ); - - // angle from z-axis around y-axis - spherical.setFromVector3( offset ); - - if ( scope.autoRotate && state === STATE.NONE ) { - - rotateLeft( getAutoRotationAngle() ); - - } - - spherical.theta += sphericalDelta.theta; - spherical.phi += sphericalDelta.phi; - - // restrict theta to be between desired limits - spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); - - // restrict phi to be between desired limits - spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); - - spherical.makeSafe(); - - - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - - // move target to panned location - scope.target.add( panOffset ); - - offset.setFromSpherical( spherical ); - - // rotate offset back to "camera-up-vector-is-up" space - offset.applyQuaternion( quatInverse ); - - position.copy( scope.target ).add( offset ); - - scope.object.lookAt( scope.target ); - - if ( scope.enableDamping === true ) { - - sphericalDelta.theta *= ( 1 - scope.dampingFactor ); - sphericalDelta.phi *= ( 1 - scope.dampingFactor ); - - } else { - - sphericalDelta.set( 0, 0, 0 ); - - } - - scale = 1; - panOffset.set( 0, 0, 0 ); - - // update condition is: - // min(camera displacement, camera rotation in radians)^2 > EPS - // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - - if ( zoomChanged || - lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; - - return true; - - } - - return false; - - }; - - }(); - - this.dispose = function() { - - scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); - scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - window.removeEventListener( 'keydown', onKeyDown, false ); - - //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? - - }; - - // - // internals - // - - var scope = this; - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; - - var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; - - var state = STATE.NONE; - - var EPS = 0.000001; - - // current position in spherical coordinates - var spherical = new Spherical(); - var sphericalDelta = new Spherical(); - - var scale = 1; - var panOffset = new Vector3(); - var zoomChanged = false; - - var rotateStart = new Vector2(); - var rotateEnd = new Vector2(); - var rotateDelta = new Vector2(); - - var panStart = new Vector2(); - var panEnd = new Vector2(); - var panDelta = new Vector2(); - - var dollyStart = new Vector2(); - var dollyEnd = new Vector2(); - var dollyDelta = new Vector2(); - - function getAutoRotationAngle() { - - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - - } - - function getZoomScale() { - - return Math.pow( 0.95, scope.zoomSpeed ); - - } - - function rotateLeft( angle ) { - - sphericalDelta.theta -= angle; - - } - - function rotateUp( angle ) { - - sphericalDelta.phi -= angle; - - } - - var panLeft = function() { - - var v = new Vector3(); - - return function panLeft( distance, objectMatrix ) { - - v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix - v.multiplyScalar( - distance ); - - panOffset.add( v ); - - }; - - }(); - - var panUp = function() { - - var v = new Vector3(); - - return function panUp( distance, objectMatrix ) { - - v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix - v.multiplyScalar( distance ); - - panOffset.add( v ); - - }; - - }(); - - // deltaX and deltaY are in pixels; right and down are positive - var pan = function() { - - var offset = new Vector3(); - - return function pan ( deltaX, deltaY ) { - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - if ( scope.object instanceof PerspectiveCamera ) { - - // perspective - var position = scope.object.position; - offset.copy( position ).sub( scope.target ); - var targetDistance = offset.length(); - - // half of the fov is center to top of screen - targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); - - // we actually don't use screenWidth, since perspective camera is fixed to screen height - panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); - panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); - - } else if ( scope.object instanceof OrthographicCamera ) { - - // orthographic - panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); - panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); - - } else { - - // camera neither orthographic nor perspective - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); - scope.enablePan = false; - - } - - }; - - }(); - - function dollyIn( dollyScale ) { - - if ( scope.object instanceof PerspectiveCamera ) { - - scale /= dollyScale; - - } else if ( scope.object instanceof OrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - function dollyOut( dollyScale ) { - - if ( scope.object instanceof PerspectiveCamera ) { - - scale *= dollyScale; - - } else if ( scope.object instanceof OrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - // - // event callbacks - update the object state - // - - function handleMouseDownRotate( event ) { - - //console.log( 'handleMouseDownRotate' ); - - rotateStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownDolly( event ) { - - //console.log( 'handleMouseDownDolly' ); - - dollyStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownPan( event ) { - - //console.log( 'handleMouseDownPan' ); - - panStart.set( event.clientX, event.clientY ); - - } - - function handleMouseMoveRotate( event ) { - - //console.log( 'handleMouseMoveRotate' ); - - rotateEnd.set( event.clientX, event.clientY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleMouseMoveDolly( event ) { - - //console.log( 'handleMouseMoveDolly' ); - - dollyEnd.set( event.clientX, event.clientY ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyIn( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyOut( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleMouseMovePan( event ) { - - //console.log( 'handleMouseMovePan' ); - - panEnd.set( event.clientX, event.clientY ); - - panDelta.subVectors( panEnd, panStart ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleMouseUp( event ) { - - //console.log( 'handleMouseUp' ); - - } - - function handleMouseWheel( event ) { - - //console.log( 'handleMouseWheel' ); - - if ( event.deltaY < 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( event.deltaY > 0 ) { - - dollyIn( getZoomScale() ); - - } - - scope.update(); - - } - - function handleKeyDown( event ) { - - //console.log( 'handleKeyDown' ); - - switch ( event.keyCode ) { - - case scope.keys.UP: - pan( 0, scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.BOTTOM: - pan( 0, - scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.LEFT: - pan( scope.keyPanSpeed, 0 ); - scope.update(); - break; - - case scope.keys.RIGHT: - pan( - scope.keyPanSpeed, 0 ); - scope.update(); - break; - - } - - } - - function handleTouchStartRotate( event ) { - - //console.log( 'handleTouchStartRotate' ); - - rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchStartDolly( event ) { - - //console.log( 'handleTouchStartDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyStart.set( 0, distance ); - - } - - function handleTouchStartPan( event ) { - - //console.log( 'handleTouchStartPan' ); - - panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchMoveRotate( event ) { - - //console.log( 'handleTouchMoveRotate' ); - - rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleTouchMoveDolly( event ) { - - //console.log( 'handleTouchMoveDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyEnd.set( 0, distance ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyIn( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleTouchMovePan( event ) { - - //console.log( 'handleTouchMovePan' ); - - panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - panDelta.subVectors( panEnd, panStart ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleTouchEnd( event ) { - - //console.log( 'handleTouchEnd' ); - - } - - // - // event handlers - FSM: listen for events and reset state - // - - function onMouseDown( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - if ( event.button === scope.mouseButtons.ORBIT ) { - - if ( scope.enableRotate === false ) return; - - handleMouseDownRotate( event ); - - state = STATE.ROTATE; - - } else if ( event.button === scope.mouseButtons.ZOOM ) { - - if ( scope.enableZoom === false ) return; - - handleMouseDownDolly( event ); - - state = STATE.DOLLY; - - } else if ( event.button === scope.mouseButtons.PAN ) { - - if ( scope.enablePan === false ) return; - - handleMouseDownPan( event ); - - state = STATE.PAN; - - } - - if ( state !== STATE.NONE ) { - - document.addEventListener( 'mousemove', onMouseMove, false ); - document.addEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( startEvent ); - - } - - } - - function onMouseMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - if ( state === STATE.ROTATE ) { - - if ( scope.enableRotate === false ) return; - - handleMouseMoveRotate( event ); - - } else if ( state === STATE.DOLLY ) { - - if ( scope.enableZoom === false ) return; - - handleMouseMoveDolly( event ); - - } else if ( state === STATE.PAN ) { - - if ( scope.enablePan === false ) return; - - handleMouseMovePan( event ); - - } - - } - - function onMouseUp( event ) { - - if ( scope.enabled === false ) return; - - handleMouseUp( event ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onMouseWheel( event ) { - - if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; - - event.preventDefault(); - event.stopPropagation(); - - handleMouseWheel( event ); - - scope.dispatchEvent( startEvent ); // not sure why these are here... - scope.dispatchEvent( endEvent ); - - } - - function onKeyDown( event ) { - - if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; - - handleKeyDown( event ); - - } - - function onTouchStart( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - - handleTouchStartRotate( event ); - - state = STATE.TOUCH_ROTATE; - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - - handleTouchStartDolly( event ); - - state = STATE.TOUCH_DOLLY; - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - - handleTouchStartPan( event ); - - state = STATE.TOUCH_PAN; - - break; - - default: - - state = STATE.NONE; - - } - - if ( state !== STATE.NONE ) { - - scope.dispatchEvent( startEvent ); - - } - - } - - function onTouchMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... - - handleTouchMoveRotate( event ); - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... - - handleTouchMoveDolly( event ); - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... - - handleTouchMovePan( event ); - - break; - - default: - - state = STATE.NONE; - - } - - } - - function onTouchEnd( event ) { - - if ( scope.enabled === false ) return; - - handleTouchEnd( event ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onContextMenu( event ) { - - event.preventDefault(); - - } - - // - - scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); - - scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); - - window.addEventListener( 'keydown', onKeyDown, false ); - - // force an update at start - - this.update(); - -} - -OrbitControls.prototype = Object.create( EventDispatcher.prototype ); -OrbitControls.prototype.constructor = OrbitControls; - -//import { DirectionGlobe } from '../analysis/DirectionGlobe'; - -//import { LeakWatch } from '../../../../LeakWatch/src/LeakWatch'; - -var lightPosition = new Vector3( -1, -1, 0.5 ); -var RETILE_TIMEOUT = 150; // ms pause after last movement before attempting retiling - -var caveIsLoaded = false; - -var container; - -// THREE.js objects - -var renderer; -var scene = new Scene(); -var oCamera; -var pCamera; - -var camera; - -var mouse = new Vector2(); -var mouseMode = MOUSE_MODE_NORMAL; -var mouseTargets = []; - -var raycaster; -var terrain = null; -var directionalLight; -var survey; -var limits; -var stats = {}; -var zScale; - -var cursorHeight; - -var shadingMode; -var surfaceShadingMode = SHADING_SINGLE; -var terrainShadingMode; - -var overlays = {}; -var activeOverlay = null; - -var cameraMode; -var selectedSection = 0; - -var controls; -var defaultTarget = new Vector3(); - -var cameraMove; - -var lastActivityTime = 0; -//var leakWatcher; - -var Viewer = Object.create( EventDispatcher.prototype ); - -function init ( domID, configuration ) { // public method - - console.log( 'CaveView v' + VERSION ); - - container = document.getElementById( domID ); - - if ( ! container ) alert( 'No container DOM object [' + domID + '] available' ); - - setEnvironment( configuration ); - - var width = container.clientWidth; - var height = container.clientHeight; - - renderer = new WebGLRenderer( { antialias: true } ) ; - - renderer.setSize( width, height ); - renderer.setPixelRatio( window.devicePixelRatio ); - renderer.setClearColor( 0x000000 ); - renderer.autoClear = false; - - oCamera = new OrthographicCamera( -width / 2, width / 2, height / 2, -height / 2, 1, 4000 ); - - oCamera.rotateOnAxis( upAxis, Math.PI / 2 ); - - initCamera( oCamera ); - - pCamera = new PerspectiveCamera( 75, width / height, 1, 16000 ); - - initCamera( pCamera ); - - camera = pCamera; - - scene.add( pCamera ); - scene.add( oCamera ); - - directionalLight = new DirectionalLight( 0xffffff ); - directionalLight.position.copy( lightPosition ); - - scene.add( directionalLight ); - - scene.add( new HemisphereLight( 0xffffff, 0x00ffff, 0.3 ) ); - - raycaster = new Raycaster(); - - renderer.clear(); - - container.appendChild( renderer.domElement ); - - controls = new OrbitControls( camera, renderer.domElement ); - - cameraMove = new CameraMove( controls, renderView, onCameraMoveEnd ); - - controls.addEventListener( 'change', function () { cameraMove.prepare( null, null ); cameraMove.start( 80 ); } ); - - controls.enableDamping = true; - - // event handler - window.addEventListener( 'resize', resize ); - - Object.defineProperties( Viewer, { - - 'container': { - value: container - }, - - 'terrain': { - writeable: true, - get: function () { return testCameraLayer( FEATURE_TERRAIN ); }, - set: function ( x ) { loadTerrain( x ); } - }, - - 'terrainShading': { - writeable: true, - get: function () { return terrainShadingMode; }, - set: function ( x ) { _stateSetter( setTerrainShadingMode, 'terrainShading', x ); } - }, - - 'hasTerrain': { - get: function () { return !! terrain; } - }, - - 'terrainDatumShift': { - writeable: true, - get: function () { return !! terrain.activeDatumShift; }, - set: function ( x ) { applyTerrainDatumShift( x ); } - }, - - 'terrainOverlays': { - get: function () { if ( terrain.isTiled ) return Object.keys( overlays ); else return terrain.hasOverlay ? [ true ] : []; } - }, - - 'terrainOverlay': { - writeable: true, - get: function () { return activeOverlay; }, - set: function ( x ) { _stateSetter( setTerrainOverlay, 'terrainOverlay', x ); } - }, - - 'terrainOpacity': { - writeable: true, - get: function () { return terrain.getOpacity(); }, - set: function ( x ) { setTerrainOpacity( x ); } - }, - - 'shadingMode': { - writeable: true, - get: function () { return shadingMode; }, - set: function ( x ) { _stateSetter( setShadingMode, 'shadingMode', x ); } - }, - - 'surfaceShading': { - writeable: true, - get: function () { return surfaceShadingMode; }, - set: function ( x ) { _stateSetter( setSurfaceShadingMode, 'surfaceShading', x ); } - }, - - 'cameraType': { - writeable: true, - get: function () { return cameraMode; }, - set: function ( x ) { _stateSetter( setCameraMode, 'cameraType', x ); } - }, - - 'view': { - writeable: true, - get: function () { return VIEW_NONE; }, - set: function ( x ) { _stateSetter( setViewMode, 'view', x ); } - }, - - 'cursorHeight': { - writeable: true, - get: function () { return cursorHeight; }, - set: function ( x ) { setCursorHeight( x ); } - }, - - 'initCursorHeight': { - writeable: true, - get: function () { return cursorHeight; }, - set: function ( x ) { cursorHeight = x; } - }, - - 'maxHeight': { - get: function () { return limits.max.z; } - }, - - 'minHeight': { - get: function () { return limits.min.z; } - }, - - 'maxLegLength': { - get: function () { return stats.maxLegLength; } - }, - - 'minLegLength': { - get: function () { return stats.minLegLength; } - }, - - 'section': { - writeable: true, - get: function () { return selectedSection; }, - set: function ( x ) { _stateSetter( selectSection, 'section', x ); } - }, - - 'highlight': { - writeable: true, - set: function ( x ) { _stateSetter( highlightSelection, 'highlight', x ); } - }, - - 'routeEdit': { - writeable: true, - get: function () { return ( mouseMode === MOUSE_MODE_ROUTE_EDIT ); }, - set: function ( x ) { _setRouteEdit( x ); this.dispatchEvent( { type: 'change', name: 'routeEdit' } ); } - }, - - 'setPOI': { - writeable: true, - get: function () { return true; }, - set: function ( x ) { _stateSetter( setCameraPOI, 'setPOI', x ); } - }, - - 'developerInfo': { - writeable: true, - get: function () { return true; }, - set: function ( x ) { showDeveloperInfo( x ); } - }, - - 'HUD': { - writeable: true, - get: function () { return HUD.getVisibility(); }, - set: function ( x ) { HUD.setVisibility( x ); } - }, - - 'cut': { - writeable: true, - get: function () { return true; }, - set: function () { cutSection(); } - }, - - 'zScale': { - writeable: true, - get: function () { return zScale; }, - set: function ( x ) { setZScale( x ); } - }, - - 'autoRotate': { - writeable: true, - get: function () { return controls.autoRotate; }, - set: function ( x ) { setAutoRotate( !! x ); } - }, - - 'autoRotateSpeed': { - writeable: true, - get: function () { return controls.autoRotateSpeed / 11; }, - set: function ( x ) { controls.autoRotateSpeed = x * 11; } - } - - } ); - - _enableLayer( FEATURE_BOX, 'box' ); - - _conditionalLayer( FEATURE_ENTRANCES, 'entrances' ); - _conditionalLayer( FEATURE_STATIONS, 'stations' ); - _conditionalLayer( FEATURE_TRACES, 'traces' ); - _conditionalLayer( FACE_SCRAPS, 'scraps' ); - _conditionalLayer( FACE_WALLS, 'walls' ); - _conditionalLayer( LEG_SPLAY, 'splays' ); - _conditionalLayer( LEG_SURFACE, 'surfaceLegs' ); - _conditionalLayer( LABEL_STATION, 'stationLabels' ); - - Materials$1.initCache( Viewer ); - - HUD.init( domID, renderer ); - - return; - - function _enableLayer ( layerTag, name ) { - - Object.defineProperty( Viewer, name, { - writeable: true, - get: function () { return testCameraLayer( layerTag ); }, - set: function ( x ) { setCameraLayer( layerTag, x ); this.dispatchEvent( { type: 'change', name: name } ); } - } ); - - } - - function _conditionalLayer ( layerTag, name ) { - - _enableLayer ( layerTag, name ); - - name = 'has' + name.substr( 0, 1 ).toUpperCase() + name.substr( 1 ); - - Object.defineProperty( Viewer, name, { - get: function () { return survey.hasFeature( layerTag ); } - } ); - - } - - function _stateSetter ( modeFunction, name, newMode ) { - - modeFunction( isNaN( newMode ) ? newMode : Number( newMode ) ); - - Viewer.dispatchEvent( { type: 'change', name: name } ); - - } - - function _setRouteEdit ( x ) { - - mouseMode = x ? MOUSE_MODE_ROUTE_EDIT : MOUSE_MODE_NORMAL; - - switch ( mouseMode ) { - - case MOUSE_MODE_NORMAL: - - mouseTargets = survey.pointTargets; - - break; - - case MOUSE_MODE_ROUTE_EDIT: - - mouseTargets = survey.legTargets; - - break; - - default: - - console.warn( 'invalid mouse mode' ); - - } - - } - -} - -function setZScale ( scale ) { - - // scale - in range 0 - 1 - - var lastScale = Math.pow( 2, ( zScale - 0.5 ) * 4 ); - var newScale = Math.pow( 2, ( scale - 0.5 ) * 4 ); - - survey.applyMatrix( new Matrix4().makeScale( 1, 1, newScale / lastScale ) ); - - zScale = scale; - - renderView(); - -} - -function setAutoRotate ( state ) { - - controls.autoRotate = state; - - if ( state ) { - - cameraMove.prepare( null, null ); - cameraMove.start( 2952000 ); - - } else { - - cameraMove.stop(); - - } - -} - -function setCursorHeight ( x ) { - - cursorHeight = x; - Viewer.dispatchEvent( { type: 'cursorChange', name: 'cursorHeight' } ); - - renderView(); - -} - -function setTerrainOpacity ( x ) { - - terrain.setOpacity( x ); - Viewer.dispatchEvent( { type: 'change', name: 'terrainOpacity' } ); - - renderView(); - -} - -function applyTerrainDatumShift( x ) { - - terrain.applyDatumShift( x ); - Viewer.dispatchEvent( { type: 'change', name: 'terrainDatumShift' } ); - - renderView(); - -} - -function showDeveloperInfo( /* x */ ) { - -// console.log( renderer.info ); -/* - var info = renderer.getResourceInfo(); - - if ( leakWatcher === undefined ) { - - leakWatcher = new LeakWatch(); - leakWatcher.setBaseline( scene, info ); - - } else { - - leakWatcher.compare( scene, info ); - - } -*/ - -} - -function renderDepthTexture () { - - if ( terrain === null || ! terrain.isLoaded() ) return; - - var dim = 512; - - // set camera frustrum to cover region/survey area - - var width = container.clientWidth; - var height = container.clientHeight; - - var range = limits.getSize(); - - var scaleX = width / range.x; - var scaleY = height / range.y; - - if ( scaleX < scaleY ) { - - height = height * scaleX / scaleY; - - } else { - - width = width * scaleY / scaleX; - - } - - // render the terrain to a new canvas square canvas and extract image data - - var rtCamera = new OrthographicCamera( -width / 2, width / 2, height / 2, -height / 2, -10000, 10000 ); - - rtCamera.layers.set( FEATURE_TERRAIN ); // just render the terrain - - scene.overrideMaterial = Materials$1.getDepthMapMaterial( terrain ); - - var renderTarget = new WebGLRenderTarget( dim, dim, { minFilter: LinearFilter, magFilter: NearestFilter, format: RGBAFormat } ); - - renderTarget.texture.generateMipmaps = false; - renderTarget.texture.name = 'CV.DepthMapTexture'; - - Materials$1.setTerrain( terrain ); - - renderer.setSize( dim, dim ); - renderer.setPixelRatio( 1 ); - - renderer.clear(); - renderer.render( scene, rtCamera, renderTarget, true ); - - // correct height between entrances and terrain ( compensates for mismatch beween CRS and datums ) - - terrain.addHeightMap( renderer, renderTarget ); - - survey.calibrateTerrain( terrain ); - - // restore renderer to normal render size and target - - renderer.setRenderTarget(); // revert to screen canvas - - renderer.setSize( container.clientWidth, container.clientHeight ); - renderer.setPixelRatio( window.devicePixelRatio ); - - scene.overrideMaterial = null; - - renderView(); - - // clear renderList to release objects on heap associated with rtCamera - renderer.renderLists.dispose(); - -} - -function setCameraMode ( mode ) { - - if ( mode === cameraMode ) return; - - // get offset vector of current camera from target - - var offset = camera.position.clone().sub( controls.target ); - - switch ( mode ) { - - case CAMERA_PERSPECTIVE: - - offset.setLength( CAMERA_OFFSET / oCamera.zoom ); - - camera = pCamera; - - break; - - case CAMERA_ORTHOGRAPHIC: - - // calculate zoom from ratio of pCamera distance from target to base distance. - oCamera.zoom = CAMERA_OFFSET / offset.length(); - - offset.setLength( CAMERA_OFFSET * 2 ); - - camera = oCamera; - - break; - - default: - - console.warn( 'unknown camera mode', mode ); - return; - - } - - // update new camera with position to give same apparent zoom and view - - camera.position.copy( offset.add( controls.target ) ); - - camera.updateProjectionMatrix(); - camera.lookAt( controls.target ); - - controls.object = camera; - - cameraMode = mode; - - HUD.update(); - - renderView(); - -} - -function initCamera ( camera ) { - - camera.up = upAxis; - camera.zoom = 1; - - camera.layers.set( 0 ); - - camera.layers.enable( LEG_CAVE ); - camera.layers.enable( FEATURE_ENTRANCES ); - camera.layers.enable( FEATURE_BOX ); - camera.layers.enable( FEATURE_SELECTED_BOX ); - - camera.position.set( 0, 0, CAMERA_OFFSET ); - camera.lookAt( 0, 0, 0 ); - camera.updateProjectionMatrix(); - -} - -function setCameraLayer ( layerTag, enable ) { - - if ( enable ) { - - oCamera.layers.enable( layerTag ); - pCamera.layers.enable( layerTag ); - - } else { - - oCamera.layers.disable( layerTag ); - pCamera.layers.disable( layerTag ); - - } - - renderView(); - -} - -function testCameraLayer ( layerTag ) { - - return ( ( camera.layers.mask & 1 << layerTag ) > 0 ); - -} - -function setViewMode ( mode, t ) { - - var cameraPosition = new Vector3(); - var tAnimate = t || 240; - - switch ( mode ) { - - case VIEW_PLAN: - - // reset camera to start position - cameraPosition.set( 0, 0, CAMERA_OFFSET ); - - break; - - case VIEW_ELEVATION_N: - - cameraPosition.set( 0, CAMERA_OFFSET, 0 ); - - break; - - case VIEW_ELEVATION_S: - - cameraPosition.set( 0, -CAMERA_OFFSET, 0 ); - - break; - - case VIEW_ELEVATION_E: - - cameraPosition.set( CAMERA_OFFSET, 0, 0 ); - - break; - - case VIEW_ELEVATION_W: - - cameraPosition.set( -CAMERA_OFFSET, 0, 0 ); - - break; - - default: - - console.warn( 'invalid view mode specified: ', mode ); - return; - - } - - cameraPosition.add( defaultTarget ); - - cameraMove.cancel(); - cameraMove.prepare( cameraPosition, defaultTarget ); - cameraMove.start( tAnimate ); - -} - -function setTerrainShadingMode ( mode ) { - - if ( terrain.setShadingMode( mode, renderView ) ) terrainShadingMode = mode; - - renderView(); - -} - -function setShadingMode ( mode ) { - - if ( terrain === null && ( mode === SHADING_DEPTH || mode === SHADING_DEPTH_CURSOR ) ) return; - if ( survey.setShadingMode( mode ) ) shadingMode = mode; - - renderView(); - -} - -function setSurfaceShadingMode ( mode ) { - - if ( survey.setLegShading( LEG_SURFACE, mode ) ) surfaceShadingMode = mode; - - renderView(); - -} - -function setTerrainOverlay ( overlayName ) { - - if ( terrainShadingMode === SHADING_OVERLAY ) { - - activeOverlay = overlayName; - - terrain.setOverlay( overlays[ overlayName ], renderView ); - - } - -} - -function addOverlay ( name, overlayProvider ) { - - overlays[ name ] = new Overlay( overlayProvider, container ); - - if ( Object.keys( overlays ).length === 1 ) { - - activeOverlay = name; - - } - -} - -function cutSection () { - - if ( selectedSection === 0 ) return; - - survey.remove( terrain ); - survey.cutSection( selectedSection ); - - // grab a reference to prevent survey being destroyed in clearView() - var cutSurvey = survey; - - // reset view - clearView(); - - loadSurvey( cutSurvey ); - -} - -function highlightSelection ( id ) { - - survey.highlightSelection( id ); - - renderView(); - -} - -function selectSection ( id ) { - - var node = survey.selectSection( id ); - - setShadingMode( shadingMode ); - - selectedSection = id; - - if ( id === 0 ) return; - - if ( node.p === undefined ) { - - if ( node.boundingBox === undefined ) return; - // a section of the survey rather than a station - - var boundingBox = node.boundingBox.clone(); - - cameraMove.prepare( null, boundingBox.applyMatrix4( survey.matrixWorld ) ); - - } else { - - // a single station - - cameraMove.prepare( null, survey.getWorldPosition( node.p ) ); - - } - - renderView(); - -} - -function resize () { - - var width = container.clientWidth; - var height = container.clientHeight; - - // adjust the renderer to the new canvas size - renderer.setSize( width, height ); - - if ( oCamera === undefined ) return; - - // adjust cameras to new aspect ratio etc. - oCamera.left = -width / 2; - oCamera.right = width / 2; - oCamera.top = height / 2; - oCamera.bottom = -height / 2; - - oCamera.updateProjectionMatrix(); - - pCamera.aspect = width / height; - - pCamera.updateProjectionMatrix(); - - renderView(); - -} - -function clearView () { - - // clear the current cave model, and clear the screen - caveIsLoaded = false; - - renderer.clear(); - - HUD.setVisibility( false ); - - if ( survey ) { - - survey.remove( terrain ); - scene.remove( survey ); - - } - - controls.enabled = false; - - survey = null; - terrain = null; - selectedSection = 0; - mouseMode = MOUSE_MODE_NORMAL; - mouseTargets = []; - - shadingMode = SHADING_HEIGHT; - surfaceShadingMode = SHADING_SINGLE; - terrainShadingMode = SHADING_SHADED; - - // remove event listeners - - unloadTerrainListeners(); - - Materials$1.flushCache(); - - container.removeEventListener( 'mousedown', mouseDown ); - - initCamera( pCamera ); - initCamera( oCamera ); - - Viewer.cameraType = CAMERA_PERSPECTIVE; - setViewMode( VIEW_PLAN, 1 ); - - renderView(); - -} - -function loadCave ( cave ) { - - if ( ! cave ) { - - alert( 'failed loading cave information' ); - return; - - } - - loadSurvey( new Survey( cave ) ); - -} - -function loadSurvey ( newSurvey ) { - - var asyncTerrainLoading = false; - - survey = newSurvey; - - stats = survey.getFeature( LEG_CAVE ).stats; - - setScale( survey ); - - terrain = survey.terrain; - - scene.up = upAxis; - - scene.add( survey ); -// scene.add( new DirectionGlobe( survey ) ); - - caveIsLoaded = true; - - selectSection( 0 ); - - mouseTargets = survey.pointTargets; - - setSurfaceShadingMode( surfaceShadingMode ); - // set if we have independant terrain maps - - if ( terrain === null ) { - - terrain = new WebTerrain( survey, _terrainReady, _tilesLoaded, renderView ); - asyncTerrainLoading = true; - - } else { - - survey.add( terrain ); - setTerrainShadingMode( terrainShadingMode ); - - renderDepthTexture(); - - } - - scene.matrixAutoUpdate = false; - - container.addEventListener( 'mousedown', mouseDown, false ); - - HUD.setVisibility( true ); - - // signal any listeners that we have a new cave - if ( ! asyncTerrainLoading ) Viewer.dispatchEvent( { type: 'newCave', name: 'newCave' } ); - - controls.object = camera; - controls.enabled = true; - - survey.getRoutes().addEventListener( 'changed', _routesChanged ); - - setViewMode( VIEW_PLAN, 1 ); - - renderView(); - - function _terrainReady () { - - if ( terrain.hasCoverage() ) { - - setTerrainShadingMode( terrainShadingMode ); - - terrain.tileArea( survey.limits ); - terrain.setDefaultOverlay( overlays[ activeOverlay ] ); - - survey.add( terrain ); - - } else { - - terrain = null; - - } - - // delayed notification to ensure and event listeners get accurate terrain information - Viewer.dispatchEvent( { type: 'newCave', name: 'newCave' } ); - - } - - function _tilesLoaded () { - - renderView(); - loadTerrainListeners(); - - if ( terrain.depthTexture === null ) renderDepthTexture(); - - } - - function _routesChanged ( /* event */ ) { - - setShadingMode( shadingMode ); - renderView(); - - } - -} - -function loadTerrain ( mode ) { - - if ( terrain.isLoaded() ) { - - if ( mode ) { - - loadTerrainListeners(); - - } else { - - unloadTerrainListeners(); - - } - - terrain.setVisibility( mode ); - - setCameraLayer( FEATURE_TERRAIN, mode ); - - Viewer.dispatchEvent( { type: 'change', name: 'terrain' } ); - - } - -} - -function loadTerrainListeners () { - - clockStart(); - - controls.addEventListener( 'end', clockStart ); - -} - -function unloadTerrainListeners () { - - if ( ! controls ) return; - - controls.removeEventListener( 'end', clockStart ); - - clockStop(); - -} - -function clockStart ( /* event */ ) { - - lastActivityTime = performance.now(); - -} - -function clockStop ( /* event */ ) { - - lastActivityTime = 0; - -} - -function mouseDown ( event ) { - - var picked, result; - - mouse.x = ( event.clientX / container.clientWidth ) * 2 - 1; - mouse.y = - ( event.clientY / container.clientHeight ) * 2 + 1; - - raycaster.setFromCamera( mouse, camera ); - - var intersects = raycaster.intersectObjects( mouseTargets, false ); - - for ( var i = 0, l = intersects.length; i < l; i++ ) { - - picked = intersects[ i ]; - - switch ( mouseMode ) { - - case MOUSE_MODE_NORMAL: - - if ( picked.object.isPoints ) { - - result = _selectStation( picked ); - - } else { - - result = _selectEntrance( picked ); - - } - - break; - - case MOUSE_MODE_ROUTE_EDIT: - - result = _selectSegment( picked ); - - break; - - } - - if ( result ) break; - - } - - function _selectStation ( picked ) { - - var station = survey.selectStation( picked.index ); - - renderView(); - - var depth = ( terrain ) ? station.p.z - terrain.getHeight( station.p ) : null; - - var popup = new StationPopup( station, survey.getGeographicalPosition( station.p ), depth ); - - var p = survey.getWorldPosition( station.p ); - - popup.display( container, event.clientX, event.clientY, camera, p ); - - cameraMove.prepare( null, p.clone() ); - - return true; - - } - - function _selectSegment ( picked ) { - - var routes = getRoutes(); - - routes.toggleSegment( picked.index ); - - setShadingMode( SHADING_PATH ); - - renderView(); - - return true; - - } - - function _selectEntrance ( picked ) { - - if ( ! Viewer.entrances ) return false; - - var entrance = picked.object; - var position = entrance.getWorldPosition(); - - cameraMove.prepare( position.clone().add( new Vector3( 0, 0, 5 ) ), position ); - - console.log( entrance.type, entrance.name ); - - if ( survey.isRegion === true ) { - - survey.loadFromEntrance( entrance, _loaded ); - - } else { - - cameraMove.start( 80 ); - - } - - return true; - - } - - function _loaded () { - - setShadingMode( shadingMode ); - - renderView(); - - } - -} - -var renderView = function () { - - var lPosition = new Vector3(); - var rotation = new Euler(); - - return function renderView () { - - if ( ! caveIsLoaded ) return; - - camera.getWorldRotation( rotation ); - - lPosition.copy( lightPosition ); - - directionalLight.position.copy( lPosition.applyAxisAngle( upAxis, rotation.z ) ); - - survey.update( camera, controls.target ); - - renderer.clear(); - renderer.render( scene, camera ); - - HUD.renderHUD(); - - clockStart(); - - }; - -} (); - - -function onCameraMoveEnd () { - - if ( terrain && terrain.isTiled && Viewer.terrain ) setTimeout( updateTerrain, RETILE_TIMEOUT ); - -} - -function updateTerrain () { - - if ( lastActivityTime && performance.now() - lastActivityTime > RETILE_TIMEOUT ) { - - clockStop(); - - if ( terrain.zoomCheck( camera ) ) { - - setTimeout( updateTerrain, RETILE_TIMEOUT * 5 ); - - } - - } - -} - -function setCameraPOI ( /* fixme */ ) { - - cameraMove.start( 200 ); - -} - -function setScale ( obj ) { - - var width = container.clientWidth; - var height = container.clientHeight; - - // scaling to compensate distortion introduced by projection ( x and y coords only ) - approx only - var scaleFactor = survey.scaleFactor; - - limits = survey.limits; - zScale = 0.5; - - var range = limits.getSize(); - - // initialize cursor height to be mid range of heights - cursorHeight = 0; - - var hScale = Math.min( width / range.x, height / range.y ); - var vScale = hScale * scaleFactor; - - var scale = new Vector3( hScale, hScale, vScale ); - - obj.scale.copy( scale ); - - obj.position.copy( survey.modelLimits.getCenter().multiply( scale ).negate() ); - - HUD.setScale( vScale ); - - // pass to survey to adjust size of symbology - - obj.setScale( vScale ); - -} - -function getStats () { - - return stats; - -} - -function getControls () { - - return controls; - -} - -function getMetadata () { - - return survey.getMetadataURL(); - -} - -function getRoutes () { - - return survey.getRoutes(); - -} - -function getSurveyTree () { - - return survey.surveyTree; - -} - -// export public interface - -Object.assign( Viewer, { - init: init, - clearView: clearView, - loadCave: loadCave, - getMetadata: getMetadata, - getRoutes: getRoutes, - getStats: getStats, - getSurveyTree: getSurveyTree, - getControls: getControls, - getState: Viewer, - renderView: renderView, - addOverlay: addOverlay -} ); - - - - -// EOF - -function Page( id, onTop ) { - - var tab = document.createElement( 'div' ); - var page = document.createElement( 'div' ); - - var frame = Page.frame; - - page.classList.add( 'page' ); - - tab.id = id; - tab.classList.add( 'tab' ); - tab.style.top = ( Page.position++ * 40 ) + 'px'; - - tab.addEventListener( 'click', this.tabHandleClick ); - - if ( onTop !== undefined ) { - - // callback when this page is made visible - tab.addEventListener( 'click', onTop ); - - } - - if ( frame === null ) { - - // create UI side panel and reveal tabs - frame = document.createElement( 'div' ); - - frame.id = 'frame'; - frame.style.display = 'block'; - - Page.frame = frame; - - var close = document.createElement( 'div' ); - - close.id = 'close'; - - close.addEventListener( 'click', _closeFrame ); - - frame.appendChild( close ); - - } - - frame.appendChild( tab ); - frame.appendChild( page ); - - Page.pages.push( { tab: tab, page: page } ); - - this.page = page; - this.slide = undefined; - - function _closeFrame ( event ) { - - event.target.parentElement.classList.remove( 'onscreen' ); - - } - -} - -Page.pages = []; -Page.listeners = []; -Page.position = 0; -Page.inHandler = false; -Page.controls = []; -Page.frame = null; - -Page.reset = function () { - - Page.listeners = []; - Page.pages = []; - Page.position = 0; - Page.inHandler = false; - Page.controls = []; - Page.frame = null; - -}; - -Page.clear = function () { - - Page.frame.addEventListener( 'transitionend', _afterReset ); - Page.frame.classList.remove( 'onscreen' ); - - var i, l, listener; - - for ( i = 0, l = Page.listeners.length; i < l; i++ ) { - - listener = Page.listeners[ i ]; - - listener.obj.removeEventListener( listener.name, listener.handler ); - - } - - Page.listeners = []; - - function _afterReset ( event ) { - - var frame = event.target; - - frame.removeEventListener( 'transitionend', _afterReset ); - - if ( frame !== null ) frame.parentElement.removeChild( frame ); - - } - -}; - - -Page.addListener = function ( obj, name, handler ) { - - obj.addEventListener( name, handler ); - - Page.listeners.push( { - obj: obj, - name: name, - handler: handler - } ); - -}; - -Page.handleChange = function ( event ) { - - var obj = event.target; - var property = event.name; - - if ( ! Page.inHandle ) { - - if ( Page.controls[ property ] ) { - - var ctrl = Page.controls[ property ]; - - switch ( ctrl.type ) { - - case 'checkbox': - - ctrl.checked = obj[ property ]; - - break; - - case 'select-one': - case 'range': - - ctrl.value = obj[ property ]; - - break; - - case 'download': - - ctrl.href = obj[ property ]; - - break; - - } - - } - - } - -}; - -Page.prototype.constructor = Page; - -Page.prototype.addListener = function ( obj, name, handler ) { - - Page.addListener( obj, name, handler ); // redirect to :: method - allows later rework to page specific destruction - -}; - -Page.prototype.tabHandleClick = function ( event ) { - - var tab = event.target; - var pages = Page.pages; - - tab.classList.add( 'toptab' ); - tab.parentElement.classList.add( 'onscreen' ); - - for ( var i = 0, l = pages.length; i < l; i++ ) { - - var otherTab = pages[ i ].tab; - var otherPage = pages[ i ].page; - - if ( otherTab === tab ) { - - otherPage.style.display = 'block'; - - } else { - - otherTab.classList.remove( 'toptab' ); - otherPage.style.display = 'none'; - - } - - } - -}; - -Page.prototype.appendChild = function ( domElement ) { - - this.page.appendChild( domElement ); - -}; - -Page.prototype.addHeader = function ( text ) { - - var div = document.createElement( 'div' ); - - div.classList.add( 'header' ); - div.textContent = text; - - this.page.appendChild( div ); - - return div; - -}; - -Page.prototype.addText = function ( text ) { - - var p = document.createElement( 'p' ); - - p.textContent = text; - this.page.appendChild( p ); - - return p; - -}; - -Page.prototype.addSelect = function ( title, obj, trgObj, property, replace ) { - - var div = document.createElement( 'div' ); - var label = document.createElement( 'label' ); - var select = document.createElement( 'select' ); - var opt; - - div.classList.add( 'control' ); - - if ( obj instanceof Array ) { - - for ( var i = 0, l = obj.length; i < l; i++ ) { - - opt = document.createElement( 'option' ); - - opt.value = obj[ i ]; - opt.text = obj[ i ]; - - if ( opt.text === trgObj[ property ] ) opt.selected = true; - - select.add( opt, null ); - - } - - } else { - - for ( var p in obj ) { - - opt = document.createElement( 'option' ); - - opt.text = p; - opt.value = obj[ p ]; - - if ( opt.value == trgObj[ property ] ) opt.selected = true; - - select.add( opt, null ); - - } - - } - - this.addListener( select, 'change', function ( event ) { Page.inHandler = true; trgObj[ property ] = event.target.value; Page.inHandler = false; } ); - - label.textContent = title; - - Page.controls[ property ] = select; - - div.appendChild( label ); - div.appendChild( select ); - - if ( replace === undefined ) { - - this.page.appendChild( div ); - - } else { - - this.page.replaceChild( div, replace ); - - } - - return div; - -}; - -Page.prototype.addCheckbox = function ( title, obj, property ) { - - var label = document.createElement( 'label' ); - var cb = document.createElement( 'input' ); - - label.textContent = title; - - cb.type = 'checkbox'; - cb.checked = obj[ property ]; - - this.addListener( cb, 'change', _checkboxChanged ); - - Page.controls[ property ] = cb; - - label.appendChild( cb ); - - this.page.appendChild( label ); - - return label; - - function _checkboxChanged ( event ) { - - Page.inHandler = true; - - obj[ property ] = event.target.checked; - - Page.inHandler = false; - - } - -}; - -Page.prototype.addRange = function ( title, obj, property ) { - - var div = document.createElement( 'div' ); - var label = document.createElement( 'label' ); - var range = document.createElement( 'input' ); - - div.classList.add( 'control' ); - - range.type = 'range'; - - range.min = 0; - range.max = 1; - - range.step = 0.05; - range.value = obj[ property ]; - - this.addListener( range, 'input', _rangeChanged ); - this.addListener( range, 'change', _rangeChanged ); // for IE11 support - - label.textContent = title; - - Page.controls[ property ] = range; - - div.appendChild( label ); - div.appendChild( range ); - - this.page.appendChild( div ); - - return div; - - function _rangeChanged ( event ) { - - Page.inHandler = true; - - obj[ property ] = event.target.value; - - Page.inHandler = false; - - } - -}; - -Page.prototype.addSlide = function ( domElement, depth, handleClick ) { - - var slide = document.createElement( 'div' ); - - slide.classList.add( 'slide' ); - slide.style.zIndex = 200 - depth; - - slide.addEventListener( 'click', handleClick ); - slide.appendChild( domElement ); - - this.page.appendChild( slide ); - - this.slide = slide; - this.slideDepth = depth; - - return slide; - -}; - -Page.prototype.replaceSlide = function ( domElement, depth, handleClick ) { - - var newSlide = document.createElement( 'div' ); - var oldSlide = this.slide; - var page = this.page; - var redraw; // eslint-disable-line no-unused-vars - - newSlide.classList.add( 'slide' ); - newSlide.style.zIndex = 200 - depth; - newSlide.addEventListener( 'click', handleClick ); - - if ( depth < this.slideDepth ) { - - newSlide.classList.add( 'slide-out' ); - - } - - newSlide.appendChild( domElement ); - - page.appendChild( newSlide ); - - if ( depth > this.slideDepth ) { - - oldSlide.addEventListener( 'transitionend', afterSlideOut ); - oldSlide.classList.add( 'slide-out' ); - - redraw = oldSlide.clientHeight; - - } else if ( depth < this.slideDepth ) { - - newSlide.addEventListener( 'transitionend', afterSlideIn ); - - redraw = newSlide.clientHeight; - - newSlide.classList.remove( 'slide-out' ); - - } else { - - page.removeChild( oldSlide ); - - } - - this.slide = newSlide; - this.slideDepth = depth; - - return; - - function afterSlideOut () { - - oldSlide.removeEventListener( 'transitionend', afterSlideOut ); - page.removeChild( oldSlide ); - - } - - function afterSlideIn () { - - page.removeChild( oldSlide ); - newSlide.removeEventListener( 'transitionend', afterSlideIn ); - - } - -}; - -Page.prototype.addButton = function ( title, func ) { - - var button = document.createElement( 'button' ); - - button.type = 'button'; - button.textContent = title; - - this.addListener( button, 'click', func ); - - this.page.appendChild( button ); - - return button; - -}; - - -Page.prototype.addTextBox = function ( labelText, placeholder, getResultGetter ) { - - var div = document.createElement( 'div' ); - var label = document.createElement( 'label' ); - - label.textContent = labelText; - - var input = document.createElement( 'input' ); - var value; - - input.type = 'text'; - - input.placeholder = placeholder; - - div.appendChild( label ); - div.appendChild( input ); - - this.page.appendChild( div ); - - this.addListener( input, 'change', function ( e ) { value = e.target.value; return true; } ) ; - - getResultGetter( _result ); - - return div; - - function _result() { - - input.value = ''; - return value; - - } - -}; - -Page.prototype.addDownloadButton = function ( title, urlProvider, fileName ) { - - var a = document.createElement( 'a' ); - - if ( typeof a.download === 'undefined' ) return null; - - this.addListener( a, 'click', _setHref ); - - a.textContent = title; - a.type = 'download'; - a.download = fileName; - a.href = 'javascript:void();'; - - a.classList.add( 'download' ); - - this.page.appendChild( a ); - - return a; - - function _setHref() { - - a.href = urlProvider(); - - } - -}; - - - -// EOF - -function ProgressBar ( container ) { - - var offset = ( container.clientWidth - 300 ) / 2; - - var statusText = document.createElement( 'div' ); - - statusText.id = 'status-text'; - statusText.style.width = '300px'; - statusText.style.left = offset + 'px'; - - var progressBar = document.createElement( 'progress' ); - - progressBar.id = 'progress-bar'; - - progressBar.style.width = '300px'; - progressBar.style.left = offset + 'px'; - - progressBar.setAttribute( 'max', '100' ); - - this.container = container; - this.progressBar = progressBar; - this.statusText = statusText; - -} - -ProgressBar.prototype.constructor = ProgressBar; - -ProgressBar.prototype.Start = function ( text ) { - - var statusText = this.statusText; - var progressBar = this.progressBar; - - statusText.textContent = text; - progressBar.value = 0; - - this.container.appendChild( statusText ); - this.container.appendChild( progressBar ); - -}; - -ProgressBar.prototype.Update = function ( pcent ) { - - this.progressBar.value = pcent; - -}; - -ProgressBar.prototype.Add = function ( pcent ) { - - this.progressBar.value += pcent; - -}; - -ProgressBar.prototype.End = function () { - - var container = this.container; - - container.removeChild( this.statusText ); - container.removeChild( this.progressBar ); - -}; - - - -// EOF - -// Survex 3d file handler - -function Svx3dHandler ( fileName ) { - - this.fileName = fileName; - this.groups = []; - this.surface = []; - this.xGroups = []; - this.surveyTree = new Tree(); - this.sourceCRS = null; - this.targetCRS = 'EPSG:3857'; // "web mercator" - this.projection = null; - -} - -Svx3dHandler.prototype.constructor = Svx3dHandler; - -Svx3dHandler.prototype.type = 'arraybuffer'; -Svx3dHandler.prototype.isRegion = 'false'; - -Svx3dHandler.prototype.parse = function ( dataStream, metadata ) { - - this.metadata = metadata; - - var source = dataStream; // file data as arrrayBuffer - var pos = 0; // file position - - // read file header - - readLF(); // Survex 3D Image File - var version = readLF(); // 3d version - var auxInfo = readNSLF(); - readLF(); // Date - - var sourceCRS = ( auxInfo[ 1 ] === undefined ) ? null : auxInfo[ 1 ]; // coordinate reference system ( proj4 format ) - - if ( sourceCRS !== null ) { - - // work around lack of +init string support in proj4js - - var matches = sourceCRS.match( /\+init=(.*)\s/); - - if ( matches && matches.length === 2 ) { - - switch( matches[ 1 ] ) { - - case 'epsg:27700' : - - sourceCRS = '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs'; - - break; - - default: - - sourceCRS = null; - console.warn( 'unsupported projection' ); - - } - - } - - } - - // FIXME use NAD grid corrections OSTM15 etc ( UK Centric ) - - if ( sourceCRS !== null ) { - - console.log( 'Reprojecting from', sourceCRS, 'to', this.targetCRS ); - - this.sourceCRS = sourceCRS; - this.projection = proj4( this.sourceCRS, this.targetCRS ); // eslint-disable-line no-undef - - } - - console.log( 'Survex .3d version ', version ); - - switch ( version ) { - - case 'Bv0.01': - - this.handleOld( source, pos, 1 ); - - break; - - case 'v3': - case 'v4': - case 'v5': - case 'v6': - case 'v7': - case 'v8': - - this.handleVx( source, pos, Number( version.charAt( 1 ) ) ); - - break; - - default: - - alert( 'unknown .3d version ' + version ); - - } - - return this; - - function readLF () { // read until Line feed - - return readNSLF()[ 0 ]; - - } - - function readNSLF () { // read until Line feed and split by null bytes - - var bytes = new Uint8Array( source, 0 ); - - var lfString = []; - var b; - var strings = []; - - do { - - b = bytes[ pos++ ]; - - if ( b === 0x0a || b === 0 ) { - - strings.push( String.fromCharCode.apply( null, lfString ).trim() ); - lfString = []; - - } else { - - lfString.push( b ); - - } - - } while ( b != 0x0a ); - - return strings; - - } - -}; - -Svx3dHandler.prototype.handleOld = function ( source, pos, version ) { - - var groups = this.groups; - var surveyTree = this.surveyTree; - - var self = this; - - var cmd = []; - var legs = []; - var label = ''; - var stations = new Map(); - var sectionId = 0; - - var data = new Uint8Array( source, 0 ); - var dataLength = data.length; - var lastPosition = { x: 0, y:0, z: 0 }; // value to allow approach vector for xsect coord frame - var i, j, li, lj; - - var dataView = new DataView( source, 0 ); - - // selected correct read coordinates function - - var readCoordinates = ( this.projection === null ) ? __readCoordinates : __readCoordinatesProjected; - - // range - - var min = { x: Infinity, y: Infinity, z: Infinity }; - var max = { x: -Infinity, y: -Infinity, z: -Infinity }; - - // init cmd handler table withh error handler for unsupported records or invalid records - - function _errorHandler ( e ) { console.warn( 'unhandled command: ', e.toString( 16 ) ); return false; } - - for ( i = 0; i < 256; i++ ) { - - cmd[ i ] = _errorHandler; - - } - - cmd[ 0x00 ] = cmd_STOP; - cmd[ -1 ] = cmd_STOP; - - cmd[ 0x01 ] = cmd_SKIP; - - cmd[ 0x02 ] = cmd_LABEL_V1; // version numbers not related to Survex versions - cmd[ 0x03 ] = cmd_LABEL_V1; - - cmd[ 0x04 ] = cmd_MOVE; - cmd[ 0x05 ] = cmd_LINE_V1; - - cmd[ 0x06 ] = cmd_LABEL_V2; - cmd[ 0x07 ] = cmd_LABEL_V3; - - for ( i = 0x40; i < 0x80; i++ ) { - - cmd[ i ] = cmd_LABEL_V4; - - } - - for ( i = 0x80; i < 0x100; i++ ) { - - cmd[ i ] = cmd_LINE_V2; - - } - - // dispatch table end - - // common record iterator - // loop though data, handling record types as required. - - if ( version === 1 ) { - - while ( pos < dataLength ) { - - var cmdCode = dataView.getInt32( pos, true ); - pos += 4; - - if ( ! cmd[ cmdCode ]() ) break; - - } - - } else { - - alert( 'Unsupported version' + version ); - - while ( pos < dataLength ) { - - if ( ! cmd[ data[ pos ] ]( data[ pos++ ] ) ) break; - - } - - } - - groups.push( legs ); - - // assign survey ids to all leg vertices by looking up tree node for coords - var group, leg, coords, node; - - for ( i = 0, li = groups.length; i < li; i++ ) { - - group = groups[ i ]; - - for ( j = 0, lj = group.length; j < lj; j++ ) { - - leg = group[ j ]; - coords = leg.coords; - - node = stations.get( coords.x + ':' + coords.y + ':' + coords.z ); - - if ( node === undefined ) continue; - - leg.survey = node.parent.id; - - } - - } - - var offsets = { - x: ( min.x + max.x ) / 2, - y: ( min.y + max.y ) / 2, - z: ( min.z + max.z ) / 2 - }; - - surveyTree.traverse( adjustCoords ); - - this.offsets = offsets; - - this.limits = { - min: min, - max: max - }; - - return; - - function adjustCoords( node ) { - - var coords = node.p; - - if ( coords === undefined ) return; - - coords.x -= offsets.x; - coords.y -= offsets.y; - coords.z -= offsets.z; - - } - - - function cmd_STOP ( /* c */ ) { - - return true; - - } - - function cmd_SKIP ( /* c */ ) { - - console.log( 'SKIP' ); - return false; - - } - - function cmd_LABEL_V1 ( /* c */ ) { - - var db = []; - - var nextByte = data[ pos++ ]; - - while ( nextByte !== 10 ) { - - db.push( nextByte ); - nextByte = data[ pos++ ]; - - } - - if ( db[ 0 ] === 92 ) db.shift(); // remove initial '/' characters - - label = String.fromCharCode.apply( null, db ); -// console.log( 'NODE', label, lastPosition ); - - var node = surveyTree.addPath( label.split( '.' ), { p: lastPosition, type: STATION_NORMAL } ); - - // track coords to sectionId to allow survey ID's to be added to leg vertices - stations.set( lastPosition.x + ':' + lastPosition.y + ':' + lastPosition.z, node ); - - return true; - - } - - function cmd_LABEL_V2 ( /* c */ ) { - - console.log( 'LABEL_V2' ); - return false; - - } - - function cmd_LABEL_V3 ( /* c */ ) { - - console.log( 'LABEL_V3' ); - return false; - - } - function cmd_LABEL_V4 ( /* c */ ) { - - console.log( 'LABEL_V4' ); - return false; - - } - - function cmd_MOVE ( /* c */ ) { - - var coords = readCoordinates(); - - - lastPosition = coords; - - if ( version === 1 && dataView.getInt32( pos, true ) === 2 ) { - - // version 1 uses MOVE+LABEL pairs to label stations - return true; - - } - -// console.log( 'MOVE', coords ); - - if ( legs.length > 1 ) groups.push( legs ); - - legs = []; - - legs.push( { coords: coords } ); - - return true; - - } - - function cmd_LINE_V1 ( /* c */ ) { - - var coords = readCoordinates(); - - legs.push( { coords: coords, type: LEG_CAVE, survey: sectionId } ); - - lastPosition = coords; - -// console.log( 'LINE_V1', coords ); - - return true; - - } - - function cmd_LINE_V2 ( /* c */ ) { - - console.log( 'LINE_V2' ); - return false; - - } - - // functions aliased at runtime as required - - function __readCoordinatesProjected () { - - var l = new DataView( source, pos ); - - var projectedCoords = self.projection.forward( { - x: l.getInt32( 0, true ) / 100, - y: l.getInt32( 4, true ) / 100 - } ); - - var coords = { - x: projectedCoords.x, - y: projectedCoords.y, - z: l.getInt32( 8, true ) / 100 - }; - - min.x = Math.min( coords.x, min.x ); - min.y = Math.min( coords.y, min.y ); - min.z = Math.min( coords.z, min.z ); - - max.x = Math.max( coords.x, max.x ); - max.y = Math.max( coords.y, max.y ); - max.z = Math.max( coords.z, max.z ); - - pos += 12; - - return coords; - - } - - function __readCoordinates () { - - var l = new DataView( source, pos ); - - var coords = { - x: l.getInt32( 0, true ) / 100, - y: l.getInt32( 4, true ) / 100, - z: l.getInt32( 8, true ) / 100 - }; - - min.x = Math.min( coords.x, min.x ); - min.y = Math.min( coords.y, min.y ); - min.z = Math.min( coords.z, min.z ); - - max.x = Math.max( coords.x, max.x ); - max.y = Math.max( coords.y, max.y ); - max.z = Math.max( coords.z, max.z ); - - pos += 12; - - return coords; - - } - -}; - -Svx3dHandler.prototype.handleVx = function ( source, pos, version ) { - - var groups = this.groups; - var xGroups = this.xGroups; - var surveyTree = this.surveyTree; - - var self = this; - - var cmd = []; - var legs = []; - var label = ''; - var stations = new Map(); - var lineEnds = new Set(); // implied line ends to fixnup xsects - var xSects = []; - var sectionId = 0; - var sectionLabels = new Set(); - - var data = new Uint8Array( source, 0 ); - var dataLength = data.length; - var lastPosition = { x: 0, y:0, z: 0 }; // value to allow approach vector for xsect coord frame - var i; - var labelChanged = false; - - // functions - - var readLabel; - - // selected correct read coordinates function - - var readCoordinates = ( this.projection === null ) ? __readCoordinates : __readCoordinatesProjected; - - // range - - var min = { x: Infinity, y: Infinity, z: Infinity }; - var max = { x: -Infinity, y: -Infinity, z: -Infinity }; - - // init cmd handler table withh error handler for unsupported records or invalid records - - function _errorHandler ( e ) { console.warn( 'unhandled command: ', e.toString( 16 ) ); return false; } - - for ( i = 0; i < 256; i++ ) { - - cmd[ i ] = _errorHandler; - - } - - if ( version === 8 ) { - // v8 dispatch table start - - cmd[ 0x00 ] = cmd_STYLE; - cmd[ 0x01 ] = cmd_STYLE; - cmd[ 0x02 ] = cmd_STYLE; - cmd[ 0x03 ] = cmd_STYLE; - cmd[ 0x04 ] = cmd_STYLE; - - cmd[ 0x0f ] = cmd_MOVE; - cmd[ 0x10 ] = cmd_DATE_NODATE; - cmd[ 0x11 ] = cmd_DATEV8_1; - cmd[ 0x12 ] = cmd_DATEV8_2; - cmd[ 0x13 ] = cmd_DATEV8_3; - - cmd[ 0x1F ] = cmd_ERROR; - - cmd[ 0x30 ] = cmd_XSECT16; - cmd[ 0x31 ] = cmd_XSECT16; - - cmd[ 0x32 ] = cmd_XSECT32; - cmd[ 0x33 ] = cmd_XSECT32; - - for ( i = 0x40; i < 0x80; i++ ) { - - cmd[ i ] = cmd_LINE; - - } - - for ( i = 0x80; i < 0x100; i++ ) { - - cmd[ i ] = cmd_LABEL; - - } - - // dispatch table end - - readLabel = readLabelV8; - - // skip v8 file wide flags after header - pos++; - - } else { - - // dispatch table for v7 format - - for ( i = 0x01; i < 0x0f; i++ ) { - - cmd[ i ] = cmd_TRIM_PLUS; - - } - - cmd[ 0x0f ] = cmd_MOVE; - - for ( i = 0x10; i < 0x20; i++ ) { - - cmd[ i ] = cmd_TRIM; - - } - - cmd[ 0x00 ] = cmd_STOP; - cmd[ 0x20 ] = cmd_DATE_V7; - cmd[ 0x21 ] = cmd_DATE2_V7; - cmd[ 0x23 ] = cmd_DATE3_V7; - cmd[ 0x24 ] = cmd_DATE_NODATE; - cmd[ 0x22 ] = cmd_ERROR; - - cmd[ 0x30 ] = cmd_XSECT16; - cmd[ 0x31 ] = cmd_XSECT16; - - cmd[ 0x32 ] = cmd_XSECT32; - cmd[ 0x33 ] = cmd_XSECT32; - - for ( i = 0x40; i < 0x80; i++ ) { - - cmd[ i ] = cmd_LABEL; - - } - - for ( i = 0x80; i < 0xc0; i++ ) { - - cmd[ i ] = cmd_LINE; - - } - // dispatch table end - - readLabel = readLabelV7; - - } - - if ( version === 6 ) { - - cmd[ 0x20 ] = cmd_DATE_V4; - cmd[ 0x21 ] = cmd_DATE2_V4; - - } - - // common record iterator - // loop though data, handling record types as required. - - while ( pos < dataLength ) { - - if ( ! cmd[ data[ pos ] ]( data[ pos++ ] ) ) break; - - } - - if ( xSects.length > 1 ) { - - xGroups.push( xSects ); - - } - - groups.push( legs ); - - var offsets = { - x: ( min.x + max.x ) / 2, - y: ( min.y + max.y ) / 2, - z: ( min.z + max.z ) / 2 - }; - - surveyTree.traverse( adjustCoords ); - - this.offsets = offsets; - - this.limits = { - min: min, - max: max - }; - - return; - - function adjustCoords( node ) { - - var coords = node.p; - - if ( coords === undefined ) return; - - coords.x -= offsets.x; - coords.y -= offsets.y; - coords.z -= offsets.z; - - } - - function readLabelV7 () { - // find length of label and read label = v3 - v7 .3d format - - var len = 0; - var l; - - switch ( data[ pos ] ) { - - case 0xfe: - - l = new DataView( source, pos ); - - len = l.getUint16( 0, true ) + data[ pos ]; - pos += 2; - - break; - - case 0xff: - - l = new DataView( source, pos ); - - len = l.getUint32( 0, true ); - pos += 4; - - break; - - default: - - len = data[ pos++ ]; - - } - - if ( len === 0 ) return; - - var db = []; - - for ( var i = 0; i < len; i++ ) { - - db.push( data[ pos++ ] ); - - } - - label += String.fromCharCode.apply( null, db ); - labelChanged = true; - - return; - - } - - function readLabelV8 ( flags ) { - - if ( flags & 0x20 ) return false; // no label change - - var b = data[ pos++ ]; - var add = 0; - var del = 0; - var l; - - if ( b !== 0 ) { - - // handle 4b= bit del/add codes - del = b >> 4; // left most 4 bits - add = b & 0x0f; // right most 4 bits - - } else { - - // handle 8 bit and 32 bit del/add codes - b = data[ pos++ ]; - - if ( b !== 0xff ) { - - del = b; - - } else { - - l = new DataView( source, pos ); - - del = l.getUint32( 0, true ); - pos += 4; - - } - - b = data[ pos++ ]; - - if ( b !== 0xff ) { - - add = b; - - } else { - - l = new DataView( source, pos ); - - add = l.getUint32( 0, true ); - pos += 4; - - } - } - - if ( add === 0 && del === 0 ) return; - - if ( del ) label = label.slice( 0, -del ); - - if ( add ) { - - var db = []; - - for ( var i = 0; i < add; i++ ) { - - db.push( data[ pos++ ] ); - - } - - label += String.fromCharCode.apply( null, db ); - - } - - labelChanged = true; - - return; - - } - - function cmd_STOP ( /* c */ ) { - - if ( label ) label = ''; - - return true; - - } - - function cmd_TRIM_PLUS ( c ) { // v7 and previous - - label = label.slice( 0, -16 ); - - if ( label.charAt( label.length - 1 ) === '.') label = label.slice( 0, -1 ); // strip trailing '.' - - var parts = label.split( '.' ); - - parts.splice( -( c ) ); - label = parts.join( '.' ); - - if ( label ) label += '.'; - labelChanged = true; - - return true; - - } - - function cmd_TRIM ( c ) { // v7 and previous - - var trim = c - 15; - - label = label.slice( 0, -trim ); - labelChanged = true; - - return true; - - } - - function cmd_DATE_V4 ( /* c */ ) { - - pos += 4; - - return true; - - } - - function cmd_DATE_V7 ( /* c */ ) { - - pos += 2; - - return true; - - } - - function cmd_DATE3_V7 ( /* c */ ) { - - pos += 4; - - return true; - - } - - function cmd_DATE2_V4 ( /* c */ ) { - - pos += 8; - - return true; - - } - - function cmd_DATE2_V7 ( /* c */ ) { - - pos += 3; - - return true; - - } - - function cmd_STYLE ( /* c */ ) { - - return true; - - } - - function cmd_DATEV8_1 ( /* c */ ) { - - pos += 2; - - return true; - - } - - function cmd_DATEV8_2 ( /* c */ ) { - - pos += 3; - - return true; - - } - - function cmd_DATEV8_3 ( /* c */ ) { - - pos += 4; - - return true; - } - - function cmd_DATE_NODATE ( /* c */ ) { - - return true; - - } - - function cmd_LINE ( c ) { - - var flags = c & 0x3f; - - readLabel( flags ); - - if ( labelChanged && label !== '' ) { - - // we have a new section name - - var path = label.split( '.' ); - - var partLabel = path[ 0 ]; - - // save valid survey station prefixes - - sectionLabels.add( partLabel ); - - for ( var i = 1, l = path.length; i < l; i++ ) { - - partLabel = partLabel + '.' + path[ i ]; - sectionLabels.add( partLabel ); - - } - - // add it to the survey tree - sectionId = surveyTree.addPath( path ).id; // consumes path - - labelChanged = false; - - } - - var coords = readCoordinates(); - - if ( flags & 0x01 ) { - - legs.push( { coords: coords, type: LEG_SURFACE, survey: sectionId } ); - - } else if ( flags & 0x04 ) { - - legs.push( { coords: coords, type: LEG_SPLAY, survey: sectionId } ); - - } else { - - legs.push( { coords: coords, type: LEG_CAVE, survey: sectionId } ); - - } - - lastPosition = coords; - - return true; - - } - - function cmd_MOVE ( /* c */ ) { - - // new set of line segments - if ( legs.length > 1 ) groups.push( legs ); - - legs = []; - - // heuristic to detect line ends. lastPosition was presumably set in a line sequence therefore is at the end - // of a line, Add the current label, presumably specified in the last LINE, to a Set of lineEnds. - - lineEnds.add( lastPosition.x + ':' + lastPosition.y + ':' + lastPosition.z ); - - var coords = readCoordinates(); - - legs.push( { coords: coords } ); - - lastPosition = coords; - - return true; - - } - - function cmd_ERROR ( /* c */ ) { - - /* - - var l = new DataView( source, pos ); - - var legs = l.getInt32( 0, true ); - var length = l.getInt32( 4, true ); - - var E = l.getInt32( 8, true ); - var H = l.getInt32( 12, true ); - var V = l.getInt32( 16, true ); - - */ - - pos += 20; - - return true; - - } - - function cmd_LABEL ( c ) { - - var flags = c & 0x7f; - - readLabel( 0 ); - - if ( ! ( flags & 0x0E ) || flags & 0x20 ) { // skip surface only stations - - pos += 12; //skip coordinates - return true; - - } - - var coords = readCoordinates(); - - var path = label.split( '.' ); - - var prefix = path.slice( 0, -1 ).join( '.' ); - - if ( path.length > 1 && ! sectionLabels.has( prefix ) ) { - - // handle station names containing separator character - - var i = 0; - var test = path[ i ]; - - while ( sectionLabels.has( test ) ) { - - test = test + '.' + path[ ++ i ]; - - } - - var last = path.slice( i ).join( '.' ); - - path = path.slice( 0, i ); - path.push( last ); - - } - - stations.set( label, coords ); - - surveyTree.addPath( path, { p: coords, type: ( flags & 0x04 ) ? STATION_ENTRANCE : STATION_NORMAL } ); - - return true; - - } - - function cmd_XSECT16 ( c ) { - - var flags = c & 0x01; - - readLabel( flags ); - - var l = new DataView( source, pos ); - - pos += 8; - - return commonXSECT( - flags, - { - l: l.getInt16( 0, true ) / 100, - r: l.getInt16( 2, true ) / 100, - u: l.getInt16( 4, true ) / 100, - d: l.getInt16( 6, true ) / 100 - } - ); - - } - - function cmd_XSECT32 ( c ) { - - var flags = c & 0x01; - - readLabel( flags ); - - var l = new DataView( source, pos ); - - pos += 16; - - return commonXSECT( - flags, - { - l: l.getInt32( 0, true ) / 100, - r: l.getInt32( 0, true ) / 100, - u: l.getInt32( 0, true ) / 100, - d: l.getInt32( 0, true ) / 100 - } - ); - - } - - function commonXSECT ( flags, lrud ) { - - var position = stations.get( label ); - - if ( ! position ) return; - - var station = label.split( '.' ); - - // get survey path by removing last component of station name - station.pop(); - - var surveyId = surveyTree.getIdByPath( station ); - - // FIXME to get a approach vector for the first XSECT in a run so we can add it to the display - xSects.push( { start: lastPosition, end: position, lrud: lrud, survey: surveyId } ); - - lastPosition = position; - - // some XSECTS are not flagged as last in passage - // heuristic - the last line position before a move is an implied line end. - // cmd_MOVE saves these in the set lineEnds. - // this fixes up surveys that display incorrectly withg 'fly-back' artefacts in Aven and Loch. - - var endRun = false; - - if ( flags ) { - - endRun = true; - - } else if ( lineEnds.has( [ position.x, position.y, position.z ].toString() ) ) { - - endRun = true; -// console.warn( 'unterminated LRUD passage at ', label ); - - } - - if ( endRun ) { - - if ( xSects.length > 0 ) xGroups.push( xSects ); - - lastPosition = { x: 0, y: 0, z: 0 }; - xSects = []; - - } - - return true; - - } - - // functions aliased at runtime as required - - function __readCoordinatesProjected () { - - var l = new DataView( source, pos ); - - var projectedCoords = self.projection.forward( { - x: l.getInt32( 0, true ) / 100, - y: l.getInt32( 4, true ) / 100 - } ); - - var coords = { - x: projectedCoords.x, - y: projectedCoords.y, - z: l.getInt32( 8, true ) / 100 - }; - - min.x = Math.min( coords.x, min.x ); - min.y = Math.min( coords.y, min.y ); - min.z = Math.min( coords.z, min.z ); - - max.x = Math.max( coords.x, max.x ); - max.y = Math.max( coords.y, max.y ); - max.z = Math.max( coords.z, max.z ); - - pos += 12; - - return coords; - - } - - function __readCoordinates () { - - var l = new DataView( source, pos ); - - var coords = { - x: l.getInt32( 0, true ) / 100, - y: l.getInt32( 4, true ) / 100, - z: l.getInt32( 8, true ) / 100 - }; - - min.x = Math.min( coords.x, min.x ); - min.y = Math.min( coords.y, min.y ); - min.z = Math.min( coords.z, min.z ); - - max.x = Math.max( coords.x, max.x ); - max.y = Math.max( coords.y, max.y ); - max.z = Math.max( coords.z, max.z ); - - pos += 12; - - return coords; - - } - -}; - -Svx3dHandler.prototype.getLineSegments = function () { - - var lineSegments = []; - var groups = this.groups; - var offsets = this.offsets; - - for ( var i = 0, l = groups.length; i < l; i++ ) { - - var g = groups[ i ]; - - for ( var v = 0, vMax = g.length - 1; v < vMax; v++ ) { - - // create vertex pairs for each line segment. - // all vertices except first and last are duplicated. - var from = g[ v ]; - var to = g[ v + 1 ]; - - - // move coordinates around origin - - from.coords.x -= offsets.x; - from.coords.y -= offsets.y; - from.coords.z -= offsets.z; - - var fromCoords = from.coords; - var toCoords = to.coords; - - // skip repeated points ( co-located stations ) - if ( fromCoords.x === toCoords.x && fromCoords.y === toCoords.y && fromCoords.z === toCoords.z ) continue; - - lineSegments.push( { from: fromCoords, to: toCoords, type: to.type, survey: to.survey } ); - - } - - // move coordinates around origin - - to.coords.x -= offsets.x; - to.coords.y -= offsets.y; - to.coords.z -= offsets.z; - - } - - return lineSegments; - -}; - -Svx3dHandler.prototype.getTerrainDimensions = function () { - - return { lines: 0, samples: 0 }; - -}; - -Svx3dHandler.prototype.getTerrainBitmap = function () { - - return false; - -}; - -Svx3dHandler.prototype.getSurvey = function () { - - return { - title: this.fileName, - surveyTree: this.surveyTree, - sourceCRS: this.sourceCRS, - targetCRS: this.targetCRS, - limits: this.limits, - offsets: this.offsets, - lineSegments: this.getLineSegments(), - crossSections: this.xGroups, - scraps: [], - hasTerrain: false, - metadata: this.metadata - }; - -}; - - - -// EOF - -function loxHandler ( fileName ) { - - this.fileName = fileName; - this.scraps = []; - this.faults = []; - this.lineSegments = []; - this.xGroups = []; - this.surveyTree = new Tree( '', 0 ); - this.terrain = {}; - this.hasTerrain = false; - -} - -loxHandler.prototype.constructor = loxHandler; - -loxHandler.prototype.type = 'arraybuffer'; -loxHandler.prototype.isRegion = 'false'; - -loxHandler.prototype.parse = function( dataStream, metadata ) { - - this.metadata = metadata; - - var lineSegments = []; - var stations = []; - var self = this; - var surveyTree = this.surveyTree; - - // assumes little endian data ATM - FIXME - - var source = dataStream; - var pos = 0; // file position - var dataStart; - var f = new DataView( source, 0 ); - var l = source.byteLength; - - var xGroup = []; - var lastTo; - - // range - - var min = { x: Infinity, y: Infinity, z: Infinity }; - var max = { x: -Infinity, y: -Infinity, z: -Infinity }; - - while ( pos < l ) readChunkHdr(); - - this.lineSegments = lineSegments; - - // Drop data to give GC a chance ASAP - source = null; - - this.limits = { - min: min, - max: max - }; - - var offsets = { - x: ( min.x + max.x ) / 2, - y: ( min.y + max.y ) / 2, - z: ( min.z + max.z ) / 2 - }; - - this.offsets = offsets; - - // convert to origin centered coordinates - - var i, j, coords, vertices; - - for ( i = 0; i < stations.length; i++ ) { - - coords = stations[ i ]; - - coords.x -= offsets.x; - coords.y -= offsets.y; - coords.z -= offsets.z; - - } - - var scraps = this.scraps; - - // covert scraps coordinates - - for ( i = 0; i < scraps.length; i++ ) { - - vertices = scraps[ i ].vertices; - - for ( j = 0; j < vertices.length; j++ ) { - - coords = vertices[ j ]; - - coords.x -= offsets.x; - coords.y -= offsets.y; - coords.z -= offsets.z; - - } - - } - - return this; - - // .lox parsing functions - - function readChunkHdr () { - - var m_type = readUint(); - var m_recSize = readUint(); - var m_recCount = readUint(); - var m_dataSize = readUint(); - var doFunction; - - // offset of data region for out of line strings/images/scrap data. - dataStart = pos + m_recSize; - - switch ( m_type ) { - - case 1: - - doFunction = readSurvey; - - break; - - case 2: - - doFunction = readStation; - - break; - - case 3: - - doFunction = readShot; - - break; - - case 4: - - doFunction = readScrap; - - break; - - case 5: - - doFunction = readSurface; - - break; - - case 6: - - doFunction = readSurfaceBMP; - - break; - - default: - - console.warn( 'unknown chunk header. type : ', m_type ); - - } - - if ( doFunction !== undefined ) { - - for ( var i = 0; i < m_recCount; i++ ) { - - doFunction(); - - } - - } - - skipData( m_dataSize ); - - } - - function readUint () { - - var i = f.getUint32( pos, true ); - - pos += 4; - - return i; - - } - - function skipData ( i ) { - - pos += i; - - } - - function readSurvey () { - - var m_id = readUint(); - var namePtr = readDataPtr(); - var m_parent = readUint(); - var titlePtr = readDataPtr(); - - if ( m_parent != m_id ) { - - if ( ! surveyTree.addById( readString( namePtr ), m_id, m_parent ) ) console.warn( 'error constructing survey tree for', readString( titlePtr ) ); - - } - - } - - function readDataPtr () { - - var m_position = readUint(); - var m_size = readUint(); - - return { position: m_position, size: m_size }; - - } - - function readString ( ptr ) { - - // strings are null terminated. Igore last byte in string - var bytes = new Uint8Array( source, dataStart + ptr.position, ptr.size - 1 ); - - return String.fromCharCode.apply( null, bytes ); - - } - - function readStation () { - - var m_id = readUint(); - var m_surveyId = readUint(); - var namePtr = readDataPtr(); - - readDataPtr(); // commentPtr - - var m_flags = readUint(); - var coords = readCoords(); - - stations[ m_id ] = coords; - - // add stations to surveyTree make station id negative to avoid clashes with survey id space. - - // m_flags & 0x01 = surface - - surveyTree.addById( readString( namePtr ), - m_id, m_surveyId, { p: coords, type: ( m_flags & 0x02 ) ? STATION_ENTRANCE : STATION_NORMAL } ); - - } - - function readCoords () { - - var f = new DataView( source, pos ); - - pos += 24; - - coords = { - x: f.getFloat64( 0, true ), - y: f.getFloat64( 8, true ), - z: f.getFloat64( 16, true ) - }; - - min.x = Math.min( coords.x, min.x ); - min.y = Math.min( coords.y, min.y ); - min.z = Math.min( coords.z, min.z ); - - max.x = Math.max( coords.x, max.x ); - max.y = Math.max( coords.y, max.y ); - max.z = Math.max( coords.z, max.z ); - - return coords; - - } - - function readShot () { - - var m_from = readUint(); - var m_to = readUint(); - - var fromLRUD = readLRUD(); - var toLRUD = readLRUD(); - - var m_flags = readUint(); - - var m_sectionType = readUint(); - - var m_surveyId = readUint(); - - f.getFloat64( pos, true ); // m_threshold - - var type = LEG_CAVE; - - pos += 8; - - if ( m_flags & 0x01 ) type = LEG_SURFACE; - if ( m_flags & 0x08 ) type = LEG_SPLAY; - - var from = stations[ m_from ]; - var to = stations[ m_to ]; - - if ( m_sectionType !== 0x00 ) { - - if ( m_from !== lastTo ) { - - // new set of shots - - xGroup = []; - self.xGroups.push( xGroup ); - - xGroup.push( { start: to, end: from, lrud: fromLRUD, survey: m_surveyId } ); - - } - - xGroup.push( { start: from, end: to, lrud: toLRUD, survey: m_surveyId } ); - - } - - if ( from.x === to.x && from.y === to.y && from.z === to.z ) return; - - lineSegments.push( { from: from, to: to, type: type, survey: m_surveyId } ); - - lastTo = m_to; - - } - - function readLRUD () { - - var f = new DataView( source, pos ); - - pos += 32; - - return { - l: f.getFloat64( 0, true ), - r: f.getFloat64( 8, true ), - u: f.getFloat64( 16, true ), - d: f.getFloat64( 24, true ) - }; - - } - - function readScrap () { - - readUint(); // m_id - - var m_surveyId = readUint(); - - var m_numPoints = readUint(); - var pointsPtr = readDataPtr(); - - var m_num3Angles = readUint(); - var facesPtr = readDataPtr(); - - var scrap = { vertices: [], faces: [], survey: m_surveyId }; - var lastFace; - var i, offset, f; - - for ( i = 0; i < m_numPoints; i++ ) { - - offset = dataStart + pointsPtr.position + i * 24; // 24 = 3 * sizeof( double ) - f = new DataView( source, offset ); - - scrap.vertices.push( { - x: f.getFloat64( 0, true ), - y: f.getFloat64( 8, true ), - z: f.getFloat64( 16, true ) - } ); - - } - - // read faces from out of line data area - - for ( i = 0; i < m_num3Angles; i++ ) { - - offset = dataStart + facesPtr.position + i * 12; // 12 = 3 * sizeof( uint32 ) - f = new DataView( source, offset ); - - var face = [ - f.getUint32( 0, true ), - f.getUint32( 4, true ), - f.getUint32( 8, true ) - ]; - - // check for face winding order == orientation - - fix_direction: { if ( lastFace !== undefined ) { - - var j; - - for ( j = 0; j < 3; j++ ) { // this case triggers more often than those below. - - if ( face[ j ] == lastFace[ ( j + 2 ) % 3 ] && face[ ( j + 1 ) % 3 ] == lastFace[ ( j + 3 ) % 3 ] ) { - - face.reverse(); - break fix_direction; - - } - - } - - for ( j = 0; j < 3; j++ ) { - - if ( face[ j ] == lastFace[ j ] && face[ ( j + 1 ) % 3 ] == lastFace[ ( j + 1 ) % 3 ] ) { - - face.reverse(); - break fix_direction; - - } - - } - - for ( j = 0; j < 3; j++ ) { - - if ( face[ j ] == lastFace[ ( j + 1 ) % 3 ] && face[ ( j + 1 ) % 3 ] == lastFace[ ( j + 2 ) % 3 ] ) { - - face.reverse(); - break fix_direction; - - } - - } - - } } - - scrap.faces.push( face ); - lastFace = face; - - } - - self.scraps.push( scrap ); - - } - - function readSurface () { - - readUint(); // m_id - - var m_width = readUint(); - var m_height = readUint(); - - var surfacePtr = readDataPtr(); - var m_calib = readCalibration(); - - var ab = source.slice( pos, pos + surfacePtr.size ); // required for 64b alignment - - var dtm = new Float64Array( ab, 0 ); - - // flip y direction - - var data = []; - - for ( var i = 0; i < m_height; i++ ) { - - var offset = ( m_height - 1 - i ) * m_width; - - for ( var j = 0; j < m_width; j++ ) { - - data.push( dtm[ offset + j ] ); - - } - - } - - var terrain = self.terrain; - - terrain.dtm = { - data: data, - samples: m_width, - lines: m_height, - xOrigin: m_calib[ 0 ], - yOrigin: m_calib[ 1 ], - xx: m_calib[ 2 ], - xy: m_calib[ 3 ], - yx: m_calib[ 4 ], - yy: m_calib[ 5 ] - }; - - self.hasTerrain = true; - - } - - function readCalibration () { - - var f = new DataView( source, pos ); - var m_calib = []; - - m_calib[ 0 ] = f.getFloat64( 0, true ); // x origin - m_calib[ 1 ] = f.getFloat64( 8, true ); // y origin - m_calib[ 2 ] = f.getFloat64( 16, true ); // xx ( 2 x 2 ) rotate and scale matrix - m_calib[ 3 ] = f.getFloat64( 24, true ); // xy " - m_calib[ 4 ] = f.getFloat64( 32, true ); // yx " - m_calib[ 5 ] = f.getFloat64( 40, true ); // yy " - - pos += 48; - - return m_calib; - - } - - function readSurfaceBMP () { - - readUint(); // m_type - readUint(); // m_surfaceId - - var imagePtr = readDataPtr(); - - var m_calib = readCalibration(); - - self.terrain.bitmap = { - image: extractImage( imagePtr ), - xOrigin: m_calib[ 0 ], - yOrigin: m_calib[ 1 ], - xx: m_calib[ 2 ], - xy: m_calib[ 3 ], - yx: m_calib[ 4 ], - yy: m_calib[ 5 ] - }; - - } - - function extractImage ( imagePtr ) { - - var imgData = new Uint8Array( source, dataStart + imagePtr.position, imagePtr.size ); - var type; - - var b1 = imgData[ 0 ]; - var b2 = imgData[ 1 ]; - - if ( b1 === 0xff && b2 === 0xd8 ) { - - type = 'image/jpeg'; - - } else if ( b1 === 0x89 && b2 === 0x50 ) { - - type = 'image/png'; - - } - - if ( ! type ) return ''; - - var blob = new Blob( [ imgData ], { type: type } ); - var blobURL = URL.createObjectURL( blob ); - - return blobURL; - - } - -}; - -loxHandler.prototype.getSurvey = function () { - - return { - title: this.fileName, - surveyTree: this.surveyTree, - sourceCRS: null, - targetCRS: null, - lineSegments: this.lineSegments, - crossSections: this.xGroups, - scraps: this.scraps, - hasTerrain: this.hasTerrain, - metadata: this.metadata, - terrain: this.terrain, - limits: this.limits, - offsets: this.offsets - }; - -}; - - - -// EOF - -// Survex kml file handler - -//import { LEG_CAVE, LEG_SPLAY, LEG_SURFACE, STATION_NORMAL, STATION_ENTRANCE } from '../core/constants'; -function kmlHandler ( fileName ) { - - this.fileName = fileName; - this.groups = []; - this.surface = []; - this.xGroups = []; - this.surveyTree = new Tree(); - this.sourceCRS = null; - this.targetCRS = 'EPSG:3857'; // "web mercator" - this.projection = null; - -} - -kmlHandler.prototype.constructor = kmlHandler; - -kmlHandler.prototype.type = 'document'; -kmlHandler.prototype.isRegion = 'false'; -kmlHandler.prototype.mimeType = 'text/xml'; - -kmlHandler.prototype.parse = function ( dataStream, metadata ) { - - this.metadata = metadata; - - console.log( 'x', dataStream ); - for ( var n in dataStream ) { - - console.log( ':', n ); - - } - - return this; - -}; - - -kmlHandler.prototype.getLineSegments = function () { - - var lineSegments = []; - var groups = this.groups; - var offsets = this.offsets; - - for ( var i = 0, l = groups.length; i < l; i++ ) { - - var g = groups[ i ]; - - for ( var v = 0, vMax = g.length - 1; v < vMax; v++ ) { - - // create vertex pairs for each line segment. - // all vertices except first and last are duplicated. - var from = g[ v ]; - var to = g[ v + 1 ]; - - - // move coordinates around origin - - from.coords.x -= offsets.x; - from.coords.y -= offsets.y; - from.coords.z -= offsets.z; - - var fromCoords = from.coords; - var toCoords = to.coords; - - // skip repeated points ( co-located stations ) - if ( fromCoords.x === toCoords.x && fromCoords.y === toCoords.y && fromCoords.z === toCoords.z ) continue; - - lineSegments.push( { from: fromCoords, to: toCoords, type: to.type, survey: to.survey } ); - - } - - // move coordinates around origin - - to.coords.x -= offsets.x; - to.coords.y -= offsets.y; - to.coords.z -= offsets.z; - - } - - return lineSegments; - -}; - -kmlHandler.prototype.getTerrainDimensions = function () { - - return { lines: 0, samples: 0 }; - -}; - -kmlHandler.prototype.getTerrainBitmap = function () { - - return false; - -}; - -kmlHandler.prototype.getSurvey = function () { - - return { - title: this.fileName, - surveyTree: this.surveyTree, - sourceCRS: this.sourceCRS, - targetCRS: this.targetCRS, - limits: this.limits, - offsets: this.offsets, - lineSegments: this.getLineSegments(), - crossSections: this.xGroups, - scraps: [], - hasTerrain: false, - metadata: this.metadata - }; - -}; - - - -// EOF - -function RegionHandler ( filename ) { - - this.filename = filename; - this.box = new Box3(); - -} - -RegionHandler.prototype.constructor = RegionHandler; - -RegionHandler.prototype.type = 'json'; -RegionHandler.prototype.isRegion = 'true'; - -RegionHandler.prototype.parse = function ( dataStream ) { - - this.data = dataStream; - - var entrances = []; - var caves = this.data.caves; - var caveName; - - var min = this.box.min; - var max = this.box.max; - - for ( caveName in caves ) { - - var i; - var e = caves[ caveName ].entrances; - - for ( i = 0; i < e.length; i++ ) { - - var entrance = e[ i ]; - - min.min( entrance.position ); - max.max( entrance.position ); - - entrances.push( entrance ); - - } - - } - - this.data.entrances = entrances; - this.data.surveyTree = new Tree( this.data.title ); - -}; - -RegionHandler.prototype.getSurvey = function () { - - return this.data; - -}; - -RegionHandler.prototype.getLimits = function () { - - return this.box; - -}; - - - -// EOF - -function CaveLoader ( callback, progress ) { - - if ( ! callback ) { - - alert( 'No callback specified' ); - - } - - this.callback = callback; - this.progress = progress; - this.dataResponse = null; - this.metadataResponse = null; - this.taskCount = 0; - -} - -CaveLoader.prototype.constructor = CaveLoader; - -CaveLoader.prototype.setHandler = function ( fileName ) { - - var rev = fileName.split( '.' ).reverse(); - - this.extention = rev.shift().toLowerCase(); - - var handler; - - switch ( this.extention ) { - - case '3d': - - handler = new Svx3dHandler( fileName ); - - break; - - case 'lox': - - handler = new loxHandler( fileName ); - - break; - - - case 'kml': - - handler = new kmlHandler( fileName ); - - break; - - case 'reg': - case 'json': - - handler = new RegionHandler( fileName ); - - break; - - default: - - console.warn( 'Cave: unknown response extension [', self.extention, ']' ); - return false; - - } - - this.handler = handler; - - return true; - -}; - -CaveLoader.prototype.loadURL = function ( fileName ) { - - var self = this; - var prefix = getEnvironmentValue( 'surveyDirectory', '' ); - - // setup file handler - if ( ! this.setHandler( fileName ) ) { - - alert( 'Cave: unknown file extension [' + self.extention + ']' ); - return false; - - } - - var handler = this.handler; - - this.doneCount = 0; - this.taskCount = handler.isRegion ? 1 : 2; - - var loader = new FileLoader().setPath( prefix ); - - // request metadata file if not a region - - if ( ! handler.isRegion ) { - - loader.setResponseType( 'json' ).load( replaceExtension( fileName, 'json' ), _metadataLoaded, undefined, _metadataError ); - - } - - if ( handler.mimeType !== undefined ) loader.setMimeType( 'text/xml' ); - - loader.setResponseType( handler.type ); - - loader.load( fileName, _dataLoaded, _progress, _dataError ); - - return true; - - function _dataLoaded ( result ) { - - self.doneCount++; - self.dataResponse = result; - - if ( self.doneCount === self.taskCount ) self.callHandler(); - - } - - function _metadataLoaded ( result ) { - - self.doneCount++; - self.metadataResponse = result; - - if ( self.doneCount === self.taskCount ) self.callHandler(); - - } - - function _progress ( e ) { - - if ( self.progress) self.progress( Math.round( 100 * e.loaded / e.total ) ); - - } - - function _dataError ( event ) { - - self.doneCount++; - - console.warn( ' error event', event ); - - if ( self.doneCount === self.taskCount ) self.callHandler( fileName ); - - } - - function _metadataError ( /* event */ ) { - - self.doneCount++; - - if ( self.doneCount === self.taskCount ) self.callHandler( fileName ); - - } - -}; - -CaveLoader.prototype.loadFile = function ( file ) { - - var self = this; - var fileName = file.name; - - if ( ! this.setHandler( fileName ) ) { - - alert( 'Cave: unknown file extension [' + this.extention + ']' ); - return false; - - } - - var type = this.handler.type; - var fLoader = new FileReader(); - - fLoader.addEventListener( 'load', _loaded ); - fLoader.addEventListener( 'progress', _progress ); - - switch ( type ) { - - case 'arraybuffer': - - fLoader.readAsArrayBuffer( file ); - - break; - - default: - - alert( 'unknown file data type' ); - return false; - - } - - return true; - - function _loaded () { - - self.dataResponse = fLoader.result; - self.callHandler(); - - } - - function _progress ( e ) { - - if ( self.progress ) self.progress( Math.round( 100 * e.loaded / e.total ) ); - - } - -}; - -CaveLoader.prototype.callHandler = function () { - - if ( this.dataResponse === null ) { - - this.callback( false ); - return; - - } - - var data = this.dataResponse; - var metadata = this.metadataResponse; - - this.dataResponse = null; - this.metadataResponse = null; - - this.callback( this.handler.parse( data, metadata ) ); - -}; - - - -// EOF - -var cave; -var caveLoader; -var routes = null; - -var caveIndex = Infinity; -var caveList = []; -var guiState = {}; -var surveyTree; -var currentTop; - -var isCaveLoaded = false; - -var container$2; - -var file; -var progressBar; - -var terrainControls = []; -var routeControls = []; - -var terrainOverlay = null; - -var legShadingModes = { - 'by height': SHADING_HEIGHT, - 'by leg length': SHADING_LENGTH, - 'by leg inclination': SHADING_INCLINATION, - 'height cursor': SHADING_CURSOR, - 'fixed': SHADING_SINGLE, - 'survey': SHADING_SURVEY, - 'route': SHADING_PATH -}; - -var surfaceShadingModes = { - 'by height': SHADING_HEIGHT, - 'by leg inclination': SHADING_INCLINATION, - 'height cursor': SHADING_CURSOR, - 'fixed': SHADING_SINGLE -}; - -var terrainShadingModes = { - 'Relief shading': SHADING_SHADED, - 'by height': SHADING_HEIGHT -}; - -var cameraViews = { - '