scene1.fcb72093.js 1.3 MB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814288152881628817288182881928820288212882228823288242882528826288272882828829288302883128832288332883428835288362883728838288392884028841288422884328844288452884628847288482884928850288512885228853288542885528856288572885828859288602886128862288632886428865288662886728868288692887028871288722887328874288752887628877288782887928880288812888228883288842888528886288872888828889288902889128892288932889428895288962889728898288992890028901289022890328904289052890628907289082890928910289112891228913289142891528916289172891828919289202892128922289232892428925289262892728928289292893028931289322893328934289352893628937289382893928940289412894228943289442894528946289472894828949289502895128952289532895428955289562895728958289592896028961289622896328964289652896628967289682896928970289712897228973289742897528976289772897828979289802898128982289832898428985289862898728988289892899028991289922899328994289952899628997289982899929000290012900229003290042900529006290072900829009290102901129012290132901429015290162901729018290192902029021290222902329024290252902629027290282902929030290312903229033290342903529036290372903829039290402904129042290432904429045290462904729048290492905029051290522905329054290552905629057290582905929060290612906229063290642906529066290672906829069290702907129072290732907429075290762907729078290792908029081290822908329084290852908629087290882908929090290912909229093290942909529096290972909829099291002910129102291032910429105291062910729108291092911029111291122911329114291152911629117291182911929120291212912229123291242912529126291272912829129291302913129132291332913429135291362913729138291392914029141291422914329144291452914629147291482914929150291512915229153291542915529156291572915829159291602916129162291632916429165291662916729168291692917029171291722917329174291752917629177291782917929180291812918229183291842918529186291872918829189291902919129192291932919429195291962919729198291992920029201292022920329204292052920629207292082920929210292112921229213292142921529216292172921829219292202922129222292232922429225292262922729228292292923029231292322923329234292352923629237292382923929240292412924229243292442924529246292472924829249292502925129252292532925429255292562925729258292592926029261292622926329264292652926629267292682926929270292712927229273292742927529276292772927829279292802928129282292832928429285292862928729288292892929029291292922929329294292952929629297292982929929300293012930229303293042930529306293072930829309293102931129312293132931429315293162931729318293192932029321293222932329324293252932629327293282932929330293312933229333293342933529336293372933829339293402934129342293432934429345293462934729348293492935029351293522935329354293552935629357293582935929360293612936229363293642936529366293672936829369293702937129372293732937429375293762937729378293792938029381293822938329384293852938629387293882938929390293912939229393293942939529396293972939829399294002940129402294032940429405294062940729408294092941029411294122941329414294152941629417294182941929420294212942229423294242942529426294272942829429294302943129432294332943429435294362943729438294392944029441294422944329444294452944629447294482944929450294512945229453294542945529456294572945829459294602946129462294632946429465294662946729468294692947029471294722947329474294752947629477294782947929480294812948229483294842948529486294872948829489294902949129492294932949429495294962949729498294992950029501295022950329504295052950629507295082950929510295112951229513295142951529516295172951829519295202952129522295232952429525295262952729528295292953029531295322953329534295352953629537295382953929540295412954229543295442954529546295472954829549295502955129552295532955429555295562955729558295592956029561295622956329564295652956629567295682956929570295712957229573295742957529576295772957829579295802958129582295832958429585295862958729588295892959029591295922959329594295952959629597295982959929600296012960229603296042960529606296072960829609296102961129612296132961429615296162961729618296192962029621296222962329624296252962629627296282962929630296312963229633296342963529636296372963829639296402964129642296432964429645296462964729648296492965029651296522965329654296552965629657296582965929660296612966229663296642966529666296672966829669296702967129672296732967429675296762967729678296792968029681296822968329684296852968629687296882968929690296912969229693296942969529696296972969829699297002970129702297032970429705297062970729708297092971029711297122971329714297152971629717297182971929720297212972229723297242972529726297272972829729297302973129732297332973429735297362973729738297392974029741297422974329744297452974629747297482974929750297512975229753297542975529756297572975829759297602976129762297632976429765297662976729768297692977029771297722977329774297752977629777297782977929780297812978229783297842978529786297872978829789297902979129792297932979429795297962979729798297992980029801298022980329804298052980629807298082980929810298112981229813298142981529816298172981829819298202982129822298232982429825298262982729828298292983029831298322983329834298352983629837298382983929840298412984229843298442984529846298472984829849298502985129852298532985429855298562985729858298592986029861298622986329864298652986629867298682986929870298712987229873298742987529876298772987829879298802988129882298832988429885298862988729888298892989029891298922989329894298952989629897298982989929900299012990229903299042990529906299072990829909299102991129912299132991429915299162991729918299192992029921299222992329924299252992629927299282992929930299312993229933299342993529936299372993829939299402994129942299432994429945299462994729948299492995029951299522995329954299552995629957299582995929960299612996229963299642996529966299672996829969299702997129972299732997429975299762997729978299792998029981299822998329984299852998629987299882998929990299912999229993299942999529996299972999829999300003000130002300033000430005300063000730008300093001030011300123001330014300153001630017300183001930020300213002230023300243002530026300273002830029300303003130032300333003430035300363003730038300393004030041300423004330044300453004630047300483004930050300513005230053300543005530056300573005830059300603006130062300633006430065300663006730068300693007030071300723007330074300753007630077300783007930080300813008230083300843008530086300873008830089300903009130092300933009430095300963009730098300993010030101301023010330104301053010630107301083010930110301113011230113301143011530116301173011830119301203012130122301233012430125301263012730128301293013030131301323013330134301353013630137301383013930140301413014230143301443014530146301473014830149301503015130152301533015430155301563015730158301593016030161301623016330164301653016630167301683016930170301713017230173301743017530176301773017830179301803018130182301833018430185301863018730188301893019030191301923019330194301953019630197301983019930200302013020230203302043020530206302073020830209302103021130212302133021430215302163021730218302193022030221302223022330224302253022630227302283022930230302313023230233302343023530236302373023830239302403024130242302433024430245302463024730248302493025030251302523025330254302553025630257302583025930260302613026230263302643026530266302673026830269302703027130272302733027430275302763027730278302793028030281302823028330284302853028630287302883028930290302913029230293302943029530296302973029830299303003030130302303033030430305303063030730308303093031030311303123031330314303153031630317303183031930320303213032230323303243032530326303273032830329303303033130332303333033430335303363033730338303393034030341303423034330344303453034630347303483034930350303513035230353303543035530356303573035830359303603036130362303633036430365303663036730368303693037030371303723037330374303753037630377303783037930380303813038230383303843038530386303873038830389303903039130392303933039430395303963039730398303993040030401304023040330404304053040630407304083040930410304113041230413304143041530416304173041830419304203042130422304233042430425304263042730428304293043030431304323043330434304353043630437304383043930440304413044230443304443044530446304473044830449304503045130452304533045430455304563045730458304593046030461304623046330464304653046630467304683046930470304713047230473304743047530476304773047830479304803048130482304833048430485304863048730488304893049030491304923049330494304953049630497304983049930500305013050230503305043050530506305073050830509305103051130512305133051430515305163051730518305193052030521305223052330524305253052630527305283052930530305313053230533305343053530536305373053830539305403054130542305433054430545305463054730548305493055030551305523055330554305553055630557305583055930560305613056230563305643056530566305673056830569305703057130572305733057430575305763057730578305793058030581305823058330584305853058630587305883058930590305913059230593305943059530596305973059830599306003060130602306033060430605306063060730608306093061030611306123061330614306153061630617306183061930620306213062230623306243062530626306273062830629306303063130632306333063430635306363063730638306393064030641306423064330644306453064630647306483064930650306513065230653306543065530656306573065830659306603066130662306633066430665306663066730668306693067030671306723067330674306753067630677306783067930680306813068230683306843068530686306873068830689306903069130692306933069430695306963069730698306993070030701307023070330704307053070630707307083070930710307113071230713307143071530716307173071830719307203072130722307233072430725307263072730728307293073030731307323073330734307353073630737307383073930740307413074230743307443074530746307473074830749307503075130752307533075430755307563075730758307593076030761307623076330764307653076630767307683076930770307713077230773307743077530776307773077830779307803078130782307833078430785307863078730788307893079030791307923079330794307953079630797307983079930800308013080230803308043080530806308073080830809308103081130812308133081430815308163081730818308193082030821308223082330824308253082630827308283082930830308313083230833308343083530836308373083830839308403084130842308433084430845308463084730848308493085030851308523085330854308553085630857308583085930860308613086230863308643086530866308673086830869308703087130872308733087430875308763087730878308793088030881308823088330884308853088630887308883088930890308913089230893308943089530896308973089830899309003090130902309033090430905309063090730908309093091030911309123091330914309153091630917309183091930920309213092230923309243092530926309273092830929309303093130932309333093430935309363093730938309393094030941309423094330944309453094630947309483094930950309513095230953309543095530956309573095830959309603096130962309633096430965309663096730968309693097030971309723097330974309753097630977309783097930980309813098230983309843098530986309873098830989309903099130992309933099430995309963099730998309993100031001310023100331004310053100631007310083100931010310113101231013310143101531016310173101831019310203102131022310233102431025310263102731028310293103031031310323103331034310353103631037310383103931040310413104231043310443104531046310473104831049310503105131052310533105431055310563105731058310593106031061310623106331064310653106631067310683106931070310713107231073310743107531076310773107831079310803108131082310833108431085310863108731088310893109031091310923109331094310953109631097310983109931100311013110231103311043110531106311073110831109311103111131112311133111431115311163111731118311193112031121311223112331124311253112631127311283112931130311313113231133311343113531136311373113831139311403114131142311433114431145311463114731148311493115031151311523115331154311553115631157311583115931160311613116231163311643116531166311673116831169311703117131172311733117431175311763117731178311793118031181311823118331184311853118631187311883118931190311913119231193311943119531196311973119831199312003120131202312033120431205312063120731208312093121031211312123121331214312153121631217312183121931220312213122231223312243122531226312273122831229312303123131232312333123431235312363123731238312393124031241312423124331244312453124631247312483124931250312513125231253312543125531256312573125831259312603126131262312633126431265312663126731268312693127031271312723127331274312753127631277312783127931280312813128231283312843128531286312873128831289312903129131292312933129431295312963129731298312993130031301313023130331304313053130631307313083130931310313113131231313313143131531316313173131831319313203132131322313233132431325313263132731328313293133031331313323133331334313353133631337313383133931340313413134231343313443134531346313473134831349313503135131352313533135431355313563135731358313593136031361313623136331364313653136631367313683136931370313713137231373313743137531376313773137831379313803138131382313833138431385313863138731388313893139031391313923139331394313953139631397313983139931400314013140231403314043140531406314073140831409314103141131412314133141431415314163141731418314193142031421314223142331424314253142631427314283142931430314313143231433314343143531436314373143831439314403144131442314433144431445314463144731448314493145031451314523145331454314553145631457314583145931460314613146231463314643146531466314673146831469314703147131472314733147431475314763147731478314793148031481314823148331484314853148631487314883148931490314913149231493314943149531496314973149831499315003150131502315033150431505315063150731508315093151031511315123151331514315153151631517315183151931520315213152231523315243152531526315273152831529315303153131532315333153431535315363153731538315393154031541315423154331544315453154631547315483154931550315513155231553315543155531556315573155831559315603156131562315633156431565315663156731568315693157031571315723157331574315753157631577315783157931580315813158231583315843158531586315873158831589315903159131592315933159431595315963159731598315993160031601316023160331604316053160631607316083160931610316113161231613316143161531616316173161831619316203162131622316233162431625316263162731628316293163031631316323163331634316353163631637316383163931640316413164231643316443164531646316473164831649316503165131652316533165431655316563165731658316593166031661316623166331664316653166631667316683166931670316713167231673316743167531676316773167831679316803168131682316833168431685316863168731688316893169031691316923169331694316953169631697316983169931700317013170231703317043170531706317073170831709317103171131712317133171431715317163171731718317193172031721317223172331724317253172631727317283172931730317313173231733317343173531736317373173831739317403174131742317433174431745317463174731748317493175031751317523175331754317553175631757317583175931760317613176231763317643176531766317673176831769317703177131772317733177431775317763177731778317793178031781317823178331784317853178631787317883178931790317913179231793317943179531796317973179831799318003180131802318033180431805318063180731808318093181031811318123181331814318153181631817318183181931820318213182231823318243182531826318273182831829318303183131832318333183431835318363183731838318393184031841318423184331844318453184631847318483184931850318513185231853318543185531856318573185831859318603186131862318633186431865318663186731868318693187031871318723187331874318753187631877318783187931880318813188231883318843188531886318873188831889318903189131892318933189431895318963189731898318993190031901319023190331904319053190631907319083190931910319113191231913319143191531916319173191831919319203192131922319233192431925319263192731928319293193031931319323193331934319353193631937319383193931940319413194231943319443194531946319473194831949319503195131952319533195431955319563195731958319593196031961319623196331964319653196631967319683196931970319713197231973319743197531976319773197831979319803198131982319833198431985319863198731988319893199031991319923199331994319953199631997319983199932000320013200232003320043200532006320073200832009320103201132012320133201432015320163201732018320193202032021320223202332024320253202632027320283202932030320313203232033320343203532036320373203832039320403204132042320433204432045320463204732048320493205032051320523205332054320553205632057320583205932060320613206232063320643206532066320673206832069320703207132072320733207432075320763207732078320793208032081320823208332084320853208632087320883208932090320913209232093320943209532096320973209832099321003210132102321033210432105321063210732108321093211032111321123211332114321153211632117321183211932120321213212232123321243212532126321273212832129321303213132132321333213432135321363213732138321393214032141321423214332144321453214632147321483214932150321513215232153321543215532156321573215832159321603216132162321633216432165321663216732168321693217032171321723217332174321753217632177321783217932180321813218232183321843218532186321873218832189321903219132192321933219432195321963219732198321993220032201322023220332204322053220632207322083220932210322113221232213322143221532216322173221832219322203222132222322233222432225322263222732228322293223032231322323223332234322353223632237322383223932240322413224232243322443224532246322473224832249322503225132252322533225432255322563225732258322593226032261322623226332264322653226632267322683226932270322713227232273322743227532276322773227832279322803228132282322833228432285322863228732288322893229032291322923229332294322953229632297322983229932300323013230232303323043230532306323073230832309323103231132312323133231432315323163231732318323193232032321323223232332324323253232632327323283232932330323313233232333323343233532336323373233832339323403234132342323433234432345323463234732348323493235032351323523235332354323553235632357323583235932360323613236232363323643236532366323673236832369323703237132372323733237432375323763237732378323793238032381323823238332384323853238632387323883238932390323913239232393323943239532396323973239832399324003240132402324033240432405324063240732408324093241032411324123241332414324153241632417324183241932420324213242232423324243242532426324273242832429324303243132432324333243432435324363243732438324393244032441324423244332444324453244632447324483244932450324513245232453324543245532456324573245832459324603246132462324633246432465324663246732468324693247032471324723247332474324753247632477324783247932480324813248232483324843248532486324873248832489324903249132492324933249432495324963249732498324993250032501325023250332504325053250632507325083250932510325113251232513325143251532516325173251832519325203252132522325233252432525325263252732528325293253032531325323253332534325353253632537325383253932540325413254232543325443254532546325473254832549325503255132552325533255432555325563255732558325593256032561325623256332564325653256632567325683256932570325713257232573325743257532576325773257832579325803258132582325833258432585325863258732588325893259032591325923259332594325953259632597325983259932600326013260232603326043260532606326073260832609326103261132612326133261432615326163261732618326193262032621326223262332624326253262632627326283262932630326313263232633326343263532636326373263832639326403264132642326433264432645326463264732648326493265032651326523265332654326553265632657326583265932660326613266232663326643266532666326673266832669326703267132672326733267432675326763267732678326793268032681326823268332684326853268632687326883268932690326913269232693326943269532696326973269832699327003270132702327033270432705327063270732708327093271032711327123271332714327153271632717327183271932720327213272232723327243272532726327273272832729327303273132732327333273432735327363273732738327393274032741327423274332744327453274632747327483274932750327513275232753327543275532756327573275832759327603276132762327633276432765327663276732768327693277032771327723277332774327753277632777327783277932780327813278232783327843278532786327873278832789327903279132792327933279432795327963279732798327993280032801328023280332804328053280632807328083280932810328113281232813328143281532816328173281832819328203282132822328233282432825328263282732828328293283032831328323283332834328353283632837328383283932840328413284232843328443284532846328473284832849328503285132852328533285432855328563285732858328593286032861328623286332864328653286632867328683286932870328713287232873328743287532876328773287832879328803288132882328833288432885328863288732888328893289032891328923289332894328953289632897328983289932900329013290232903329043290532906329073290832909329103291132912329133291432915329163291732918329193292032921329223292332924329253292632927329283292932930329313293232933329343293532936329373293832939329403294132942329433294432945329463294732948329493295032951329523295332954329553295632957329583295932960329613296232963329643296532966329673296832969329703297132972329733297432975329763297732978329793298032981329823298332984329853298632987329883298932990329913299232993329943299532996329973299832999330003300133002330033300433005330063300733008330093301033011330123301333014330153301633017330183301933020330213302233023330243302533026330273302833029330303303133032330333303433035330363303733038330393304033041330423304333044330453304633047330483304933050330513305233053330543305533056330573305833059330603306133062330633306433065330663306733068330693307033071330723307333074330753307633077330783307933080330813308233083330843308533086330873308833089330903309133092330933309433095330963309733098330993310033101331023310333104331053310633107331083310933110331113311233113331143311533116331173311833119331203312133122331233312433125331263312733128331293313033131331323313333134331353313633137331383313933140331413314233143331443314533146331473314833149331503315133152331533315433155331563315733158331593316033161331623316333164331653316633167331683316933170331713317233173331743317533176331773317833179331803318133182331833318433185331863318733188331893319033191331923319333194331953319633197331983319933200332013320233203332043320533206332073320833209332103321133212332133321433215332163321733218332193322033221332223322333224332253322633227332283322933230332313323233233332343323533236332373323833239332403324133242332433324433245332463324733248332493325033251332523325333254332553325633257332583325933260332613326233263332643326533266332673326833269332703327133272332733327433275332763327733278332793328033281332823328333284332853328633287332883328933290332913329233293332943329533296332973329833299333003330133302333033330433305333063330733308333093331033311333123331333314333153331633317333183331933320333213332233323333243332533326333273332833329333303333133332333333333433335333363333733338333393334033341333423334333344333453334633347333483334933350333513335233353333543335533356333573335833359333603336133362333633336433365333663336733368333693337033371333723337333374333753337633377333783337933380333813338233383333843338533386333873338833389333903339133392333933339433395333963339733398333993340033401334023340333404334053340633407334083340933410334113341233413334143341533416334173341833419334203342133422334233342433425334263342733428334293343033431334323343333434334353343633437334383343933440334413344233443334443344533446334473344833449334503345133452334533345433455334563345733458334593346033461334623346333464334653346633467334683346933470334713347233473334743347533476334773347833479334803348133482334833348433485334863348733488334893349033491334923349333494334953349633497334983349933500335013350233503335043350533506335073350833509335103351133512335133351433515335163351733518335193352033521335223352333524335253352633527335283352933530335313353233533335343353533536335373353833539335403354133542335433354433545335463354733548335493355033551335523355333554335553355633557335583355933560335613356233563335643356533566335673356833569335703357133572335733357433575335763357733578335793358033581335823358333584335853358633587335883358933590335913359233593335943359533596335973359833599336003360133602336033360433605336063360733608336093361033611336123361333614336153361633617336183361933620336213362233623336243362533626336273362833629336303363133632336333363433635336363363733638336393364033641336423364333644336453364633647336483364933650336513365233653336543365533656336573365833659336603366133662336633366433665336663366733668336693367033671336723367333674336753367633677336783367933680336813368233683336843368533686336873368833689336903369133692336933369433695336963369733698336993370033701337023370333704337053370633707337083370933710337113371233713337143371533716337173371833719337203372133722337233372433725337263372733728337293373033731337323373333734337353373633737337383373933740337413374233743337443374533746337473374833749337503375133752337533375433755337563375733758337593376033761337623376333764337653376633767337683376933770337713377233773337743377533776337773377833779337803378133782337833378433785337863378733788337893379033791337923379333794337953379633797337983379933800338013380233803338043380533806338073380833809338103381133812338133381433815338163381733818338193382033821338223382333824338253382633827338283382933830338313383233833338343383533836338373383833839338403384133842338433384433845338463384733848338493385033851338523385333854338553385633857338583385933860338613386233863338643386533866338673386833869338703387133872338733387433875338763387733878338793388033881338823388333884338853388633887338883388933890338913389233893338943389533896338973389833899339003390133902339033390433905339063390733908339093391033911339123391333914339153391633917339183391933920339213392233923339243392533926339273392833929339303393133932339333393433935339363393733938339393394033941339423394333944339453394633947339483394933950339513395233953339543395533956339573395833959339603396133962339633396433965339663396733968339693397033971339723397333974339753397633977339783397933980339813398233983339843398533986339873398833989339903399133992339933399433995339963399733998339993400034001340023400334004340053400634007340083400934010340113401234013340143401534016340173401834019340203402134022340233402434025340263402734028340293403034031340323403334034340353403634037340383403934040340413404234043340443404534046340473404834049340503405134052340533405434055340563405734058340593406034061340623406334064340653406634067340683406934070340713407234073340743407534076340773407834079340803408134082340833408434085340863408734088340893409034091340923409334094340953409634097340983409934100341013410234103341043410534106341073410834109341103411134112341133411434115341163411734118341193412034121341223412334124341253412634127341283412934130341313413234133341343413534136341373413834139341403414134142341433414434145341463414734148341493415034151341523415334154341553415634157341583415934160341613416234163341643416534166341673416834169341703417134172341733417434175341763417734178341793418034181341823418334184341853418634187341883418934190341913419234193341943419534196341973419834199342003420134202342033420434205342063420734208342093421034211342123421334214342153421634217342183421934220342213422234223342243422534226342273422834229342303423134232342333423434235342363423734238342393424034241342423424334244342453424634247342483424934250342513425234253342543425534256342573425834259342603426134262342633426434265342663426734268342693427034271342723427334274342753427634277342783427934280342813428234283342843428534286342873428834289342903429134292342933429434295342963429734298342993430034301343023430334304343053430634307343083430934310343113431234313343143431534316343173431834319343203432134322343233432434325343263432734328343293433034331343323433334334343353433634337343383433934340343413434234343343443434534346343473434834349343503435134352343533435434355343563435734358343593436034361343623436334364343653436634367343683436934370343713437234373343743437534376343773437834379343803438134382343833438434385343863438734388343893439034391343923439334394343953439634397343983439934400344013440234403344043440534406344073440834409344103441134412344133441434415344163441734418344193442034421344223442334424344253442634427344283442934430344313443234433344343443534436344373443834439344403444134442344433444434445344463444734448344493445034451344523445334454344553445634457344583445934460344613446234463344643446534466344673446834469344703447134472344733447434475344763447734478344793448034481344823448334484344853448634487344883448934490344913449234493344943449534496344973449834499345003450134502345033450434505345063450734508345093451034511345123451334514345153451634517345183451934520345213452234523345243452534526345273452834529345303453134532345333453434535345363453734538345393454034541345423454334544345453454634547345483454934550345513455234553345543455534556345573455834559345603456134562345633456434565345663456734568345693457034571345723457334574345753457634577345783457934580345813458234583345843458534586345873458834589345903459134592345933459434595345963459734598345993460034601346023460334604346053460634607346083460934610346113461234613346143461534616346173461834619346203462134622346233462434625346263462734628346293463034631346323463334634346353463634637346383463934640346413464234643346443464534646346473464834649346503465134652346533465434655346563465734658346593466034661346623466334664346653466634667346683466934670346713467234673346743467534676346773467834679346803468134682346833468434685346863468734688346893469034691346923469334694346953469634697346983469934700347013470234703347043470534706347073470834709347103471134712347133471434715347163471734718347193472034721347223472334724347253472634727347283472934730347313473234733347343473534736347373473834739347403474134742347433474434745347463474734748347493475034751347523475334754347553475634757347583475934760347613476234763347643476534766347673476834769347703477134772347733477434775347763477734778347793478034781347823478334784347853478634787347883478934790347913479234793347943479534796347973479834799348003480134802348033480434805348063480734808348093481034811348123481334814348153481634817348183481934820348213482234823348243482534826348273482834829348303483134832348333483434835348363483734838348393484034841348423484334844348453484634847348483484934850348513485234853348543485534856348573485834859348603486134862348633486434865348663486734868348693487034871348723487334874348753487634877348783487934880348813488234883348843488534886348873488834889348903489134892348933489434895348963489734898348993490034901349023490334904349053490634907349083490934910349113491234913349143491534916349173491834919349203492134922349233492434925349263492734928349293493034931349323493334934349353493634937349383493934940349413494234943349443494534946349473494834949349503495134952349533495434955349563495734958349593496034961349623496334964349653496634967349683496934970349713497234973349743497534976349773497834979349803498134982349833498434985349863498734988349893499034991349923499334994349953499634997349983499935000350013500235003350043500535006350073500835009350103501135012350133501435015350163501735018350193502035021350223502335024350253502635027350283502935030350313503235033350343503535036350373503835039350403504135042350433504435045350463504735048350493505035051350523505335054350553505635057350583505935060350613506235063350643506535066350673506835069350703507135072350733507435075350763507735078350793508035081350823508335084350853508635087350883508935090350913509235093350943509535096350973509835099351003510135102351033510435105351063510735108351093511035111351123511335114351153511635117351183511935120351213512235123351243512535126351273512835129351303513135132351333513435135351363513735138351393514035141351423514335144351453514635147351483514935150351513515235153351543515535156351573515835159351603516135162351633516435165351663516735168351693517035171351723517335174351753517635177351783517935180351813518235183351843518535186351873518835189351903519135192351933519435195351963519735198351993520035201352023520335204352053520635207352083520935210352113521235213352143521535216352173521835219352203522135222352233522435225352263522735228352293523035231352323523335234352353523635237352383523935240352413524235243352443524535246352473524835249352503525135252352533525435255352563525735258352593526035261352623526335264352653526635267352683526935270352713527235273352743527535276352773527835279352803528135282352833528435285352863528735288352893529035291352923529335294352953529635297352983529935300353013530235303353043530535306353073530835309353103531135312353133531435315353163531735318353193532035321353223532335324353253532635327353283532935330353313533235333353343533535336353373533835339353403534135342353433534435345353463534735348353493535035351353523535335354353553535635357353583535935360353613536235363353643536535366353673536835369353703537135372353733537435375353763537735378353793538035381353823538335384353853538635387353883538935390353913539235393353943539535396353973539835399354003540135402354033540435405354063540735408354093541035411354123541335414354153541635417354183541935420354213542235423354243542535426354273542835429354303543135432354333543435435354363543735438354393544035441354423544335444354453544635447354483544935450354513545235453354543545535456354573545835459354603546135462354633546435465354663546735468354693547035471354723547335474354753547635477354783547935480354813548235483354843548535486354873548835489354903549135492354933549435495354963549735498354993550035501355023550335504355053550635507355083550935510355113551235513355143551535516355173551835519355203552135522355233552435525355263552735528355293553035531355323553335534355353553635537355383553935540355413554235543355443554535546355473554835549355503555135552355533555435555355563555735558355593556035561355623556335564355653556635567355683556935570355713557235573355743557535576355773557835579355803558135582355833558435585355863558735588355893559035591355923559335594355953559635597355983559935600356013560235603356043560535606356073560835609356103561135612356133561435615356163561735618356193562035621356223562335624356253562635627356283562935630356313563235633356343563535636356373563835639356403564135642356433564435645356463564735648356493565035651356523565335654356553565635657356583565935660356613566235663356643566535666356673566835669356703567135672356733567435675356763567735678356793568035681356823568335684356853568635687356883568935690356913569235693356943569535696356973569835699357003570135702357033570435705357063570735708357093571035711357123571335714357153571635717357183571935720357213572235723357243572535726357273572835729357303573135732357333573435735357363573735738357393574035741357423574335744357453574635747357483574935750357513575235753357543575535756357573575835759357603576135762357633576435765357663576735768357693577035771357723577335774357753577635777357783577935780357813578235783357843578535786357873578835789357903579135792357933579435795357963579735798357993580035801358023580335804358053580635807358083580935810358113581235813358143581535816358173581835819358203582135822358233582435825358263582735828358293583035831358323583335834358353583635837358383583935840358413584235843358443584535846358473584835849358503585135852358533585435855358563585735858358593586035861358623586335864358653586635867358683586935870358713587235873358743587535876358773587835879358803588135882358833588435885358863588735888358893589035891358923589335894358953589635897358983589935900359013590235903359043590535906359073590835909359103591135912359133591435915359163591735918359193592035921359223592335924359253592635927359283592935930359313593235933359343593535936359373593835939359403594135942359433594435945359463594735948359493595035951359523595335954359553595635957359583595935960359613596235963359643596535966359673596835969359703597135972359733597435975359763597735978359793598035981359823598335984359853598635987359883598935990359913599235993359943599535996359973599835999360003600136002360033600436005360063600736008360093601036011360123601336014360153601636017360183601936020360213602236023360243602536026360273602836029360303603136032360333603436035360363603736038360393604036041360423604336044360453604636047360483604936050360513605236053360543605536056360573605836059360603606136062360633606436065360663606736068360693607036071360723607336074360753607636077360783607936080360813608236083360843608536086360873608836089360903609136092360933609436095360963609736098360993610036101361023610336104361053610636107361083610936110361113611236113361143611536116361173611836119361203612136122361233612436125361263612736128361293613036131361323613336134361353613636137361383613936140361413614236143361443614536146361473614836149361503615136152361533615436155361563615736158361593616036161361623616336164361653616636167361683616936170361713617236173361743617536176361773617836179361803618136182361833618436185361863618736188361893619036191361923619336194361953619636197361983619936200362013620236203362043620536206362073620836209362103621136212362133621436215362163621736218362193622036221362223622336224362253622636227362283622936230362313623236233362343623536236362373623836239362403624136242362433624436245362463624736248362493625036251362523625336254362553625636257362583625936260362613626236263362643626536266362673626836269362703627136272362733627436275362763627736278362793628036281362823628336284362853628636287362883628936290362913629236293362943629536296362973629836299363003630136302363033630436305363063630736308363093631036311363123631336314363153631636317363183631936320363213632236323363243632536326363273632836329363303633136332363333633436335363363633736338363393634036341363423634336344363453634636347363483634936350363513635236353363543635536356363573635836359363603636136362363633636436365363663636736368363693637036371363723637336374363753637636377363783637936380363813638236383363843638536386363873638836389363903639136392363933639436395363963639736398363993640036401364023640336404364053640636407364083640936410364113641236413364143641536416364173641836419364203642136422364233642436425364263642736428364293643036431364323643336434364353643636437364383643936440364413644236443364443644536446364473644836449364503645136452364533645436455364563645736458364593646036461364623646336464364653646636467364683646936470364713647236473364743647536476364773647836479364803648136482364833648436485364863648736488364893649036491364923649336494364953649636497364983649936500365013650236503365043650536506365073650836509365103651136512365133651436515365163651736518365193652036521365223652336524365253652636527365283652936530365313653236533365343653536536365373653836539365403654136542365433654436545365463654736548365493655036551365523655336554365553655636557365583655936560365613656236563365643656536566365673656836569365703657136572365733657436575365763657736578365793658036581365823658336584365853658636587365883658936590365913659236593365943659536596365973659836599366003660136602366033660436605366063660736608366093661036611366123661336614366153661636617366183661936620366213662236623366243662536626366273662836629366303663136632366333663436635366363663736638366393664036641366423664336644366453664636647366483664936650366513665236653366543665536656366573665836659366603666136662366633666436665366663666736668366693667036671366723667336674366753667636677366783667936680366813668236683366843668536686366873668836689366903669136692366933669436695366963669736698366993670036701367023670336704367053670636707367083670936710367113671236713367143671536716367173671836719367203672136722367233672436725367263672736728367293673036731367323673336734367353673636737367383673936740367413674236743367443674536746367473674836749367503675136752367533675436755367563675736758367593676036761367623676336764367653676636767367683676936770367713677236773367743677536776367773677836779367803678136782367833678436785367863678736788367893679036791367923679336794367953679636797367983679936800368013680236803368043680536806368073680836809368103681136812368133681436815368163681736818368193682036821368223682336824368253682636827368283682936830368313683236833368343683536836368373683836839368403684136842368433684436845368463684736848368493685036851368523685336854368553685636857368583685936860368613686236863368643686536866368673686836869368703687136872368733687436875368763687736878368793688036881368823688336884368853688636887368883688936890368913689236893368943689536896368973689836899369003690136902369033690436905369063690736908369093691036911369123691336914369153691636917369183691936920369213692236923369243692536926369273692836929369303693136932369333693436935369363693736938369393694036941369423694336944369453694636947369483694936950369513695236953369543695536956369573695836959369603696136962369633696436965369663696736968369693697036971369723697336974369753697636977369783697936980369813698236983369843698536986369873698836989369903699136992369933699436995369963699736998369993700037001370023700337004370053700637007370083700937010370113701237013370143701537016370173701837019370203702137022370233702437025370263702737028370293703037031370323703337034370353703637037370383703937040370413704237043370443704537046370473704837049370503705137052370533705437055370563705737058370593706037061370623706337064370653706637067370683706937070370713707237073370743707537076370773707837079370803708137082370833708437085370863708737088370893709037091370923709337094370953709637097370983709937100371013710237103371043710537106371073710837109371103711137112371133711437115371163711737118371193712037121371223712337124371253712637127371283712937130371313713237133371343713537136371373713837139371403714137142371433714437145371463714737148371493715037151371523715337154371553715637157371583715937160371613716237163371643716537166371673716837169371703717137172371733717437175371763717737178371793718037181371823718337184371853718637187371883718937190371913719237193371943719537196371973719837199372003720137202372033720437205372063720737208372093721037211372123721337214372153721637217372183721937220372213722237223372243722537226372273722837229372303723137232372333723437235372363723737238372393724037241372423724337244372453724637247372483724937250372513725237253372543725537256372573725837259372603726137262372633726437265372663726737268372693727037271372723727337274372753727637277372783727937280372813728237283372843728537286372873728837289372903729137292372933729437295372963729737298372993730037301373023730337304373053730637307373083730937310373113731237313373143731537316373173731837319373203732137322373233732437325373263732737328373293733037331373323733337334373353733637337373383733937340373413734237343373443734537346373473734837349373503735137352373533735437355373563735737358373593736037361373623736337364373653736637367373683736937370373713737237373373743737537376373773737837379373803738137382373833738437385373863738737388373893739037391373923739337394373953739637397373983739937400374013740237403374043740537406374073740837409374103741137412374133741437415374163741737418374193742037421374223742337424374253742637427374283742937430374313743237433374343743537436374373743837439374403744137442374433744437445374463744737448374493745037451374523745337454374553745637457374583745937460374613746237463374643746537466374673746837469374703747137472374733747437475374763747737478374793748037481374823748337484374853748637487374883748937490374913749237493374943749537496374973749837499375003750137502375033750437505375063750737508375093751037511375123751337514375153751637517375183751937520375213752237523375243752537526375273752837529375303753137532375333753437535375363753737538375393754037541375423754337544375453754637547375483754937550375513755237553375543755537556375573755837559375603756137562375633756437565375663756737568375693757037571375723757337574375753757637577375783757937580375813758237583375843758537586375873758837589375903759137592375933759437595375963759737598375993760037601376023760337604376053760637607376083760937610376113761237613376143761537616376173761837619376203762137622376233762437625376263762737628376293763037631376323763337634376353763637637376383763937640376413764237643376443764537646376473764837649376503765137652376533765437655376563765737658376593766037661376623766337664376653766637667376683766937670376713767237673376743767537676376773767837679376803768137682376833768437685376863768737688376893769037691376923769337694376953769637697376983769937700377013770237703377043770537706377073770837709377103771137712377133771437715377163771737718377193772037721377223772337724377253772637727377283772937730377313773237733377343773537736377373773837739377403774137742377433774437745377463774737748377493775037751377523775337754377553775637757377583775937760377613776237763377643776537766377673776837769377703777137772377733777437775377763777737778377793778037781377823778337784377853778637787377883778937790377913779237793377943779537796377973779837799378003780137802378033780437805378063780737808378093781037811378123781337814378153781637817378183781937820378213782237823378243782537826378273782837829378303783137832378333783437835378363783737838378393784037841378423784337844378453784637847378483784937850378513785237853378543785537856378573785837859378603786137862378633786437865378663786737868378693787037871378723787337874378753787637877378783787937880378813788237883378843788537886378873788837889378903789137892378933789437895378963789737898378993790037901379023790337904379053790637907379083790937910379113791237913379143791537916379173791837919379203792137922379233792437925379263792737928379293793037931379323793337934379353793637937379383793937940379413794237943379443794537946379473794837949379503795137952379533795437955379563795737958379593796037961379623796337964379653796637967379683796937970379713797237973379743797537976379773797837979379803798137982379833798437985379863798737988379893799037991379923799337994379953799637997379983799938000380013800238003380043800538006380073800838009380103801138012380133801438015380163801738018380193802038021380223802338024380253802638027380283802938030380313803238033380343803538036380373803838039380403804138042380433804438045380463804738048380493805038051380523805338054380553805638057380583805938060380613806238063380643806538066380673806838069380703807138072380733807438075380763807738078380793808038081380823808338084380853808638087380883808938090380913809238093380943809538096380973809838099381003810138102381033810438105381063810738108381093811038111381123811338114381153811638117381183811938120381213812238123381243812538126381273812838129381303813138132381333813438135381363813738138381393814038141381423814338144381453814638147381483814938150381513815238153381543815538156381573815838159381603816138162381633816438165381663816738168381693817038171381723817338174381753817638177381783817938180381813818238183381843818538186381873818838189381903819138192381933819438195381963819738198381993820038201382023820338204382053820638207382083820938210382113821238213382143821538216382173821838219382203822138222382233822438225382263822738228382293823038231382323823338234382353823638237382383823938240382413824238243382443824538246382473824838249382503825138252382533825438255382563825738258382593826038261382623826338264382653826638267382683826938270382713827238273382743827538276382773827838279382803828138282382833828438285382863828738288382893829038291382923829338294382953829638297382983829938300383013830238303383043830538306383073830838309383103831138312383133831438315383163831738318383193832038321383223832338324383253832638327383283832938330383313833238333383343833538336383373833838339383403834138342383433834438345383463834738348383493835038351383523835338354383553835638357383583835938360383613836238363383643836538366383673836838369383703837138372383733837438375383763837738378383793838038381383823838338384383853838638387383883838938390383913839238393383943839538396383973839838399384003840138402384033840438405384063840738408384093841038411384123841338414384153841638417384183841938420384213842238423384243842538426384273842838429384303843138432384333843438435384363843738438384393844038441384423844338444384453844638447384483844938450384513845238453384543845538456384573845838459384603846138462384633846438465384663846738468384693847038471384723847338474384753847638477384783847938480384813848238483384843848538486384873848838489384903849138492384933849438495384963849738498384993850038501385023850338504385053850638507385083850938510385113851238513385143851538516385173851838519385203852138522385233852438525385263852738528385293853038531385323853338534385353853638537385383853938540385413854238543385443854538546385473854838549385503855138552385533855438555385563855738558385593856038561385623856338564385653856638567385683856938570385713857238573385743857538576385773857838579385803858138582385833858438585385863858738588385893859038591385923859338594385953859638597385983859938600386013860238603386043860538606386073860838609386103861138612386133861438615386163861738618386193862038621386223862338624386253862638627386283862938630386313863238633386343863538636386373863838639386403864138642386433864438645386463864738648386493865038651386523865338654386553865638657386583865938660386613866238663386643866538666386673866838669386703867138672386733867438675386763867738678386793868038681386823868338684386853868638687386883868938690386913869238693386943869538696386973869838699387003870138702387033870438705387063870738708387093871038711387123871338714387153871638717387183871938720387213872238723387243872538726387273872838729387303873138732387333873438735387363873738738387393874038741387423874338744387453874638747387483874938750387513875238753387543875538756387573875838759387603876138762387633876438765387663876738768387693877038771387723877338774387753877638777387783877938780387813878238783387843878538786387873878838789387903879138792387933879438795387963879738798387993880038801388023880338804388053880638807388083880938810388113881238813388143881538816388173881838819388203882138822388233882438825388263882738828388293883038831388323883338834388353883638837388383883938840388413884238843388443884538846388473884838849388503885138852388533885438855388563885738858388593886038861388623886338864388653886638867388683886938870388713887238873388743887538876388773887838879388803888138882388833888438885388863888738888388893889038891388923889338894388953889638897388983889938900389013890238903389043890538906389073890838909389103891138912389133891438915389163891738918389193892038921389223892338924389253892638927389283892938930389313893238933389343893538936389373893838939389403894138942389433894438945389463894738948389493895038951389523895338954389553895638957389583895938960389613896238963389643896538966389673896838969389703897138972389733897438975389763897738978389793898038981389823898338984389853898638987389883898938990389913899238993389943899538996389973899838999390003900139002390033900439005390063900739008390093901039011390123901339014390153901639017390183901939020390213902239023390243902539026390273902839029390303903139032390333903439035390363903739038390393904039041390423904339044390453904639047390483904939050390513905239053390543905539056390573905839059390603906139062390633906439065390663906739068390693907039071390723907339074390753907639077390783907939080390813908239083390843908539086390873908839089390903909139092390933909439095390963909739098390993910039101391023910339104391053910639107391083910939110391113911239113391143911539116391173911839119391203912139122391233912439125391263912739128391293913039131391323913339134391353913639137391383913939140391413914239143391443914539146391473914839149391503915139152391533915439155391563915739158391593916039161391623916339164391653916639167391683916939170391713917239173391743917539176391773917839179391803918139182391833918439185391863918739188391893919039191391923919339194391953919639197391983919939200392013920239203392043920539206392073920839209392103921139212392133921439215392163921739218392193922039221392223922339224392253922639227392283922939230392313923239233392343923539236392373923839239392403924139242392433924439245392463924739248392493925039251392523925339254392553925639257392583925939260392613926239263392643926539266392673926839269392703927139272392733927439275392763927739278392793928039281392823928339284392853928639287392883928939290392913929239293392943929539296392973929839299393003930139302393033930439305393063930739308393093931039311393123931339314393153931639317393183931939320393213932239323393243932539326393273932839329393303933139332393333933439335393363933739338393393934039341393423934339344393453934639347393483934939350393513935239353393543935539356393573935839359393603936139362393633936439365393663936739368393693937039371393723937339374393753937639377393783937939380393813938239383393843938539386393873938839389393903939139392393933939439395393963939739398393993940039401394023940339404394053940639407394083940939410394113941239413394143941539416394173941839419394203942139422394233942439425394263942739428394293943039431394323943339434394353943639437394383943939440394413944239443394443944539446394473944839449394503945139452394533945439455394563945739458394593946039461394623946339464394653946639467394683946939470394713947239473394743947539476394773947839479394803948139482394833948439485394863948739488394893949039491394923949339494394953949639497394983949939500395013950239503395043950539506395073950839509395103951139512395133951439515395163951739518395193952039521395223952339524395253952639527395283952939530395313953239533395343953539536395373953839539395403954139542395433954439545395463954739548395493955039551395523955339554395553955639557395583955939560395613956239563395643956539566395673956839569395703957139572395733957439575395763957739578395793958039581395823958339584395853958639587395883958939590395913959239593395943959539596395973959839599396003960139602396033960439605396063960739608396093961039611396123961339614396153961639617396183961939620396213962239623396243962539626396273962839629396303963139632396333963439635396363963739638396393964039641396423964339644396453964639647396483964939650396513965239653396543965539656396573965839659396603966139662396633966439665396663966739668396693967039671396723967339674396753967639677396783967939680396813968239683396843968539686396873968839689396903969139692396933969439695396963969739698396993970039701397023970339704397053970639707397083970939710397113971239713397143971539716397173971839719397203972139722397233972439725397263972739728397293973039731397323973339734397353973639737397383973939740397413974239743397443974539746397473974839749397503975139752397533975439755397563975739758397593976039761397623976339764397653976639767397683976939770397713977239773397743977539776397773977839779397803978139782397833978439785397863978739788397893979039791397923979339794397953979639797397983979939800398013980239803398043980539806398073980839809398103981139812398133981439815398163981739818398193982039821398223982339824398253982639827398283982939830398313983239833398343983539836398373983839839398403984139842398433984439845398463984739848398493985039851398523985339854398553985639857398583985939860398613986239863398643986539866398673986839869398703987139872398733987439875398763987739878398793988039881398823988339884398853988639887398883988939890398913989239893398943989539896398973989839899399003990139902399033990439905399063990739908399093991039911399123991339914399153991639917399183991939920399213992239923399243992539926399273992839929399303993139932399333993439935399363993739938399393994039941399423994339944399453994639947399483994939950399513995239953399543995539956399573995839959399603996139962399633996439965399663996739968399693997039971399723997339974399753997639977399783997939980399813998239983399843998539986399873998839989399903999139992399933999439995399963999739998399994000040001400024000340004400054000640007400084000940010400114001240013400144001540016400174001840019400204002140022400234002440025400264002740028400294003040031400324003340034400354003640037400384003940040400414004240043400444004540046400474004840049400504005140052400534005440055400564005740058400594006040061400624006340064400654006640067400684006940070400714007240073400744007540076400774007840079400804008140082400834008440085400864008740088400894009040091400924009340094400954009640097400984009940100401014010240103401044010540106401074010840109401104011140112401134011440115401164011740118401194012040121401224012340124401254012640127401284012940130401314013240133401344013540136401374013840139401404014140142401434014440145401464014740148401494015040151401524015340154401554015640157401584015940160401614016240163401644016540166401674016840169401704017140172401734017440175401764017740178401794018040181401824018340184401854018640187401884018940190401914019240193401944019540196401974019840199402004020140202402034020440205402064020740208402094021040211402124021340214402154021640217402184021940220402214022240223402244022540226402274022840229402304023140232402334023440235402364023740238402394024040241402424024340244402454024640247402484024940250402514025240253402544025540256402574025840259402604026140262402634026440265402664026740268402694027040271402724027340274402754027640277402784027940280402814028240283402844028540286402874028840289402904029140292402934029440295402964029740298402994030040301403024030340304403054030640307403084030940310403114031240313403144031540316403174031840319403204032140322403234032440325403264032740328403294033040331403324033340334403354033640337403384033940340403414034240343403444034540346403474034840349403504035140352403534035440355403564035740358403594036040361403624036340364403654036640367403684036940370403714037240373403744037540376403774037840379403804038140382403834038440385403864038740388403894039040391403924039340394403954039640397403984039940400404014040240403404044040540406404074040840409404104041140412404134041440415404164041740418404194042040421404224042340424404254042640427404284042940430404314043240433404344043540436404374043840439404404044140442404434044440445404464044740448404494045040451404524045340454404554045640457404584045940460404614046240463404644046540466404674046840469404704047140472404734047440475404764047740478404794048040481404824048340484404854048640487404884048940490404914049240493404944049540496404974049840499405004050140502405034050440505405064050740508405094051040511405124051340514405154051640517405184051940520405214052240523405244052540526405274052840529405304053140532405334053440535405364053740538405394054040541405424054340544405454054640547405484054940550405514055240553405544055540556405574055840559405604056140562405634056440565405664056740568405694057040571405724057340574405754057640577405784057940580405814058240583405844058540586405874058840589405904059140592405934059440595405964059740598405994060040601406024060340604406054060640607406084060940610406114061240613406144061540616406174061840619406204062140622406234062440625406264062740628406294063040631406324063340634406354063640637406384063940640406414064240643406444064540646406474064840649406504065140652406534065440655406564065740658406594066040661406624066340664406654066640667406684066940670406714067240673406744067540676406774067840679406804068140682406834068440685406864068740688406894069040691406924069340694406954069640697406984069940700407014070240703407044070540706407074070840709407104071140712407134071440715407164071740718407194072040721407224072340724407254072640727407284072940730407314073240733407344073540736407374073840739407404074140742407434074440745407464074740748407494075040751407524075340754407554075640757407584075940760407614076240763407644076540766407674076840769407704077140772407734077440775407764077740778407794078040781407824078340784407854078640787407884078940790407914079240793407944079540796407974079840799408004080140802408034080440805408064080740808408094081040811408124081340814408154081640817408184081940820408214082240823408244082540826408274082840829408304083140832408334083440835408364083740838408394084040841408424084340844408454084640847408484084940850408514085240853408544085540856408574085840859408604086140862408634086440865408664086740868408694087040871408724087340874408754087640877408784087940880408814088240883408844088540886408874088840889408904089140892408934089440895408964089740898408994090040901409024090340904409054090640907409084090940910409114091240913409144091540916409174091840919409204092140922409234092440925409264092740928409294093040931409324093340934409354093640937409384093940940409414094240943409444094540946409474094840949409504095140952409534095440955409564095740958409594096040961409624096340964409654096640967409684096940970409714097240973409744097540976409774097840979409804098140982409834098440985409864098740988409894099040991409924099340994409954099640997409984099941000410014100241003410044100541006410074100841009410104101141012410134101441015410164101741018410194102041021410224102341024410254102641027410284102941030410314103241033410344103541036410374103841039410404104141042410434104441045410464104741048410494105041051410524105341054410554105641057410584105941060410614106241063410644106541066410674106841069410704107141072410734107441075410764107741078410794108041081410824108341084410854108641087410884108941090410914109241093410944109541096410974109841099411004110141102411034110441105411064110741108411094111041111411124111341114411154111641117411184111941120411214112241123411244112541126411274112841129411304113141132411334113441135411364113741138411394114041141411424114341144411454114641147411484114941150411514115241153411544115541156411574115841159411604116141162411634116441165411664116741168411694117041171411724117341174411754117641177411784117941180411814118241183411844118541186411874118841189411904119141192411934119441195411964119741198411994120041201412024120341204412054120641207412084120941210412114121241213412144121541216412174121841219412204122141222412234122441225412264122741228412294123041231412324123341234412354123641237412384123941240412414124241243412444124541246412474124841249412504125141252412534125441255412564125741258412594126041261412624126341264412654126641267412684126941270412714127241273412744127541276412774127841279412804128141282412834128441285412864128741288412894129041291412924129341294412954129641297412984129941300413014130241303413044130541306413074130841309413104131141312413134131441315413164131741318413194132041321413224132341324413254132641327413284132941330413314133241333413344133541336413374133841339413404134141342413434134441345413464134741348413494135041351413524135341354413554135641357413584135941360413614136241363413644136541366413674136841369413704137141372413734137441375413764137741378413794138041381413824138341384413854138641387413884138941390413914139241393413944139541396413974139841399414004140141402414034140441405414064140741408414094141041411414124141341414414154141641417414184141941420414214142241423414244142541426414274142841429414304143141432414334143441435414364143741438414394144041441414424144341444414454144641447414484144941450414514145241453414544145541456414574145841459414604146141462414634146441465414664146741468414694147041471414724147341474414754147641477414784147941480414814148241483414844148541486414874148841489414904149141492414934149441495414964149741498414994150041501415024150341504415054150641507415084150941510415114151241513415144151541516415174151841519415204152141522415234152441525415264152741528415294153041531415324153341534415354153641537415384153941540415414154241543415444154541546415474154841549415504155141552415534155441555415564155741558415594156041561415624156341564415654156641567415684156941570415714157241573415744157541576415774157841579415804158141582415834158441585415864158741588415894159041591415924159341594415954159641597415984159941600416014160241603416044160541606416074160841609416104161141612416134161441615416164161741618416194162041621416224162341624416254162641627416284162941630416314163241633416344163541636416374163841639416404164141642416434164441645416464164741648416494165041651416524165341654416554165641657416584165941660416614166241663416644166541666416674166841669416704167141672416734167441675416764167741678416794168041681416824168341684416854168641687416884168941690416914169241693416944169541696416974169841699417004170141702417034170441705417064170741708417094171041711417124171341714417154171641717417184171941720417214172241723417244172541726417274172841729417304173141732417334173441735417364173741738417394174041741417424174341744417454174641747417484174941750417514175241753417544175541756417574175841759417604176141762417634176441765417664176741768417694177041771417724177341774417754177641777417784177941780417814178241783417844178541786417874178841789417904179141792417934179441795417964179741798417994180041801418024180341804418054180641807418084180941810418114181241813418144181541816418174181841819418204182141822418234182441825418264182741828418294183041831418324183341834418354183641837418384183941840418414184241843418444184541846418474184841849418504185141852418534185441855418564185741858418594186041861418624186341864418654186641867418684186941870418714187241873418744187541876418774187841879418804188141882418834188441885418864188741888418894189041891418924189341894418954189641897418984189941900419014190241903419044190541906419074190841909419104191141912419134191441915419164191741918419194192041921419224192341924419254192641927419284192941930419314193241933419344193541936419374193841939419404194141942419434194441945419464194741948419494195041951419524195341954419554195641957419584195941960419614196241963419644196541966419674196841969419704197141972419734197441975419764197741978419794198041981419824198341984419854198641987419884198941990419914199241993419944199541996419974199841999420004200142002420034200442005420064200742008420094201042011420124201342014420154201642017420184201942020420214202242023420244202542026420274202842029420304203142032420334203442035420364203742038420394204042041420424204342044420454204642047420484204942050420514205242053420544205542056420574205842059420604206142062420634206442065420664206742068420694207042071420724207342074420754207642077420784207942080420814208242083420844208542086420874208842089420904209142092420934209442095420964209742098420994210042101421024210342104421054210642107421084210942110421114211242113421144211542116421174211842119421204212142122421234212442125421264212742128421294213042131421324213342134421354213642137421384213942140421414214242143421444214542146421474214842149421504215142152421534215442155421564215742158421594216042161421624216342164421654216642167421684216942170421714217242173421744217542176421774217842179421804218142182421834218442185421864218742188421894219042191421924219342194421954219642197421984219942200422014220242203422044220542206422074220842209422104221142212422134221442215422164221742218422194222042221422224222342224422254222642227422284222942230422314223242233422344223542236422374223842239422404224142242422434224442245422464224742248422494225042251422524225342254422554225642257422584225942260422614226242263422644226542266422674226842269422704227142272422734227442275422764227742278422794228042281422824228342284422854228642287422884228942290422914229242293422944229542296422974229842299423004230142302423034230442305423064230742308423094231042311423124231342314423154231642317423184231942320423214232242323423244232542326423274232842329423304233142332423334233442335423364233742338423394234042341423424234342344423454234642347423484234942350423514235242353423544235542356423574235842359423604236142362423634236442365423664236742368423694237042371423724237342374423754237642377423784237942380423814238242383423844238542386423874238842389423904239142392423934239442395423964239742398423994240042401424024240342404424054240642407424084240942410424114241242413424144241542416424174241842419424204242142422424234242442425424264242742428424294243042431424324243342434424354243642437424384243942440424414244242443424444244542446424474244842449424504245142452424534245442455424564245742458424594246042461424624246342464424654246642467424684246942470424714247242473424744247542476424774247842479424804248142482424834248442485424864248742488424894249042491424924249342494424954249642497424984249942500425014250242503425044250542506425074250842509425104251142512425134251442515425164251742518425194252042521425224252342524425254252642527425284252942530425314253242533425344253542536425374253842539425404254142542425434254442545425464254742548425494255042551425524255342554425554255642557425584255942560425614256242563425644256542566425674256842569425704257142572425734257442575425764257742578425794258042581425824258342584425854258642587425884258942590425914259242593425944259542596425974259842599426004260142602426034260442605426064260742608426094261042611426124261342614426154261642617426184261942620426214262242623426244262542626426274262842629426304263142632426334263442635426364263742638426394264042641426424264342644426454264642647426484264942650426514265242653426544265542656426574265842659426604266142662426634266442665426664266742668426694267042671426724267342674426754267642677426784267942680426814268242683426844268542686426874268842689426904269142692426934269442695426964269742698426994270042701427024270342704427054270642707427084270942710427114271242713427144271542716427174271842719427204272142722427234272442725427264272742728427294273042731427324273342734427354273642737427384273942740427414274242743427444274542746427474274842749427504275142752427534275442755427564275742758427594276042761427624276342764427654276642767427684276942770427714277242773427744277542776427774277842779427804278142782427834278442785427864278742788427894279042791427924279342794427954279642797427984279942800428014280242803428044280542806428074280842809428104281142812428134281442815428164281742818428194282042821428224282342824428254282642827428284282942830428314283242833428344283542836428374283842839428404284142842428434284442845428464284742848428494285042851428524285342854428554285642857428584285942860428614286242863428644286542866428674286842869428704287142872428734287442875428764287742878428794288042881428824288342884428854288642887428884288942890428914289242893428944289542896428974289842899429004290142902429034290442905429064290742908429094291042911429124291342914429154291642917429184291942920429214292242923429244292542926429274292842929429304293142932429334293442935429364293742938429394294042941429424294342944429454294642947429484294942950429514295242953429544295542956429574295842959429604296142962429634296442965429664296742968429694297042971429724297342974429754297642977429784297942980429814298242983429844298542986429874298842989429904299142992429934299442995429964299742998429994300043001430024300343004430054300643007430084300943010430114301243013430144301543016430174301843019430204302143022430234302443025430264302743028430294303043031430324303343034430354303643037430384303943040430414304243043430444304543046430474304843049430504305143052430534305443055430564305743058430594306043061430624306343064430654306643067430684306943070430714307243073430744307543076430774307843079430804308143082430834308443085430864308743088430894309043091430924309343094430954309643097430984309943100431014310243103431044310543106431074310843109431104311143112431134311443115431164311743118431194312043121431224312343124431254312643127431284312943130431314313243133431344313543136431374313843139431404314143142431434314443145431464314743148431494315043151431524315343154431554315643157431584315943160431614316243163431644316543166431674316843169431704317143172431734317443175431764317743178431794318043181431824318343184431854318643187431884318943190431914319243193431944319543196431974319843199432004320143202432034320443205432064320743208432094321043211432124321343214432154321643217432184321943220432214322243223432244322543226432274322843229432304323143232432334323443235432364323743238432394324043241432424324343244432454324643247432484324943250432514325243253432544325543256432574325843259432604326143262432634326443265432664326743268432694327043271432724327343274432754327643277432784327943280432814328243283432844328543286432874328843289432904329143292432934329443295432964329743298432994330043301433024330343304433054330643307433084330943310433114331243313433144331543316433174331843319433204332143322433234332443325433264332743328433294333043331433324333343334433354333643337433384333943340433414334243343433444334543346433474334843349433504335143352433534335443355433564335743358433594336043361433624336343364433654336643367433684336943370433714337243373433744337543376433774337843379433804338143382433834338443385433864338743388433894339043391433924339343394433954339643397433984339943400434014340243403434044340543406434074340843409434104341143412434134341443415434164341743418434194342043421434224342343424434254342643427434284342943430434314343243433434344343543436434374343843439434404344143442434434344443445434464344743448434494345043451434524345343454434554345643457434584345943460434614346243463434644346543466434674346843469434704347143472434734347443475434764347743478434794348043481434824348343484434854348643487434884348943490434914349243493434944349543496434974349843499435004350143502435034350443505435064350743508435094351043511435124351343514435154351643517435184351943520435214352243523435244352543526435274352843529435304353143532435334353443535435364353743538435394354043541435424354343544435454354643547435484354943550435514355243553435544355543556435574355843559435604356143562435634356443565435664356743568435694357043571435724357343574435754357643577435784357943580435814358243583435844358543586435874358843589435904359143592435934359443595435964359743598435994360043601436024360343604436054360643607436084360943610436114361243613436144361543616436174361843619436204362143622436234362443625436264362743628436294363043631436324363343634436354363643637436384363943640436414364243643436444364543646436474364843649436504365143652436534365443655436564365743658436594366043661436624366343664436654366643667436684366943670436714367243673436744367543676436774367843679436804368143682436834368443685436864368743688436894369043691436924369343694436954369643697436984369943700437014370243703437044370543706437074370843709437104371143712437134371443715437164371743718437194372043721437224372343724437254372643727437284372943730437314373243733437344373543736437374373843739437404374143742437434374443745437464374743748437494375043751437524375343754437554375643757437584375943760437614376243763437644376543766437674376843769437704377143772437734377443775437764377743778437794378043781437824378343784437854378643787437884378943790437914379243793437944379543796437974379843799438004380143802438034380443805438064380743808438094381043811438124381343814438154381643817438184381943820438214382243823438244382543826438274382843829438304383143832438334383443835438364383743838438394384043841438424384343844438454384643847438484384943850438514385243853438544385543856438574385843859438604386143862438634386443865438664386743868438694387043871438724387343874438754387643877438784387943880438814388243883438844388543886438874388843889438904389143892438934389443895438964389743898438994390043901439024390343904439054390643907439084390943910439114391243913439144391543916439174391843919439204392143922439234392443925439264392743928439294393043931439324393343934439354393643937439384393943940439414394243943439444394543946439474394843949439504395143952439534395443955439564395743958439594396043961439624396343964439654396643967439684396943970439714397243973439744397543976439774397843979439804398143982439834398443985439864398743988439894399043991439924399343994439954399643997439984399944000440014400244003440044400544006440074400844009440104401144012440134401444015440164401744018440194402044021440224402344024440254402644027440284402944030440314403244033440344403544036440374403844039440404404144042440434404444045440464404744048440494405044051440524405344054440554405644057440584405944060440614406244063440644406544066440674406844069440704407144072440734407444075440764407744078440794408044081440824408344084440854408644087440884408944090440914409244093440944409544096440974409844099441004410144102441034410444105441064410744108441094411044111441124411344114441154411644117441184411944120441214412244123441244412544126441274412844129441304413144132441334413444135441364413744138441394414044141441424414344144441454414644147441484414944150441514415244153441544415544156441574415844159441604416144162441634416444165441664416744168441694417044171441724417344174441754417644177441784417944180441814418244183441844418544186441874418844189441904419144192441934419444195441964419744198441994420044201442024420344204442054420644207442084420944210442114421244213442144421544216442174421844219442204422144222442234422444225442264422744228442294423044231442324423344234442354423644237442384423944240442414424244243442444424544246442474424844249442504425144252442534425444255442564425744258442594426044261442624426344264442654426644267442684426944270442714427244273442744427544276442774427844279442804428144282442834428444285442864428744288442894429044291442924429344294442954429644297442984429944300443014430244303443044430544306443074430844309443104431144312443134431444315443164431744318443194432044321443224432344324443254432644327443284432944330443314433244333443344433544336443374433844339443404434144342443434434444345443464434744348443494435044351443524435344354443554435644357443584435944360443614436244363443644436544366443674436844369443704437144372443734437444375443764437744378443794438044381443824438344384443854438644387443884438944390443914439244393443944439544396443974439844399444004440144402444034440444405444064440744408444094441044411444124441344414444154441644417444184441944420444214442244423444244442544426444274442844429444304443144432444334443444435444364443744438444394444044441444424444344444444454444644447444484444944450444514445244453444544445544456444574445844459444604446144462444634446444465444664446744468444694447044471444724447344474444754447644477444784447944480444814448244483444844448544486444874448844489444904449144492444934449444495444964449744498444994450044501445024450344504445054450644507445084450944510445114451244513445144451544516445174451844519445204452144522445234452444525445264452744528445294453044531445324453344534445354453644537445384453944540445414454244543445444454544546445474454844549445504455144552445534455444555445564455744558445594456044561445624456344564445654456644567445684456944570445714457244573445744457544576445774457844579445804458144582445834458444585445864458744588445894459044591445924459344594445954459644597445984459944600446014460244603446044460544606446074460844609446104461144612446134461444615446164461744618446194462044621446224462344624446254462644627446284462944630446314463244633446344463544636446374463844639446404464144642446434464444645446464464744648446494465044651446524465344654446554465644657446584465944660446614466244663446644466544666446674466844669446704467144672446734467444675446764467744678446794468044681446824468344684446854468644687446884468944690446914469244693446944469544696446974469844699447004470144702447034470444705447064470744708447094471044711447124471344714447154471644717447184471944720447214472244723447244472544726447274472844729447304473144732447334473444735447364473744738447394474044741447424474344744447454474644747447484474944750447514475244753447544475544756447574475844759447604476144762447634476444765447664476744768447694477044771447724477344774447754477644777447784477944780447814478244783447844478544786447874478844789447904479144792447934479444795447964479744798447994480044801448024480344804448054480644807448084480944810448114481244813448144481544816448174481844819448204482144822448234482444825448264482744828448294483044831448324483344834448354483644837448384483944840448414484244843448444484544846448474484844849448504485144852448534485444855448564485744858448594486044861448624486344864448654486644867448684486944870448714487244873448744487544876448774487844879448804488144882448834488444885448864488744888448894489044891448924489344894448954489644897448984489944900449014490244903449044490544906449074490844909449104491144912449134491444915449164491744918449194492044921449224492344924449254492644927449284492944930449314493244933449344493544936449374493844939449404494144942449434494444945449464494744948449494495044951449524495344954449554495644957449584495944960449614496244963449644496544966449674496844969449704497144972449734497444975449764497744978449794498044981449824498344984449854498644987449884498944990449914499244993449944499544996449974499844999450004500145002450034500445005450064500745008450094501045011450124501345014450154501645017450184501945020450214502245023450244502545026450274502845029450304503145032450334503445035450364503745038450394504045041450424504345044450454504645047450484504945050450514505245053450544505545056450574505845059450604506145062450634506445065450664506745068450694507045071450724507345074450754507645077450784507945080450814508245083450844508545086450874508845089450904509145092450934509445095450964509745098450994510045101451024510345104451054510645107451084510945110451114511245113451144511545116451174511845119451204512145122451234512445125451264512745128451294513045131451324513345134451354513645137451384513945140451414514245143451444514545146451474514845149451504515145152451534515445155451564515745158451594516045161451624516345164451654516645167451684516945170451714517245173451744517545176451774517845179451804518145182451834518445185451864518745188451894519045191451924519345194451954519645197451984519945200452014520245203452044520545206452074520845209452104521145212452134521445215452164521745218452194522045221452224522345224452254522645227452284522945230452314523245233452344523545236452374523845239452404524145242452434524445245452464524745248452494525045251452524525345254452554525645257452584525945260452614526245263452644526545266452674526845269452704527145272452734527445275452764527745278452794528045281452824528345284452854528645287452884528945290452914529245293452944529545296452974529845299453004530145302453034530445305453064530745308453094531045311453124531345314453154531645317453184531945320453214532245323453244532545326453274532845329453304533145332453334533445335453364533745338453394534045341453424534345344453454534645347453484534945350453514535245353453544535545356453574535845359453604536145362453634536445365453664536745368453694537045371453724537345374453754537645377453784537945380453814538245383453844538545386453874538845389453904539145392453934539445395453964539745398453994540045401454024540345404454054540645407454084540945410454114541245413454144541545416454174541845419454204542145422454234542445425454264542745428454294543045431454324543345434454354543645437454384543945440454414544245443454444544545446454474544845449454504545145452454534545445455454564545745458454594546045461454624546345464454654546645467454684546945470454714547245473454744547545476454774547845479454804548145482454834548445485454864548745488454894549045491454924549345494454954549645497454984549945500455014550245503455044550545506455074550845509455104551145512455134551445515455164551745518455194552045521455224552345524455254552645527455284552945530455314553245533455344553545536455374553845539455404554145542455434554445545455464554745548455494555045551455524555345554455554555645557455584555945560455614556245563455644556545566455674556845569455704557145572455734557445575455764557745578455794558045581455824558345584455854558645587455884558945590455914559245593455944559545596455974559845599456004560145602456034560445605456064560745608456094561045611456124561345614456154561645617456184561945620456214562245623456244562545626456274562845629456304563145632456334563445635456364563745638456394564045641456424564345644456454564645647456484564945650456514565245653456544565545656456574565845659456604566145662456634566445665456664566745668456694567045671456724567345674456754567645677456784567945680456814568245683456844568545686456874568845689456904569145692456934569445695456964569745698456994570045701457024570345704457054570645707457084570945710457114571245713457144571545716457174571845719457204572145722457234572445725457264572745728457294573045731457324573345734457354573645737457384573945740457414574245743457444574545746457474574845749457504575145752457534575445755457564575745758457594576045761457624576345764457654576645767457684576945770457714577245773457744577545776457774577845779457804578145782457834578445785457864578745788457894579045791457924579345794457954579645797457984579945800458014580245803458044580545806458074580845809458104581145812458134581445815458164581745818458194582045821458224582345824458254582645827458284582945830458314583245833458344583545836458374583845839458404584145842458434584445845458464584745848458494585045851458524585345854458554585645857458584585945860458614586245863458644586545866458674586845869458704587145872458734587445875458764587745878458794588045881458824588345884458854588645887458884588945890458914589245893458944589545896458974589845899459004590145902459034590445905459064590745908459094591045911459124591345914459154591645917459184591945920459214592245923459244592545926459274592845929459304593145932459334593445935459364593745938459394594045941459424594345944459454594645947459484594945950459514595245953459544595545956459574595845959459604596145962459634596445965459664596745968459694597045971459724597345974459754597645977459784597945980459814598245983459844598545986459874598845989459904599145992459934599445995459964599745998459994600046001460024600346004460054600646007460084600946010460114601246013460144601546016460174601846019460204602146022460234602446025460264602746028460294603046031460324603346034460354603646037460384603946040460414604246043460444604546046460474604846049460504605146052460534605446055460564605746058460594606046061460624606346064460654606646067460684606946070460714607246073460744607546076460774607846079460804608146082460834608446085460864608746088460894609046091460924609346094460954609646097460984609946100461014610246103461044610546106461074610846109461104611146112461134611446115461164611746118461194612046121461224612346124461254612646127461284612946130461314613246133461344613546136461374613846139461404614146142461434614446145461464614746148461494615046151461524615346154461554615646157461584615946160461614616246163461644616546166461674616846169461704617146172461734617446175461764617746178461794618046181461824618346184461854618646187461884618946190461914619246193461944619546196461974619846199462004620146202462034620446205462064620746208462094621046211462124621346214462154621646217462184621946220462214622246223462244622546226462274622846229462304623146232462334623446235462364623746238462394624046241462424624346244462454624646247462484624946250462514625246253462544625546256462574625846259462604626146262462634626446265462664626746268462694627046271462724627346274462754627646277462784627946280462814628246283462844628546286462874628846289462904629146292462934629446295462964629746298462994630046301463024630346304463054630646307463084630946310463114631246313463144631546316463174631846319463204632146322463234632446325463264632746328463294633046331463324633346334463354633646337463384633946340463414634246343463444634546346463474634846349463504635146352463534635446355463564635746358463594636046361463624636346364463654636646367463684636946370463714637246373463744637546376463774637846379463804638146382463834638446385463864638746388463894639046391463924639346394463954639646397463984639946400464014640246403464044640546406464074640846409464104641146412464134641446415464164641746418464194642046421464224642346424464254642646427464284642946430464314643246433464344643546436464374643846439464404644146442464434644446445464464644746448464494645046451464524645346454464554645646457464584645946460464614646246463464644646546466464674646846469464704647146472464734647446475464764647746478464794648046481464824648346484464854648646487464884648946490464914649246493464944649546496464974649846499465004650146502465034650446505465064650746508465094651046511465124651346514465154651646517465184651946520465214652246523465244652546526465274652846529465304653146532465334653446535465364653746538465394654046541465424654346544465454654646547465484654946550465514655246553465544655546556465574655846559465604656146562465634656446565465664656746568465694657046571465724657346574465754657646577465784657946580465814658246583465844658546586465874658846589465904659146592465934659446595465964659746598465994660046601466024660346604466054660646607466084660946610466114661246613466144661546616466174661846619466204662146622466234662446625466264662746628466294663046631466324663346634466354663646637466384663946640466414664246643466444664546646466474664846649466504665146652466534665446655466564665746658466594666046661466624666346664466654666646667466684666946670466714667246673466744667546676466774667846679466804668146682466834668446685466864668746688466894669046691466924669346694466954669646697466984669946700467014670246703467044670546706467074670846709467104671146712467134671446715467164671746718467194672046721467224672346724467254672646727467284672946730467314673246733467344673546736467374673846739467404674146742467434674446745467464674746748467494675046751467524675346754467554675646757467584675946760467614676246763467644676546766467674676846769467704677146772467734677446775467764677746778467794678046781467824678346784467854678646787467884678946790467914679246793467944679546796467974679846799468004680146802468034680446805468064680746808468094681046811468124681346814468154681646817468184681946820468214682246823468244682546826468274682846829468304683146832468334683446835468364683746838468394684046841468424684346844468454684646847468484684946850468514685246853468544685546856468574685846859468604686146862468634686446865468664686746868468694687046871468724687346874468754687646877468784687946880468814688246883468844688546886468874688846889468904689146892468934689446895468964689746898468994690046901469024690346904469054690646907469084690946910469114691246913469144691546916469174691846919469204692146922469234692446925469264692746928469294693046931469324693346934469354693646937469384693946940469414694246943469444694546946469474694846949469504695146952469534695446955469564695746958469594696046961469624696346964469654696646967469684696946970469714697246973469744697546976469774697846979469804698146982469834698446985469864698746988469894699046991469924699346994469954699646997469984699947000470014700247003470044700547006470074700847009470104701147012470134701447015470164701747018470194702047021470224702347024470254702647027470284702947030470314703247033470344703547036470374703847039470404704147042470434704447045470464704747048470494705047051470524705347054470554705647057470584705947060470614706247063470644706547066470674706847069470704707147072470734707447075470764707747078470794708047081470824708347084470854708647087470884708947090470914709247093470944709547096470974709847099471004710147102471034710447105471064710747108471094711047111471124711347114471154711647117471184711947120471214712247123471244712547126471274712847129471304713147132471334713447135471364713747138471394714047141471424714347144471454714647147471484714947150471514715247153471544715547156471574715847159471604716147162471634716447165471664716747168471694717047171471724717347174471754717647177471784717947180471814718247183471844718547186471874718847189471904719147192471934719447195471964719747198471994720047201472024720347204472054720647207472084720947210472114721247213472144721547216472174721847219472204722147222472234722447225472264722747228472294723047231472324723347234472354723647237472384723947240472414724247243472444724547246472474724847249472504725147252472534725447255472564725747258472594726047261472624726347264472654726647267472684726947270472714727247273472744727547276472774727847279472804728147282472834728447285472864728747288472894729047291472924729347294472954729647297472984729947300473014730247303473044730547306473074730847309473104731147312473134731447315473164731747318473194732047321473224732347324473254732647327473284732947330473314733247333473344733547336473374733847339473404734147342473434734447345473464734747348473494735047351473524735347354473554735647357473584735947360473614736247363473644736547366473674736847369473704737147372473734737447375473764737747378473794738047381473824738347384473854738647387473884738947390473914739247393473944739547396473974739847399474004740147402474034740447405474064740747408474094741047411474124741347414474154741647417474184741947420474214742247423474244742547426474274742847429474304743147432474334743447435474364743747438474394744047441474424744347444474454744647447474484744947450474514745247453474544745547456474574745847459474604746147462474634746447465474664746747468474694747047471474724747347474474754747647477474784747947480474814748247483474844748547486474874748847489474904749147492474934749447495474964749747498474994750047501475024750347504475054750647507475084750947510475114751247513475144751547516475174751847519475204752147522475234752447525475264752747528475294753047531475324753347534475354753647537475384753947540475414754247543475444754547546475474754847549475504755147552475534755447555475564755747558475594756047561475624756347564475654756647567475684756947570475714757247573475744757547576475774757847579475804758147582475834758447585475864758747588475894759047591475924759347594475954759647597475984759947600476014760247603476044760547606476074760847609476104761147612476134761447615476164761747618476194762047621476224762347624476254762647627476284762947630476314763247633476344763547636476374763847639476404764147642476434764447645476464764747648476494765047651476524765347654476554765647657476584765947660476614766247663476644766547666476674766847669476704767147672476734767447675476764767747678476794768047681476824768347684476854768647687476884768947690476914769247693476944769547696476974769847699477004770147702477034770447705477064770747708477094771047711477124771347714477154771647717477184771947720477214772247723477244772547726477274772847729477304773147732477334773447735477364773747738477394774047741477424774347744477454774647747477484774947750477514775247753477544775547756477574775847759477604776147762477634776447765477664776747768477694777047771477724777347774477754777647777477784777947780477814778247783477844778547786477874778847789477904779147792477934779447795477964779747798477994780047801478024780347804478054780647807478084780947810478114781247813478144781547816478174781847819478204782147822478234782447825478264782747828478294783047831478324783347834478354783647837478384783947840478414784247843478444784547846478474784847849478504785147852478534785447855478564785747858478594786047861478624786347864478654786647867478684786947870478714787247873478744787547876478774787847879478804788147882478834788447885478864788747888478894789047891478924789347894478954789647897478984789947900479014790247903479044790547906479074790847909479104791147912479134791447915479164791747918479194792047921479224792347924479254792647927479284792947930479314793247933479344793547936479374793847939479404794147942479434794447945479464794747948479494795047951479524795347954479554795647957479584795947960479614796247963479644796547966479674796847969479704797147972479734797447975479764797747978479794798047981479824798347984479854798647987479884798947990479914799247993479944799547996479974799847999480004800148002480034800448005480064800748008480094801048011480124801348014480154801648017480184801948020480214802248023480244802548026480274802848029480304803148032480334803448035480364803748038480394804048041480424804348044480454804648047480484804948050480514805248053480544805548056480574805848059480604806148062480634806448065480664806748068480694807048071480724807348074480754807648077480784807948080480814808248083480844808548086480874808848089480904809148092480934809448095480964809748098480994810048101481024810348104481054810648107481084810948110481114811248113481144811548116481174811848119481204812148122481234812448125481264812748128481294813048131481324813348134481354813648137481384813948140481414814248143481444814548146481474814848149481504815148152481534815448155481564815748158481594816048161481624816348164481654816648167481684816948170481714817248173481744817548176481774817848179481804818148182481834818448185481864818748188481894819048191481924819348194481954819648197481984819948200482014820248203482044820548206482074820848209482104821148212482134821448215482164821748218482194822048221482224822348224482254822648227482284822948230482314823248233482344823548236482374823848239482404824148242482434824448245482464824748248482494825048251482524825348254482554825648257482584825948260482614826248263482644826548266482674826848269482704827148272482734827448275482764827748278482794828048281482824828348284482854828648287482884828948290482914829248293482944829548296482974829848299483004830148302483034830448305483064830748308483094831048311483124831348314483154831648317483184831948320483214832248323483244832548326483274832848329483304833148332483334833448335483364833748338483394834048341483424834348344483454834648347483484834948350483514835248353483544835548356483574835848359483604836148362483634836448365483664836748368483694837048371483724837348374483754837648377483784837948380483814838248383483844838548386483874838848389483904839148392483934839448395483964839748398483994840048401484024840348404484054840648407484084840948410484114841248413484144841548416484174841848419484204842148422484234842448425484264842748428484294843048431484324843348434484354843648437484384843948440484414844248443484444844548446484474844848449484504845148452484534845448455484564845748458484594846048461484624846348464484654846648467484684846948470484714847248473484744847548476484774847848479484804848148482484834848448485484864848748488484894849048491484924849348494484954849648497484984849948500485014850248503485044850548506485074850848509485104851148512485134851448515485164851748518485194852048521485224852348524485254852648527485284852948530485314853248533485344853548536485374853848539485404854148542485434854448545485464854748548485494855048551485524855348554485554855648557485584855948560485614856248563485644856548566485674856848569485704857148572485734857448575485764857748578485794858048581485824858348584485854858648587485884858948590485914859248593485944859548596485974859848599486004860148602486034860448605486064860748608486094861048611486124861348614486154861648617486184861948620486214862248623486244862548626486274862848629486304863148632486334863448635486364863748638486394864048641486424864348644486454864648647486484864948650486514865248653486544865548656486574865848659486604866148662486634866448665486664866748668486694867048671486724867348674486754867648677486784867948680486814868248683486844868548686486874868848689486904869148692486934869448695486964869748698486994870048701487024870348704487054870648707487084870948710487114871248713487144871548716487174871848719487204872148722487234872448725487264872748728487294873048731487324873348734487354873648737487384873948740487414874248743487444874548746487474874848749487504875148752487534875448755487564875748758487594876048761487624876348764487654876648767487684876948770487714877248773487744877548776487774877848779487804878148782487834878448785487864878748788487894879048791487924879348794487954879648797487984879948800488014880248803488044880548806488074880848809488104881148812488134881448815488164881748818488194882048821488224882348824488254882648827488284882948830488314883248833488344883548836488374883848839488404884148842488434884448845488464884748848488494885048851488524885348854488554885648857488584885948860488614886248863488644886548866488674886848869488704887148872488734887448875488764887748878488794888048881488824888348884488854888648887488884888948890488914889248893488944889548896488974889848899489004890148902489034890448905489064890748908489094891048911489124891348914489154891648917489184891948920489214892248923489244892548926489274892848929489304893148932489334893448935489364893748938489394894048941489424894348944489454894648947489484894948950489514895248953489544895548956489574895848959489604896148962489634896448965489664896748968489694897048971489724897348974489754897648977489784897948980489814898248983489844898548986489874898848989489904899148992489934899448995489964899748998489994900049001490024900349004490054900649007490084900949010490114901249013490144901549016490174901849019490204902149022490234902449025490264902749028490294903049031490324903349034490354903649037490384903949040490414904249043490444904549046490474904849049490504905149052490534905449055490564905749058490594906049061490624906349064490654906649067490684906949070490714907249073490744907549076490774907849079490804908149082490834908449085490864908749088490894909049091490924909349094490954909649097490984909949100491014910249103491044910549106491074910849109491104911149112491134911449115491164911749118491194912049121491224912349124491254912649127491284912949130491314913249133491344913549136491374913849139491404914149142491434914449145491464914749148491494915049151491524915349154491554915649157491584915949160491614916249163491644916549166491674916849169491704917149172491734917449175491764917749178491794918049181491824918349184491854918649187491884918949190491914919249193491944919549196491974919849199492004920149202492034920449205492064920749208492094921049211492124921349214492154921649217492184921949220492214922249223492244922549226492274922849229492304923149232492334923449235492364923749238492394924049241492424924349244492454924649247492484924949250492514925249253492544925549256492574925849259492604926149262492634926449265492664926749268492694927049271492724927349274492754927649277492784927949280492814928249283492844928549286492874928849289492904929149292492934929449295492964929749298492994930049301493024930349304493054930649307493084930949310493114931249313493144931549316493174931849319493204932149322493234932449325493264932749328493294933049331493324933349334493354933649337493384933949340493414934249343493444934549346493474934849349493504935149352493534935449355493564935749358493594936049361493624936349364493654936649367493684936949370493714937249373493744937549376493774937849379493804938149382493834938449385493864938749388493894939049391493924939349394493954939649397493984939949400494014940249403494044940549406494074940849409494104941149412494134941449415494164941749418494194942049421494224942349424494254942649427494284942949430494314943249433494344943549436494374943849439494404944149442494434944449445494464944749448494494945049451494524945349454494554945649457494584945949460494614946249463494644946549466494674946849469494704947149472494734947449475494764947749478494794948049481494824948349484494854948649487494884948949490494914949249493494944949549496494974949849499495004950149502495034950449505495064950749508495094951049511495124951349514495154951649517495184951949520495214952249523495244952549526495274952849529495304953149532495334953449535495364953749538495394954049541495424954349544495454954649547495484954949550495514955249553495544955549556495574955849559495604956149562495634956449565495664956749568495694957049571495724957349574495754957649577495784957949580495814958249583495844958549586495874958849589495904959149592495934959449595495964959749598495994960049601496024960349604496054960649607496084960949610496114961249613496144961549616496174961849619496204962149622496234962449625496264962749628496294963049631496324963349634496354963649637496384963949640496414964249643496444964549646496474964849649496504965149652496534965449655496564965749658496594966049661496624966349664496654966649667496684966949670496714967249673496744967549676496774967849679496804968149682496834968449685496864968749688496894969049691496924969349694496954969649697496984969949700497014970249703497044970549706497074970849709497104971149712497134971449715497164971749718497194972049721497224972349724497254972649727497284972949730497314973249733497344973549736497374973849739497404974149742497434974449745497464974749748497494975049751497524975349754497554975649757497584975949760497614976249763497644976549766497674976849769497704977149772497734977449775497764977749778497794978049781497824978349784497854978649787497884978949790497914979249793497944979549796497974979849799498004980149802498034980449805498064980749808498094981049811498124981349814498154981649817498184981949820498214982249823498244982549826498274982849829498304983149832498334983449835498364983749838498394984049841498424984349844498454984649847498484984949850498514985249853498544985549856498574985849859498604986149862498634986449865498664986749868498694987049871498724987349874498754987649877498784987949880498814988249883498844988549886498874988849889498904989149892498934989449895498964989749898498994990049901499024990349904499054990649907499084990949910499114991249913499144991549916499174991849919499204992149922499234992449925499264992749928499294993049931499324993349934499354993649937499384993949940499414994249943499444994549946499474994849949499504995149952499534995449955499564995749958499594996049961499624996349964499654996649967499684996949970499714997249973499744997549976499774997849979499804998149982499834998449985499864998749988499894999049991499924999349994499954999649997499984999950000500015000250003500045000550006500075000850009500105001150012500135001450015500165001750018500195002050021500225002350024500255002650027500285002950030500315003250033500345003550036500375003850039500405004150042500435004450045500465004750048500495005050051500525005350054500555005650057500585005950060500615006250063500645006550066500675006850069500705007150072500735007450075500765007750078500795008050081500825008350084500855008650087500885008950090500915009250093500945009550096500975009850099501005010150102501035010450105501065010750108501095011050111501125011350114501155011650117501185011950120501215012250123501245012550126501275012850129501305013150132501335013450135501365013750138501395014050141501425014350144501455014650147501485014950150501515015250153501545015550156501575015850159501605016150162501635016450165501665016750168501695017050171501725017350174501755017650177501785017950180501815018250183501845018550186501875018850189501905019150192501935019450195501965019750198501995020050201502025020350204502055020650207502085020950210502115021250213502145021550216502175021850219502205022150222502235022450225502265022750228502295023050231502325023350234502355023650237502385023950240502415024250243502445024550246502475024850249502505025150252502535025450255502565025750258502595026050261502625026350264502655026650267502685026950270502715027250273502745027550276502775027850279502805028150282502835028450285502865028750288502895029050291502925029350294502955029650297502985029950300503015030250303503045030550306503075030850309503105031150312503135031450315503165031750318503195032050321503225032350324503255032650327503285032950330503315033250333503345033550336503375033850339503405034150342503435034450345503465034750348503495035050351503525035350354503555035650357503585035950360503615036250363503645036550366503675036850369503705037150372503735037450375503765037750378503795038050381503825038350384503855038650387503885038950390503915039250393503945039550396503975039850399504005040150402504035040450405504065040750408504095041050411504125041350414504155041650417504185041950420504215042250423504245042550426504275042850429504305043150432504335043450435504365043750438504395044050441504425044350444504455044650447504485044950450504515045250453504545045550456504575045850459504605046150462504635046450465504665046750468504695047050471504725047350474504755047650477504785047950480504815048250483504845048550486504875048850489504905049150492504935049450495504965049750498504995050050501505025050350504505055050650507505085050950510505115051250513505145051550516505175051850519505205052150522505235052450525505265052750528505295053050531505325053350534505355053650537505385053950540505415054250543505445054550546505475054850549505505055150552505535055450555505565055750558505595056050561505625056350564505655056650567505685056950570505715057250573505745057550576505775057850579505805058150582505835058450585505865058750588505895059050591505925059350594505955059650597505985059950600506015060250603506045060550606506075060850609506105061150612506135061450615506165061750618506195062050621506225062350624506255062650627506285062950630506315063250633506345063550636506375063850639506405064150642506435064450645506465064750648506495065050651506525065350654506555065650657506585065950660506615066250663506645066550666506675066850669506705067150672506735067450675506765067750678506795068050681506825068350684506855068650687506885068950690506915069250693506945069550696506975069850699507005070150702507035070450705507065070750708507095071050711507125071350714507155071650717507185071950720507215072250723507245072550726507275072850729507305073150732507335073450735507365073750738507395074050741507425074350744507455074650747507485074950750507515075250753507545075550756507575075850759507605076150762507635076450765507665076750768507695077050771507725077350774507755077650777507785077950780507815078250783507845078550786507875078850789507905079150792507935079450795507965079750798507995080050801508025080350804508055080650807508085080950810508115081250813508145081550816508175081850819508205082150822508235082450825508265082750828508295083050831508325083350834508355083650837508385083950840508415084250843508445084550846508475084850849508505085150852508535085450855508565085750858508595086050861508625086350864508655086650867508685086950870508715087250873508745087550876508775087850879508805088150882508835088450885508865088750888508895089050891508925089350894508955089650897508985089950900509015090250903509045090550906509075090850909509105091150912509135091450915509165091750918509195092050921509225092350924509255092650927509285092950930509315093250933509345093550936509375093850939509405094150942509435094450945509465094750948509495095050951509525095350954509555095650957509585095950960509615096250963509645096550966509675096850969509705097150972509735097450975509765097750978509795098050981509825098350984509855098650987509885098950990509915099250993509945099550996509975099850999510005100151002510035100451005510065100751008510095101051011510125101351014510155101651017510185101951020510215102251023510245102551026510275102851029510305103151032510335103451035510365103751038510395104051041510425104351044510455104651047510485104951050510515105251053510545105551056510575105851059510605106151062510635106451065510665106751068510695107051071510725107351074510755107651077510785107951080510815108251083510845108551086510875108851089510905109151092510935109451095510965109751098510995110051101511025110351104511055110651107511085110951110511115111251113511145111551116511175111851119511205112151122511235112451125511265112751128511295113051131511325113351134511355113651137511385113951140511415114251143511445114551146511475114851149511505115151152511535115451155511565115751158511595116051161511625116351164511655116651167511685116951170511715117251173511745117551176511775117851179511805118151182511835118451185511865118751188511895119051191511925119351194511955119651197511985119951200512015120251203512045120551206512075120851209512105121151212512135121451215512165121751218512195122051221512225122351224512255122651227512285122951230512315123251233512345123551236512375123851239512405124151242512435124451245512465124751248512495125051251512525125351254512555125651257512585125951260512615126251263512645126551266512675126851269512705127151272512735127451275512765127751278512795128051281512825128351284512855128651287512885128951290512915129251293512945129551296512975129851299513005130151302513035130451305513065130751308513095131051311513125131351314513155131651317513185131951320513215132251323513245132551326513275132851329513305133151332513335133451335513365133751338513395134051341513425134351344513455134651347513485134951350513515135251353513545135551356513575135851359513605136151362513635136451365513665136751368513695137051371513725137351374513755137651377513785137951380513815138251383513845138551386513875138851389513905139151392513935139451395513965139751398513995140051401514025140351404514055140651407514085140951410514115141251413514145141551416514175141851419514205142151422514235142451425514265142751428514295143051431514325143351434514355143651437514385143951440514415144251443514445144551446514475144851449514505145151452514535145451455514565145751458514595146051461514625146351464514655146651467514685146951470514715147251473514745147551476514775147851479514805148151482514835148451485514865148751488514895149051491514925149351494514955149651497514985149951500515015150251503515045150551506515075150851509515105151151512515135151451515515165151751518515195152051521515225152351524515255152651527515285152951530515315153251533515345153551536515375153851539515405154151542515435154451545515465154751548515495155051551515525155351554515555155651557515585155951560515615156251563515645156551566515675156851569515705157151572515735157451575515765157751578515795158051581515825158351584515855158651587515885158951590515915159251593515945159551596515975159851599516005160151602516035160451605516065160751608516095161051611516125161351614516155161651617516185161951620516215162251623516245162551626516275162851629516305163151632516335163451635516365163751638516395164051641516425164351644516455164651647516485164951650516515165251653516545165551656516575165851659516605166151662516635166451665516665166751668516695167051671516725167351674516755167651677516785167951680516815168251683516845168551686516875168851689516905169151692516935169451695516965169751698516995170051701517025170351704517055170651707517085170951710517115171251713517145171551716517175171851719517205172151722517235172451725517265172751728517295173051731517325173351734517355173651737517385173951740517415174251743517445174551746517475174851749517505175151752517535175451755517565175751758517595176051761517625176351764517655176651767517685176951770517715177251773517745177551776517775177851779517805178151782517835178451785517865178751788517895179051791517925179351794517955179651797517985179951800518015180251803518045180551806518075180851809518105181151812518135181451815518165181751818518195182051821518225182351824518255182651827518285182951830518315183251833518345183551836518375183851839518405184151842518435184451845518465184751848518495185051851518525185351854518555185651857518585185951860518615186251863518645186551866518675186851869518705187151872518735187451875518765187751878518795188051881518825188351884518855188651887518885188951890518915189251893518945189551896518975189851899519005190151902519035190451905519065190751908519095191051911519125191351914519155191651917519185191951920519215192251923519245192551926
  1. // modules are defined as an array
  2. // [ module function, map of requires ]
  3. //
  4. // map of requires is short require name -> numeric require
  5. //
  6. // anything defined in a previous bundle is accessed via the
  7. // orig method which is the require for previous bundles
  8. // eslint-disable-next-line no-global-assign
  9. parcelRequire = (function (modules, cache, entry, globalName) {
  10. // Save the require from previous bundle to this closure if any
  11. var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
  12. var nodeRequire = typeof require === 'function' && require;
  13. function newRequire(name, jumped) {
  14. if (!cache[name]) {
  15. if (!modules[name]) {
  16. // if we cannot find the module within our internal map or
  17. // cache jump to the current global require ie. the last bundle
  18. // that was added to the page.
  19. var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
  20. if (!jumped && currentRequire) {
  21. return currentRequire(name, true);
  22. }
  23. // If there are other bundles on this page the require from the
  24. // previous one is saved to 'previousRequire'. Repeat this as
  25. // many times as there are bundles until the module is found or
  26. // we exhaust the require chain.
  27. if (previousRequire) {
  28. return previousRequire(name, true);
  29. }
  30. // Try the node require function if it exists.
  31. if (nodeRequire && typeof name === 'string') {
  32. return nodeRequire(name);
  33. }
  34. var err = new Error('Cannot find module \'' + name + '\'');
  35. err.code = 'MODULE_NOT_FOUND';
  36. throw err;
  37. }
  38. localRequire.resolve = resolve;
  39. var module = cache[name] = new newRequire.Module(name);
  40. modules[name][0].call(module.exports, localRequire, module, module.exports, this);
  41. }
  42. return cache[name].exports;
  43. function localRequire(x){
  44. return newRequire(localRequire.resolve(x));
  45. }
  46. function resolve(x){
  47. return modules[name][1][x] || x;
  48. }
  49. }
  50. function Module(moduleName) {
  51. this.id = moduleName;
  52. this.bundle = newRequire;
  53. this.exports = {};
  54. }
  55. newRequire.isParcelRequire = true;
  56. newRequire.Module = Module;
  57. newRequire.modules = modules;
  58. newRequire.cache = cache;
  59. newRequire.parent = previousRequire;
  60. for (var i = 0; i < entry.length; i++) {
  61. newRequire(entry[i]);
  62. }
  63. if (entry.length) {
  64. // Expose entry point to Node, AMD or browser globals
  65. // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
  66. var mainExports = newRequire(entry[entry.length - 1]);
  67. // CommonJS
  68. if (typeof exports === "object" && typeof module !== "undefined") {
  69. module.exports = mainExports;
  70. // RequireJS
  71. } else if (typeof define === "function" && define.amd) {
  72. define(function () {
  73. return mainExports;
  74. });
  75. // <script>
  76. } else if (globalName) {
  77. this[globalName] = mainExports;
  78. }
  79. }
  80. // Override the current require with this new one
  81. return newRequire;
  82. })({106:[function(require,module,exports) {
  83. var bundleURL = null;
  84. function getBundleURLCached() {
  85. if (!bundleURL) {
  86. bundleURL = getBundleURL();
  87. }
  88. return bundleURL;
  89. }
  90. function getBundleURL() {
  91. // Attempt to find the URL of the current script and use that as the base URL
  92. try {
  93. throw new Error();
  94. } catch (err) {
  95. var matches = ('' + err.stack).match(/(https?|file|ftp):\/\/[^)\n]+/g);
  96. if (matches) {
  97. return getBaseURL(matches[0]);
  98. }
  99. }
  100. return '/';
  101. }
  102. function getBaseURL(url) {
  103. return ('' + url).replace(/^((?:https?|file|ftp):\/\/.+)\/[^/]+$/, '$1') + '/';
  104. }
  105. exports.getBundleURL = getBundleURLCached;
  106. exports.getBaseURL = getBaseURL;
  107. },{}],46:[function(require,module,exports) {
  108. var bundle = require('./bundle-url');
  109. function updateLink(link) {
  110. var newLink = link.cloneNode();
  111. newLink.onload = function () {
  112. link.remove();
  113. };
  114. newLink.href = link.href.split('?')[0] + '?' + Date.now();
  115. link.parentNode.insertBefore(newLink, link.nextSibling);
  116. }
  117. var cssTimeout = null;
  118. function reloadCSS() {
  119. if (cssTimeout) {
  120. return;
  121. }
  122. cssTimeout = setTimeout(function () {
  123. var links = document.querySelectorAll('link[rel="stylesheet"]');
  124. for (var i = 0; i < links.length; i++) {
  125. if (bundle.getBaseURL(links[i].href) === bundle.getBundleURL()) {
  126. updateLink(links[i]);
  127. }
  128. }
  129. cssTimeout = null;
  130. }, 50);
  131. }
  132. module.exports = reloadCSS;
  133. },{"./bundle-url":106}],107:[function(require,module,exports) {
  134. var reloadCSS = require('_css_loader');
  135. module.hot.dispose(reloadCSS);
  136. module.hot.accept(reloadCSS);
  137. },{"./photo-sphere-viewer.min.css":115,"./../img/lock.png":116,"./../img/close-icon.png":117,"./../img/lookout-pic.jpg":118,"./../img/P2-lookout.jpg":119,"./../img/P3-lookout.jpg":120,"./../img/P1-lake.jpg":121,"./../img/P2-road.jpg":122,"./../img/P3-road.jpg":123,"./../img/P1-loading.jpg":124,"./../img/P2-loading.jpg":125,"./../img/P3-loading.jpg":126,"./../img/m/euqit-nav-bg.png":136,"./../img/weapon-icon.png":127,"./../img/fodder-icon.png":128,"./../img/glass-icon.png":129,"./../img/book-icon.jpg":130,"./../img/snow-icon.png":131,"./../img/bgm-icon.png":132,"./../img/comment-icon.png":133,"./../img/reset-btn.png":134,"./../img/eyes-logo.png":135,"./../img/m/orient-lock-pic.png":137,"./../img/m/bag-a.png":138,"./../img/m/bag-a-active.png":139,"./../img/m/bag-b.png":140,"./../img/m/bag-b-active.png":141,"_css_loader":46}],110:[function(require,module,exports) {
  138. var reloadCSS = require('_css_loader');
  139. module.hot.dispose(reloadCSS);
  140. module.hot.accept(reloadCSS);
  141. },{"./../../img/comment-bg.jpg":142,"./../../img/hunter-logo.png":143,"_css_loader":46}],145:[function(require,module,exports) {
  142. 'use strict';
  143. Object.defineProperty(exports, "__esModule", {
  144. value: true
  145. });
  146. // Polyfills
  147. if (Number.EPSILON === undefined) {
  148. Number.EPSILON = Math.pow(2, -52);
  149. }
  150. if (Number.isInteger === undefined) {
  151. // Missing in IE
  152. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
  153. Number.isInteger = function (value) {
  154. return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
  155. };
  156. }
  157. //
  158. if (Math.sign === undefined) {
  159. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
  160. Math.sign = function (x) {
  161. return x < 0 ? -1 : x > 0 ? 1 : +x;
  162. };
  163. }
  164. if ('name' in Function.prototype === false) {
  165. // Missing in IE
  166. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
  167. Object.defineProperty(Function.prototype, 'name', {
  168. get: function () {
  169. return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1];
  170. }
  171. });
  172. }
  173. if (Object.assign === undefined) {
  174. // Missing in IE
  175. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  176. (function () {
  177. Object.assign = function (target) {
  178. if (target === undefined || target === null) {
  179. throw new TypeError('Cannot convert undefined or null to object');
  180. }
  181. var output = Object(target);
  182. for (var index = 1; index < arguments.length; index++) {
  183. var source = arguments[index];
  184. if (source !== undefined && source !== null) {
  185. for (var nextKey in source) {
  186. if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
  187. output[nextKey] = source[nextKey];
  188. }
  189. }
  190. }
  191. }
  192. return output;
  193. };
  194. })();
  195. }
  196. /**
  197. * https://github.com/mrdoob/eventdispatcher.js/
  198. */
  199. function EventDispatcher() {}
  200. Object.assign(EventDispatcher.prototype, {
  201. addEventListener: function (type, listener) {
  202. if (this._listeners === undefined) this._listeners = {};
  203. var listeners = this._listeners;
  204. if (listeners[type] === undefined) {
  205. listeners[type] = [];
  206. }
  207. if (listeners[type].indexOf(listener) === -1) {
  208. listeners[type].push(listener);
  209. }
  210. },
  211. hasEventListener: function (type, listener) {
  212. if (this._listeners === undefined) return false;
  213. var listeners = this._listeners;
  214. return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1;
  215. },
  216. removeEventListener: function (type, listener) {
  217. if (this._listeners === undefined) return;
  218. var listeners = this._listeners;
  219. var listenerArray = listeners[type];
  220. if (listenerArray !== undefined) {
  221. var index = listenerArray.indexOf(listener);
  222. if (index !== -1) {
  223. listenerArray.splice(index, 1);
  224. }
  225. }
  226. },
  227. dispatchEvent: function (event) {
  228. if (this._listeners === undefined) return;
  229. var listeners = this._listeners;
  230. var listenerArray = listeners[event.type];
  231. if (listenerArray !== undefined) {
  232. event.target = this;
  233. var array = listenerArray.slice(0);
  234. for (var i = 0, l = array.length; i < l; i++) {
  235. array[i].call(this, event);
  236. }
  237. }
  238. }
  239. });
  240. var REVISION = '93';
  241. var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
  242. var CullFaceNone = 0;
  243. var CullFaceBack = 1;
  244. var CullFaceFront = 2;
  245. var CullFaceFrontBack = 3;
  246. var FrontFaceDirectionCW = 0;
  247. var FrontFaceDirectionCCW = 1;
  248. var BasicShadowMap = 0;
  249. var PCFShadowMap = 1;
  250. var PCFSoftShadowMap = 2;
  251. var FrontSide = 0;
  252. var BackSide = 1;
  253. var DoubleSide = 2;
  254. var FlatShading = 1;
  255. var SmoothShading = 2;
  256. var NoColors = 0;
  257. var FaceColors = 1;
  258. var VertexColors = 2;
  259. var NoBlending = 0;
  260. var NormalBlending = 1;
  261. var AdditiveBlending = 2;
  262. var SubtractiveBlending = 3;
  263. var MultiplyBlending = 4;
  264. var CustomBlending = 5;
  265. var AddEquation = 100;
  266. var SubtractEquation = 101;
  267. var ReverseSubtractEquation = 102;
  268. var MinEquation = 103;
  269. var MaxEquation = 104;
  270. var ZeroFactor = 200;
  271. var OneFactor = 201;
  272. var SrcColorFactor = 202;
  273. var OneMinusSrcColorFactor = 203;
  274. var SrcAlphaFactor = 204;
  275. var OneMinusSrcAlphaFactor = 205;
  276. var DstAlphaFactor = 206;
  277. var OneMinusDstAlphaFactor = 207;
  278. var DstColorFactor = 208;
  279. var OneMinusDstColorFactor = 209;
  280. var SrcAlphaSaturateFactor = 210;
  281. var NeverDepth = 0;
  282. var AlwaysDepth = 1;
  283. var LessDepth = 2;
  284. var LessEqualDepth = 3;
  285. var EqualDepth = 4;
  286. var GreaterEqualDepth = 5;
  287. var GreaterDepth = 6;
  288. var NotEqualDepth = 7;
  289. var MultiplyOperation = 0;
  290. var MixOperation = 1;
  291. var AddOperation = 2;
  292. var NoToneMapping = 0;
  293. var LinearToneMapping = 1;
  294. var ReinhardToneMapping = 2;
  295. var Uncharted2ToneMapping = 3;
  296. var CineonToneMapping = 4;
  297. var UVMapping = 300;
  298. var CubeReflectionMapping = 301;
  299. var CubeRefractionMapping = 302;
  300. var EquirectangularReflectionMapping = 303;
  301. var EquirectangularRefractionMapping = 304;
  302. var SphericalReflectionMapping = 305;
  303. var CubeUVReflectionMapping = 306;
  304. var CubeUVRefractionMapping = 307;
  305. var RepeatWrapping = 1000;
  306. var ClampToEdgeWrapping = 1001;
  307. var MirroredRepeatWrapping = 1002;
  308. var NearestFilter = 1003;
  309. var NearestMipMapNearestFilter = 1004;
  310. var NearestMipMapLinearFilter = 1005;
  311. var LinearFilter = 1006;
  312. var LinearMipMapNearestFilter = 1007;
  313. var LinearMipMapLinearFilter = 1008;
  314. var UnsignedByteType = 1009;
  315. var ByteType = 1010;
  316. var ShortType = 1011;
  317. var UnsignedShortType = 1012;
  318. var IntType = 1013;
  319. var UnsignedIntType = 1014;
  320. var FloatType = 1015;
  321. var HalfFloatType = 1016;
  322. var UnsignedShort4444Type = 1017;
  323. var UnsignedShort5551Type = 1018;
  324. var UnsignedShort565Type = 1019;
  325. var UnsignedInt248Type = 1020;
  326. var AlphaFormat = 1021;
  327. var RGBFormat = 1022;
  328. var RGBAFormat = 1023;
  329. var LuminanceFormat = 1024;
  330. var LuminanceAlphaFormat = 1025;
  331. var RGBEFormat = RGBAFormat;
  332. var DepthFormat = 1026;
  333. var DepthStencilFormat = 1027;
  334. var RGB_S3TC_DXT1_Format = 33776;
  335. var RGBA_S3TC_DXT1_Format = 33777;
  336. var RGBA_S3TC_DXT3_Format = 33778;
  337. var RGBA_S3TC_DXT5_Format = 33779;
  338. var RGB_PVRTC_4BPPV1_Format = 35840;
  339. var RGB_PVRTC_2BPPV1_Format = 35841;
  340. var RGBA_PVRTC_4BPPV1_Format = 35842;
  341. var RGBA_PVRTC_2BPPV1_Format = 35843;
  342. var RGB_ETC1_Format = 36196;
  343. var RGBA_ASTC_4x4_Format = 37808;
  344. var RGBA_ASTC_5x4_Format = 37809;
  345. var RGBA_ASTC_5x5_Format = 37810;
  346. var RGBA_ASTC_6x5_Format = 37811;
  347. var RGBA_ASTC_6x6_Format = 37812;
  348. var RGBA_ASTC_8x5_Format = 37813;
  349. var RGBA_ASTC_8x6_Format = 37814;
  350. var RGBA_ASTC_8x8_Format = 37815;
  351. var RGBA_ASTC_10x5_Format = 37816;
  352. var RGBA_ASTC_10x6_Format = 37817;
  353. var RGBA_ASTC_10x8_Format = 37818;
  354. var RGBA_ASTC_10x10_Format = 37819;
  355. var RGBA_ASTC_12x10_Format = 37820;
  356. var RGBA_ASTC_12x12_Format = 37821;
  357. var LoopOnce = 2200;
  358. var LoopRepeat = 2201;
  359. var LoopPingPong = 2202;
  360. var InterpolateDiscrete = 2300;
  361. var InterpolateLinear = 2301;
  362. var InterpolateSmooth = 2302;
  363. var ZeroCurvatureEnding = 2400;
  364. var ZeroSlopeEnding = 2401;
  365. var WrapAroundEnding = 2402;
  366. var TrianglesDrawMode = 0;
  367. var TriangleStripDrawMode = 1;
  368. var TriangleFanDrawMode = 2;
  369. var LinearEncoding = 3000;
  370. var sRGBEncoding = 3001;
  371. var GammaEncoding = 3007;
  372. var RGBEEncoding = 3002;
  373. var LogLuvEncoding = 3003;
  374. var RGBM7Encoding = 3004;
  375. var RGBM16Encoding = 3005;
  376. var RGBDEncoding = 3006;
  377. var BasicDepthPacking = 3200;
  378. var RGBADepthPacking = 3201;
  379. /**
  380. * @author alteredq / http://alteredqualia.com/
  381. * @author mrdoob / http://mrdoob.com/
  382. */
  383. var _Math = {
  384. DEG2RAD: Math.PI / 180,
  385. RAD2DEG: 180 / Math.PI,
  386. generateUUID: function () {
  387. // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
  388. var lut = [];
  389. for (var i = 0; i < 256; i++) {
  390. lut[i] = (i < 16 ? '0' : '') + i.toString(16);
  391. }
  392. return function generateUUID() {
  393. var d0 = Math.random() * 0xffffffff | 0;
  394. var d1 = Math.random() * 0xffffffff | 0;
  395. var d2 = Math.random() * 0xffffffff | 0;
  396. var d3 = Math.random() * 0xffffffff | 0;
  397. var uuid = lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' + lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' + lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] + lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
  398. // .toUpperCase() here flattens concatenated strings to save heap memory space.
  399. return uuid.toUpperCase();
  400. };
  401. }(),
  402. clamp: function (value, min, max) {
  403. return Math.max(min, Math.min(max, value));
  404. },
  405. // compute euclidian modulo of m % n
  406. // https://en.wikipedia.org/wiki/Modulo_operation
  407. euclideanModulo: function (n, m) {
  408. return (n % m + m) % m;
  409. },
  410. // Linear mapping from range <a1, a2> to range <b1, b2>
  411. mapLinear: function (x, a1, a2, b1, b2) {
  412. return b1 + (x - a1) * (b2 - b1) / (a2 - a1);
  413. },
  414. // https://en.wikipedia.org/wiki/Linear_interpolation
  415. lerp: function (x, y, t) {
  416. return (1 - t) * x + t * y;
  417. },
  418. // http://en.wikipedia.org/wiki/Smoothstep
  419. smoothstep: function (x, min, max) {
  420. if (x <= min) return 0;
  421. if (x >= max) return 1;
  422. x = (x - min) / (max - min);
  423. return x * x * (3 - 2 * x);
  424. },
  425. smootherstep: function (x, min, max) {
  426. if (x <= min) return 0;
  427. if (x >= max) return 1;
  428. x = (x - min) / (max - min);
  429. return x * x * x * (x * (x * 6 - 15) + 10);
  430. },
  431. // Random integer from <low, high> interval
  432. randInt: function (low, high) {
  433. return low + Math.floor(Math.random() * (high - low + 1));
  434. },
  435. // Random float from <low, high> interval
  436. randFloat: function (low, high) {
  437. return low + Math.random() * (high - low);
  438. },
  439. // Random float from <-range/2, range/2> interval
  440. randFloatSpread: function (range) {
  441. return range * (0.5 - Math.random());
  442. },
  443. degToRad: function (degrees) {
  444. return degrees * _Math.DEG2RAD;
  445. },
  446. radToDeg: function (radians) {
  447. return radians * _Math.RAD2DEG;
  448. },
  449. isPowerOfTwo: function (value) {
  450. return (value & value - 1) === 0 && value !== 0;
  451. },
  452. ceilPowerOfTwo: function (value) {
  453. return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
  454. },
  455. floorPowerOfTwo: function (value) {
  456. return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
  457. }
  458. };
  459. /**
  460. * @author mrdoob / http://mrdoob.com/
  461. * @author philogb / http://blog.thejit.org/
  462. * @author egraether / http://egraether.com/
  463. * @author zz85 / http://www.lab4games.net/zz85/blog
  464. */
  465. function Vector2(x, y) {
  466. this.x = x || 0;
  467. this.y = y || 0;
  468. }
  469. Object.defineProperties(Vector2.prototype, {
  470. "width": {
  471. get: function () {
  472. return this.x;
  473. },
  474. set: function (value) {
  475. this.x = value;
  476. }
  477. },
  478. "height": {
  479. get: function () {
  480. return this.y;
  481. },
  482. set: function (value) {
  483. this.y = value;
  484. }
  485. }
  486. });
  487. Object.assign(Vector2.prototype, {
  488. isVector2: true,
  489. set: function (x, y) {
  490. this.x = x;
  491. this.y = y;
  492. return this;
  493. },
  494. setScalar: function (scalar) {
  495. this.x = scalar;
  496. this.y = scalar;
  497. return this;
  498. },
  499. setX: function (x) {
  500. this.x = x;
  501. return this;
  502. },
  503. setY: function (y) {
  504. this.y = y;
  505. return this;
  506. },
  507. setComponent: function (index, value) {
  508. switch (index) {
  509. case 0:
  510. this.x = value;break;
  511. case 1:
  512. this.y = value;break;
  513. default:
  514. throw new Error('index is out of range: ' + index);
  515. }
  516. return this;
  517. },
  518. getComponent: function (index) {
  519. switch (index) {
  520. case 0:
  521. return this.x;
  522. case 1:
  523. return this.y;
  524. default:
  525. throw new Error('index is out of range: ' + index);
  526. }
  527. },
  528. clone: function () {
  529. return new this.constructor(this.x, this.y);
  530. },
  531. copy: function (v) {
  532. this.x = v.x;
  533. this.y = v.y;
  534. return this;
  535. },
  536. add: function (v, w) {
  537. if (w !== undefined) {
  538. console.warn('THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
  539. return this.addVectors(v, w);
  540. }
  541. this.x += v.x;
  542. this.y += v.y;
  543. return this;
  544. },
  545. addScalar: function (s) {
  546. this.x += s;
  547. this.y += s;
  548. return this;
  549. },
  550. addVectors: function (a, b) {
  551. this.x = a.x + b.x;
  552. this.y = a.y + b.y;
  553. return this;
  554. },
  555. addScaledVector: function (v, s) {
  556. this.x += v.x * s;
  557. this.y += v.y * s;
  558. return this;
  559. },
  560. sub: function (v, w) {
  561. if (w !== undefined) {
  562. console.warn('THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
  563. return this.subVectors(v, w);
  564. }
  565. this.x -= v.x;
  566. this.y -= v.y;
  567. return this;
  568. },
  569. subScalar: function (s) {
  570. this.x -= s;
  571. this.y -= s;
  572. return this;
  573. },
  574. subVectors: function (a, b) {
  575. this.x = a.x - b.x;
  576. this.y = a.y - b.y;
  577. return this;
  578. },
  579. multiply: function (v) {
  580. this.x *= v.x;
  581. this.y *= v.y;
  582. return this;
  583. },
  584. multiplyScalar: function (scalar) {
  585. this.x *= scalar;
  586. this.y *= scalar;
  587. return this;
  588. },
  589. divide: function (v) {
  590. this.x /= v.x;
  591. this.y /= v.y;
  592. return this;
  593. },
  594. divideScalar: function (scalar) {
  595. return this.multiplyScalar(1 / scalar);
  596. },
  597. applyMatrix3: function (m) {
  598. var x = this.x,
  599. y = this.y;
  600. var e = m.elements;
  601. this.x = e[0] * x + e[3] * y + e[6];
  602. this.y = e[1] * x + e[4] * y + e[7];
  603. return this;
  604. },
  605. min: function (v) {
  606. this.x = Math.min(this.x, v.x);
  607. this.y = Math.min(this.y, v.y);
  608. return this;
  609. },
  610. max: function (v) {
  611. this.x = Math.max(this.x, v.x);
  612. this.y = Math.max(this.y, v.y);
  613. return this;
  614. },
  615. clamp: function (min, max) {
  616. // assumes min < max, componentwise
  617. this.x = Math.max(min.x, Math.min(max.x, this.x));
  618. this.y = Math.max(min.y, Math.min(max.y, this.y));
  619. return this;
  620. },
  621. clampScalar: function () {
  622. var min = new Vector2();
  623. var max = new Vector2();
  624. return function clampScalar(minVal, maxVal) {
  625. min.set(minVal, minVal);
  626. max.set(maxVal, maxVal);
  627. return this.clamp(min, max);
  628. };
  629. }(),
  630. clampLength: function (min, max) {
  631. var length = this.length();
  632. return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
  633. },
  634. floor: function () {
  635. this.x = Math.floor(this.x);
  636. this.y = Math.floor(this.y);
  637. return this;
  638. },
  639. ceil: function () {
  640. this.x = Math.ceil(this.x);
  641. this.y = Math.ceil(this.y);
  642. return this;
  643. },
  644. round: function () {
  645. this.x = Math.round(this.x);
  646. this.y = Math.round(this.y);
  647. return this;
  648. },
  649. roundToZero: function () {
  650. this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
  651. this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
  652. return this;
  653. },
  654. negate: function () {
  655. this.x = -this.x;
  656. this.y = -this.y;
  657. return this;
  658. },
  659. dot: function (v) {
  660. return this.x * v.x + this.y * v.y;
  661. },
  662. lengthSq: function () {
  663. return this.x * this.x + this.y * this.y;
  664. },
  665. length: function () {
  666. return Math.sqrt(this.x * this.x + this.y * this.y);
  667. },
  668. manhattanLength: function () {
  669. return Math.abs(this.x) + Math.abs(this.y);
  670. },
  671. normalize: function () {
  672. return this.divideScalar(this.length() || 1);
  673. },
  674. angle: function () {
  675. // computes the angle in radians with respect to the positive x-axis
  676. var angle = Math.atan2(this.y, this.x);
  677. if (angle < 0) angle += 2 * Math.PI;
  678. return angle;
  679. },
  680. distanceTo: function (v) {
  681. return Math.sqrt(this.distanceToSquared(v));
  682. },
  683. distanceToSquared: function (v) {
  684. var dx = this.x - v.x,
  685. dy = this.y - v.y;
  686. return dx * dx + dy * dy;
  687. },
  688. manhattanDistanceTo: function (v) {
  689. return Math.abs(this.x - v.x) + Math.abs(this.y - v.y);
  690. },
  691. setLength: function (length) {
  692. return this.normalize().multiplyScalar(length);
  693. },
  694. lerp: function (v, alpha) {
  695. this.x += (v.x - this.x) * alpha;
  696. this.y += (v.y - this.y) * alpha;
  697. return this;
  698. },
  699. lerpVectors: function (v1, v2, alpha) {
  700. return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
  701. },
  702. equals: function (v) {
  703. return v.x === this.x && v.y === this.y;
  704. },
  705. fromArray: function (array, offset) {
  706. if (offset === undefined) offset = 0;
  707. this.x = array[offset];
  708. this.y = array[offset + 1];
  709. return this;
  710. },
  711. toArray: function (array, offset) {
  712. if (array === undefined) array = [];
  713. if (offset === undefined) offset = 0;
  714. array[offset] = this.x;
  715. array[offset + 1] = this.y;
  716. return array;
  717. },
  718. fromBufferAttribute: function (attribute, index, offset) {
  719. if (offset !== undefined) {
  720. console.warn('THREE.Vector2: offset has been removed from .fromBufferAttribute().');
  721. }
  722. this.x = attribute.getX(index);
  723. this.y = attribute.getY(index);
  724. return this;
  725. },
  726. rotateAround: function (center, angle) {
  727. var c = Math.cos(angle),
  728. s = Math.sin(angle);
  729. var x = this.x - center.x;
  730. var y = this.y - center.y;
  731. this.x = x * c - y * s + center.x;
  732. this.y = x * s + y * c + center.y;
  733. return this;
  734. }
  735. });
  736. /**
  737. * @author mrdoob / http://mrdoob.com/
  738. * @author supereggbert / http://www.paulbrunt.co.uk/
  739. * @author philogb / http://blog.thejit.org/
  740. * @author jordi_ros / http://plattsoft.com
  741. * @author D1plo1d / http://github.com/D1plo1d
  742. * @author alteredq / http://alteredqualia.com/
  743. * @author mikael emtinger / http://gomo.se/
  744. * @author timknip / http://www.floorplanner.com/
  745. * @author bhouston / http://clara.io
  746. * @author WestLangley / http://github.com/WestLangley
  747. */
  748. function Matrix4() {
  749. this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
  750. if (arguments.length > 0) {
  751. console.error('THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.');
  752. }
  753. }
  754. Object.assign(Matrix4.prototype, {
  755. isMatrix4: true,
  756. set: function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
  757. var te = this.elements;
  758. te[0] = n11;te[4] = n12;te[8] = n13;te[12] = n14;
  759. te[1] = n21;te[5] = n22;te[9] = n23;te[13] = n24;
  760. te[2] = n31;te[6] = n32;te[10] = n33;te[14] = n34;
  761. te[3] = n41;te[7] = n42;te[11] = n43;te[15] = n44;
  762. return this;
  763. },
  764. identity: function () {
  765. this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
  766. return this;
  767. },
  768. clone: function () {
  769. return new Matrix4().fromArray(this.elements);
  770. },
  771. copy: function (m) {
  772. var te = this.elements;
  773. var me = m.elements;
  774. te[0] = me[0];te[1] = me[1];te[2] = me[2];te[3] = me[3];
  775. te[4] = me[4];te[5] = me[5];te[6] = me[6];te[7] = me[7];
  776. te[8] = me[8];te[9] = me[9];te[10] = me[10];te[11] = me[11];
  777. te[12] = me[12];te[13] = me[13];te[14] = me[14];te[15] = me[15];
  778. return this;
  779. },
  780. copyPosition: function (m) {
  781. var te = this.elements,
  782. me = m.elements;
  783. te[12] = me[12];
  784. te[13] = me[13];
  785. te[14] = me[14];
  786. return this;
  787. },
  788. extractBasis: function (xAxis, yAxis, zAxis) {
  789. xAxis.setFromMatrixColumn(this, 0);
  790. yAxis.setFromMatrixColumn(this, 1);
  791. zAxis.setFromMatrixColumn(this, 2);
  792. return this;
  793. },
  794. makeBasis: function (xAxis, yAxis, zAxis) {
  795. 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);
  796. return this;
  797. },
  798. extractRotation: function () {
  799. var v1 = new Vector3();
  800. return function extractRotation(m) {
  801. // this method does not support reflection matrices
  802. var te = this.elements;
  803. var me = m.elements;
  804. var scaleX = 1 / v1.setFromMatrixColumn(m, 0).length();
  805. var scaleY = 1 / v1.setFromMatrixColumn(m, 1).length();
  806. var scaleZ = 1 / v1.setFromMatrixColumn(m, 2).length();
  807. te[0] = me[0] * scaleX;
  808. te[1] = me[1] * scaleX;
  809. te[2] = me[2] * scaleX;
  810. te[3] = 0;
  811. te[4] = me[4] * scaleY;
  812. te[5] = me[5] * scaleY;
  813. te[6] = me[6] * scaleY;
  814. te[7] = 0;
  815. te[8] = me[8] * scaleZ;
  816. te[9] = me[9] * scaleZ;
  817. te[10] = me[10] * scaleZ;
  818. te[11] = 0;
  819. te[12] = 0;
  820. te[13] = 0;
  821. te[14] = 0;
  822. te[15] = 1;
  823. return this;
  824. };
  825. }(),
  826. makeRotationFromEuler: function (euler) {
  827. if (!(euler && euler.isEuler)) {
  828. console.error('THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.');
  829. }
  830. var te = this.elements;
  831. var x = euler.x,
  832. y = euler.y,
  833. z = euler.z;
  834. var a = Math.cos(x),
  835. b = Math.sin(x);
  836. var c = Math.cos(y),
  837. d = Math.sin(y);
  838. var e = Math.cos(z),
  839. f = Math.sin(z);
  840. if (euler.order === 'XYZ') {
  841. var ae = a * e,
  842. af = a * f,
  843. be = b * e,
  844. bf = b * f;
  845. te[0] = c * e;
  846. te[4] = -c * f;
  847. te[8] = d;
  848. te[1] = af + be * d;
  849. te[5] = ae - bf * d;
  850. te[9] = -b * c;
  851. te[2] = bf - ae * d;
  852. te[6] = be + af * d;
  853. te[10] = a * c;
  854. } else if (euler.order === 'YXZ') {
  855. var ce = c * e,
  856. cf = c * f,
  857. de = d * e,
  858. df = d * f;
  859. te[0] = ce + df * b;
  860. te[4] = de * b - cf;
  861. te[8] = a * d;
  862. te[1] = a * f;
  863. te[5] = a * e;
  864. te[9] = -b;
  865. te[2] = cf * b - de;
  866. te[6] = df + ce * b;
  867. te[10] = a * c;
  868. } else if (euler.order === 'ZXY') {
  869. var ce = c * e,
  870. cf = c * f,
  871. de = d * e,
  872. df = d * f;
  873. te[0] = ce - df * b;
  874. te[4] = -a * f;
  875. te[8] = de + cf * b;
  876. te[1] = cf + de * b;
  877. te[5] = a * e;
  878. te[9] = df - ce * b;
  879. te[2] = -a * d;
  880. te[6] = b;
  881. te[10] = a * c;
  882. } else if (euler.order === 'ZYX') {
  883. var ae = a * e,
  884. af = a * f,
  885. be = b * e,
  886. bf = b * f;
  887. te[0] = c * e;
  888. te[4] = be * d - af;
  889. te[8] = ae * d + bf;
  890. te[1] = c * f;
  891. te[5] = bf * d + ae;
  892. te[9] = af * d - be;
  893. te[2] = -d;
  894. te[6] = b * c;
  895. te[10] = a * c;
  896. } else if (euler.order === 'YZX') {
  897. var ac = a * c,
  898. ad = a * d,
  899. bc = b * c,
  900. bd = b * d;
  901. te[0] = c * e;
  902. te[4] = bd - ac * f;
  903. te[8] = bc * f + ad;
  904. te[1] = f;
  905. te[5] = a * e;
  906. te[9] = -b * e;
  907. te[2] = -d * e;
  908. te[6] = ad * f + bc;
  909. te[10] = ac - bd * f;
  910. } else if (euler.order === 'XZY') {
  911. var ac = a * c,
  912. ad = a * d,
  913. bc = b * c,
  914. bd = b * d;
  915. te[0] = c * e;
  916. te[4] = -f;
  917. te[8] = d * e;
  918. te[1] = ac * f + bd;
  919. te[5] = a * e;
  920. te[9] = ad * f - bc;
  921. te[2] = bc * f - ad;
  922. te[6] = b * e;
  923. te[10] = bd * f + ac;
  924. }
  925. // bottom row
  926. te[3] = 0;
  927. te[7] = 0;
  928. te[11] = 0;
  929. // last column
  930. te[12] = 0;
  931. te[13] = 0;
  932. te[14] = 0;
  933. te[15] = 1;
  934. return this;
  935. },
  936. makeRotationFromQuaternion: function () {
  937. var zero = new Vector3(0, 0, 0);
  938. var one = new Vector3(1, 1, 1);
  939. return function makeRotationFromQuaternion(q) {
  940. return this.compose(zero, q, one);
  941. };
  942. }(),
  943. lookAt: function () {
  944. var x = new Vector3();
  945. var y = new Vector3();
  946. var z = new Vector3();
  947. return function lookAt(eye, target, up) {
  948. var te = this.elements;
  949. z.subVectors(eye, target);
  950. if (z.lengthSq() === 0) {
  951. // eye and target are in the same position
  952. z.z = 1;
  953. }
  954. z.normalize();
  955. x.crossVectors(up, z);
  956. if (x.lengthSq() === 0) {
  957. // up and z are parallel
  958. if (Math.abs(up.z) === 1) {
  959. z.x += 0.0001;
  960. } else {
  961. z.z += 0.0001;
  962. }
  963. z.normalize();
  964. x.crossVectors(up, z);
  965. }
  966. x.normalize();
  967. y.crossVectors(z, x);
  968. te[0] = x.x;te[4] = y.x;te[8] = z.x;
  969. te[1] = x.y;te[5] = y.y;te[9] = z.y;
  970. te[2] = x.z;te[6] = y.z;te[10] = z.z;
  971. return this;
  972. };
  973. }(),
  974. multiply: function (m, n) {
  975. if (n !== undefined) {
  976. console.warn('THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.');
  977. return this.multiplyMatrices(m, n);
  978. }
  979. return this.multiplyMatrices(this, m);
  980. },
  981. premultiply: function (m) {
  982. return this.multiplyMatrices(m, this);
  983. },
  984. multiplyMatrices: function (a, b) {
  985. var ae = a.elements;
  986. var be = b.elements;
  987. var te = this.elements;
  988. var a11 = ae[0],
  989. a12 = ae[4],
  990. a13 = ae[8],
  991. a14 = ae[12];
  992. var a21 = ae[1],
  993. a22 = ae[5],
  994. a23 = ae[9],
  995. a24 = ae[13];
  996. var a31 = ae[2],
  997. a32 = ae[6],
  998. a33 = ae[10],
  999. a34 = ae[14];
  1000. var a41 = ae[3],
  1001. a42 = ae[7],
  1002. a43 = ae[11],
  1003. a44 = ae[15];
  1004. var b11 = be[0],
  1005. b12 = be[4],
  1006. b13 = be[8],
  1007. b14 = be[12];
  1008. var b21 = be[1],
  1009. b22 = be[5],
  1010. b23 = be[9],
  1011. b24 = be[13];
  1012. var b31 = be[2],
  1013. b32 = be[6],
  1014. b33 = be[10],
  1015. b34 = be[14];
  1016. var b41 = be[3],
  1017. b42 = be[7],
  1018. b43 = be[11],
  1019. b44 = be[15];
  1020. te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
  1021. te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
  1022. te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
  1023. te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
  1024. te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
  1025. te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
  1026. te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
  1027. te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
  1028. te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
  1029. te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
  1030. te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
  1031. te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
  1032. te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
  1033. te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
  1034. te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
  1035. te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
  1036. return this;
  1037. },
  1038. multiplyScalar: function (s) {
  1039. var te = this.elements;
  1040. te[0] *= s;te[4] *= s;te[8] *= s;te[12] *= s;
  1041. te[1] *= s;te[5] *= s;te[9] *= s;te[13] *= s;
  1042. te[2] *= s;te[6] *= s;te[10] *= s;te[14] *= s;
  1043. te[3] *= s;te[7] *= s;te[11] *= s;te[15] *= s;
  1044. return this;
  1045. },
  1046. applyToBufferAttribute: function () {
  1047. var v1 = new Vector3();
  1048. return function applyToBufferAttribute(attribute) {
  1049. for (var i = 0, l = attribute.count; i < l; i++) {
  1050. v1.x = attribute.getX(i);
  1051. v1.y = attribute.getY(i);
  1052. v1.z = attribute.getZ(i);
  1053. v1.applyMatrix4(this);
  1054. attribute.setXYZ(i, v1.x, v1.y, v1.z);
  1055. }
  1056. return attribute;
  1057. };
  1058. }(),
  1059. determinant: function () {
  1060. var te = this.elements;
  1061. var n11 = te[0],
  1062. n12 = te[4],
  1063. n13 = te[8],
  1064. n14 = te[12];
  1065. var n21 = te[1],
  1066. n22 = te[5],
  1067. n23 = te[9],
  1068. n24 = te[13];
  1069. var n31 = te[2],
  1070. n32 = te[6],
  1071. n33 = te[10],
  1072. n34 = te[14];
  1073. var n41 = te[3],
  1074. n42 = te[7],
  1075. n43 = te[11],
  1076. n44 = te[15];
  1077. //TODO: make this more efficient
  1078. //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
  1079. 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);
  1080. },
  1081. transpose: function () {
  1082. var te = this.elements;
  1083. var tmp;
  1084. tmp = te[1];te[1] = te[4];te[4] = tmp;
  1085. tmp = te[2];te[2] = te[8];te[8] = tmp;
  1086. tmp = te[6];te[6] = te[9];te[9] = tmp;
  1087. tmp = te[3];te[3] = te[12];te[12] = tmp;
  1088. tmp = te[7];te[7] = te[13];te[13] = tmp;
  1089. tmp = te[11];te[11] = te[14];te[14] = tmp;
  1090. return this;
  1091. },
  1092. setPosition: function (v) {
  1093. var te = this.elements;
  1094. te[12] = v.x;
  1095. te[13] = v.y;
  1096. te[14] = v.z;
  1097. return this;
  1098. },
  1099. getInverse: function (m, throwOnDegenerate) {
  1100. // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
  1101. var te = this.elements,
  1102. me = m.elements,
  1103. n11 = me[0],
  1104. n21 = me[1],
  1105. n31 = me[2],
  1106. n41 = me[3],
  1107. n12 = me[4],
  1108. n22 = me[5],
  1109. n32 = me[6],
  1110. n42 = me[7],
  1111. n13 = me[8],
  1112. n23 = me[9],
  1113. n33 = me[10],
  1114. n43 = me[11],
  1115. n14 = me[12],
  1116. n24 = me[13],
  1117. n34 = me[14],
  1118. n44 = me[15],
  1119. t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
  1120. t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
  1121. t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
  1122. t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
  1123. var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
  1124. if (det === 0) {
  1125. var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
  1126. if (throwOnDegenerate === true) {
  1127. throw new Error(msg);
  1128. } else {
  1129. console.warn(msg);
  1130. }
  1131. return this.identity();
  1132. }
  1133. var detInv = 1 / det;
  1134. te[0] = t11 * detInv;
  1135. te[1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * detInv;
  1136. te[2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * detInv;
  1137. te[3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * detInv;
  1138. te[4] = t12 * detInv;
  1139. te[5] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * detInv;
  1140. te[6] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * detInv;
  1141. te[7] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * detInv;
  1142. te[8] = t13 * detInv;
  1143. te[9] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * detInv;
  1144. te[10] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * detInv;
  1145. te[11] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * detInv;
  1146. te[12] = t14 * detInv;
  1147. te[13] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * detInv;
  1148. te[14] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * detInv;
  1149. te[15] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * detInv;
  1150. return this;
  1151. },
  1152. scale: function (v) {
  1153. var te = this.elements;
  1154. var x = v.x,
  1155. y = v.y,
  1156. z = v.z;
  1157. te[0] *= x;te[4] *= y;te[8] *= z;
  1158. te[1] *= x;te[5] *= y;te[9] *= z;
  1159. te[2] *= x;te[6] *= y;te[10] *= z;
  1160. te[3] *= x;te[7] *= y;te[11] *= z;
  1161. return this;
  1162. },
  1163. getMaxScaleOnAxis: function () {
  1164. var te = this.elements;
  1165. var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
  1166. var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
  1167. var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
  1168. return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));
  1169. },
  1170. makeTranslation: function (x, y, z) {
  1171. this.set(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1);
  1172. return this;
  1173. },
  1174. makeRotationX: function (theta) {
  1175. var c = Math.cos(theta),
  1176. s = Math.sin(theta);
  1177. this.set(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
  1178. return this;
  1179. },
  1180. makeRotationY: function (theta) {
  1181. var c = Math.cos(theta),
  1182. s = Math.sin(theta);
  1183. this.set(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
  1184. return this;
  1185. },
  1186. makeRotationZ: function (theta) {
  1187. var c = Math.cos(theta),
  1188. s = Math.sin(theta);
  1189. this.set(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
  1190. return this;
  1191. },
  1192. makeRotationAxis: function (axis, angle) {
  1193. // Based on http://www.gamedev.net/reference/articles/article1199.asp
  1194. var c = Math.cos(angle);
  1195. var s = Math.sin(angle);
  1196. var t = 1 - c;
  1197. var x = axis.x,
  1198. y = axis.y,
  1199. z = axis.z;
  1200. var tx = t * x,
  1201. ty = t * y;
  1202. 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);
  1203. return this;
  1204. },
  1205. makeScale: function (x, y, z) {
  1206. this.set(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);
  1207. return this;
  1208. },
  1209. makeShear: function (x, y, z) {
  1210. this.set(1, y, z, 0, x, 1, z, 0, x, y, 1, 0, 0, 0, 0, 1);
  1211. return this;
  1212. },
  1213. compose: function (position, quaternion, scale) {
  1214. var te = this.elements;
  1215. var x = quaternion._x,
  1216. y = quaternion._y,
  1217. z = quaternion._z,
  1218. w = quaternion._w;
  1219. var x2 = x + x,
  1220. y2 = y + y,
  1221. z2 = z + z;
  1222. var xx = x * x2,
  1223. xy = x * y2,
  1224. xz = x * z2;
  1225. var yy = y * y2,
  1226. yz = y * z2,
  1227. zz = z * z2;
  1228. var wx = w * x2,
  1229. wy = w * y2,
  1230. wz = w * z2;
  1231. var sx = scale.x,
  1232. sy = scale.y,
  1233. sz = scale.z;
  1234. te[0] = (1 - (yy + zz)) * sx;
  1235. te[1] = (xy + wz) * sx;
  1236. te[2] = (xz - wy) * sx;
  1237. te[3] = 0;
  1238. te[4] = (xy - wz) * sy;
  1239. te[5] = (1 - (xx + zz)) * sy;
  1240. te[6] = (yz + wx) * sy;
  1241. te[7] = 0;
  1242. te[8] = (xz + wy) * sz;
  1243. te[9] = (yz - wx) * sz;
  1244. te[10] = (1 - (xx + yy)) * sz;
  1245. te[11] = 0;
  1246. te[12] = position.x;
  1247. te[13] = position.y;
  1248. te[14] = position.z;
  1249. te[15] = 1;
  1250. return this;
  1251. },
  1252. decompose: function () {
  1253. var vector = new Vector3();
  1254. var matrix = new Matrix4();
  1255. return function decompose(position, quaternion, scale) {
  1256. var te = this.elements;
  1257. var sx = vector.set(te[0], te[1], te[2]).length();
  1258. var sy = vector.set(te[4], te[5], te[6]).length();
  1259. var sz = vector.set(te[8], te[9], te[10]).length();
  1260. // if determine is negative, we need to invert one scale
  1261. var det = this.determinant();
  1262. if (det < 0) sx = -sx;
  1263. position.x = te[12];
  1264. position.y = te[13];
  1265. position.z = te[14];
  1266. // scale the rotation part
  1267. matrix.copy(this);
  1268. var invSX = 1 / sx;
  1269. var invSY = 1 / sy;
  1270. var invSZ = 1 / sz;
  1271. matrix.elements[0] *= invSX;
  1272. matrix.elements[1] *= invSX;
  1273. matrix.elements[2] *= invSX;
  1274. matrix.elements[4] *= invSY;
  1275. matrix.elements[5] *= invSY;
  1276. matrix.elements[6] *= invSY;
  1277. matrix.elements[8] *= invSZ;
  1278. matrix.elements[9] *= invSZ;
  1279. matrix.elements[10] *= invSZ;
  1280. quaternion.setFromRotationMatrix(matrix);
  1281. scale.x = sx;
  1282. scale.y = sy;
  1283. scale.z = sz;
  1284. return this;
  1285. };
  1286. }(),
  1287. makePerspective: function (left, right, top, bottom, near, far) {
  1288. if (far === undefined) {
  1289. console.warn('THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.');
  1290. }
  1291. var te = this.elements;
  1292. var x = 2 * near / (right - left);
  1293. var y = 2 * near / (top - bottom);
  1294. var a = (right + left) / (right - left);
  1295. var b = (top + bottom) / (top - bottom);
  1296. var c = -(far + near) / (far - near);
  1297. var d = -2 * far * near / (far - near);
  1298. te[0] = x;te[4] = 0;te[8] = a;te[12] = 0;
  1299. te[1] = 0;te[5] = y;te[9] = b;te[13] = 0;
  1300. te[2] = 0;te[6] = 0;te[10] = c;te[14] = d;
  1301. te[3] = 0;te[7] = 0;te[11] = -1;te[15] = 0;
  1302. return this;
  1303. },
  1304. makeOrthographic: function (left, right, top, bottom, near, far) {
  1305. var te = this.elements;
  1306. var w = 1.0 / (right - left);
  1307. var h = 1.0 / (top - bottom);
  1308. var p = 1.0 / (far - near);
  1309. var x = (right + left) * w;
  1310. var y = (top + bottom) * h;
  1311. var z = (far + near) * p;
  1312. te[0] = 2 * w;te[4] = 0;te[8] = 0;te[12] = -x;
  1313. te[1] = 0;te[5] = 2 * h;te[9] = 0;te[13] = -y;
  1314. te[2] = 0;te[6] = 0;te[10] = -2 * p;te[14] = -z;
  1315. te[3] = 0;te[7] = 0;te[11] = 0;te[15] = 1;
  1316. return this;
  1317. },
  1318. equals: function (matrix) {
  1319. var te = this.elements;
  1320. var me = matrix.elements;
  1321. for (var i = 0; i < 16; i++) {
  1322. if (te[i] !== me[i]) return false;
  1323. }
  1324. return true;
  1325. },
  1326. fromArray: function (array, offset) {
  1327. if (offset === undefined) offset = 0;
  1328. for (var i = 0; i < 16; i++) {
  1329. this.elements[i] = array[i + offset];
  1330. }
  1331. return this;
  1332. },
  1333. toArray: function (array, offset) {
  1334. if (array === undefined) array = [];
  1335. if (offset === undefined) offset = 0;
  1336. var te = this.elements;
  1337. array[offset] = te[0];
  1338. array[offset + 1] = te[1];
  1339. array[offset + 2] = te[2];
  1340. array[offset + 3] = te[3];
  1341. array[offset + 4] = te[4];
  1342. array[offset + 5] = te[5];
  1343. array[offset + 6] = te[6];
  1344. array[offset + 7] = te[7];
  1345. array[offset + 8] = te[8];
  1346. array[offset + 9] = te[9];
  1347. array[offset + 10] = te[10];
  1348. array[offset + 11] = te[11];
  1349. array[offset + 12] = te[12];
  1350. array[offset + 13] = te[13];
  1351. array[offset + 14] = te[14];
  1352. array[offset + 15] = te[15];
  1353. return array;
  1354. }
  1355. });
  1356. /**
  1357. * @author mikael emtinger / http://gomo.se/
  1358. * @author alteredq / http://alteredqualia.com/
  1359. * @author WestLangley / http://github.com/WestLangley
  1360. * @author bhouston / http://clara.io
  1361. */
  1362. function Quaternion(x, y, z, w) {
  1363. this._x = x || 0;
  1364. this._y = y || 0;
  1365. this._z = z || 0;
  1366. this._w = w !== undefined ? w : 1;
  1367. }
  1368. Object.assign(Quaternion, {
  1369. slerp: function (qa, qb, qm, t) {
  1370. return qm.copy(qa).slerp(qb, t);
  1371. },
  1372. slerpFlat: function (dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) {
  1373. // fuzz-free, array-based Quaternion SLERP operation
  1374. var x0 = src0[srcOffset0 + 0],
  1375. y0 = src0[srcOffset0 + 1],
  1376. z0 = src0[srcOffset0 + 2],
  1377. w0 = src0[srcOffset0 + 3],
  1378. x1 = src1[srcOffset1 + 0],
  1379. y1 = src1[srcOffset1 + 1],
  1380. z1 = src1[srcOffset1 + 2],
  1381. w1 = src1[srcOffset1 + 3];
  1382. if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) {
  1383. var s = 1 - t,
  1384. cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
  1385. dir = cos >= 0 ? 1 : -1,
  1386. sqrSin = 1 - cos * cos;
  1387. // Skip the Slerp for tiny steps to avoid numeric problems:
  1388. if (sqrSin > Number.EPSILON) {
  1389. var sin = Math.sqrt(sqrSin),
  1390. len = Math.atan2(sin, cos * dir);
  1391. s = Math.sin(s * len) / sin;
  1392. t = Math.sin(t * len) / sin;
  1393. }
  1394. var tDir = t * dir;
  1395. x0 = x0 * s + x1 * tDir;
  1396. y0 = y0 * s + y1 * tDir;
  1397. z0 = z0 * s + z1 * tDir;
  1398. w0 = w0 * s + w1 * tDir;
  1399. // Normalize in case we just did a lerp:
  1400. if (s === 1 - t) {
  1401. var f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
  1402. x0 *= f;
  1403. y0 *= f;
  1404. z0 *= f;
  1405. w0 *= f;
  1406. }
  1407. }
  1408. dst[dstOffset] = x0;
  1409. dst[dstOffset + 1] = y0;
  1410. dst[dstOffset + 2] = z0;
  1411. dst[dstOffset + 3] = w0;
  1412. }
  1413. });
  1414. Object.defineProperties(Quaternion.prototype, {
  1415. x: {
  1416. get: function () {
  1417. return this._x;
  1418. },
  1419. set: function (value) {
  1420. this._x = value;
  1421. this.onChangeCallback();
  1422. }
  1423. },
  1424. y: {
  1425. get: function () {
  1426. return this._y;
  1427. },
  1428. set: function (value) {
  1429. this._y = value;
  1430. this.onChangeCallback();
  1431. }
  1432. },
  1433. z: {
  1434. get: function () {
  1435. return this._z;
  1436. },
  1437. set: function (value) {
  1438. this._z = value;
  1439. this.onChangeCallback();
  1440. }
  1441. },
  1442. w: {
  1443. get: function () {
  1444. return this._w;
  1445. },
  1446. set: function (value) {
  1447. this._w = value;
  1448. this.onChangeCallback();
  1449. }
  1450. }
  1451. });
  1452. Object.assign(Quaternion.prototype, {
  1453. set: function (x, y, z, w) {
  1454. this._x = x;
  1455. this._y = y;
  1456. this._z = z;
  1457. this._w = w;
  1458. this.onChangeCallback();
  1459. return this;
  1460. },
  1461. clone: function () {
  1462. return new this.constructor(this._x, this._y, this._z, this._w);
  1463. },
  1464. copy: function (quaternion) {
  1465. this._x = quaternion.x;
  1466. this._y = quaternion.y;
  1467. this._z = quaternion.z;
  1468. this._w = quaternion.w;
  1469. this.onChangeCallback();
  1470. return this;
  1471. },
  1472. setFromEuler: function (euler, update) {
  1473. if (!(euler && euler.isEuler)) {
  1474. throw new Error('THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.');
  1475. }
  1476. var x = euler._x,
  1477. y = euler._y,
  1478. z = euler._z,
  1479. order = euler.order;
  1480. // http://www.mathworks.com/matlabcentral/fileexchange/
  1481. // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
  1482. // content/SpinCalc.m
  1483. var cos = Math.cos;
  1484. var sin = Math.sin;
  1485. var c1 = cos(x / 2);
  1486. var c2 = cos(y / 2);
  1487. var c3 = cos(z / 2);
  1488. var s1 = sin(x / 2);
  1489. var s2 = sin(y / 2);
  1490. var s3 = sin(z / 2);
  1491. if (order === 'XYZ') {
  1492. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  1493. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  1494. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  1495. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  1496. } else if (order === 'YXZ') {
  1497. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  1498. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  1499. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  1500. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  1501. } else if (order === 'ZXY') {
  1502. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  1503. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  1504. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  1505. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  1506. } else if (order === 'ZYX') {
  1507. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  1508. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  1509. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  1510. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  1511. } else if (order === 'YZX') {
  1512. this._x = s1 * c2 * c3 + c1 * s2 * s3;
  1513. this._y = c1 * s2 * c3 + s1 * c2 * s3;
  1514. this._z = c1 * c2 * s3 - s1 * s2 * c3;
  1515. this._w = c1 * c2 * c3 - s1 * s2 * s3;
  1516. } else if (order === 'XZY') {
  1517. this._x = s1 * c2 * c3 - c1 * s2 * s3;
  1518. this._y = c1 * s2 * c3 - s1 * c2 * s3;
  1519. this._z = c1 * c2 * s3 + s1 * s2 * c3;
  1520. this._w = c1 * c2 * c3 + s1 * s2 * s3;
  1521. }
  1522. if (update !== false) this.onChangeCallback();
  1523. return this;
  1524. },
  1525. setFromAxisAngle: function (axis, angle) {
  1526. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
  1527. // assumes axis is normalized
  1528. var halfAngle = angle / 2,
  1529. s = Math.sin(halfAngle);
  1530. this._x = axis.x * s;
  1531. this._y = axis.y * s;
  1532. this._z = axis.z * s;
  1533. this._w = Math.cos(halfAngle);
  1534. this.onChangeCallback();
  1535. return this;
  1536. },
  1537. setFromRotationMatrix: function (m) {
  1538. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  1539. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  1540. var te = m.elements,
  1541. m11 = te[0],
  1542. m12 = te[4],
  1543. m13 = te[8],
  1544. m21 = te[1],
  1545. m22 = te[5],
  1546. m23 = te[9],
  1547. m31 = te[2],
  1548. m32 = te[6],
  1549. m33 = te[10],
  1550. trace = m11 + m22 + m33,
  1551. s;
  1552. if (trace > 0) {
  1553. s = 0.5 / Math.sqrt(trace + 1.0);
  1554. this._w = 0.25 / s;
  1555. this._x = (m32 - m23) * s;
  1556. this._y = (m13 - m31) * s;
  1557. this._z = (m21 - m12) * s;
  1558. } else if (m11 > m22 && m11 > m33) {
  1559. s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
  1560. this._w = (m32 - m23) / s;
  1561. this._x = 0.25 * s;
  1562. this._y = (m12 + m21) / s;
  1563. this._z = (m13 + m31) / s;
  1564. } else if (m22 > m33) {
  1565. s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
  1566. this._w = (m13 - m31) / s;
  1567. this._x = (m12 + m21) / s;
  1568. this._y = 0.25 * s;
  1569. this._z = (m23 + m32) / s;
  1570. } else {
  1571. s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
  1572. this._w = (m21 - m12) / s;
  1573. this._x = (m13 + m31) / s;
  1574. this._y = (m23 + m32) / s;
  1575. this._z = 0.25 * s;
  1576. }
  1577. this.onChangeCallback();
  1578. return this;
  1579. },
  1580. setFromUnitVectors: function () {
  1581. // assumes direction vectors vFrom and vTo are normalized
  1582. var v1 = new Vector3();
  1583. var r;
  1584. var EPS = 0.000001;
  1585. return function setFromUnitVectors(vFrom, vTo) {
  1586. if (v1 === undefined) v1 = new Vector3();
  1587. r = vFrom.dot(vTo) + 1;
  1588. if (r < EPS) {
  1589. r = 0;
  1590. if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
  1591. v1.set(-vFrom.y, vFrom.x, 0);
  1592. } else {
  1593. v1.set(0, -vFrom.z, vFrom.y);
  1594. }
  1595. } else {
  1596. v1.crossVectors(vFrom, vTo);
  1597. }
  1598. this._x = v1.x;
  1599. this._y = v1.y;
  1600. this._z = v1.z;
  1601. this._w = r;
  1602. return this.normalize();
  1603. };
  1604. }(),
  1605. inverse: function () {
  1606. // quaternion is assumed to have unit length
  1607. return this.conjugate();
  1608. },
  1609. conjugate: function () {
  1610. this._x *= -1;
  1611. this._y *= -1;
  1612. this._z *= -1;
  1613. this.onChangeCallback();
  1614. return this;
  1615. },
  1616. dot: function (v) {
  1617. return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
  1618. },
  1619. lengthSq: function () {
  1620. return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
  1621. },
  1622. length: function () {
  1623. return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
  1624. },
  1625. normalize: function () {
  1626. var l = this.length();
  1627. if (l === 0) {
  1628. this._x = 0;
  1629. this._y = 0;
  1630. this._z = 0;
  1631. this._w = 1;
  1632. } else {
  1633. l = 1 / l;
  1634. this._x = this._x * l;
  1635. this._y = this._y * l;
  1636. this._z = this._z * l;
  1637. this._w = this._w * l;
  1638. }
  1639. this.onChangeCallback();
  1640. return this;
  1641. },
  1642. multiply: function (q, p) {
  1643. if (p !== undefined) {
  1644. console.warn('THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.');
  1645. return this.multiplyQuaternions(q, p);
  1646. }
  1647. return this.multiplyQuaternions(this, q);
  1648. },
  1649. premultiply: function (q) {
  1650. return this.multiplyQuaternions(q, this);
  1651. },
  1652. multiplyQuaternions: function (a, b) {
  1653. // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
  1654. var qax = a._x,
  1655. qay = a._y,
  1656. qaz = a._z,
  1657. qaw = a._w;
  1658. var qbx = b._x,
  1659. qby = b._y,
  1660. qbz = b._z,
  1661. qbw = b._w;
  1662. this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
  1663. this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
  1664. this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
  1665. this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
  1666. this.onChangeCallback();
  1667. return this;
  1668. },
  1669. slerp: function (qb, t) {
  1670. if (t === 0) return this;
  1671. if (t === 1) return this.copy(qb);
  1672. var x = this._x,
  1673. y = this._y,
  1674. z = this._z,
  1675. w = this._w;
  1676. // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
  1677. var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
  1678. if (cosHalfTheta < 0) {
  1679. this._w = -qb._w;
  1680. this._x = -qb._x;
  1681. this._y = -qb._y;
  1682. this._z = -qb._z;
  1683. cosHalfTheta = -cosHalfTheta;
  1684. } else {
  1685. this.copy(qb);
  1686. }
  1687. if (cosHalfTheta >= 1.0) {
  1688. this._w = w;
  1689. this._x = x;
  1690. this._y = y;
  1691. this._z = z;
  1692. return this;
  1693. }
  1694. var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
  1695. if (Math.abs(sinHalfTheta) < 0.001) {
  1696. this._w = 0.5 * (w + this._w);
  1697. this._x = 0.5 * (x + this._x);
  1698. this._y = 0.5 * (y + this._y);
  1699. this._z = 0.5 * (z + this._z);
  1700. return this;
  1701. }
  1702. var halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
  1703. var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
  1704. ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
  1705. this._w = w * ratioA + this._w * ratioB;
  1706. this._x = x * ratioA + this._x * ratioB;
  1707. this._y = y * ratioA + this._y * ratioB;
  1708. this._z = z * ratioA + this._z * ratioB;
  1709. this.onChangeCallback();
  1710. return this;
  1711. },
  1712. equals: function (quaternion) {
  1713. return quaternion._x === this._x && quaternion._y === this._y && quaternion._z === this._z && quaternion._w === this._w;
  1714. },
  1715. fromArray: function (array, offset) {
  1716. if (offset === undefined) offset = 0;
  1717. this._x = array[offset];
  1718. this._y = array[offset + 1];
  1719. this._z = array[offset + 2];
  1720. this._w = array[offset + 3];
  1721. this.onChangeCallback();
  1722. return this;
  1723. },
  1724. toArray: function (array, offset) {
  1725. if (array === undefined) array = [];
  1726. if (offset === undefined) offset = 0;
  1727. array[offset] = this._x;
  1728. array[offset + 1] = this._y;
  1729. array[offset + 2] = this._z;
  1730. array[offset + 3] = this._w;
  1731. return array;
  1732. },
  1733. onChange: function (callback) {
  1734. this.onChangeCallback = callback;
  1735. return this;
  1736. },
  1737. onChangeCallback: function () {}
  1738. });
  1739. /**
  1740. * @author mrdoob / http://mrdoob.com/
  1741. * @author kile / http://kile.stravaganza.org/
  1742. * @author philogb / http://blog.thejit.org/
  1743. * @author mikael emtinger / http://gomo.se/
  1744. * @author egraether / http://egraether.com/
  1745. * @author WestLangley / http://github.com/WestLangley
  1746. */
  1747. function Vector3(x, y, z) {
  1748. this.x = x || 0;
  1749. this.y = y || 0;
  1750. this.z = z || 0;
  1751. }
  1752. Object.assign(Vector3.prototype, {
  1753. isVector3: true,
  1754. set: function (x, y, z) {
  1755. this.x = x;
  1756. this.y = y;
  1757. this.z = z;
  1758. return this;
  1759. },
  1760. setScalar: function (scalar) {
  1761. this.x = scalar;
  1762. this.y = scalar;
  1763. this.z = scalar;
  1764. return this;
  1765. },
  1766. setX: function (x) {
  1767. this.x = x;
  1768. return this;
  1769. },
  1770. setY: function (y) {
  1771. this.y = y;
  1772. return this;
  1773. },
  1774. setZ: function (z) {
  1775. this.z = z;
  1776. return this;
  1777. },
  1778. setComponent: function (index, value) {
  1779. switch (index) {
  1780. case 0:
  1781. this.x = value;break;
  1782. case 1:
  1783. this.y = value;break;
  1784. case 2:
  1785. this.z = value;break;
  1786. default:
  1787. throw new Error('index is out of range: ' + index);
  1788. }
  1789. return this;
  1790. },
  1791. getComponent: function (index) {
  1792. switch (index) {
  1793. case 0:
  1794. return this.x;
  1795. case 1:
  1796. return this.y;
  1797. case 2:
  1798. return this.z;
  1799. default:
  1800. throw new Error('index is out of range: ' + index);
  1801. }
  1802. },
  1803. clone: function () {
  1804. return new this.constructor(this.x, this.y, this.z);
  1805. },
  1806. copy: function (v) {
  1807. this.x = v.x;
  1808. this.y = v.y;
  1809. this.z = v.z;
  1810. return this;
  1811. },
  1812. add: function (v, w) {
  1813. if (w !== undefined) {
  1814. console.warn('THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
  1815. return this.addVectors(v, w);
  1816. }
  1817. this.x += v.x;
  1818. this.y += v.y;
  1819. this.z += v.z;
  1820. return this;
  1821. },
  1822. addScalar: function (s) {
  1823. this.x += s;
  1824. this.y += s;
  1825. this.z += s;
  1826. return this;
  1827. },
  1828. addVectors: function (a, b) {
  1829. this.x = a.x + b.x;
  1830. this.y = a.y + b.y;
  1831. this.z = a.z + b.z;
  1832. return this;
  1833. },
  1834. addScaledVector: function (v, s) {
  1835. this.x += v.x * s;
  1836. this.y += v.y * s;
  1837. this.z += v.z * s;
  1838. return this;
  1839. },
  1840. sub: function (v, w) {
  1841. if (w !== undefined) {
  1842. console.warn('THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
  1843. return this.subVectors(v, w);
  1844. }
  1845. this.x -= v.x;
  1846. this.y -= v.y;
  1847. this.z -= v.z;
  1848. return this;
  1849. },
  1850. subScalar: function (s) {
  1851. this.x -= s;
  1852. this.y -= s;
  1853. this.z -= s;
  1854. return this;
  1855. },
  1856. subVectors: function (a, b) {
  1857. this.x = a.x - b.x;
  1858. this.y = a.y - b.y;
  1859. this.z = a.z - b.z;
  1860. return this;
  1861. },
  1862. multiply: function (v, w) {
  1863. if (w !== undefined) {
  1864. console.warn('THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.');
  1865. return this.multiplyVectors(v, w);
  1866. }
  1867. this.x *= v.x;
  1868. this.y *= v.y;
  1869. this.z *= v.z;
  1870. return this;
  1871. },
  1872. multiplyScalar: function (scalar) {
  1873. this.x *= scalar;
  1874. this.y *= scalar;
  1875. this.z *= scalar;
  1876. return this;
  1877. },
  1878. multiplyVectors: function (a, b) {
  1879. this.x = a.x * b.x;
  1880. this.y = a.y * b.y;
  1881. this.z = a.z * b.z;
  1882. return this;
  1883. },
  1884. applyEuler: function () {
  1885. var quaternion = new Quaternion();
  1886. return function applyEuler(euler) {
  1887. if (!(euler && euler.isEuler)) {
  1888. console.error('THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.');
  1889. }
  1890. return this.applyQuaternion(quaternion.setFromEuler(euler));
  1891. };
  1892. }(),
  1893. applyAxisAngle: function () {
  1894. var quaternion = new Quaternion();
  1895. return function applyAxisAngle(axis, angle) {
  1896. return this.applyQuaternion(quaternion.setFromAxisAngle(axis, angle));
  1897. };
  1898. }(),
  1899. applyMatrix3: function (m) {
  1900. var x = this.x,
  1901. y = this.y,
  1902. z = this.z;
  1903. var e = m.elements;
  1904. this.x = e[0] * x + e[3] * y + e[6] * z;
  1905. this.y = e[1] * x + e[4] * y + e[7] * z;
  1906. this.z = e[2] * x + e[5] * y + e[8] * z;
  1907. return this;
  1908. },
  1909. applyMatrix4: function (m) {
  1910. var x = this.x,
  1911. y = this.y,
  1912. z = this.z;
  1913. var e = m.elements;
  1914. var w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]);
  1915. this.x = (e[0] * x + e[4] * y + e[8] * z + e[12]) * w;
  1916. this.y = (e[1] * x + e[5] * y + e[9] * z + e[13]) * w;
  1917. this.z = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w;
  1918. return this;
  1919. },
  1920. applyQuaternion: function (q) {
  1921. var x = this.x,
  1922. y = this.y,
  1923. z = this.z;
  1924. var qx = q.x,
  1925. qy = q.y,
  1926. qz = q.z,
  1927. qw = q.w;
  1928. // calculate quat * vector
  1929. var ix = qw * x + qy * z - qz * y;
  1930. var iy = qw * y + qz * x - qx * z;
  1931. var iz = qw * z + qx * y - qy * x;
  1932. var iw = -qx * x - qy * y - qz * z;
  1933. // calculate result * inverse quat
  1934. this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  1935. this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  1936. this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  1937. return this;
  1938. },
  1939. project: function () {
  1940. var matrix = new Matrix4();
  1941. return function project(camera) {
  1942. matrix.multiplyMatrices(camera.projectionMatrix, matrix.getInverse(camera.matrixWorld));
  1943. return this.applyMatrix4(matrix);
  1944. };
  1945. }(),
  1946. unproject: function () {
  1947. var matrix = new Matrix4();
  1948. return function unproject(camera) {
  1949. matrix.multiplyMatrices(camera.matrixWorld, matrix.getInverse(camera.projectionMatrix));
  1950. return this.applyMatrix4(matrix);
  1951. };
  1952. }(),
  1953. transformDirection: function (m) {
  1954. // input: THREE.Matrix4 affine matrix
  1955. // vector interpreted as a direction
  1956. var x = this.x,
  1957. y = this.y,
  1958. z = this.z;
  1959. var e = m.elements;
  1960. this.x = e[0] * x + e[4] * y + e[8] * z;
  1961. this.y = e[1] * x + e[5] * y + e[9] * z;
  1962. this.z = e[2] * x + e[6] * y + e[10] * z;
  1963. return this.normalize();
  1964. },
  1965. divide: function (v) {
  1966. this.x /= v.x;
  1967. this.y /= v.y;
  1968. this.z /= v.z;
  1969. return this;
  1970. },
  1971. divideScalar: function (scalar) {
  1972. return this.multiplyScalar(1 / scalar);
  1973. },
  1974. min: function (v) {
  1975. this.x = Math.min(this.x, v.x);
  1976. this.y = Math.min(this.y, v.y);
  1977. this.z = Math.min(this.z, v.z);
  1978. return this;
  1979. },
  1980. max: function (v) {
  1981. this.x = Math.max(this.x, v.x);
  1982. this.y = Math.max(this.y, v.y);
  1983. this.z = Math.max(this.z, v.z);
  1984. return this;
  1985. },
  1986. clamp: function (min, max) {
  1987. // assumes min < max, componentwise
  1988. this.x = Math.max(min.x, Math.min(max.x, this.x));
  1989. this.y = Math.max(min.y, Math.min(max.y, this.y));
  1990. this.z = Math.max(min.z, Math.min(max.z, this.z));
  1991. return this;
  1992. },
  1993. clampScalar: function () {
  1994. var min = new Vector3();
  1995. var max = new Vector3();
  1996. return function clampScalar(minVal, maxVal) {
  1997. min.set(minVal, minVal, minVal);
  1998. max.set(maxVal, maxVal, maxVal);
  1999. return this.clamp(min, max);
  2000. };
  2001. }(),
  2002. clampLength: function (min, max) {
  2003. var length = this.length();
  2004. return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
  2005. },
  2006. floor: function () {
  2007. this.x = Math.floor(this.x);
  2008. this.y = Math.floor(this.y);
  2009. this.z = Math.floor(this.z);
  2010. return this;
  2011. },
  2012. ceil: function () {
  2013. this.x = Math.ceil(this.x);
  2014. this.y = Math.ceil(this.y);
  2015. this.z = Math.ceil(this.z);
  2016. return this;
  2017. },
  2018. round: function () {
  2019. this.x = Math.round(this.x);
  2020. this.y = Math.round(this.y);
  2021. this.z = Math.round(this.z);
  2022. return this;
  2023. },
  2024. roundToZero: function () {
  2025. this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
  2026. this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
  2027. this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z);
  2028. return this;
  2029. },
  2030. negate: function () {
  2031. this.x = -this.x;
  2032. this.y = -this.y;
  2033. this.z = -this.z;
  2034. return this;
  2035. },
  2036. dot: function (v) {
  2037. return this.x * v.x + this.y * v.y + this.z * v.z;
  2038. },
  2039. // TODO lengthSquared?
  2040. lengthSq: function () {
  2041. return this.x * this.x + this.y * this.y + this.z * this.z;
  2042. },
  2043. length: function () {
  2044. return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
  2045. },
  2046. manhattanLength: function () {
  2047. return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z);
  2048. },
  2049. normalize: function () {
  2050. return this.divideScalar(this.length() || 1);
  2051. },
  2052. setLength: function (length) {
  2053. return this.normalize().multiplyScalar(length);
  2054. },
  2055. lerp: function (v, alpha) {
  2056. this.x += (v.x - this.x) * alpha;
  2057. this.y += (v.y - this.y) * alpha;
  2058. this.z += (v.z - this.z) * alpha;
  2059. return this;
  2060. },
  2061. lerpVectors: function (v1, v2, alpha) {
  2062. return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
  2063. },
  2064. cross: function (v, w) {
  2065. if (w !== undefined) {
  2066. console.warn('THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.');
  2067. return this.crossVectors(v, w);
  2068. }
  2069. return this.crossVectors(this, v);
  2070. },
  2071. crossVectors: function (a, b) {
  2072. var ax = a.x,
  2073. ay = a.y,
  2074. az = a.z;
  2075. var bx = b.x,
  2076. by = b.y,
  2077. bz = b.z;
  2078. this.x = ay * bz - az * by;
  2079. this.y = az * bx - ax * bz;
  2080. this.z = ax * by - ay * bx;
  2081. return this;
  2082. },
  2083. projectOnVector: function (vector) {
  2084. var scalar = vector.dot(this) / vector.lengthSq();
  2085. return this.copy(vector).multiplyScalar(scalar);
  2086. },
  2087. projectOnPlane: function () {
  2088. var v1 = new Vector3();
  2089. return function projectOnPlane(planeNormal) {
  2090. v1.copy(this).projectOnVector(planeNormal);
  2091. return this.sub(v1);
  2092. };
  2093. }(),
  2094. reflect: function () {
  2095. // reflect incident vector off plane orthogonal to normal
  2096. // normal is assumed to have unit length
  2097. var v1 = new Vector3();
  2098. return function reflect(normal) {
  2099. return this.sub(v1.copy(normal).multiplyScalar(2 * this.dot(normal)));
  2100. };
  2101. }(),
  2102. angleTo: function (v) {
  2103. var theta = this.dot(v) / Math.sqrt(this.lengthSq() * v.lengthSq());
  2104. // clamp, to handle numerical problems
  2105. return Math.acos(_Math.clamp(theta, -1, 1));
  2106. },
  2107. distanceTo: function (v) {
  2108. return Math.sqrt(this.distanceToSquared(v));
  2109. },
  2110. distanceToSquared: function (v) {
  2111. var dx = this.x - v.x,
  2112. dy = this.y - v.y,
  2113. dz = this.z - v.z;
  2114. return dx * dx + dy * dy + dz * dz;
  2115. },
  2116. manhattanDistanceTo: function (v) {
  2117. return Math.abs(this.x - v.x) + Math.abs(this.y - v.y) + Math.abs(this.z - v.z);
  2118. },
  2119. setFromSpherical: function (s) {
  2120. var sinPhiRadius = Math.sin(s.phi) * s.radius;
  2121. this.x = sinPhiRadius * Math.sin(s.theta);
  2122. this.y = Math.cos(s.phi) * s.radius;
  2123. this.z = sinPhiRadius * Math.cos(s.theta);
  2124. return this;
  2125. },
  2126. setFromCylindrical: function (c) {
  2127. this.x = c.radius * Math.sin(c.theta);
  2128. this.y = c.y;
  2129. this.z = c.radius * Math.cos(c.theta);
  2130. return this;
  2131. },
  2132. setFromMatrixPosition: function (m) {
  2133. var e = m.elements;
  2134. this.x = e[12];
  2135. this.y = e[13];
  2136. this.z = e[14];
  2137. return this;
  2138. },
  2139. setFromMatrixScale: function (m) {
  2140. var sx = this.setFromMatrixColumn(m, 0).length();
  2141. var sy = this.setFromMatrixColumn(m, 1).length();
  2142. var sz = this.setFromMatrixColumn(m, 2).length();
  2143. this.x = sx;
  2144. this.y = sy;
  2145. this.z = sz;
  2146. return this;
  2147. },
  2148. setFromMatrixColumn: function (m, index) {
  2149. return this.fromArray(m.elements, index * 4);
  2150. },
  2151. equals: function (v) {
  2152. return v.x === this.x && v.y === this.y && v.z === this.z;
  2153. },
  2154. fromArray: function (array, offset) {
  2155. if (offset === undefined) offset = 0;
  2156. this.x = array[offset];
  2157. this.y = array[offset + 1];
  2158. this.z = array[offset + 2];
  2159. return this;
  2160. },
  2161. toArray: function (array, offset) {
  2162. if (array === undefined) array = [];
  2163. if (offset === undefined) offset = 0;
  2164. array[offset] = this.x;
  2165. array[offset + 1] = this.y;
  2166. array[offset + 2] = this.z;
  2167. return array;
  2168. },
  2169. fromBufferAttribute: function (attribute, index, offset) {
  2170. if (offset !== undefined) {
  2171. console.warn('THREE.Vector3: offset has been removed from .fromBufferAttribute().');
  2172. }
  2173. this.x = attribute.getX(index);
  2174. this.y = attribute.getY(index);
  2175. this.z = attribute.getZ(index);
  2176. return this;
  2177. }
  2178. });
  2179. /**
  2180. * @author alteredq / http://alteredqualia.com/
  2181. * @author WestLangley / http://github.com/WestLangley
  2182. * @author bhouston / http://clara.io
  2183. * @author tschw
  2184. */
  2185. function Matrix3() {
  2186. this.elements = [1, 0, 0, 0, 1, 0, 0, 0, 1];
  2187. if (arguments.length > 0) {
  2188. console.error('THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.');
  2189. }
  2190. }
  2191. Object.assign(Matrix3.prototype, {
  2192. isMatrix3: true,
  2193. set: function (n11, n12, n13, n21, n22, n23, n31, n32, n33) {
  2194. var te = this.elements;
  2195. te[0] = n11;te[1] = n21;te[2] = n31;
  2196. te[3] = n12;te[4] = n22;te[5] = n32;
  2197. te[6] = n13;te[7] = n23;te[8] = n33;
  2198. return this;
  2199. },
  2200. identity: function () {
  2201. this.set(1, 0, 0, 0, 1, 0, 0, 0, 1);
  2202. return this;
  2203. },
  2204. clone: function () {
  2205. return new this.constructor().fromArray(this.elements);
  2206. },
  2207. copy: function (m) {
  2208. var te = this.elements;
  2209. var me = m.elements;
  2210. te[0] = me[0];te[1] = me[1];te[2] = me[2];
  2211. te[3] = me[3];te[4] = me[4];te[5] = me[5];
  2212. te[6] = me[6];te[7] = me[7];te[8] = me[8];
  2213. return this;
  2214. },
  2215. setFromMatrix4: function (m) {
  2216. var me = m.elements;
  2217. this.set(me[0], me[4], me[8], me[1], me[5], me[9], me[2], me[6], me[10]);
  2218. return this;
  2219. },
  2220. applyToBufferAttribute: function () {
  2221. var v1 = new Vector3();
  2222. return function applyToBufferAttribute(attribute) {
  2223. for (var i = 0, l = attribute.count; i < l; i++) {
  2224. v1.x = attribute.getX(i);
  2225. v1.y = attribute.getY(i);
  2226. v1.z = attribute.getZ(i);
  2227. v1.applyMatrix3(this);
  2228. attribute.setXYZ(i, v1.x, v1.y, v1.z);
  2229. }
  2230. return attribute;
  2231. };
  2232. }(),
  2233. multiply: function (m) {
  2234. return this.multiplyMatrices(this, m);
  2235. },
  2236. premultiply: function (m) {
  2237. return this.multiplyMatrices(m, this);
  2238. },
  2239. multiplyMatrices: function (a, b) {
  2240. var ae = a.elements;
  2241. var be = b.elements;
  2242. var te = this.elements;
  2243. var a11 = ae[0],
  2244. a12 = ae[3],
  2245. a13 = ae[6];
  2246. var a21 = ae[1],
  2247. a22 = ae[4],
  2248. a23 = ae[7];
  2249. var a31 = ae[2],
  2250. a32 = ae[5],
  2251. a33 = ae[8];
  2252. var b11 = be[0],
  2253. b12 = be[3],
  2254. b13 = be[6];
  2255. var b21 = be[1],
  2256. b22 = be[4],
  2257. b23 = be[7];
  2258. var b31 = be[2],
  2259. b32 = be[5],
  2260. b33 = be[8];
  2261. te[0] = a11 * b11 + a12 * b21 + a13 * b31;
  2262. te[3] = a11 * b12 + a12 * b22 + a13 * b32;
  2263. te[6] = a11 * b13 + a12 * b23 + a13 * b33;
  2264. te[1] = a21 * b11 + a22 * b21 + a23 * b31;
  2265. te[4] = a21 * b12 + a22 * b22 + a23 * b32;
  2266. te[7] = a21 * b13 + a22 * b23 + a23 * b33;
  2267. te[2] = a31 * b11 + a32 * b21 + a33 * b31;
  2268. te[5] = a31 * b12 + a32 * b22 + a33 * b32;
  2269. te[8] = a31 * b13 + a32 * b23 + a33 * b33;
  2270. return this;
  2271. },
  2272. multiplyScalar: function (s) {
  2273. var te = this.elements;
  2274. te[0] *= s;te[3] *= s;te[6] *= s;
  2275. te[1] *= s;te[4] *= s;te[7] *= s;
  2276. te[2] *= s;te[5] *= s;te[8] *= s;
  2277. return this;
  2278. },
  2279. determinant: function () {
  2280. var te = this.elements;
  2281. var a = te[0],
  2282. b = te[1],
  2283. c = te[2],
  2284. d = te[3],
  2285. e = te[4],
  2286. f = te[5],
  2287. g = te[6],
  2288. h = te[7],
  2289. i = te[8];
  2290. return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
  2291. },
  2292. getInverse: function (matrix, throwOnDegenerate) {
  2293. if (matrix && matrix.isMatrix4) {
  2294. console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");
  2295. }
  2296. var me = matrix.elements,
  2297. te = this.elements,
  2298. n11 = me[0],
  2299. n21 = me[1],
  2300. n31 = me[2],
  2301. n12 = me[3],
  2302. n22 = me[4],
  2303. n32 = me[5],
  2304. n13 = me[6],
  2305. n23 = me[7],
  2306. n33 = me[8],
  2307. t11 = n33 * n22 - n32 * n23,
  2308. t12 = n32 * n13 - n33 * n12,
  2309. t13 = n23 * n12 - n22 * n13,
  2310. det = n11 * t11 + n21 * t12 + n31 * t13;
  2311. if (det === 0) {
  2312. var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
  2313. if (throwOnDegenerate === true) {
  2314. throw new Error(msg);
  2315. } else {
  2316. console.warn(msg);
  2317. }
  2318. return this.identity();
  2319. }
  2320. var detInv = 1 / det;
  2321. te[0] = t11 * detInv;
  2322. te[1] = (n31 * n23 - n33 * n21) * detInv;
  2323. te[2] = (n32 * n21 - n31 * n22) * detInv;
  2324. te[3] = t12 * detInv;
  2325. te[4] = (n33 * n11 - n31 * n13) * detInv;
  2326. te[5] = (n31 * n12 - n32 * n11) * detInv;
  2327. te[6] = t13 * detInv;
  2328. te[7] = (n21 * n13 - n23 * n11) * detInv;
  2329. te[8] = (n22 * n11 - n21 * n12) * detInv;
  2330. return this;
  2331. },
  2332. transpose: function () {
  2333. var tmp,
  2334. m = this.elements;
  2335. tmp = m[1];m[1] = m[3];m[3] = tmp;
  2336. tmp = m[2];m[2] = m[6];m[6] = tmp;
  2337. tmp = m[5];m[5] = m[7];m[7] = tmp;
  2338. return this;
  2339. },
  2340. getNormalMatrix: function (matrix4) {
  2341. return this.setFromMatrix4(matrix4).getInverse(this).transpose();
  2342. },
  2343. transposeIntoArray: function (r) {
  2344. var m = this.elements;
  2345. r[0] = m[0];
  2346. r[1] = m[3];
  2347. r[2] = m[6];
  2348. r[3] = m[1];
  2349. r[4] = m[4];
  2350. r[5] = m[7];
  2351. r[6] = m[2];
  2352. r[7] = m[5];
  2353. r[8] = m[8];
  2354. return this;
  2355. },
  2356. setUvTransform: function (tx, ty, sx, sy, rotation, cx, cy) {
  2357. var c = Math.cos(rotation);
  2358. var s = Math.sin(rotation);
  2359. this.set(sx * c, sx * s, -sx * (c * cx + s * cy) + cx + tx, -sy * s, sy * c, -sy * (-s * cx + c * cy) + cy + ty, 0, 0, 1);
  2360. },
  2361. scale: function (sx, sy) {
  2362. var te = this.elements;
  2363. te[0] *= sx;te[3] *= sx;te[6] *= sx;
  2364. te[1] *= sy;te[4] *= sy;te[7] *= sy;
  2365. return this;
  2366. },
  2367. rotate: function (theta) {
  2368. var c = Math.cos(theta);
  2369. var s = Math.sin(theta);
  2370. var te = this.elements;
  2371. var a11 = te[0],
  2372. a12 = te[3],
  2373. a13 = te[6];
  2374. var a21 = te[1],
  2375. a22 = te[4],
  2376. a23 = te[7];
  2377. te[0] = c * a11 + s * a21;
  2378. te[3] = c * a12 + s * a22;
  2379. te[6] = c * a13 + s * a23;
  2380. te[1] = -s * a11 + c * a21;
  2381. te[4] = -s * a12 + c * a22;
  2382. te[7] = -s * a13 + c * a23;
  2383. return this;
  2384. },
  2385. translate: function (tx, ty) {
  2386. var te = this.elements;
  2387. te[0] += tx * te[2];te[3] += tx * te[5];te[6] += tx * te[8];
  2388. te[1] += ty * te[2];te[4] += ty * te[5];te[7] += ty * te[8];
  2389. return this;
  2390. },
  2391. equals: function (matrix) {
  2392. var te = this.elements;
  2393. var me = matrix.elements;
  2394. for (var i = 0; i < 9; i++) {
  2395. if (te[i] !== me[i]) return false;
  2396. }
  2397. return true;
  2398. },
  2399. fromArray: function (array, offset) {
  2400. if (offset === undefined) offset = 0;
  2401. for (var i = 0; i < 9; i++) {
  2402. this.elements[i] = array[i + offset];
  2403. }
  2404. return this;
  2405. },
  2406. toArray: function (array, offset) {
  2407. if (array === undefined) array = [];
  2408. if (offset === undefined) offset = 0;
  2409. var te = this.elements;
  2410. array[offset] = te[0];
  2411. array[offset + 1] = te[1];
  2412. array[offset + 2] = te[2];
  2413. array[offset + 3] = te[3];
  2414. array[offset + 4] = te[4];
  2415. array[offset + 5] = te[5];
  2416. array[offset + 6] = te[6];
  2417. array[offset + 7] = te[7];
  2418. array[offset + 8] = te[8];
  2419. return array;
  2420. }
  2421. });
  2422. /**
  2423. * @author mrdoob / http://mrdoob.com/
  2424. * @author alteredq / http://alteredqualia.com/
  2425. * @author szimek / https://github.com/szimek/
  2426. */
  2427. var textureId = 0;
  2428. function Texture(image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding) {
  2429. Object.defineProperty(this, 'id', { value: textureId++ });
  2430. this.uuid = _Math.generateUUID();
  2431. this.name = '';
  2432. this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
  2433. this.mipmaps = [];
  2434. this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
  2435. this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
  2436. this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
  2437. this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
  2438. this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
  2439. this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
  2440. this.format = format !== undefined ? format : RGBAFormat;
  2441. this.type = type !== undefined ? type : UnsignedByteType;
  2442. this.offset = new Vector2(0, 0);
  2443. this.repeat = new Vector2(1, 1);
  2444. this.center = new Vector2(0, 0);
  2445. this.rotation = 0;
  2446. this.matrixAutoUpdate = true;
  2447. this.matrix = new Matrix3();
  2448. this.generateMipmaps = true;
  2449. this.premultiplyAlpha = false;
  2450. this.flipY = true;
  2451. this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
  2452. // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
  2453. //
  2454. // Also changing the encoding after already used by a Material will not automatically make the Material
  2455. // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
  2456. this.encoding = encoding !== undefined ? encoding : LinearEncoding;
  2457. this.version = 0;
  2458. this.onUpdate = null;
  2459. }
  2460. Texture.DEFAULT_IMAGE = undefined;
  2461. Texture.DEFAULT_MAPPING = UVMapping;
  2462. Texture.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  2463. constructor: Texture,
  2464. isTexture: true,
  2465. updateMatrix: function () {
  2466. this.matrix.setUvTransform(this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y);
  2467. },
  2468. clone: function () {
  2469. return new this.constructor().copy(this);
  2470. },
  2471. copy: function (source) {
  2472. this.name = source.name;
  2473. this.image = source.image;
  2474. this.mipmaps = source.mipmaps.slice(0);
  2475. this.mapping = source.mapping;
  2476. this.wrapS = source.wrapS;
  2477. this.wrapT = source.wrapT;
  2478. this.magFilter = source.magFilter;
  2479. this.minFilter = source.minFilter;
  2480. this.anisotropy = source.anisotropy;
  2481. this.format = source.format;
  2482. this.type = source.type;
  2483. this.offset.copy(source.offset);
  2484. this.repeat.copy(source.repeat);
  2485. this.center.copy(source.center);
  2486. this.rotation = source.rotation;
  2487. this.matrixAutoUpdate = source.matrixAutoUpdate;
  2488. this.matrix.copy(source.matrix);
  2489. this.generateMipmaps = source.generateMipmaps;
  2490. this.premultiplyAlpha = source.premultiplyAlpha;
  2491. this.flipY = source.flipY;
  2492. this.unpackAlignment = source.unpackAlignment;
  2493. this.encoding = source.encoding;
  2494. return this;
  2495. },
  2496. toJSON: function (meta) {
  2497. var isRootObject = meta === undefined || typeof meta === 'string';
  2498. if (!isRootObject && meta.textures[this.uuid] !== undefined) {
  2499. return meta.textures[this.uuid];
  2500. }
  2501. function getDataURL(image) {
  2502. var canvas;
  2503. if (image instanceof HTMLCanvasElement) {
  2504. canvas = image;
  2505. } else {
  2506. canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
  2507. canvas.width = image.width;
  2508. canvas.height = image.height;
  2509. var context = canvas.getContext('2d');
  2510. if (image instanceof ImageData) {
  2511. context.putImageData(image, 0, 0);
  2512. } else {
  2513. context.drawImage(image, 0, 0, image.width, image.height);
  2514. }
  2515. }
  2516. if (canvas.width > 2048 || canvas.height > 2048) {
  2517. return canvas.toDataURL('image/jpeg', 0.6);
  2518. } else {
  2519. return canvas.toDataURL('image/png');
  2520. }
  2521. }
  2522. var output = {
  2523. metadata: {
  2524. version: 4.5,
  2525. type: 'Texture',
  2526. generator: 'Texture.toJSON'
  2527. },
  2528. uuid: this.uuid,
  2529. name: this.name,
  2530. mapping: this.mapping,
  2531. repeat: [this.repeat.x, this.repeat.y],
  2532. offset: [this.offset.x, this.offset.y],
  2533. center: [this.center.x, this.center.y],
  2534. rotation: this.rotation,
  2535. wrap: [this.wrapS, this.wrapT],
  2536. format: this.format,
  2537. minFilter: this.minFilter,
  2538. magFilter: this.magFilter,
  2539. anisotropy: this.anisotropy,
  2540. flipY: this.flipY
  2541. };
  2542. if (this.image !== undefined) {
  2543. // TODO: Move to THREE.Image
  2544. var image = this.image;
  2545. if (image.uuid === undefined) {
  2546. image.uuid = _Math.generateUUID(); // UGH
  2547. }
  2548. if (!isRootObject && meta.images[image.uuid] === undefined) {
  2549. meta.images[image.uuid] = {
  2550. uuid: image.uuid,
  2551. url: getDataURL(image)
  2552. };
  2553. }
  2554. output.image = image.uuid;
  2555. }
  2556. if (!isRootObject) {
  2557. meta.textures[this.uuid] = output;
  2558. }
  2559. return output;
  2560. },
  2561. dispose: function () {
  2562. this.dispatchEvent({ type: 'dispose' });
  2563. },
  2564. transformUv: function (uv) {
  2565. if (this.mapping !== UVMapping) return;
  2566. uv.applyMatrix3(this.matrix);
  2567. if (uv.x < 0 || uv.x > 1) {
  2568. switch (this.wrapS) {
  2569. case RepeatWrapping:
  2570. uv.x = uv.x - Math.floor(uv.x);
  2571. break;
  2572. case ClampToEdgeWrapping:
  2573. uv.x = uv.x < 0 ? 0 : 1;
  2574. break;
  2575. case MirroredRepeatWrapping:
  2576. if (Math.abs(Math.floor(uv.x) % 2) === 1) {
  2577. uv.x = Math.ceil(uv.x) - uv.x;
  2578. } else {
  2579. uv.x = uv.x - Math.floor(uv.x);
  2580. }
  2581. break;
  2582. }
  2583. }
  2584. if (uv.y < 0 || uv.y > 1) {
  2585. switch (this.wrapT) {
  2586. case RepeatWrapping:
  2587. uv.y = uv.y - Math.floor(uv.y);
  2588. break;
  2589. case ClampToEdgeWrapping:
  2590. uv.y = uv.y < 0 ? 0 : 1;
  2591. break;
  2592. case MirroredRepeatWrapping:
  2593. if (Math.abs(Math.floor(uv.y) % 2) === 1) {
  2594. uv.y = Math.ceil(uv.y) - uv.y;
  2595. } else {
  2596. uv.y = uv.y - Math.floor(uv.y);
  2597. }
  2598. break;
  2599. }
  2600. }
  2601. if (this.flipY) {
  2602. uv.y = 1 - uv.y;
  2603. }
  2604. }
  2605. });
  2606. Object.defineProperty(Texture.prototype, "needsUpdate", {
  2607. set: function (value) {
  2608. if (value === true) this.version++;
  2609. }
  2610. });
  2611. /**
  2612. * @author supereggbert / http://www.paulbrunt.co.uk/
  2613. * @author philogb / http://blog.thejit.org/
  2614. * @author mikael emtinger / http://gomo.se/
  2615. * @author egraether / http://egraether.com/
  2616. * @author WestLangley / http://github.com/WestLangley
  2617. */
  2618. function Vector4(x, y, z, w) {
  2619. this.x = x || 0;
  2620. this.y = y || 0;
  2621. this.z = z || 0;
  2622. this.w = w !== undefined ? w : 1;
  2623. }
  2624. Object.assign(Vector4.prototype, {
  2625. isVector4: true,
  2626. set: function (x, y, z, w) {
  2627. this.x = x;
  2628. this.y = y;
  2629. this.z = z;
  2630. this.w = w;
  2631. return this;
  2632. },
  2633. setScalar: function (scalar) {
  2634. this.x = scalar;
  2635. this.y = scalar;
  2636. this.z = scalar;
  2637. this.w = scalar;
  2638. return this;
  2639. },
  2640. setX: function (x) {
  2641. this.x = x;
  2642. return this;
  2643. },
  2644. setY: function (y) {
  2645. this.y = y;
  2646. return this;
  2647. },
  2648. setZ: function (z) {
  2649. this.z = z;
  2650. return this;
  2651. },
  2652. setW: function (w) {
  2653. this.w = w;
  2654. return this;
  2655. },
  2656. setComponent: function (index, value) {
  2657. switch (index) {
  2658. case 0:
  2659. this.x = value;break;
  2660. case 1:
  2661. this.y = value;break;
  2662. case 2:
  2663. this.z = value;break;
  2664. case 3:
  2665. this.w = value;break;
  2666. default:
  2667. throw new Error('index is out of range: ' + index);
  2668. }
  2669. return this;
  2670. },
  2671. getComponent: function (index) {
  2672. switch (index) {
  2673. case 0:
  2674. return this.x;
  2675. case 1:
  2676. return this.y;
  2677. case 2:
  2678. return this.z;
  2679. case 3:
  2680. return this.w;
  2681. default:
  2682. throw new Error('index is out of range: ' + index);
  2683. }
  2684. },
  2685. clone: function () {
  2686. return new this.constructor(this.x, this.y, this.z, this.w);
  2687. },
  2688. copy: function (v) {
  2689. this.x = v.x;
  2690. this.y = v.y;
  2691. this.z = v.z;
  2692. this.w = v.w !== undefined ? v.w : 1;
  2693. return this;
  2694. },
  2695. add: function (v, w) {
  2696. if (w !== undefined) {
  2697. console.warn('THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
  2698. return this.addVectors(v, w);
  2699. }
  2700. this.x += v.x;
  2701. this.y += v.y;
  2702. this.z += v.z;
  2703. this.w += v.w;
  2704. return this;
  2705. },
  2706. addScalar: function (s) {
  2707. this.x += s;
  2708. this.y += s;
  2709. this.z += s;
  2710. this.w += s;
  2711. return this;
  2712. },
  2713. addVectors: function (a, b) {
  2714. this.x = a.x + b.x;
  2715. this.y = a.y + b.y;
  2716. this.z = a.z + b.z;
  2717. this.w = a.w + b.w;
  2718. return this;
  2719. },
  2720. addScaledVector: function (v, s) {
  2721. this.x += v.x * s;
  2722. this.y += v.y * s;
  2723. this.z += v.z * s;
  2724. this.w += v.w * s;
  2725. return this;
  2726. },
  2727. sub: function (v, w) {
  2728. if (w !== undefined) {
  2729. console.warn('THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
  2730. return this.subVectors(v, w);
  2731. }
  2732. this.x -= v.x;
  2733. this.y -= v.y;
  2734. this.z -= v.z;
  2735. this.w -= v.w;
  2736. return this;
  2737. },
  2738. subScalar: function (s) {
  2739. this.x -= s;
  2740. this.y -= s;
  2741. this.z -= s;
  2742. this.w -= s;
  2743. return this;
  2744. },
  2745. subVectors: function (a, b) {
  2746. this.x = a.x - b.x;
  2747. this.y = a.y - b.y;
  2748. this.z = a.z - b.z;
  2749. this.w = a.w - b.w;
  2750. return this;
  2751. },
  2752. multiplyScalar: function (scalar) {
  2753. this.x *= scalar;
  2754. this.y *= scalar;
  2755. this.z *= scalar;
  2756. this.w *= scalar;
  2757. return this;
  2758. },
  2759. applyMatrix4: function (m) {
  2760. var x = this.x,
  2761. y = this.y,
  2762. z = this.z,
  2763. w = this.w;
  2764. var e = m.elements;
  2765. this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w;
  2766. this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w;
  2767. this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w;
  2768. this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w;
  2769. return this;
  2770. },
  2771. divideScalar: function (scalar) {
  2772. return this.multiplyScalar(1 / scalar);
  2773. },
  2774. setAxisAngleFromQuaternion: function (q) {
  2775. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
  2776. // q is assumed to be normalized
  2777. this.w = 2 * Math.acos(q.w);
  2778. var s = Math.sqrt(1 - q.w * q.w);
  2779. if (s < 0.0001) {
  2780. this.x = 1;
  2781. this.y = 0;
  2782. this.z = 0;
  2783. } else {
  2784. this.x = q.x / s;
  2785. this.y = q.y / s;
  2786. this.z = q.z / s;
  2787. }
  2788. return this;
  2789. },
  2790. setAxisAngleFromRotationMatrix: function (m) {
  2791. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
  2792. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  2793. var angle,
  2794. x,
  2795. y,
  2796. z,
  2797. // variables for result
  2798. epsilon = 0.01,
  2799. // margin to allow for rounding errors
  2800. epsilon2 = 0.1,
  2801. // margin to distinguish between 0 and 180 degrees
  2802. te = m.elements,
  2803. m11 = te[0],
  2804. m12 = te[4],
  2805. m13 = te[8],
  2806. m21 = te[1],
  2807. m22 = te[5],
  2808. m23 = te[9],
  2809. m31 = te[2],
  2810. m32 = te[6],
  2811. m33 = te[10];
  2812. if (Math.abs(m12 - m21) < epsilon && Math.abs(m13 - m31) < epsilon && Math.abs(m23 - m32) < epsilon) {
  2813. // singularity found
  2814. // first check for identity matrix which must have +1 for all terms
  2815. // in leading diagonal and zero in other terms
  2816. if (Math.abs(m12 + m21) < epsilon2 && Math.abs(m13 + m31) < epsilon2 && Math.abs(m23 + m32) < epsilon2 && Math.abs(m11 + m22 + m33 - 3) < epsilon2) {
  2817. // this singularity is identity matrix so angle = 0
  2818. this.set(1, 0, 0, 0);
  2819. return this; // zero angle, arbitrary axis
  2820. }
  2821. // otherwise this singularity is angle = 180
  2822. angle = Math.PI;
  2823. var xx = (m11 + 1) / 2;
  2824. var yy = (m22 + 1) / 2;
  2825. var zz = (m33 + 1) / 2;
  2826. var xy = (m12 + m21) / 4;
  2827. var xz = (m13 + m31) / 4;
  2828. var yz = (m23 + m32) / 4;
  2829. if (xx > yy && xx > zz) {
  2830. // m11 is the largest diagonal term
  2831. if (xx < epsilon) {
  2832. x = 0;
  2833. y = 0.707106781;
  2834. z = 0.707106781;
  2835. } else {
  2836. x = Math.sqrt(xx);
  2837. y = xy / x;
  2838. z = xz / x;
  2839. }
  2840. } else if (yy > zz) {
  2841. // m22 is the largest diagonal term
  2842. if (yy < epsilon) {
  2843. x = 0.707106781;
  2844. y = 0;
  2845. z = 0.707106781;
  2846. } else {
  2847. y = Math.sqrt(yy);
  2848. x = xy / y;
  2849. z = yz / y;
  2850. }
  2851. } else {
  2852. // m33 is the largest diagonal term so base result on this
  2853. if (zz < epsilon) {
  2854. x = 0.707106781;
  2855. y = 0.707106781;
  2856. z = 0;
  2857. } else {
  2858. z = Math.sqrt(zz);
  2859. x = xz / z;
  2860. y = yz / z;
  2861. }
  2862. }
  2863. this.set(x, y, z, angle);
  2864. return this; // return 180 deg rotation
  2865. }
  2866. // as we have reached here there are no singularities so we can handle normally
  2867. var s = Math.sqrt((m32 - m23) * (m32 - m23) + (m13 - m31) * (m13 - m31) + (m21 - m12) * (m21 - m12)); // used to normalize
  2868. if (Math.abs(s) < 0.001) s = 1;
  2869. // prevent divide by zero, should not happen if matrix is orthogonal and should be
  2870. // caught by singularity test above, but I've left it in just in case
  2871. this.x = (m32 - m23) / s;
  2872. this.y = (m13 - m31) / s;
  2873. this.z = (m21 - m12) / s;
  2874. this.w = Math.acos((m11 + m22 + m33 - 1) / 2);
  2875. return this;
  2876. },
  2877. min: function (v) {
  2878. this.x = Math.min(this.x, v.x);
  2879. this.y = Math.min(this.y, v.y);
  2880. this.z = Math.min(this.z, v.z);
  2881. this.w = Math.min(this.w, v.w);
  2882. return this;
  2883. },
  2884. max: function (v) {
  2885. this.x = Math.max(this.x, v.x);
  2886. this.y = Math.max(this.y, v.y);
  2887. this.z = Math.max(this.z, v.z);
  2888. this.w = Math.max(this.w, v.w);
  2889. return this;
  2890. },
  2891. clamp: function (min, max) {
  2892. // assumes min < max, componentwise
  2893. this.x = Math.max(min.x, Math.min(max.x, this.x));
  2894. this.y = Math.max(min.y, Math.min(max.y, this.y));
  2895. this.z = Math.max(min.z, Math.min(max.z, this.z));
  2896. this.w = Math.max(min.w, Math.min(max.w, this.w));
  2897. return this;
  2898. },
  2899. clampScalar: function () {
  2900. var min, max;
  2901. return function clampScalar(minVal, maxVal) {
  2902. if (min === undefined) {
  2903. min = new Vector4();
  2904. max = new Vector4();
  2905. }
  2906. min.set(minVal, minVal, minVal, minVal);
  2907. max.set(maxVal, maxVal, maxVal, maxVal);
  2908. return this.clamp(min, max);
  2909. };
  2910. }(),
  2911. clampLength: function (min, max) {
  2912. var length = this.length();
  2913. return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
  2914. },
  2915. floor: function () {
  2916. this.x = Math.floor(this.x);
  2917. this.y = Math.floor(this.y);
  2918. this.z = Math.floor(this.z);
  2919. this.w = Math.floor(this.w);
  2920. return this;
  2921. },
  2922. ceil: function () {
  2923. this.x = Math.ceil(this.x);
  2924. this.y = Math.ceil(this.y);
  2925. this.z = Math.ceil(this.z);
  2926. this.w = Math.ceil(this.w);
  2927. return this;
  2928. },
  2929. round: function () {
  2930. this.x = Math.round(this.x);
  2931. this.y = Math.round(this.y);
  2932. this.z = Math.round(this.z);
  2933. this.w = Math.round(this.w);
  2934. return this;
  2935. },
  2936. roundToZero: function () {
  2937. this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
  2938. this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
  2939. this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z);
  2940. this.w = this.w < 0 ? Math.ceil(this.w) : Math.floor(this.w);
  2941. return this;
  2942. },
  2943. negate: function () {
  2944. this.x = -this.x;
  2945. this.y = -this.y;
  2946. this.z = -this.z;
  2947. this.w = -this.w;
  2948. return this;
  2949. },
  2950. dot: function (v) {
  2951. return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
  2952. },
  2953. lengthSq: function () {
  2954. return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
  2955. },
  2956. length: function () {
  2957. return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
  2958. },
  2959. manhattanLength: function () {
  2960. return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w);
  2961. },
  2962. normalize: function () {
  2963. return this.divideScalar(this.length() || 1);
  2964. },
  2965. setLength: function (length) {
  2966. return this.normalize().multiplyScalar(length);
  2967. },
  2968. lerp: function (v, alpha) {
  2969. this.x += (v.x - this.x) * alpha;
  2970. this.y += (v.y - this.y) * alpha;
  2971. this.z += (v.z - this.z) * alpha;
  2972. this.w += (v.w - this.w) * alpha;
  2973. return this;
  2974. },
  2975. lerpVectors: function (v1, v2, alpha) {
  2976. return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
  2977. },
  2978. equals: function (v) {
  2979. return v.x === this.x && v.y === this.y && v.z === this.z && v.w === this.w;
  2980. },
  2981. fromArray: function (array, offset) {
  2982. if (offset === undefined) offset = 0;
  2983. this.x = array[offset];
  2984. this.y = array[offset + 1];
  2985. this.z = array[offset + 2];
  2986. this.w = array[offset + 3];
  2987. return this;
  2988. },
  2989. toArray: function (array, offset) {
  2990. if (array === undefined) array = [];
  2991. if (offset === undefined) offset = 0;
  2992. array[offset] = this.x;
  2993. array[offset + 1] = this.y;
  2994. array[offset + 2] = this.z;
  2995. array[offset + 3] = this.w;
  2996. return array;
  2997. },
  2998. fromBufferAttribute: function (attribute, index, offset) {
  2999. if (offset !== undefined) {
  3000. console.warn('THREE.Vector4: offset has been removed from .fromBufferAttribute().');
  3001. }
  3002. this.x = attribute.getX(index);
  3003. this.y = attribute.getY(index);
  3004. this.z = attribute.getZ(index);
  3005. this.w = attribute.getW(index);
  3006. return this;
  3007. }
  3008. });
  3009. /**
  3010. * @author szimek / https://github.com/szimek/
  3011. * @author alteredq / http://alteredqualia.com/
  3012. * @author Marius Kintel / https://github.com/kintel
  3013. */
  3014. /*
  3015. In options, we can specify:
  3016. * Texture parameters for an auto-generated target texture
  3017. * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
  3018. */
  3019. function WebGLRenderTarget(width, height, options) {
  3020. this.width = width;
  3021. this.height = height;
  3022. this.scissor = new Vector4(0, 0, width, height);
  3023. this.scissorTest = false;
  3024. this.viewport = new Vector4(0, 0, width, height);
  3025. options = options || {};
  3026. if (options.minFilter === undefined) options.minFilter = LinearFilter;
  3027. this.texture = new Texture(undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding);
  3028. this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : true;
  3029. this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
  3030. this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
  3031. this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
  3032. }
  3033. WebGLRenderTarget.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  3034. constructor: WebGLRenderTarget,
  3035. isWebGLRenderTarget: true,
  3036. setSize: function (width, height) {
  3037. if (this.width !== width || this.height !== height) {
  3038. this.width = width;
  3039. this.height = height;
  3040. this.dispose();
  3041. }
  3042. this.viewport.set(0, 0, width, height);
  3043. this.scissor.set(0, 0, width, height);
  3044. },
  3045. clone: function () {
  3046. return new this.constructor().copy(this);
  3047. },
  3048. copy: function (source) {
  3049. this.width = source.width;
  3050. this.height = source.height;
  3051. this.viewport.copy(source.viewport);
  3052. this.texture = source.texture.clone();
  3053. this.depthBuffer = source.depthBuffer;
  3054. this.stencilBuffer = source.stencilBuffer;
  3055. this.depthTexture = source.depthTexture;
  3056. return this;
  3057. },
  3058. dispose: function () {
  3059. this.dispatchEvent({ type: 'dispose' });
  3060. }
  3061. });
  3062. /**
  3063. * @author alteredq / http://alteredqualia.com
  3064. */
  3065. function WebGLRenderTargetCube(width, height, options) {
  3066. WebGLRenderTarget.call(this, width, height, options);
  3067. this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
  3068. this.activeMipMapLevel = 0;
  3069. }
  3070. WebGLRenderTargetCube.prototype = Object.create(WebGLRenderTarget.prototype);
  3071. WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
  3072. WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
  3073. /**
  3074. * @author alteredq / http://alteredqualia.com/
  3075. */
  3076. function DataTexture(data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding) {
  3077. Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding);
  3078. this.image = { data: data, width: width, height: height };
  3079. this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
  3080. this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
  3081. this.generateMipmaps = false;
  3082. this.flipY = false;
  3083. this.unpackAlignment = 1;
  3084. }
  3085. DataTexture.prototype = Object.create(Texture.prototype);
  3086. DataTexture.prototype.constructor = DataTexture;
  3087. DataTexture.prototype.isDataTexture = true;
  3088. /**
  3089. * @author bhouston / http://clara.io
  3090. * @author WestLangley / http://github.com/WestLangley
  3091. */
  3092. function Box3(min, max) {
  3093. this.min = min !== undefined ? min : new Vector3(+Infinity, +Infinity, +Infinity);
  3094. this.max = max !== undefined ? max : new Vector3(-Infinity, -Infinity, -Infinity);
  3095. }
  3096. Object.assign(Box3.prototype, {
  3097. isBox3: true,
  3098. set: function (min, max) {
  3099. this.min.copy(min);
  3100. this.max.copy(max);
  3101. return this;
  3102. },
  3103. setFromArray: function (array) {
  3104. var minX = +Infinity;
  3105. var minY = +Infinity;
  3106. var minZ = +Infinity;
  3107. var maxX = -Infinity;
  3108. var maxY = -Infinity;
  3109. var maxZ = -Infinity;
  3110. for (var i = 0, l = array.length; i < l; i += 3) {
  3111. var x = array[i];
  3112. var y = array[i + 1];
  3113. var z = array[i + 2];
  3114. if (x < minX) minX = x;
  3115. if (y < minY) minY = y;
  3116. if (z < minZ) minZ = z;
  3117. if (x > maxX) maxX = x;
  3118. if (y > maxY) maxY = y;
  3119. if (z > maxZ) maxZ = z;
  3120. }
  3121. this.min.set(minX, minY, minZ);
  3122. this.max.set(maxX, maxY, maxZ);
  3123. return this;
  3124. },
  3125. setFromBufferAttribute: function (attribute) {
  3126. var minX = +Infinity;
  3127. var minY = +Infinity;
  3128. var minZ = +Infinity;
  3129. var maxX = -Infinity;
  3130. var maxY = -Infinity;
  3131. var maxZ = -Infinity;
  3132. for (var i = 0, l = attribute.count; i < l; i++) {
  3133. var x = attribute.getX(i);
  3134. var y = attribute.getY(i);
  3135. var z = attribute.getZ(i);
  3136. if (x < minX) minX = x;
  3137. if (y < minY) minY = y;
  3138. if (z < minZ) minZ = z;
  3139. if (x > maxX) maxX = x;
  3140. if (y > maxY) maxY = y;
  3141. if (z > maxZ) maxZ = z;
  3142. }
  3143. this.min.set(minX, minY, minZ);
  3144. this.max.set(maxX, maxY, maxZ);
  3145. return this;
  3146. },
  3147. setFromPoints: function (points) {
  3148. this.makeEmpty();
  3149. for (var i = 0, il = points.length; i < il; i++) {
  3150. this.expandByPoint(points[i]);
  3151. }
  3152. return this;
  3153. },
  3154. setFromCenterAndSize: function () {
  3155. var v1 = new Vector3();
  3156. return function setFromCenterAndSize(center, size) {
  3157. var halfSize = v1.copy(size).multiplyScalar(0.5);
  3158. this.min.copy(center).sub(halfSize);
  3159. this.max.copy(center).add(halfSize);
  3160. return this;
  3161. };
  3162. }(),
  3163. setFromObject: function (object) {
  3164. this.makeEmpty();
  3165. return this.expandByObject(object);
  3166. },
  3167. clone: function () {
  3168. return new this.constructor().copy(this);
  3169. },
  3170. copy: function (box) {
  3171. this.min.copy(box.min);
  3172. this.max.copy(box.max);
  3173. return this;
  3174. },
  3175. makeEmpty: function () {
  3176. this.min.x = this.min.y = this.min.z = +Infinity;
  3177. this.max.x = this.max.y = this.max.z = -Infinity;
  3178. return this;
  3179. },
  3180. isEmpty: function () {
  3181. // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  3182. return this.max.x < this.min.x || this.max.y < this.min.y || this.max.z < this.min.z;
  3183. },
  3184. getCenter: function (target) {
  3185. if (target === undefined) {
  3186. console.warn('THREE.Box3: .getCenter() target is now required');
  3187. target = new Vector3();
  3188. }
  3189. return this.isEmpty() ? target.set(0, 0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5);
  3190. },
  3191. getSize: function (target) {
  3192. if (target === undefined) {
  3193. console.warn('THREE.Box3: .getSize() target is now required');
  3194. target = new Vector3();
  3195. }
  3196. return this.isEmpty() ? target.set(0, 0, 0) : target.subVectors(this.max, this.min);
  3197. },
  3198. expandByPoint: function (point) {
  3199. this.min.min(point);
  3200. this.max.max(point);
  3201. return this;
  3202. },
  3203. expandByVector: function (vector) {
  3204. this.min.sub(vector);
  3205. this.max.add(vector);
  3206. return this;
  3207. },
  3208. expandByScalar: function (scalar) {
  3209. this.min.addScalar(-scalar);
  3210. this.max.addScalar(scalar);
  3211. return this;
  3212. },
  3213. expandByObject: function () {
  3214. // Computes the world-axis-aligned bounding box of an object (including its children),
  3215. // accounting for both the object's, and children's, world transforms
  3216. var scope, i, l;
  3217. var v1 = new Vector3();
  3218. function traverse(node) {
  3219. var geometry = node.geometry;
  3220. if (geometry !== undefined) {
  3221. if (geometry.isGeometry) {
  3222. var vertices = geometry.vertices;
  3223. for (i = 0, l = vertices.length; i < l; i++) {
  3224. v1.copy(vertices[i]);
  3225. v1.applyMatrix4(node.matrixWorld);
  3226. scope.expandByPoint(v1);
  3227. }
  3228. } else if (geometry.isBufferGeometry) {
  3229. var attribute = geometry.attributes.position;
  3230. if (attribute !== undefined) {
  3231. for (i = 0, l = attribute.count; i < l; i++) {
  3232. v1.fromBufferAttribute(attribute, i).applyMatrix4(node.matrixWorld);
  3233. scope.expandByPoint(v1);
  3234. }
  3235. }
  3236. }
  3237. }
  3238. }
  3239. return function expandByObject(object) {
  3240. scope = this;
  3241. object.updateMatrixWorld(true);
  3242. object.traverse(traverse);
  3243. return this;
  3244. };
  3245. }(),
  3246. containsPoint: function (point) {
  3247. 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;
  3248. },
  3249. containsBox: function (box) {
  3250. 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;
  3251. },
  3252. getParameter: function (point, target) {
  3253. // This can potentially have a divide by zero if the box
  3254. // has a size dimension of 0.
  3255. if (target === undefined) {
  3256. console.warn('THREE.Box3: .getParameter() target is now required');
  3257. target = new Vector3();
  3258. }
  3259. return target.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));
  3260. },
  3261. intersectsBox: function (box) {
  3262. // using 6 splitting planes to rule out intersections.
  3263. 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;
  3264. },
  3265. intersectsSphere: function () {
  3266. var closestPoint = new Vector3();
  3267. return function intersectsSphere(sphere) {
  3268. // Find the point on the AABB closest to the sphere center.
  3269. this.clampPoint(sphere.center, closestPoint);
  3270. // If that point is inside the sphere, the AABB and sphere intersect.
  3271. return closestPoint.distanceToSquared(sphere.center) <= sphere.radius * sphere.radius;
  3272. };
  3273. }(),
  3274. intersectsPlane: function (plane) {
  3275. // We compute the minimum and maximum dot product values. If those values
  3276. // are on the same side (back or front) of the plane, then there is no intersection.
  3277. var min, max;
  3278. if (plane.normal.x > 0) {
  3279. min = plane.normal.x * this.min.x;
  3280. max = plane.normal.x * this.max.x;
  3281. } else {
  3282. min = plane.normal.x * this.max.x;
  3283. max = plane.normal.x * this.min.x;
  3284. }
  3285. if (plane.normal.y > 0) {
  3286. min += plane.normal.y * this.min.y;
  3287. max += plane.normal.y * this.max.y;
  3288. } else {
  3289. min += plane.normal.y * this.max.y;
  3290. max += plane.normal.y * this.min.y;
  3291. }
  3292. if (plane.normal.z > 0) {
  3293. min += plane.normal.z * this.min.z;
  3294. max += plane.normal.z * this.max.z;
  3295. } else {
  3296. min += plane.normal.z * this.max.z;
  3297. max += plane.normal.z * this.min.z;
  3298. }
  3299. return min <= plane.constant && max >= plane.constant;
  3300. },
  3301. intersectsTriangle: function () {
  3302. // triangle centered vertices
  3303. var v0 = new Vector3();
  3304. var v1 = new Vector3();
  3305. var v2 = new Vector3();
  3306. // triangle edge vectors
  3307. var f0 = new Vector3();
  3308. var f1 = new Vector3();
  3309. var f2 = new Vector3();
  3310. var testAxis = new Vector3();
  3311. var center = new Vector3();
  3312. var extents = new Vector3();
  3313. var triangleNormal = new Vector3();
  3314. function satForAxes(axes) {
  3315. var i, j;
  3316. for (i = 0, j = axes.length - 3; i <= j; i += 3) {
  3317. testAxis.fromArray(axes, i);
  3318. // project the aabb onto the seperating axis
  3319. var r = extents.x * Math.abs(testAxis.x) + extents.y * Math.abs(testAxis.y) + extents.z * Math.abs(testAxis.z);
  3320. // project all 3 vertices of the triangle onto the seperating axis
  3321. var p0 = v0.dot(testAxis);
  3322. var p1 = v1.dot(testAxis);
  3323. var p2 = v2.dot(testAxis);
  3324. // actual test, basically see if either of the most extreme of the triangle points intersects r
  3325. if (Math.max(-Math.max(p0, p1, p2), Math.min(p0, p1, p2)) > r) {
  3326. // points of the projected triangle are outside the projected half-length of the aabb
  3327. // the axis is seperating and we can exit
  3328. return false;
  3329. }
  3330. }
  3331. return true;
  3332. }
  3333. return function intersectsTriangle(triangle) {
  3334. if (this.isEmpty()) {
  3335. return false;
  3336. }
  3337. // compute box center and extents
  3338. this.getCenter(center);
  3339. extents.subVectors(this.max, center);
  3340. // translate triangle to aabb origin
  3341. v0.subVectors(triangle.a, center);
  3342. v1.subVectors(triangle.b, center);
  3343. v2.subVectors(triangle.c, center);
  3344. // compute edge vectors for triangle
  3345. f0.subVectors(v1, v0);
  3346. f1.subVectors(v2, v1);
  3347. f2.subVectors(v0, v2);
  3348. // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
  3349. // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
  3350. // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
  3351. var axes = [0, -f0.z, f0.y, 0, -f1.z, f1.y, 0, -f2.z, f2.y, f0.z, 0, -f0.x, f1.z, 0, -f1.x, f2.z, 0, -f2.x, -f0.y, f0.x, 0, -f1.y, f1.x, 0, -f2.y, f2.x, 0];
  3352. if (!satForAxes(axes)) {
  3353. return false;
  3354. }
  3355. // test 3 face normals from the aabb
  3356. axes = [1, 0, 0, 0, 1, 0, 0, 0, 1];
  3357. if (!satForAxes(axes)) {
  3358. return false;
  3359. }
  3360. // finally testing the face normal of the triangle
  3361. // use already existing triangle edge vectors here
  3362. triangleNormal.crossVectors(f0, f1);
  3363. axes = [triangleNormal.x, triangleNormal.y, triangleNormal.z];
  3364. return satForAxes(axes);
  3365. };
  3366. }(),
  3367. clampPoint: function (point, target) {
  3368. if (target === undefined) {
  3369. console.warn('THREE.Box3: .clampPoint() target is now required');
  3370. target = new Vector3();
  3371. }
  3372. return target.copy(point).clamp(this.min, this.max);
  3373. },
  3374. distanceToPoint: function () {
  3375. var v1 = new Vector3();
  3376. return function distanceToPoint(point) {
  3377. var clampedPoint = v1.copy(point).clamp(this.min, this.max);
  3378. return clampedPoint.sub(point).length();
  3379. };
  3380. }(),
  3381. getBoundingSphere: function () {
  3382. var v1 = new Vector3();
  3383. return function getBoundingSphere(target) {
  3384. if (target === undefined) {
  3385. console.warn('THREE.Box3: .getBoundingSphere() target is now required');
  3386. target = new Sphere();
  3387. }
  3388. this.getCenter(target.center);
  3389. target.radius = this.getSize(v1).length() * 0.5;
  3390. return target;
  3391. };
  3392. }(),
  3393. intersect: function (box) {
  3394. this.min.max(box.min);
  3395. this.max.min(box.max);
  3396. // 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.
  3397. if (this.isEmpty()) this.makeEmpty();
  3398. return this;
  3399. },
  3400. union: function (box) {
  3401. this.min.min(box.min);
  3402. this.max.max(box.max);
  3403. return this;
  3404. },
  3405. applyMatrix4: function (matrix) {
  3406. // transform of empty box is an empty box.
  3407. if (this.isEmpty()) return this;
  3408. var m = matrix.elements;
  3409. var xax = m[0] * this.min.x,
  3410. xay = m[1] * this.min.x,
  3411. xaz = m[2] * this.min.x;
  3412. var xbx = m[0] * this.max.x,
  3413. xby = m[1] * this.max.x,
  3414. xbz = m[2] * this.max.x;
  3415. var yax = m[4] * this.min.y,
  3416. yay = m[5] * this.min.y,
  3417. yaz = m[6] * this.min.y;
  3418. var ybx = m[4] * this.max.y,
  3419. yby = m[5] * this.max.y,
  3420. ybz = m[6] * this.max.y;
  3421. var zax = m[8] * this.min.z,
  3422. zay = m[9] * this.min.z,
  3423. zaz = m[10] * this.min.z;
  3424. var zbx = m[8] * this.max.z,
  3425. zby = m[9] * this.max.z,
  3426. zbz = m[10] * this.max.z;
  3427. this.min.x = Math.min(xax, xbx) + Math.min(yax, ybx) + Math.min(zax, zbx) + m[12];
  3428. this.min.y = Math.min(xay, xby) + Math.min(yay, yby) + Math.min(zay, zby) + m[13];
  3429. this.min.z = Math.min(xaz, xbz) + Math.min(yaz, ybz) + Math.min(zaz, zbz) + m[14];
  3430. this.max.x = Math.max(xax, xbx) + Math.max(yax, ybx) + Math.max(zax, zbx) + m[12];
  3431. this.max.y = Math.max(xay, xby) + Math.max(yay, yby) + Math.max(zay, zby) + m[13];
  3432. this.max.z = Math.max(xaz, xbz) + Math.max(yaz, ybz) + Math.max(zaz, zbz) + m[14];
  3433. return this;
  3434. },
  3435. translate: function (offset) {
  3436. this.min.add(offset);
  3437. this.max.add(offset);
  3438. return this;
  3439. },
  3440. equals: function (box) {
  3441. return box.min.equals(this.min) && box.max.equals(this.max);
  3442. }
  3443. });
  3444. /**
  3445. * @author bhouston / http://clara.io
  3446. * @author mrdoob / http://mrdoob.com/
  3447. */
  3448. function Sphere(center, radius) {
  3449. this.center = center !== undefined ? center : new Vector3();
  3450. this.radius = radius !== undefined ? radius : 0;
  3451. }
  3452. Object.assign(Sphere.prototype, {
  3453. set: function (center, radius) {
  3454. this.center.copy(center);
  3455. this.radius = radius;
  3456. return this;
  3457. },
  3458. setFromPoints: function () {
  3459. var box = new Box3();
  3460. return function setFromPoints(points, optionalCenter) {
  3461. var center = this.center;
  3462. if (optionalCenter !== undefined) {
  3463. center.copy(optionalCenter);
  3464. } else {
  3465. box.setFromPoints(points).getCenter(center);
  3466. }
  3467. var maxRadiusSq = 0;
  3468. for (var i = 0, il = points.length; i < il; i++) {
  3469. maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i]));
  3470. }
  3471. this.radius = Math.sqrt(maxRadiusSq);
  3472. return this;
  3473. };
  3474. }(),
  3475. clone: function () {
  3476. return new this.constructor().copy(this);
  3477. },
  3478. copy: function (sphere) {
  3479. this.center.copy(sphere.center);
  3480. this.radius = sphere.radius;
  3481. return this;
  3482. },
  3483. empty: function () {
  3484. return this.radius <= 0;
  3485. },
  3486. containsPoint: function (point) {
  3487. return point.distanceToSquared(this.center) <= this.radius * this.radius;
  3488. },
  3489. distanceToPoint: function (point) {
  3490. return point.distanceTo(this.center) - this.radius;
  3491. },
  3492. intersectsSphere: function (sphere) {
  3493. var radiusSum = this.radius + sphere.radius;
  3494. return sphere.center.distanceToSquared(this.center) <= radiusSum * radiusSum;
  3495. },
  3496. intersectsBox: function (box) {
  3497. return box.intersectsSphere(this);
  3498. },
  3499. intersectsPlane: function (plane) {
  3500. return Math.abs(plane.distanceToPoint(this.center)) <= this.radius;
  3501. },
  3502. clampPoint: function (point, target) {
  3503. var deltaLengthSq = this.center.distanceToSquared(point);
  3504. if (target === undefined) {
  3505. console.warn('THREE.Sphere: .clampPoint() target is now required');
  3506. target = new Vector3();
  3507. }
  3508. target.copy(point);
  3509. if (deltaLengthSq > this.radius * this.radius) {
  3510. target.sub(this.center).normalize();
  3511. target.multiplyScalar(this.radius).add(this.center);
  3512. }
  3513. return target;
  3514. },
  3515. getBoundingBox: function (target) {
  3516. if (target === undefined) {
  3517. console.warn('THREE.Sphere: .getBoundingBox() target is now required');
  3518. target = new Box3();
  3519. }
  3520. target.set(this.center, this.center);
  3521. target.expandByScalar(this.radius);
  3522. return target;
  3523. },
  3524. applyMatrix4: function (matrix) {
  3525. this.center.applyMatrix4(matrix);
  3526. this.radius = this.radius * matrix.getMaxScaleOnAxis();
  3527. return this;
  3528. },
  3529. translate: function (offset) {
  3530. this.center.add(offset);
  3531. return this;
  3532. },
  3533. equals: function (sphere) {
  3534. return sphere.center.equals(this.center) && sphere.radius === this.radius;
  3535. }
  3536. });
  3537. /**
  3538. * @author bhouston / http://clara.io
  3539. */
  3540. function Plane(normal, constant) {
  3541. // normal is assumed to be normalized
  3542. this.normal = normal !== undefined ? normal : new Vector3(1, 0, 0);
  3543. this.constant = constant !== undefined ? constant : 0;
  3544. }
  3545. Object.assign(Plane.prototype, {
  3546. set: function (normal, constant) {
  3547. this.normal.copy(normal);
  3548. this.constant = constant;
  3549. return this;
  3550. },
  3551. setComponents: function (x, y, z, w) {
  3552. this.normal.set(x, y, z);
  3553. this.constant = w;
  3554. return this;
  3555. },
  3556. setFromNormalAndCoplanarPoint: function (normal, point) {
  3557. this.normal.copy(normal);
  3558. this.constant = -point.dot(this.normal);
  3559. return this;
  3560. },
  3561. setFromCoplanarPoints: function () {
  3562. var v1 = new Vector3();
  3563. var v2 = new Vector3();
  3564. return function setFromCoplanarPoints(a, b, c) {
  3565. var normal = v1.subVectors(c, b).cross(v2.subVectors(a, b)).normalize();
  3566. // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
  3567. this.setFromNormalAndCoplanarPoint(normal, a);
  3568. return this;
  3569. };
  3570. }(),
  3571. clone: function () {
  3572. return new this.constructor().copy(this);
  3573. },
  3574. copy: function (plane) {
  3575. this.normal.copy(plane.normal);
  3576. this.constant = plane.constant;
  3577. return this;
  3578. },
  3579. normalize: function () {
  3580. // Note: will lead to a divide by zero if the plane is invalid.
  3581. var inverseNormalLength = 1.0 / this.normal.length();
  3582. this.normal.multiplyScalar(inverseNormalLength);
  3583. this.constant *= inverseNormalLength;
  3584. return this;
  3585. },
  3586. negate: function () {
  3587. this.constant *= -1;
  3588. this.normal.negate();
  3589. return this;
  3590. },
  3591. distanceToPoint: function (point) {
  3592. return this.normal.dot(point) + this.constant;
  3593. },
  3594. distanceToSphere: function (sphere) {
  3595. return this.distanceToPoint(sphere.center) - sphere.radius;
  3596. },
  3597. projectPoint: function (point, target) {
  3598. if (target === undefined) {
  3599. console.warn('THREE.Plane: .projectPoint() target is now required');
  3600. target = new Vector3();
  3601. }
  3602. return target.copy(this.normal).multiplyScalar(-this.distanceToPoint(point)).add(point);
  3603. },
  3604. intersectLine: function () {
  3605. var v1 = new Vector3();
  3606. return function intersectLine(line, target) {
  3607. if (target === undefined) {
  3608. console.warn('THREE.Plane: .intersectLine() target is now required');
  3609. target = new Vector3();
  3610. }
  3611. var direction = line.delta(v1);
  3612. var denominator = this.normal.dot(direction);
  3613. if (denominator === 0) {
  3614. // line is coplanar, return origin
  3615. if (this.distanceToPoint(line.start) === 0) {
  3616. return target.copy(line.start);
  3617. }
  3618. // Unsure if this is the correct method to handle this case.
  3619. return undefined;
  3620. }
  3621. var t = -(line.start.dot(this.normal) + this.constant) / denominator;
  3622. if (t < 0 || t > 1) {
  3623. return undefined;
  3624. }
  3625. return target.copy(direction).multiplyScalar(t).add(line.start);
  3626. };
  3627. }(),
  3628. intersectsLine: function (line) {
  3629. // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
  3630. var startSign = this.distanceToPoint(line.start);
  3631. var endSign = this.distanceToPoint(line.end);
  3632. return startSign < 0 && endSign > 0 || endSign < 0 && startSign > 0;
  3633. },
  3634. intersectsBox: function (box) {
  3635. return box.intersectsPlane(this);
  3636. },
  3637. intersectsSphere: function (sphere) {
  3638. return sphere.intersectsPlane(this);
  3639. },
  3640. coplanarPoint: function (target) {
  3641. if (target === undefined) {
  3642. console.warn('THREE.Plane: .coplanarPoint() target is now required');
  3643. target = new Vector3();
  3644. }
  3645. return target.copy(this.normal).multiplyScalar(-this.constant);
  3646. },
  3647. applyMatrix4: function () {
  3648. var v1 = new Vector3();
  3649. var m1 = new Matrix3();
  3650. return function applyMatrix4(matrix, optionalNormalMatrix) {
  3651. var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix(matrix);
  3652. var referencePoint = this.coplanarPoint(v1).applyMatrix4(matrix);
  3653. var normal = this.normal.applyMatrix3(normalMatrix).normalize();
  3654. this.constant = -referencePoint.dot(normal);
  3655. return this;
  3656. };
  3657. }(),
  3658. translate: function (offset) {
  3659. this.constant -= offset.dot(this.normal);
  3660. return this;
  3661. },
  3662. equals: function (plane) {
  3663. return plane.normal.equals(this.normal) && plane.constant === this.constant;
  3664. }
  3665. });
  3666. /**
  3667. * @author mrdoob / http://mrdoob.com/
  3668. * @author alteredq / http://alteredqualia.com/
  3669. * @author bhouston / http://clara.io
  3670. */
  3671. function Frustum(p0, p1, p2, p3, p4, p5) {
  3672. 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()];
  3673. }
  3674. Object.assign(Frustum.prototype, {
  3675. set: function (p0, p1, p2, p3, p4, p5) {
  3676. var planes = this.planes;
  3677. planes[0].copy(p0);
  3678. planes[1].copy(p1);
  3679. planes[2].copy(p2);
  3680. planes[3].copy(p3);
  3681. planes[4].copy(p4);
  3682. planes[5].copy(p5);
  3683. return this;
  3684. },
  3685. clone: function () {
  3686. return new this.constructor().copy(this);
  3687. },
  3688. copy: function (frustum) {
  3689. var planes = this.planes;
  3690. for (var i = 0; i < 6; i++) {
  3691. planes[i].copy(frustum.planes[i]);
  3692. }
  3693. return this;
  3694. },
  3695. setFromMatrix: function (m) {
  3696. var planes = this.planes;
  3697. var me = m.elements;
  3698. var me0 = me[0],
  3699. me1 = me[1],
  3700. me2 = me[2],
  3701. me3 = me[3];
  3702. var me4 = me[4],
  3703. me5 = me[5],
  3704. me6 = me[6],
  3705. me7 = me[7];
  3706. var me8 = me[8],
  3707. me9 = me[9],
  3708. me10 = me[10],
  3709. me11 = me[11];
  3710. var me12 = me[12],
  3711. me13 = me[13],
  3712. me14 = me[14],
  3713. me15 = me[15];
  3714. planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize();
  3715. planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize();
  3716. planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize();
  3717. planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize();
  3718. planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize();
  3719. planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize();
  3720. return this;
  3721. },
  3722. intersectsObject: function () {
  3723. var sphere = new Sphere();
  3724. return function intersectsObject(object) {
  3725. var geometry = object.geometry;
  3726. if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
  3727. sphere.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld);
  3728. return this.intersectsSphere(sphere);
  3729. };
  3730. }(),
  3731. intersectsSprite: function () {
  3732. var sphere = new Sphere();
  3733. return function intersectsSprite(sprite) {
  3734. sphere.center.set(0, 0, 0);
  3735. sphere.radius = 0.7071067811865476;
  3736. sphere.applyMatrix4(sprite.matrixWorld);
  3737. return this.intersectsSphere(sphere);
  3738. };
  3739. }(),
  3740. intersectsSphere: function (sphere) {
  3741. var planes = this.planes;
  3742. var center = sphere.center;
  3743. var negRadius = -sphere.radius;
  3744. for (var i = 0; i < 6; i++) {
  3745. var distance = planes[i].distanceToPoint(center);
  3746. if (distance < negRadius) {
  3747. return false;
  3748. }
  3749. }
  3750. return true;
  3751. },
  3752. intersectsBox: function () {
  3753. var p1 = new Vector3(),
  3754. p2 = new Vector3();
  3755. return function intersectsBox(box) {
  3756. var planes = this.planes;
  3757. for (var i = 0; i < 6; i++) {
  3758. var plane = planes[i];
  3759. p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
  3760. p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
  3761. p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
  3762. p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
  3763. p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
  3764. p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
  3765. var d1 = plane.distanceToPoint(p1);
  3766. var d2 = plane.distanceToPoint(p2);
  3767. // if both outside plane, no intersection
  3768. if (d1 < 0 && d2 < 0) {
  3769. return false;
  3770. }
  3771. }
  3772. return true;
  3773. };
  3774. }(),
  3775. containsPoint: function (point) {
  3776. var planes = this.planes;
  3777. for (var i = 0; i < 6; i++) {
  3778. if (planes[i].distanceToPoint(point) < 0) {
  3779. return false;
  3780. }
  3781. }
  3782. return true;
  3783. }
  3784. });
  3785. var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
  3786. var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
  3787. var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
  3788. var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
  3789. var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
  3790. var begin_vertex = "\nvec3 transformed = vec3( position );\n";
  3791. var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
  3792. var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";
  3793. var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
  3794. var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif\n";
  3795. var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
  3796. var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
  3797. var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
  3798. var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
  3799. var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
  3800. var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
  3801. var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
  3802. var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\n";
  3803. var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
  3804. var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n";
  3805. var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
  3806. var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
  3807. var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
  3808. var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
  3809. var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
  3810. var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";
  3811. var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";
  3812. var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
  3813. var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
  3814. var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";
  3815. var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
  3816. var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n";
  3817. var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";
  3818. var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n";
  3819. var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
  3820. var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
  3821. var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
  3822. var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
  3823. var lights_pars_begin = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n";
  3824. var lights_pars_maps = "#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
  3825. var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
  3826. var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";
  3827. var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
  3828. var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";
  3829. var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearCoatRadiance = vec3( 0.0 );\n#endif\n";
  3830. var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), maxMipLevel );\n\t#ifndef STANDARD\n\t\tclearCoatRadiance += getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );\n\t#endif\n#endif\n";
  3831. var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
  3832. var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
  3833. var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
  3834. var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
  3835. var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif\n";
  3836. var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
  3837. var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
  3838. var map_particle_fragment = "#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
  3839. var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n";
  3840. var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";
  3841. var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
  3842. var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
  3843. var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
  3844. var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
  3845. var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n";
  3846. var normal_fragment_maps = "#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
  3847. var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy *= normalScale;\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
  3848. var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";
  3849. var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
  3850. var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n";
  3851. var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";
  3852. var dithering_pars_fragment = "#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n";
  3853. var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";
  3854. var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
  3855. var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";
  3856. var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";
  3857. var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";
  3858. var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
  3859. var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
  3860. var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";
  3861. var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif\n";
  3862. var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
  3863. var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
  3864. var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
  3865. var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
  3866. var tonemapping_pars_fragment = "#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";
  3867. var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";
  3868. var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\n";
  3869. var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
  3870. var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
  3871. var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
  3872. var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
  3873. var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n";
  3874. var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
  3875. var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}\n";
  3876. var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
  3877. var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n";
  3878. var distanceRGBA_frag = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}\n";
  3879. var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}\n";
  3880. var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
  3881. var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
  3882. var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  3883. var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";
  3884. var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  3885. var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n";
  3886. var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
  3887. var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  3888. var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
  3889. var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  3890. var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
  3891. var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  3892. var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";
  3893. var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";
  3894. var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  3895. var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}\n";
  3896. var shadow_frag = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <fog_fragment>\n}\n";
  3897. var shadow_vert = "#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  3898. var ShaderChunk = {
  3899. alphamap_fragment: alphamap_fragment,
  3900. alphamap_pars_fragment: alphamap_pars_fragment,
  3901. alphatest_fragment: alphatest_fragment,
  3902. aomap_fragment: aomap_fragment,
  3903. aomap_pars_fragment: aomap_pars_fragment,
  3904. begin_vertex: begin_vertex,
  3905. beginnormal_vertex: beginnormal_vertex,
  3906. bsdfs: bsdfs,
  3907. bumpmap_pars_fragment: bumpmap_pars_fragment,
  3908. clipping_planes_fragment: clipping_planes_fragment,
  3909. clipping_planes_pars_fragment: clipping_planes_pars_fragment,
  3910. clipping_planes_pars_vertex: clipping_planes_pars_vertex,
  3911. clipping_planes_vertex: clipping_planes_vertex,
  3912. color_fragment: color_fragment,
  3913. color_pars_fragment: color_pars_fragment,
  3914. color_pars_vertex: color_pars_vertex,
  3915. color_vertex: color_vertex,
  3916. common: common,
  3917. cube_uv_reflection_fragment: cube_uv_reflection_fragment,
  3918. defaultnormal_vertex: defaultnormal_vertex,
  3919. displacementmap_pars_vertex: displacementmap_pars_vertex,
  3920. displacementmap_vertex: displacementmap_vertex,
  3921. emissivemap_fragment: emissivemap_fragment,
  3922. emissivemap_pars_fragment: emissivemap_pars_fragment,
  3923. encodings_fragment: encodings_fragment,
  3924. encodings_pars_fragment: encodings_pars_fragment,
  3925. envmap_fragment: envmap_fragment,
  3926. envmap_pars_fragment: envmap_pars_fragment,
  3927. envmap_pars_vertex: envmap_pars_vertex,
  3928. envmap_vertex: envmap_vertex,
  3929. fog_vertex: fog_vertex,
  3930. fog_pars_vertex: fog_pars_vertex,
  3931. fog_fragment: fog_fragment,
  3932. fog_pars_fragment: fog_pars_fragment,
  3933. gradientmap_pars_fragment: gradientmap_pars_fragment,
  3934. lightmap_fragment: lightmap_fragment,
  3935. lightmap_pars_fragment: lightmap_pars_fragment,
  3936. lights_lambert_vertex: lights_lambert_vertex,
  3937. lights_pars_begin: lights_pars_begin,
  3938. lights_pars_maps: lights_pars_maps,
  3939. lights_phong_fragment: lights_phong_fragment,
  3940. lights_phong_pars_fragment: lights_phong_pars_fragment,
  3941. lights_physical_fragment: lights_physical_fragment,
  3942. lights_physical_pars_fragment: lights_physical_pars_fragment,
  3943. lights_fragment_begin: lights_fragment_begin,
  3944. lights_fragment_maps: lights_fragment_maps,
  3945. lights_fragment_end: lights_fragment_end,
  3946. logdepthbuf_fragment: logdepthbuf_fragment,
  3947. logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
  3948. logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
  3949. logdepthbuf_vertex: logdepthbuf_vertex,
  3950. map_fragment: map_fragment,
  3951. map_pars_fragment: map_pars_fragment,
  3952. map_particle_fragment: map_particle_fragment,
  3953. map_particle_pars_fragment: map_particle_pars_fragment,
  3954. metalnessmap_fragment: metalnessmap_fragment,
  3955. metalnessmap_pars_fragment: metalnessmap_pars_fragment,
  3956. morphnormal_vertex: morphnormal_vertex,
  3957. morphtarget_pars_vertex: morphtarget_pars_vertex,
  3958. morphtarget_vertex: morphtarget_vertex,
  3959. normal_fragment_begin: normal_fragment_begin,
  3960. normal_fragment_maps: normal_fragment_maps,
  3961. normalmap_pars_fragment: normalmap_pars_fragment,
  3962. packing: packing,
  3963. premultiplied_alpha_fragment: premultiplied_alpha_fragment,
  3964. project_vertex: project_vertex,
  3965. dithering_fragment: dithering_fragment,
  3966. dithering_pars_fragment: dithering_pars_fragment,
  3967. roughnessmap_fragment: roughnessmap_fragment,
  3968. roughnessmap_pars_fragment: roughnessmap_pars_fragment,
  3969. shadowmap_pars_fragment: shadowmap_pars_fragment,
  3970. shadowmap_pars_vertex: shadowmap_pars_vertex,
  3971. shadowmap_vertex: shadowmap_vertex,
  3972. shadowmask_pars_fragment: shadowmask_pars_fragment,
  3973. skinbase_vertex: skinbase_vertex,
  3974. skinning_pars_vertex: skinning_pars_vertex,
  3975. skinning_vertex: skinning_vertex,
  3976. skinnormal_vertex: skinnormal_vertex,
  3977. specularmap_fragment: specularmap_fragment,
  3978. specularmap_pars_fragment: specularmap_pars_fragment,
  3979. tonemapping_fragment: tonemapping_fragment,
  3980. tonemapping_pars_fragment: tonemapping_pars_fragment,
  3981. uv_pars_fragment: uv_pars_fragment,
  3982. uv_pars_vertex: uv_pars_vertex,
  3983. uv_vertex: uv_vertex,
  3984. uv2_pars_fragment: uv2_pars_fragment,
  3985. uv2_pars_vertex: uv2_pars_vertex,
  3986. uv2_vertex: uv2_vertex,
  3987. worldpos_vertex: worldpos_vertex,
  3988. cube_frag: cube_frag,
  3989. cube_vert: cube_vert,
  3990. depth_frag: depth_frag,
  3991. depth_vert: depth_vert,
  3992. distanceRGBA_frag: distanceRGBA_frag,
  3993. distanceRGBA_vert: distanceRGBA_vert,
  3994. equirect_frag: equirect_frag,
  3995. equirect_vert: equirect_vert,
  3996. linedashed_frag: linedashed_frag,
  3997. linedashed_vert: linedashed_vert,
  3998. meshbasic_frag: meshbasic_frag,
  3999. meshbasic_vert: meshbasic_vert,
  4000. meshlambert_frag: meshlambert_frag,
  4001. meshlambert_vert: meshlambert_vert,
  4002. meshphong_frag: meshphong_frag,
  4003. meshphong_vert: meshphong_vert,
  4004. meshphysical_frag: meshphysical_frag,
  4005. meshphysical_vert: meshphysical_vert,
  4006. normal_frag: normal_frag,
  4007. normal_vert: normal_vert,
  4008. points_frag: points_frag,
  4009. points_vert: points_vert,
  4010. shadow_frag: shadow_frag,
  4011. shadow_vert: shadow_vert
  4012. };
  4013. /**
  4014. * Uniform Utilities
  4015. */
  4016. var UniformsUtils = {
  4017. merge: function (uniforms) {
  4018. var merged = {};
  4019. for (var u = 0; u < uniforms.length; u++) {
  4020. var tmp = this.clone(uniforms[u]);
  4021. for (var p in tmp) {
  4022. merged[p] = tmp[p];
  4023. }
  4024. }
  4025. return merged;
  4026. },
  4027. clone: function (uniforms_src) {
  4028. var uniforms_dst = {};
  4029. for (var u in uniforms_src) {
  4030. uniforms_dst[u] = {};
  4031. for (var p in uniforms_src[u]) {
  4032. var parameter_src = uniforms_src[u][p];
  4033. if (parameter_src && (parameter_src.isColor || parameter_src.isMatrix3 || parameter_src.isMatrix4 || parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || parameter_src.isTexture)) {
  4034. uniforms_dst[u][p] = parameter_src.clone();
  4035. } else if (Array.isArray(parameter_src)) {
  4036. uniforms_dst[u][p] = parameter_src.slice();
  4037. } else {
  4038. uniforms_dst[u][p] = parameter_src;
  4039. }
  4040. }
  4041. }
  4042. return uniforms_dst;
  4043. }
  4044. };
  4045. /**
  4046. * @author mrdoob / http://mrdoob.com/
  4047. */
  4048. var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
  4049. 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
  4050. 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
  4051. 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
  4052. 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
  4053. 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
  4054. 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
  4055. 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
  4056. 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
  4057. 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
  4058. 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
  4059. 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
  4060. 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
  4061. 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
  4062. 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
  4063. 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
  4064. 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
  4065. 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
  4066. 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
  4067. 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
  4068. 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
  4069. 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
  4070. 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
  4071. 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
  4072. function Color(r, g, b) {
  4073. if (g === undefined && b === undefined) {
  4074. // r is THREE.Color, hex or string
  4075. return this.set(r);
  4076. }
  4077. return this.setRGB(r, g, b);
  4078. }
  4079. Object.assign(Color.prototype, {
  4080. isColor: true,
  4081. r: 1, g: 1, b: 1,
  4082. set: function (value) {
  4083. if (value && value.isColor) {
  4084. this.copy(value);
  4085. } else if (typeof value === 'number') {
  4086. this.setHex(value);
  4087. } else if (typeof value === 'string') {
  4088. this.setStyle(value);
  4089. }
  4090. return this;
  4091. },
  4092. setScalar: function (scalar) {
  4093. this.r = scalar;
  4094. this.g = scalar;
  4095. this.b = scalar;
  4096. return this;
  4097. },
  4098. setHex: function (hex) {
  4099. hex = Math.floor(hex);
  4100. this.r = (hex >> 16 & 255) / 255;
  4101. this.g = (hex >> 8 & 255) / 255;
  4102. this.b = (hex & 255) / 255;
  4103. return this;
  4104. },
  4105. setRGB: function (r, g, b) {
  4106. this.r = r;
  4107. this.g = g;
  4108. this.b = b;
  4109. return this;
  4110. },
  4111. setHSL: function () {
  4112. function hue2rgb(p, q, t) {
  4113. if (t < 0) t += 1;
  4114. if (t > 1) t -= 1;
  4115. if (t < 1 / 6) return p + (q - p) * 6 * t;
  4116. if (t < 1 / 2) return q;
  4117. if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t);
  4118. return p;
  4119. }
  4120. return function setHSL(h, s, l) {
  4121. // h,s,l ranges are in 0.0 - 1.0
  4122. h = _Math.euclideanModulo(h, 1);
  4123. s = _Math.clamp(s, 0, 1);
  4124. l = _Math.clamp(l, 0, 1);
  4125. if (s === 0) {
  4126. this.r = this.g = this.b = l;
  4127. } else {
  4128. var p = l <= 0.5 ? l * (1 + s) : l + s - l * s;
  4129. var q = 2 * l - p;
  4130. this.r = hue2rgb(q, p, h + 1 / 3);
  4131. this.g = hue2rgb(q, p, h);
  4132. this.b = hue2rgb(q, p, h - 1 / 3);
  4133. }
  4134. return this;
  4135. };
  4136. }(),
  4137. setStyle: function (style) {
  4138. function handleAlpha(string) {
  4139. if (string === undefined) return;
  4140. if (parseFloat(string) < 1) {
  4141. console.warn('THREE.Color: Alpha component of ' + style + ' will be ignored.');
  4142. }
  4143. }
  4144. var m;
  4145. if (m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(style)) {
  4146. // rgb / hsl
  4147. var color;
  4148. var name = m[1];
  4149. var components = m[2];
  4150. switch (name) {
  4151. case 'rgb':
  4152. case 'rgba':
  4153. if (color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(components)) {
  4154. // rgb(255,0,0) rgba(255,0,0,0.5)
  4155. this.r = Math.min(255, parseInt(color[1], 10)) / 255;
  4156. this.g = Math.min(255, parseInt(color[2], 10)) / 255;
  4157. this.b = Math.min(255, parseInt(color[3], 10)) / 255;
  4158. handleAlpha(color[5]);
  4159. return this;
  4160. }
  4161. if (color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(components)) {
  4162. // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
  4163. this.r = Math.min(100, parseInt(color[1], 10)) / 100;
  4164. this.g = Math.min(100, parseInt(color[2], 10)) / 100;
  4165. this.b = Math.min(100, parseInt(color[3], 10)) / 100;
  4166. handleAlpha(color[5]);
  4167. return this;
  4168. }
  4169. break;
  4170. case 'hsl':
  4171. case 'hsla':
  4172. if (color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(components)) {
  4173. // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
  4174. var h = parseFloat(color[1]) / 360;
  4175. var s = parseInt(color[2], 10) / 100;
  4176. var l = parseInt(color[3], 10) / 100;
  4177. handleAlpha(color[5]);
  4178. return this.setHSL(h, s, l);
  4179. }
  4180. break;
  4181. }
  4182. } else if (m = /^\#([A-Fa-f0-9]+)$/.exec(style)) {
  4183. // hex color
  4184. var hex = m[1];
  4185. var size = hex.length;
  4186. if (size === 3) {
  4187. // #ff0
  4188. this.r = parseInt(hex.charAt(0) + hex.charAt(0), 16) / 255;
  4189. this.g = parseInt(hex.charAt(1) + hex.charAt(1), 16) / 255;
  4190. this.b = parseInt(hex.charAt(2) + hex.charAt(2), 16) / 255;
  4191. return this;
  4192. } else if (size === 6) {
  4193. // #ff0000
  4194. this.r = parseInt(hex.charAt(0) + hex.charAt(1), 16) / 255;
  4195. this.g = parseInt(hex.charAt(2) + hex.charAt(3), 16) / 255;
  4196. this.b = parseInt(hex.charAt(4) + hex.charAt(5), 16) / 255;
  4197. return this;
  4198. }
  4199. }
  4200. if (style && style.length > 0) {
  4201. // color keywords
  4202. var hex = ColorKeywords[style];
  4203. if (hex !== undefined) {
  4204. // red
  4205. this.setHex(hex);
  4206. } else {
  4207. // unknown color
  4208. console.warn('THREE.Color: Unknown color ' + style);
  4209. }
  4210. }
  4211. return this;
  4212. },
  4213. clone: function () {
  4214. return new this.constructor(this.r, this.g, this.b);
  4215. },
  4216. copy: function (color) {
  4217. this.r = color.r;
  4218. this.g = color.g;
  4219. this.b = color.b;
  4220. return this;
  4221. },
  4222. copyGammaToLinear: function (color, gammaFactor) {
  4223. if (gammaFactor === undefined) gammaFactor = 2.0;
  4224. this.r = Math.pow(color.r, gammaFactor);
  4225. this.g = Math.pow(color.g, gammaFactor);
  4226. this.b = Math.pow(color.b, gammaFactor);
  4227. return this;
  4228. },
  4229. copyLinearToGamma: function (color, gammaFactor) {
  4230. if (gammaFactor === undefined) gammaFactor = 2.0;
  4231. var safeInverse = gammaFactor > 0 ? 1.0 / gammaFactor : 1.0;
  4232. this.r = Math.pow(color.r, safeInverse);
  4233. this.g = Math.pow(color.g, safeInverse);
  4234. this.b = Math.pow(color.b, safeInverse);
  4235. return this;
  4236. },
  4237. convertGammaToLinear: function (gammaFactor) {
  4238. this.copyGammaToLinear(this, gammaFactor);
  4239. return this;
  4240. },
  4241. convertLinearToGamma: function (gammaFactor) {
  4242. this.copyLinearToGamma(this, gammaFactor);
  4243. return this;
  4244. },
  4245. getHex: function () {
  4246. return this.r * 255 << 16 ^ this.g * 255 << 8 ^ this.b * 255 << 0;
  4247. },
  4248. getHexString: function () {
  4249. return ('000000' + this.getHex().toString(16)).slice(-6);
  4250. },
  4251. getHSL: function (target) {
  4252. // h,s,l ranges are in 0.0 - 1.0
  4253. if (target === undefined) {
  4254. console.warn('THREE.Color: .getHSL() target is now required');
  4255. target = { h: 0, s: 0, l: 0 };
  4256. }
  4257. var r = this.r,
  4258. g = this.g,
  4259. b = this.b;
  4260. var max = Math.max(r, g, b);
  4261. var min = Math.min(r, g, b);
  4262. var hue, saturation;
  4263. var lightness = (min + max) / 2.0;
  4264. if (min === max) {
  4265. hue = 0;
  4266. saturation = 0;
  4267. } else {
  4268. var delta = max - min;
  4269. saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
  4270. switch (max) {
  4271. case r:
  4272. hue = (g - b) / delta + (g < b ? 6 : 0);break;
  4273. case g:
  4274. hue = (b - r) / delta + 2;break;
  4275. case b:
  4276. hue = (r - g) / delta + 4;break;
  4277. }
  4278. hue /= 6;
  4279. }
  4280. target.h = hue;
  4281. target.s = saturation;
  4282. target.l = lightness;
  4283. return target;
  4284. },
  4285. getStyle: function () {
  4286. return 'rgb(' + (this.r * 255 | 0) + ',' + (this.g * 255 | 0) + ',' + (this.b * 255 | 0) + ')';
  4287. },
  4288. offsetHSL: function () {
  4289. var hsl = {};
  4290. return function (h, s, l) {
  4291. this.getHSL(hsl);
  4292. hsl.h += h;hsl.s += s;hsl.l += l;
  4293. this.setHSL(hsl.h, hsl.s, hsl.l);
  4294. return this;
  4295. };
  4296. }(),
  4297. add: function (color) {
  4298. this.r += color.r;
  4299. this.g += color.g;
  4300. this.b += color.b;
  4301. return this;
  4302. },
  4303. addColors: function (color1, color2) {
  4304. this.r = color1.r + color2.r;
  4305. this.g = color1.g + color2.g;
  4306. this.b = color1.b + color2.b;
  4307. return this;
  4308. },
  4309. addScalar: function (s) {
  4310. this.r += s;
  4311. this.g += s;
  4312. this.b += s;
  4313. return this;
  4314. },
  4315. sub: function (color) {
  4316. this.r = Math.max(0, this.r - color.r);
  4317. this.g = Math.max(0, this.g - color.g);
  4318. this.b = Math.max(0, this.b - color.b);
  4319. return this;
  4320. },
  4321. multiply: function (color) {
  4322. this.r *= color.r;
  4323. this.g *= color.g;
  4324. this.b *= color.b;
  4325. return this;
  4326. },
  4327. multiplyScalar: function (s) {
  4328. this.r *= s;
  4329. this.g *= s;
  4330. this.b *= s;
  4331. return this;
  4332. },
  4333. lerp: function (color, alpha) {
  4334. this.r += (color.r - this.r) * alpha;
  4335. this.g += (color.g - this.g) * alpha;
  4336. this.b += (color.b - this.b) * alpha;
  4337. return this;
  4338. },
  4339. equals: function (c) {
  4340. return c.r === this.r && c.g === this.g && c.b === this.b;
  4341. },
  4342. fromArray: function (array, offset) {
  4343. if (offset === undefined) offset = 0;
  4344. this.r = array[offset];
  4345. this.g = array[offset + 1];
  4346. this.b = array[offset + 2];
  4347. return this;
  4348. },
  4349. toArray: function (array, offset) {
  4350. if (array === undefined) array = [];
  4351. if (offset === undefined) offset = 0;
  4352. array[offset] = this.r;
  4353. array[offset + 1] = this.g;
  4354. array[offset + 2] = this.b;
  4355. return array;
  4356. },
  4357. toJSON: function () {
  4358. return this.getHex();
  4359. }
  4360. });
  4361. /**
  4362. * Uniforms library for shared webgl shaders
  4363. */
  4364. var UniformsLib = {
  4365. common: {
  4366. diffuse: { value: new Color(0xeeeeee) },
  4367. opacity: { value: 1.0 },
  4368. map: { value: null },
  4369. uvTransform: { value: new Matrix3() },
  4370. alphaMap: { value: null }
  4371. },
  4372. specularmap: {
  4373. specularMap: { value: null }
  4374. },
  4375. envmap: {
  4376. envMap: { value: null },
  4377. flipEnvMap: { value: -1 },
  4378. reflectivity: { value: 1.0 },
  4379. refractionRatio: { value: 0.98 },
  4380. maxMipLevel: { value: 0 }
  4381. },
  4382. aomap: {
  4383. aoMap: { value: null },
  4384. aoMapIntensity: { value: 1 }
  4385. },
  4386. lightmap: {
  4387. lightMap: { value: null },
  4388. lightMapIntensity: { value: 1 }
  4389. },
  4390. emissivemap: {
  4391. emissiveMap: { value: null }
  4392. },
  4393. bumpmap: {
  4394. bumpMap: { value: null },
  4395. bumpScale: { value: 1 }
  4396. },
  4397. normalmap: {
  4398. normalMap: { value: null },
  4399. normalScale: { value: new Vector2(1, 1) }
  4400. },
  4401. displacementmap: {
  4402. displacementMap: { value: null },
  4403. displacementScale: { value: 1 },
  4404. displacementBias: { value: 0 }
  4405. },
  4406. roughnessmap: {
  4407. roughnessMap: { value: null }
  4408. },
  4409. metalnessmap: {
  4410. metalnessMap: { value: null }
  4411. },
  4412. gradientmap: {
  4413. gradientMap: { value: null }
  4414. },
  4415. fog: {
  4416. fogDensity: { value: 0.00025 },
  4417. fogNear: { value: 1 },
  4418. fogFar: { value: 2000 },
  4419. fogColor: { value: new Color(0xffffff) }
  4420. },
  4421. lights: {
  4422. ambientLightColor: { value: [] },
  4423. directionalLights: { value: [], properties: {
  4424. direction: {},
  4425. color: {},
  4426. shadow: {},
  4427. shadowBias: {},
  4428. shadowRadius: {},
  4429. shadowMapSize: {}
  4430. } },
  4431. directionalShadowMap: { value: [] },
  4432. directionalShadowMatrix: { value: [] },
  4433. spotLights: { value: [], properties: {
  4434. color: {},
  4435. position: {},
  4436. direction: {},
  4437. distance: {},
  4438. coneCos: {},
  4439. penumbraCos: {},
  4440. decay: {},
  4441. shadow: {},
  4442. shadowBias: {},
  4443. shadowRadius: {},
  4444. shadowMapSize: {}
  4445. } },
  4446. spotShadowMap: { value: [] },
  4447. spotShadowMatrix: { value: [] },
  4448. pointLights: { value: [], properties: {
  4449. color: {},
  4450. position: {},
  4451. decay: {},
  4452. distance: {},
  4453. shadow: {},
  4454. shadowBias: {},
  4455. shadowRadius: {},
  4456. shadowMapSize: {},
  4457. shadowCameraNear: {},
  4458. shadowCameraFar: {}
  4459. } },
  4460. pointShadowMap: { value: [] },
  4461. pointShadowMatrix: { value: [] },
  4462. hemisphereLights: { value: [], properties: {
  4463. direction: {},
  4464. skyColor: {},
  4465. groundColor: {}
  4466. } },
  4467. // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
  4468. rectAreaLights: { value: [], properties: {
  4469. color: {},
  4470. position: {},
  4471. width: {},
  4472. height: {}
  4473. } }
  4474. },
  4475. points: {
  4476. diffuse: { value: new Color(0xeeeeee) },
  4477. opacity: { value: 1.0 },
  4478. size: { value: 1.0 },
  4479. scale: { value: 1.0 },
  4480. map: { value: null },
  4481. uvTransform: { value: new Matrix3() }
  4482. }
  4483. };
  4484. /**
  4485. * @author alteredq / http://alteredqualia.com/
  4486. * @author mrdoob / http://mrdoob.com/
  4487. * @author mikael emtinger / http://gomo.se/
  4488. */
  4489. var ShaderLib = {
  4490. basic: {
  4491. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.specularmap, UniformsLib.envmap, UniformsLib.aomap, UniformsLib.lightmap, UniformsLib.fog]),
  4492. vertexShader: ShaderChunk.meshbasic_vert,
  4493. fragmentShader: ShaderChunk.meshbasic_frag
  4494. },
  4495. lambert: {
  4496. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.specularmap, UniformsLib.envmap, UniformsLib.aomap, UniformsLib.lightmap, UniformsLib.emissivemap, UniformsLib.fog, UniformsLib.lights, {
  4497. emissive: { value: new Color(0x000000) }
  4498. }]),
  4499. vertexShader: ShaderChunk.meshlambert_vert,
  4500. fragmentShader: ShaderChunk.meshlambert_frag
  4501. },
  4502. phong: {
  4503. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.specularmap, UniformsLib.envmap, UniformsLib.aomap, UniformsLib.lightmap, UniformsLib.emissivemap, UniformsLib.bumpmap, UniformsLib.normalmap, UniformsLib.displacementmap, UniformsLib.gradientmap, UniformsLib.fog, UniformsLib.lights, {
  4504. emissive: { value: new Color(0x000000) },
  4505. specular: { value: new Color(0x111111) },
  4506. shininess: { value: 30 }
  4507. }]),
  4508. vertexShader: ShaderChunk.meshphong_vert,
  4509. fragmentShader: ShaderChunk.meshphong_frag
  4510. },
  4511. standard: {
  4512. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.envmap, UniformsLib.aomap, UniformsLib.lightmap, UniformsLib.emissivemap, UniformsLib.bumpmap, UniformsLib.normalmap, UniformsLib.displacementmap, UniformsLib.roughnessmap, UniformsLib.metalnessmap, UniformsLib.fog, UniformsLib.lights, {
  4513. emissive: { value: new Color(0x000000) },
  4514. roughness: { value: 0.5 },
  4515. metalness: { value: 0.5 },
  4516. envMapIntensity: { value: 1 // temporary
  4517. } }]),
  4518. vertexShader: ShaderChunk.meshphysical_vert,
  4519. fragmentShader: ShaderChunk.meshphysical_frag
  4520. },
  4521. points: {
  4522. uniforms: UniformsUtils.merge([UniformsLib.points, UniformsLib.fog]),
  4523. vertexShader: ShaderChunk.points_vert,
  4524. fragmentShader: ShaderChunk.points_frag
  4525. },
  4526. dashed: {
  4527. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.fog, {
  4528. scale: { value: 1 },
  4529. dashSize: { value: 1 },
  4530. totalSize: { value: 2 }
  4531. }]),
  4532. vertexShader: ShaderChunk.linedashed_vert,
  4533. fragmentShader: ShaderChunk.linedashed_frag
  4534. },
  4535. depth: {
  4536. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.displacementmap]),
  4537. vertexShader: ShaderChunk.depth_vert,
  4538. fragmentShader: ShaderChunk.depth_frag
  4539. },
  4540. normal: {
  4541. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.bumpmap, UniformsLib.normalmap, UniformsLib.displacementmap, {
  4542. opacity: { value: 1.0 }
  4543. }]),
  4544. vertexShader: ShaderChunk.normal_vert,
  4545. fragmentShader: ShaderChunk.normal_frag
  4546. },
  4547. /* -------------------------------------------------------------------------
  4548. // Cube map shader
  4549. ------------------------------------------------------------------------- */
  4550. cube: {
  4551. uniforms: {
  4552. tCube: { value: null },
  4553. tFlip: { value: -1 },
  4554. opacity: { value: 1.0 }
  4555. },
  4556. vertexShader: ShaderChunk.cube_vert,
  4557. fragmentShader: ShaderChunk.cube_frag
  4558. },
  4559. equirect: {
  4560. uniforms: {
  4561. tEquirect: { value: null }
  4562. },
  4563. vertexShader: ShaderChunk.equirect_vert,
  4564. fragmentShader: ShaderChunk.equirect_frag
  4565. },
  4566. distanceRGBA: {
  4567. uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.displacementmap, {
  4568. referencePosition: { value: new Vector3() },
  4569. nearDistance: { value: 1 },
  4570. farDistance: { value: 1000 }
  4571. }]),
  4572. vertexShader: ShaderChunk.distanceRGBA_vert,
  4573. fragmentShader: ShaderChunk.distanceRGBA_frag
  4574. },
  4575. shadow: {
  4576. uniforms: UniformsUtils.merge([UniformsLib.lights, UniformsLib.fog, {
  4577. color: { value: new Color(0x00000) },
  4578. opacity: { value: 1.0 }
  4579. }]),
  4580. vertexShader: ShaderChunk.shadow_vert,
  4581. fragmentShader: ShaderChunk.shadow_frag
  4582. }
  4583. };
  4584. ShaderLib.physical = {
  4585. uniforms: UniformsUtils.merge([ShaderLib.standard.uniforms, {
  4586. clearCoat: { value: 0 },
  4587. clearCoatRoughness: { value: 0 }
  4588. }]),
  4589. vertexShader: ShaderChunk.meshphysical_vert,
  4590. fragmentShader: ShaderChunk.meshphysical_frag
  4591. };
  4592. /**
  4593. * @author mrdoob / http://mrdoob.com/
  4594. */
  4595. function WebGLAnimation() {
  4596. var context = null;
  4597. var isAnimating = false;
  4598. var animationLoop = null;
  4599. function onAnimationFrame(time, frame) {
  4600. if (isAnimating === false) return;
  4601. animationLoop(time, frame);
  4602. context.requestAnimationFrame(onAnimationFrame);
  4603. }
  4604. return {
  4605. start: function () {
  4606. if (isAnimating === true) return;
  4607. if (animationLoop === null) return;
  4608. context.requestAnimationFrame(onAnimationFrame);
  4609. isAnimating = true;
  4610. },
  4611. stop: function () {
  4612. isAnimating = false;
  4613. },
  4614. setAnimationLoop: function (callback) {
  4615. animationLoop = callback;
  4616. },
  4617. setContext: function (value) {
  4618. context = value;
  4619. }
  4620. };
  4621. }
  4622. /**
  4623. * @author mrdoob / http://mrdoob.com/
  4624. */
  4625. function WebGLAttributes(gl) {
  4626. var buffers = new WeakMap();
  4627. function createBuffer(attribute, bufferType) {
  4628. var array = attribute.array;
  4629. var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
  4630. var buffer = gl.createBuffer();
  4631. gl.bindBuffer(bufferType, buffer);
  4632. gl.bufferData(bufferType, array, usage);
  4633. attribute.onUploadCallback();
  4634. var type = gl.FLOAT;
  4635. if (array instanceof Float32Array) {
  4636. type = gl.FLOAT;
  4637. } else if (array instanceof Float64Array) {
  4638. console.warn('THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.');
  4639. } else if (array instanceof Uint16Array) {
  4640. type = gl.UNSIGNED_SHORT;
  4641. } else if (array instanceof Int16Array) {
  4642. type = gl.SHORT;
  4643. } else if (array instanceof Uint32Array) {
  4644. type = gl.UNSIGNED_INT;
  4645. } else if (array instanceof Int32Array) {
  4646. type = gl.INT;
  4647. } else if (array instanceof Int8Array) {
  4648. type = gl.BYTE;
  4649. } else if (array instanceof Uint8Array) {
  4650. type = gl.UNSIGNED_BYTE;
  4651. }
  4652. return {
  4653. buffer: buffer,
  4654. type: type,
  4655. bytesPerElement: array.BYTES_PER_ELEMENT,
  4656. version: attribute.version
  4657. };
  4658. }
  4659. function updateBuffer(buffer, attribute, bufferType) {
  4660. var array = attribute.array;
  4661. var updateRange = attribute.updateRange;
  4662. gl.bindBuffer(bufferType, buffer);
  4663. if (attribute.dynamic === false) {
  4664. gl.bufferData(bufferType, array, gl.STATIC_DRAW);
  4665. } else if (updateRange.count === -1) {
  4666. // Not using update ranges
  4667. gl.bufferSubData(bufferType, 0, array);
  4668. } else if (updateRange.count === 0) {
  4669. 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.');
  4670. } else {
  4671. gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, array.subarray(updateRange.offset, updateRange.offset + updateRange.count));
  4672. updateRange.count = -1; // reset range
  4673. }
  4674. }
  4675. //
  4676. function get(attribute) {
  4677. if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
  4678. return buffers.get(attribute);
  4679. }
  4680. function remove(attribute) {
  4681. if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
  4682. var data = buffers.get(attribute);
  4683. if (data) {
  4684. gl.deleteBuffer(data.buffer);
  4685. buffers.delete(attribute);
  4686. }
  4687. }
  4688. function update(attribute, bufferType) {
  4689. if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
  4690. var data = buffers.get(attribute);
  4691. if (data === undefined) {
  4692. buffers.set(attribute, createBuffer(attribute, bufferType));
  4693. } else if (data.version < attribute.version) {
  4694. updateBuffer(data.buffer, attribute, bufferType);
  4695. data.version = attribute.version;
  4696. }
  4697. }
  4698. return {
  4699. get: get,
  4700. remove: remove,
  4701. update: update
  4702. };
  4703. }
  4704. /**
  4705. * @author mrdoob / http://mrdoob.com/
  4706. * @author WestLangley / http://github.com/WestLangley
  4707. * @author bhouston / http://clara.io
  4708. */
  4709. function Euler(x, y, z, order) {
  4710. this._x = x || 0;
  4711. this._y = y || 0;
  4712. this._z = z || 0;
  4713. this._order = order || Euler.DefaultOrder;
  4714. }
  4715. Euler.RotationOrders = ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'];
  4716. Euler.DefaultOrder = 'XYZ';
  4717. Object.defineProperties(Euler.prototype, {
  4718. x: {
  4719. get: function () {
  4720. return this._x;
  4721. },
  4722. set: function (value) {
  4723. this._x = value;
  4724. this.onChangeCallback();
  4725. }
  4726. },
  4727. y: {
  4728. get: function () {
  4729. return this._y;
  4730. },
  4731. set: function (value) {
  4732. this._y = value;
  4733. this.onChangeCallback();
  4734. }
  4735. },
  4736. z: {
  4737. get: function () {
  4738. return this._z;
  4739. },
  4740. set: function (value) {
  4741. this._z = value;
  4742. this.onChangeCallback();
  4743. }
  4744. },
  4745. order: {
  4746. get: function () {
  4747. return this._order;
  4748. },
  4749. set: function (value) {
  4750. this._order = value;
  4751. this.onChangeCallback();
  4752. }
  4753. }
  4754. });
  4755. Object.assign(Euler.prototype, {
  4756. isEuler: true,
  4757. set: function (x, y, z, order) {
  4758. this._x = x;
  4759. this._y = y;
  4760. this._z = z;
  4761. this._order = order || this._order;
  4762. this.onChangeCallback();
  4763. return this;
  4764. },
  4765. clone: function () {
  4766. return new this.constructor(this._x, this._y, this._z, this._order);
  4767. },
  4768. copy: function (euler) {
  4769. this._x = euler._x;
  4770. this._y = euler._y;
  4771. this._z = euler._z;
  4772. this._order = euler._order;
  4773. this.onChangeCallback();
  4774. return this;
  4775. },
  4776. setFromRotationMatrix: function (m, order, update) {
  4777. var clamp = _Math.clamp;
  4778. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  4779. var te = m.elements;
  4780. var m11 = te[0],
  4781. m12 = te[4],
  4782. m13 = te[8];
  4783. var m21 = te[1],
  4784. m22 = te[5],
  4785. m23 = te[9];
  4786. var m31 = te[2],
  4787. m32 = te[6],
  4788. m33 = te[10];
  4789. order = order || this._order;
  4790. if (order === 'XYZ') {
  4791. this._y = Math.asin(clamp(m13, -1, 1));
  4792. if (Math.abs(m13) < 0.99999) {
  4793. this._x = Math.atan2(-m23, m33);
  4794. this._z = Math.atan2(-m12, m11);
  4795. } else {
  4796. this._x = Math.atan2(m32, m22);
  4797. this._z = 0;
  4798. }
  4799. } else if (order === 'YXZ') {
  4800. this._x = Math.asin(-clamp(m23, -1, 1));
  4801. if (Math.abs(m23) < 0.99999) {
  4802. this._y = Math.atan2(m13, m33);
  4803. this._z = Math.atan2(m21, m22);
  4804. } else {
  4805. this._y = Math.atan2(-m31, m11);
  4806. this._z = 0;
  4807. }
  4808. } else if (order === 'ZXY') {
  4809. this._x = Math.asin(clamp(m32, -1, 1));
  4810. if (Math.abs(m32) < 0.99999) {
  4811. this._y = Math.atan2(-m31, m33);
  4812. this._z = Math.atan2(-m12, m22);
  4813. } else {
  4814. this._y = 0;
  4815. this._z = Math.atan2(m21, m11);
  4816. }
  4817. } else if (order === 'ZYX') {
  4818. this._y = Math.asin(-clamp(m31, -1, 1));
  4819. if (Math.abs(m31) < 0.99999) {
  4820. this._x = Math.atan2(m32, m33);
  4821. this._z = Math.atan2(m21, m11);
  4822. } else {
  4823. this._x = 0;
  4824. this._z = Math.atan2(-m12, m22);
  4825. }
  4826. } else if (order === 'YZX') {
  4827. this._z = Math.asin(clamp(m21, -1, 1));
  4828. if (Math.abs(m21) < 0.99999) {
  4829. this._x = Math.atan2(-m23, m22);
  4830. this._y = Math.atan2(-m31, m11);
  4831. } else {
  4832. this._x = 0;
  4833. this._y = Math.atan2(m13, m33);
  4834. }
  4835. } else if (order === 'XZY') {
  4836. this._z = Math.asin(-clamp(m12, -1, 1));
  4837. if (Math.abs(m12) < 0.99999) {
  4838. this._x = Math.atan2(m32, m22);
  4839. this._y = Math.atan2(m13, m11);
  4840. } else {
  4841. this._x = Math.atan2(-m23, m33);
  4842. this._y = 0;
  4843. }
  4844. } else {
  4845. console.warn('THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order);
  4846. }
  4847. this._order = order;
  4848. if (update !== false) this.onChangeCallback();
  4849. return this;
  4850. },
  4851. setFromQuaternion: function () {
  4852. var matrix = new Matrix4();
  4853. return function setFromQuaternion(q, order, update) {
  4854. matrix.makeRotationFromQuaternion(q);
  4855. return this.setFromRotationMatrix(matrix, order, update);
  4856. };
  4857. }(),
  4858. setFromVector3: function (v, order) {
  4859. return this.set(v.x, v.y, v.z, order || this._order);
  4860. },
  4861. reorder: function () {
  4862. // WARNING: this discards revolution information -bhouston
  4863. var q = new Quaternion();
  4864. return function reorder(newOrder) {
  4865. q.setFromEuler(this);
  4866. return this.setFromQuaternion(q, newOrder);
  4867. };
  4868. }(),
  4869. equals: function (euler) {
  4870. return euler._x === this._x && euler._y === this._y && euler._z === this._z && euler._order === this._order;
  4871. },
  4872. fromArray: function (array) {
  4873. this._x = array[0];
  4874. this._y = array[1];
  4875. this._z = array[2];
  4876. if (array[3] !== undefined) this._order = array[3];
  4877. this.onChangeCallback();
  4878. return this;
  4879. },
  4880. toArray: function (array, offset) {
  4881. if (array === undefined) array = [];
  4882. if (offset === undefined) offset = 0;
  4883. array[offset] = this._x;
  4884. array[offset + 1] = this._y;
  4885. array[offset + 2] = this._z;
  4886. array[offset + 3] = this._order;
  4887. return array;
  4888. },
  4889. toVector3: function (optionalResult) {
  4890. if (optionalResult) {
  4891. return optionalResult.set(this._x, this._y, this._z);
  4892. } else {
  4893. return new Vector3(this._x, this._y, this._z);
  4894. }
  4895. },
  4896. onChange: function (callback) {
  4897. this.onChangeCallback = callback;
  4898. return this;
  4899. },
  4900. onChangeCallback: function () {}
  4901. });
  4902. /**
  4903. * @author mrdoob / http://mrdoob.com/
  4904. */
  4905. function Layers() {
  4906. this.mask = 1 | 0;
  4907. }
  4908. Object.assign(Layers.prototype, {
  4909. set: function (channel) {
  4910. this.mask = 1 << channel | 0;
  4911. },
  4912. enable: function (channel) {
  4913. this.mask |= 1 << channel | 0;
  4914. },
  4915. toggle: function (channel) {
  4916. this.mask ^= 1 << channel | 0;
  4917. },
  4918. disable: function (channel) {
  4919. this.mask &= ~(1 << channel | 0);
  4920. },
  4921. test: function (layers) {
  4922. return (this.mask & layers.mask) !== 0;
  4923. }
  4924. });
  4925. /**
  4926. * @author mrdoob / http://mrdoob.com/
  4927. * @author mikael emtinger / http://gomo.se/
  4928. * @author alteredq / http://alteredqualia.com/
  4929. * @author WestLangley / http://github.com/WestLangley
  4930. * @author elephantatwork / www.elephantatwork.ch
  4931. */
  4932. var object3DId = 0;
  4933. function Object3D() {
  4934. Object.defineProperty(this, 'id', { value: object3DId++ });
  4935. this.uuid = _Math.generateUUID();
  4936. this.name = '';
  4937. this.type = 'Object3D';
  4938. this.parent = null;
  4939. this.children = [];
  4940. this.up = Object3D.DefaultUp.clone();
  4941. var position = new Vector3();
  4942. var rotation = new Euler();
  4943. var quaternion = new Quaternion();
  4944. var scale = new Vector3(1, 1, 1);
  4945. function onRotationChange() {
  4946. quaternion.setFromEuler(rotation, false);
  4947. }
  4948. function onQuaternionChange() {
  4949. rotation.setFromQuaternion(quaternion, undefined, false);
  4950. }
  4951. rotation.onChange(onRotationChange);
  4952. quaternion.onChange(onQuaternionChange);
  4953. Object.defineProperties(this, {
  4954. position: {
  4955. enumerable: true,
  4956. value: position
  4957. },
  4958. rotation: {
  4959. enumerable: true,
  4960. value: rotation
  4961. },
  4962. quaternion: {
  4963. enumerable: true,
  4964. value: quaternion
  4965. },
  4966. scale: {
  4967. enumerable: true,
  4968. value: scale
  4969. },
  4970. modelViewMatrix: {
  4971. value: new Matrix4()
  4972. },
  4973. normalMatrix: {
  4974. value: new Matrix3()
  4975. }
  4976. });
  4977. this.matrix = new Matrix4();
  4978. this.matrixWorld = new Matrix4();
  4979. this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
  4980. this.matrixWorldNeedsUpdate = false;
  4981. this.layers = new Layers();
  4982. this.visible = true;
  4983. this.castShadow = false;
  4984. this.receiveShadow = false;
  4985. this.frustumCulled = true;
  4986. this.renderOrder = 0;
  4987. this.userData = {};
  4988. }
  4989. Object3D.DefaultUp = new Vector3(0, 1, 0);
  4990. Object3D.DefaultMatrixAutoUpdate = true;
  4991. Object3D.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  4992. constructor: Object3D,
  4993. isObject3D: true,
  4994. onBeforeRender: function () {},
  4995. onAfterRender: function () {},
  4996. applyMatrix: function (matrix) {
  4997. this.matrix.multiplyMatrices(matrix, this.matrix);
  4998. this.matrix.decompose(this.position, this.quaternion, this.scale);
  4999. },
  5000. applyQuaternion: function (q) {
  5001. this.quaternion.premultiply(q);
  5002. return this;
  5003. },
  5004. setRotationFromAxisAngle: function (axis, angle) {
  5005. // assumes axis is normalized
  5006. this.quaternion.setFromAxisAngle(axis, angle);
  5007. },
  5008. setRotationFromEuler: function (euler) {
  5009. this.quaternion.setFromEuler(euler, true);
  5010. },
  5011. setRotationFromMatrix: function (m) {
  5012. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  5013. this.quaternion.setFromRotationMatrix(m);
  5014. },
  5015. setRotationFromQuaternion: function (q) {
  5016. // assumes q is normalized
  5017. this.quaternion.copy(q);
  5018. },
  5019. rotateOnAxis: function () {
  5020. // rotate object on axis in object space
  5021. // axis is assumed to be normalized
  5022. var q1 = new Quaternion();
  5023. return function rotateOnAxis(axis, angle) {
  5024. q1.setFromAxisAngle(axis, angle);
  5025. this.quaternion.multiply(q1);
  5026. return this;
  5027. };
  5028. }(),
  5029. rotateOnWorldAxis: function () {
  5030. // rotate object on axis in world space
  5031. // axis is assumed to be normalized
  5032. // method assumes no rotated parent
  5033. var q1 = new Quaternion();
  5034. return function rotateOnWorldAxis(axis, angle) {
  5035. q1.setFromAxisAngle(axis, angle);
  5036. this.quaternion.premultiply(q1);
  5037. return this;
  5038. };
  5039. }(),
  5040. rotateX: function () {
  5041. var v1 = new Vector3(1, 0, 0);
  5042. return function rotateX(angle) {
  5043. return this.rotateOnAxis(v1, angle);
  5044. };
  5045. }(),
  5046. rotateY: function () {
  5047. var v1 = new Vector3(0, 1, 0);
  5048. return function rotateY(angle) {
  5049. return this.rotateOnAxis(v1, angle);
  5050. };
  5051. }(),
  5052. rotateZ: function () {
  5053. var v1 = new Vector3(0, 0, 1);
  5054. return function rotateZ(angle) {
  5055. return this.rotateOnAxis(v1, angle);
  5056. };
  5057. }(),
  5058. translateOnAxis: function () {
  5059. // translate object by distance along axis in object space
  5060. // axis is assumed to be normalized
  5061. var v1 = new Vector3();
  5062. return function translateOnAxis(axis, distance) {
  5063. v1.copy(axis).applyQuaternion(this.quaternion);
  5064. this.position.add(v1.multiplyScalar(distance));
  5065. return this;
  5066. };
  5067. }(),
  5068. translateX: function () {
  5069. var v1 = new Vector3(1, 0, 0);
  5070. return function translateX(distance) {
  5071. return this.translateOnAxis(v1, distance);
  5072. };
  5073. }(),
  5074. translateY: function () {
  5075. var v1 = new Vector3(0, 1, 0);
  5076. return function translateY(distance) {
  5077. return this.translateOnAxis(v1, distance);
  5078. };
  5079. }(),
  5080. translateZ: function () {
  5081. var v1 = new Vector3(0, 0, 1);
  5082. return function translateZ(distance) {
  5083. return this.translateOnAxis(v1, distance);
  5084. };
  5085. }(),
  5086. localToWorld: function (vector) {
  5087. return vector.applyMatrix4(this.matrixWorld);
  5088. },
  5089. worldToLocal: function () {
  5090. var m1 = new Matrix4();
  5091. return function worldToLocal(vector) {
  5092. return vector.applyMatrix4(m1.getInverse(this.matrixWorld));
  5093. };
  5094. }(),
  5095. lookAt: function () {
  5096. // This method does not support objects with rotated and/or translated parent(s)
  5097. var m1 = new Matrix4();
  5098. var vector = new Vector3();
  5099. return function lookAt(x, y, z) {
  5100. if (x.isVector3) {
  5101. vector.copy(x);
  5102. } else {
  5103. vector.set(x, y, z);
  5104. }
  5105. if (this.isCamera) {
  5106. m1.lookAt(this.position, vector, this.up);
  5107. } else {
  5108. m1.lookAt(vector, this.position, this.up);
  5109. }
  5110. this.quaternion.setFromRotationMatrix(m1);
  5111. };
  5112. }(),
  5113. add: function (object) {
  5114. if (arguments.length > 1) {
  5115. for (var i = 0; i < arguments.length; i++) {
  5116. this.add(arguments[i]);
  5117. }
  5118. return this;
  5119. }
  5120. if (object === this) {
  5121. console.error("THREE.Object3D.add: object can't be added as a child of itself.", object);
  5122. return this;
  5123. }
  5124. if (object && object.isObject3D) {
  5125. if (object.parent !== null) {
  5126. object.parent.remove(object);
  5127. }
  5128. object.parent = this;
  5129. object.dispatchEvent({ type: 'added' });
  5130. this.children.push(object);
  5131. } else {
  5132. console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.", object);
  5133. }
  5134. return this;
  5135. },
  5136. remove: function (object) {
  5137. if (arguments.length > 1) {
  5138. for (var i = 0; i < arguments.length; i++) {
  5139. this.remove(arguments[i]);
  5140. }
  5141. return this;
  5142. }
  5143. var index = this.children.indexOf(object);
  5144. if (index !== -1) {
  5145. object.parent = null;
  5146. object.dispatchEvent({ type: 'removed' });
  5147. this.children.splice(index, 1);
  5148. }
  5149. return this;
  5150. },
  5151. getObjectById: function (id) {
  5152. return this.getObjectByProperty('id', id);
  5153. },
  5154. getObjectByName: function (name) {
  5155. return this.getObjectByProperty('name', name);
  5156. },
  5157. getObjectByProperty: function (name, value) {
  5158. if (this[name] === value) return this;
  5159. for (var i = 0, l = this.children.length; i < l; i++) {
  5160. var child = this.children[i];
  5161. var object = child.getObjectByProperty(name, value);
  5162. if (object !== undefined) {
  5163. return object;
  5164. }
  5165. }
  5166. return undefined;
  5167. },
  5168. getWorldPosition: function (target) {
  5169. if (target === undefined) {
  5170. console.warn('THREE.Object3D: .getWorldPosition() target is now required');
  5171. target = new Vector3();
  5172. }
  5173. this.updateMatrixWorld(true);
  5174. return target.setFromMatrixPosition(this.matrixWorld);
  5175. },
  5176. getWorldQuaternion: function () {
  5177. var position = new Vector3();
  5178. var scale = new Vector3();
  5179. return function getWorldQuaternion(target) {
  5180. if (target === undefined) {
  5181. console.warn('THREE.Object3D: .getWorldQuaternion() target is now required');
  5182. target = new Quaternion();
  5183. }
  5184. this.updateMatrixWorld(true);
  5185. this.matrixWorld.decompose(position, target, scale);
  5186. return target;
  5187. };
  5188. }(),
  5189. getWorldScale: function () {
  5190. var position = new Vector3();
  5191. var quaternion = new Quaternion();
  5192. return function getWorldScale(target) {
  5193. if (target === undefined) {
  5194. console.warn('THREE.Object3D: .getWorldScale() target is now required');
  5195. target = new Vector3();
  5196. }
  5197. this.updateMatrixWorld(true);
  5198. this.matrixWorld.decompose(position, quaternion, target);
  5199. return target;
  5200. };
  5201. }(),
  5202. getWorldDirection: function () {
  5203. var quaternion = new Quaternion();
  5204. return function getWorldDirection(target) {
  5205. if (target === undefined) {
  5206. console.warn('THREE.Object3D: .getWorldDirection() target is now required');
  5207. target = new Vector3();
  5208. }
  5209. this.getWorldQuaternion(quaternion);
  5210. return target.set(0, 0, 1).applyQuaternion(quaternion);
  5211. };
  5212. }(),
  5213. raycast: function () {},
  5214. traverse: function (callback) {
  5215. callback(this);
  5216. var children = this.children;
  5217. for (var i = 0, l = children.length; i < l; i++) {
  5218. children[i].traverse(callback);
  5219. }
  5220. },
  5221. traverseVisible: function (callback) {
  5222. if (this.visible === false) return;
  5223. callback(this);
  5224. var children = this.children;
  5225. for (var i = 0, l = children.length; i < l; i++) {
  5226. children[i].traverseVisible(callback);
  5227. }
  5228. },
  5229. traverseAncestors: function (callback) {
  5230. var parent = this.parent;
  5231. if (parent !== null) {
  5232. callback(parent);
  5233. parent.traverseAncestors(callback);
  5234. }
  5235. },
  5236. updateMatrix: function () {
  5237. this.matrix.compose(this.position, this.quaternion, this.scale);
  5238. this.matrixWorldNeedsUpdate = true;
  5239. },
  5240. updateMatrixWorld: function (force) {
  5241. if (this.matrixAutoUpdate) this.updateMatrix();
  5242. if (this.matrixWorldNeedsUpdate || force) {
  5243. if (this.parent === null) {
  5244. this.matrixWorld.copy(this.matrix);
  5245. } else {
  5246. this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
  5247. }
  5248. this.matrixWorldNeedsUpdate = false;
  5249. force = true;
  5250. }
  5251. // update children
  5252. var children = this.children;
  5253. for (var i = 0, l = children.length; i < l; i++) {
  5254. children[i].updateMatrixWorld(force);
  5255. }
  5256. },
  5257. toJSON: function (meta) {
  5258. // meta is a string when called from JSON.stringify
  5259. var isRootObject = meta === undefined || typeof meta === 'string';
  5260. var output = {};
  5261. // meta is a hash used to collect geometries, materials.
  5262. // not providing it implies that this is the root object
  5263. // being serialized.
  5264. if (isRootObject) {
  5265. // initialize meta obj
  5266. meta = {
  5267. geometries: {},
  5268. materials: {},
  5269. textures: {},
  5270. images: {},
  5271. shapes: {}
  5272. };
  5273. output.metadata = {
  5274. version: 4.5,
  5275. type: 'Object',
  5276. generator: 'Object3D.toJSON'
  5277. };
  5278. }
  5279. // standard Object3D serialization
  5280. var object = {};
  5281. object.uuid = this.uuid;
  5282. object.type = this.type;
  5283. if (this.name !== '') object.name = this.name;
  5284. if (this.castShadow === true) object.castShadow = true;
  5285. if (this.receiveShadow === true) object.receiveShadow = true;
  5286. if (this.visible === false) object.visible = false;
  5287. if (this.frustumCulled === false) object.frustumCulled = false;
  5288. if (this.renderOrder !== 0) object.renderOrder = this.renderOrder;
  5289. if (JSON.stringify(this.userData) !== '{}') object.userData = this.userData;
  5290. object.matrix = this.matrix.toArray();
  5291. if (this.matrixAutoUpdate === false) object.matrixAutoUpdate = false;
  5292. //
  5293. function serialize(library, element) {
  5294. if (library[element.uuid] === undefined) {
  5295. library[element.uuid] = element.toJSON(meta);
  5296. }
  5297. return element.uuid;
  5298. }
  5299. if (this.geometry !== undefined) {
  5300. object.geometry = serialize(meta.geometries, this.geometry);
  5301. var parameters = this.geometry.parameters;
  5302. if (parameters !== undefined && parameters.shapes !== undefined) {
  5303. var shapes = parameters.shapes;
  5304. if (Array.isArray(shapes)) {
  5305. for (var i = 0, l = shapes.length; i < l; i++) {
  5306. var shape = shapes[i];
  5307. serialize(meta.shapes, shape);
  5308. }
  5309. } else {
  5310. serialize(meta.shapes, shapes);
  5311. }
  5312. }
  5313. }
  5314. if (this.material !== undefined) {
  5315. if (Array.isArray(this.material)) {
  5316. var uuids = [];
  5317. for (var i = 0, l = this.material.length; i < l; i++) {
  5318. uuids.push(serialize(meta.materials, this.material[i]));
  5319. }
  5320. object.material = uuids;
  5321. } else {
  5322. object.material = serialize(meta.materials, this.material);
  5323. }
  5324. }
  5325. //
  5326. if (this.children.length > 0) {
  5327. object.children = [];
  5328. for (var i = 0; i < this.children.length; i++) {
  5329. object.children.push(this.children[i].toJSON(meta).object);
  5330. }
  5331. }
  5332. if (isRootObject) {
  5333. var geometries = extractFromCache(meta.geometries);
  5334. var materials = extractFromCache(meta.materials);
  5335. var textures = extractFromCache(meta.textures);
  5336. var images = extractFromCache(meta.images);
  5337. var shapes = extractFromCache(meta.shapes);
  5338. if (geometries.length > 0) output.geometries = geometries;
  5339. if (materials.length > 0) output.materials = materials;
  5340. if (textures.length > 0) output.textures = textures;
  5341. if (images.length > 0) output.images = images;
  5342. if (shapes.length > 0) output.shapes = shapes;
  5343. }
  5344. output.object = object;
  5345. return output;
  5346. // extract data from the cache hash
  5347. // remove metadata on each item
  5348. // and return as array
  5349. function extractFromCache(cache) {
  5350. var values = [];
  5351. for (var key in cache) {
  5352. var data = cache[key];
  5353. delete data.metadata;
  5354. values.push(data);
  5355. }
  5356. return values;
  5357. }
  5358. },
  5359. clone: function (recursive) {
  5360. return new this.constructor().copy(this, recursive);
  5361. },
  5362. copy: function (source, recursive) {
  5363. if (recursive === undefined) recursive = true;
  5364. this.name = source.name;
  5365. this.up.copy(source.up);
  5366. this.position.copy(source.position);
  5367. this.quaternion.copy(source.quaternion);
  5368. this.scale.copy(source.scale);
  5369. this.matrix.copy(source.matrix);
  5370. this.matrixWorld.copy(source.matrixWorld);
  5371. this.matrixAutoUpdate = source.matrixAutoUpdate;
  5372. this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
  5373. this.layers.mask = source.layers.mask;
  5374. this.visible = source.visible;
  5375. this.castShadow = source.castShadow;
  5376. this.receiveShadow = source.receiveShadow;
  5377. this.frustumCulled = source.frustumCulled;
  5378. this.renderOrder = source.renderOrder;
  5379. this.userData = JSON.parse(JSON.stringify(source.userData));
  5380. if (recursive === true) {
  5381. for (var i = 0; i < source.children.length; i++) {
  5382. var child = source.children[i];
  5383. this.add(child.clone());
  5384. }
  5385. }
  5386. return this;
  5387. }
  5388. });
  5389. /**
  5390. * @author mrdoob / http://mrdoob.com/
  5391. * @author mikael emtinger / http://gomo.se/
  5392. * @author WestLangley / http://github.com/WestLangley
  5393. */
  5394. function Camera() {
  5395. Object3D.call(this);
  5396. this.type = 'Camera';
  5397. this.matrixWorldInverse = new Matrix4();
  5398. this.projectionMatrix = new Matrix4();
  5399. }
  5400. Camera.prototype = Object.assign(Object.create(Object3D.prototype), {
  5401. constructor: Camera,
  5402. isCamera: true,
  5403. copy: function (source, recursive) {
  5404. Object3D.prototype.copy.call(this, source, recursive);
  5405. this.matrixWorldInverse.copy(source.matrixWorldInverse);
  5406. this.projectionMatrix.copy(source.projectionMatrix);
  5407. return this;
  5408. },
  5409. getWorldDirection: function () {
  5410. var quaternion = new Quaternion();
  5411. return function getWorldDirection(target) {
  5412. if (target === undefined) {
  5413. console.warn('THREE.Camera: .getWorldDirection() target is now required');
  5414. target = new Vector3();
  5415. }
  5416. this.getWorldQuaternion(quaternion);
  5417. return target.set(0, 0, -1).applyQuaternion(quaternion);
  5418. };
  5419. }(),
  5420. updateMatrixWorld: function (force) {
  5421. Object3D.prototype.updateMatrixWorld.call(this, force);
  5422. this.matrixWorldInverse.getInverse(this.matrixWorld);
  5423. },
  5424. clone: function () {
  5425. return new this.constructor().copy(this);
  5426. }
  5427. });
  5428. /**
  5429. * @author alteredq / http://alteredqualia.com/
  5430. * @author arose / http://github.com/arose
  5431. */
  5432. function OrthographicCamera(left, right, top, bottom, near, far) {
  5433. Camera.call(this);
  5434. this.type = 'OrthographicCamera';
  5435. this.zoom = 1;
  5436. this.view = null;
  5437. this.left = left;
  5438. this.right = right;
  5439. this.top = top;
  5440. this.bottom = bottom;
  5441. this.near = near !== undefined ? near : 0.1;
  5442. this.far = far !== undefined ? far : 2000;
  5443. this.updateProjectionMatrix();
  5444. }
  5445. OrthographicCamera.prototype = Object.assign(Object.create(Camera.prototype), {
  5446. constructor: OrthographicCamera,
  5447. isOrthographicCamera: true,
  5448. copy: function (source, recursive) {
  5449. Camera.prototype.copy.call(this, source, recursive);
  5450. this.left = source.left;
  5451. this.right = source.right;
  5452. this.top = source.top;
  5453. this.bottom = source.bottom;
  5454. this.near = source.near;
  5455. this.far = source.far;
  5456. this.zoom = source.zoom;
  5457. this.view = source.view === null ? null : Object.assign({}, source.view);
  5458. return this;
  5459. },
  5460. setViewOffset: function (fullWidth, fullHeight, x, y, width, height) {
  5461. if (this.view === null) {
  5462. this.view = {
  5463. enabled: true,
  5464. fullWidth: 1,
  5465. fullHeight: 1,
  5466. offsetX: 0,
  5467. offsetY: 0,
  5468. width: 1,
  5469. height: 1
  5470. };
  5471. }
  5472. this.view.enabled = true;
  5473. this.view.fullWidth = fullWidth;
  5474. this.view.fullHeight = fullHeight;
  5475. this.view.offsetX = x;
  5476. this.view.offsetY = y;
  5477. this.view.width = width;
  5478. this.view.height = height;
  5479. this.updateProjectionMatrix();
  5480. },
  5481. clearViewOffset: function () {
  5482. if (this.view !== null) {
  5483. this.view.enabled = false;
  5484. }
  5485. this.updateProjectionMatrix();
  5486. },
  5487. updateProjectionMatrix: function () {
  5488. var dx = (this.right - this.left) / (2 * this.zoom);
  5489. var dy = (this.top - this.bottom) / (2 * this.zoom);
  5490. var cx = (this.right + this.left) / 2;
  5491. var cy = (this.top + this.bottom) / 2;
  5492. var left = cx - dx;
  5493. var right = cx + dx;
  5494. var top = cy + dy;
  5495. var bottom = cy - dy;
  5496. if (this.view !== null && this.view.enabled) {
  5497. var zoomW = this.zoom / (this.view.width / this.view.fullWidth);
  5498. var zoomH = this.zoom / (this.view.height / this.view.fullHeight);
  5499. var scaleW = (this.right - this.left) / this.view.width;
  5500. var scaleH = (this.top - this.bottom) / this.view.height;
  5501. left += scaleW * (this.view.offsetX / zoomW);
  5502. right = left + scaleW * (this.view.width / zoomW);
  5503. top -= scaleH * (this.view.offsetY / zoomH);
  5504. bottom = top - scaleH * (this.view.height / zoomH);
  5505. }
  5506. this.projectionMatrix.makeOrthographic(left, right, top, bottom, this.near, this.far);
  5507. },
  5508. toJSON: function (meta) {
  5509. var data = Object3D.prototype.toJSON.call(this, meta);
  5510. data.object.zoom = this.zoom;
  5511. data.object.left = this.left;
  5512. data.object.right = this.right;
  5513. data.object.top = this.top;
  5514. data.object.bottom = this.bottom;
  5515. data.object.near = this.near;
  5516. data.object.far = this.far;
  5517. if (this.view !== null) data.object.view = Object.assign({}, this.view);
  5518. return data;
  5519. }
  5520. });
  5521. /**
  5522. * @author mrdoob / http://mrdoob.com/
  5523. * @author alteredq / http://alteredqualia.com/
  5524. */
  5525. function Face3(a, b, c, normal, color, materialIndex) {
  5526. this.a = a;
  5527. this.b = b;
  5528. this.c = c;
  5529. this.normal = normal && normal.isVector3 ? normal : new Vector3();
  5530. this.vertexNormals = Array.isArray(normal) ? normal : [];
  5531. this.color = color && color.isColor ? color : new Color();
  5532. this.vertexColors = Array.isArray(color) ? color : [];
  5533. this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
  5534. }
  5535. Object.assign(Face3.prototype, {
  5536. clone: function () {
  5537. return new this.constructor().copy(this);
  5538. },
  5539. copy: function (source) {
  5540. this.a = source.a;
  5541. this.b = source.b;
  5542. this.c = source.c;
  5543. this.normal.copy(source.normal);
  5544. this.color.copy(source.color);
  5545. this.materialIndex = source.materialIndex;
  5546. for (var i = 0, il = source.vertexNormals.length; i < il; i++) {
  5547. this.vertexNormals[i] = source.vertexNormals[i].clone();
  5548. }
  5549. for (var i = 0, il = source.vertexColors.length; i < il; i++) {
  5550. this.vertexColors[i] = source.vertexColors[i].clone();
  5551. }
  5552. return this;
  5553. }
  5554. });
  5555. /**
  5556. * @author mrdoob / http://mrdoob.com/
  5557. * @author kile / http://kile.stravaganza.org/
  5558. * @author alteredq / http://alteredqualia.com/
  5559. * @author mikael emtinger / http://gomo.se/
  5560. * @author zz85 / http://www.lab4games.net/zz85/blog
  5561. * @author bhouston / http://clara.io
  5562. */
  5563. var geometryId = 0; // Geometry uses even numbers as Id
  5564. function Geometry() {
  5565. Object.defineProperty(this, 'id', { value: geometryId += 2 });
  5566. this.uuid = _Math.generateUUID();
  5567. this.name = '';
  5568. this.type = 'Geometry';
  5569. this.vertices = [];
  5570. this.colors = [];
  5571. this.faces = [];
  5572. this.faceVertexUvs = [[]];
  5573. this.morphTargets = [];
  5574. this.morphNormals = [];
  5575. this.skinWeights = [];
  5576. this.skinIndices = [];
  5577. this.lineDistances = [];
  5578. this.boundingBox = null;
  5579. this.boundingSphere = null;
  5580. // update flags
  5581. this.elementsNeedUpdate = false;
  5582. this.verticesNeedUpdate = false;
  5583. this.uvsNeedUpdate = false;
  5584. this.normalsNeedUpdate = false;
  5585. this.colorsNeedUpdate = false;
  5586. this.lineDistancesNeedUpdate = false;
  5587. this.groupsNeedUpdate = false;
  5588. }
  5589. Geometry.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  5590. constructor: Geometry,
  5591. isGeometry: true,
  5592. applyMatrix: function (matrix) {
  5593. var normalMatrix = new Matrix3().getNormalMatrix(matrix);
  5594. for (var i = 0, il = this.vertices.length; i < il; i++) {
  5595. var vertex = this.vertices[i];
  5596. vertex.applyMatrix4(matrix);
  5597. }
  5598. for (var i = 0, il = this.faces.length; i < il; i++) {
  5599. var face = this.faces[i];
  5600. face.normal.applyMatrix3(normalMatrix).normalize();
  5601. for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) {
  5602. face.vertexNormals[j].applyMatrix3(normalMatrix).normalize();
  5603. }
  5604. }
  5605. if (this.boundingBox !== null) {
  5606. this.computeBoundingBox();
  5607. }
  5608. if (this.boundingSphere !== null) {
  5609. this.computeBoundingSphere();
  5610. }
  5611. this.verticesNeedUpdate = true;
  5612. this.normalsNeedUpdate = true;
  5613. return this;
  5614. },
  5615. rotateX: function () {
  5616. // rotate geometry around world x-axis
  5617. var m1 = new Matrix4();
  5618. return function rotateX(angle) {
  5619. m1.makeRotationX(angle);
  5620. this.applyMatrix(m1);
  5621. return this;
  5622. };
  5623. }(),
  5624. rotateY: function () {
  5625. // rotate geometry around world y-axis
  5626. var m1 = new Matrix4();
  5627. return function rotateY(angle) {
  5628. m1.makeRotationY(angle);
  5629. this.applyMatrix(m1);
  5630. return this;
  5631. };
  5632. }(),
  5633. rotateZ: function () {
  5634. // rotate geometry around world z-axis
  5635. var m1 = new Matrix4();
  5636. return function rotateZ(angle) {
  5637. m1.makeRotationZ(angle);
  5638. this.applyMatrix(m1);
  5639. return this;
  5640. };
  5641. }(),
  5642. translate: function () {
  5643. // translate geometry
  5644. var m1 = new Matrix4();
  5645. return function translate(x, y, z) {
  5646. m1.makeTranslation(x, y, z);
  5647. this.applyMatrix(m1);
  5648. return this;
  5649. };
  5650. }(),
  5651. scale: function () {
  5652. // scale geometry
  5653. var m1 = new Matrix4();
  5654. return function scale(x, y, z) {
  5655. m1.makeScale(x, y, z);
  5656. this.applyMatrix(m1);
  5657. return this;
  5658. };
  5659. }(),
  5660. lookAt: function () {
  5661. var obj = new Object3D();
  5662. return function lookAt(vector) {
  5663. obj.lookAt(vector);
  5664. obj.updateMatrix();
  5665. this.applyMatrix(obj.matrix);
  5666. };
  5667. }(),
  5668. fromBufferGeometry: function (geometry) {
  5669. var scope = this;
  5670. var indices = geometry.index !== null ? geometry.index.array : undefined;
  5671. var attributes = geometry.attributes;
  5672. var positions = attributes.position.array;
  5673. var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
  5674. var colors = attributes.color !== undefined ? attributes.color.array : undefined;
  5675. var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
  5676. var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
  5677. if (uvs2 !== undefined) this.faceVertexUvs[1] = [];
  5678. var tempNormals = [];
  5679. var tempUVs = [];
  5680. var tempUVs2 = [];
  5681. for (var i = 0, j = 0; i < positions.length; i += 3, j += 2) {
  5682. scope.vertices.push(new Vector3(positions[i], positions[i + 1], positions[i + 2]));
  5683. if (normals !== undefined) {
  5684. tempNormals.push(new Vector3(normals[i], normals[i + 1], normals[i + 2]));
  5685. }
  5686. if (colors !== undefined) {
  5687. scope.colors.push(new Color(colors[i], colors[i + 1], colors[i + 2]));
  5688. }
  5689. if (uvs !== undefined) {
  5690. tempUVs.push(new Vector2(uvs[j], uvs[j + 1]));
  5691. }
  5692. if (uvs2 !== undefined) {
  5693. tempUVs2.push(new Vector2(uvs2[j], uvs2[j + 1]));
  5694. }
  5695. }
  5696. function addFace(a, b, c, materialIndex) {
  5697. var vertexNormals = normals !== undefined ? [tempNormals[a].clone(), tempNormals[b].clone(), tempNormals[c].clone()] : [];
  5698. var vertexColors = colors !== undefined ? [scope.colors[a].clone(), scope.colors[b].clone(), scope.colors[c].clone()] : [];
  5699. var face = new Face3(a, b, c, vertexNormals, vertexColors, materialIndex);
  5700. scope.faces.push(face);
  5701. if (uvs !== undefined) {
  5702. scope.faceVertexUvs[0].push([tempUVs[a].clone(), tempUVs[b].clone(), tempUVs[c].clone()]);
  5703. }
  5704. if (uvs2 !== undefined) {
  5705. scope.faceVertexUvs[1].push([tempUVs2[a].clone(), tempUVs2[b].clone(), tempUVs2[c].clone()]);
  5706. }
  5707. }
  5708. var groups = geometry.groups;
  5709. if (groups.length > 0) {
  5710. for (var i = 0; i < groups.length; i++) {
  5711. var group = groups[i];
  5712. var start = group.start;
  5713. var count = group.count;
  5714. for (var j = start, jl = start + count; j < jl; j += 3) {
  5715. if (indices !== undefined) {
  5716. addFace(indices[j], indices[j + 1], indices[j + 2], group.materialIndex);
  5717. } else {
  5718. addFace(j, j + 1, j + 2, group.materialIndex);
  5719. }
  5720. }
  5721. }
  5722. } else {
  5723. if (indices !== undefined) {
  5724. for (var i = 0; i < indices.length; i += 3) {
  5725. addFace(indices[i], indices[i + 1], indices[i + 2]);
  5726. }
  5727. } else {
  5728. for (var i = 0; i < positions.length / 3; i += 3) {
  5729. addFace(i, i + 1, i + 2);
  5730. }
  5731. }
  5732. }
  5733. this.computeFaceNormals();
  5734. if (geometry.boundingBox !== null) {
  5735. this.boundingBox = geometry.boundingBox.clone();
  5736. }
  5737. if (geometry.boundingSphere !== null) {
  5738. this.boundingSphere = geometry.boundingSphere.clone();
  5739. }
  5740. return this;
  5741. },
  5742. center: function () {
  5743. var offset = new Vector3();
  5744. return function center() {
  5745. this.computeBoundingBox();
  5746. this.boundingBox.getCenter(offset).negate();
  5747. this.translate(offset.x, offset.y, offset.z);
  5748. return this;
  5749. };
  5750. }(),
  5751. normalize: function () {
  5752. this.computeBoundingSphere();
  5753. var center = this.boundingSphere.center;
  5754. var radius = this.boundingSphere.radius;
  5755. var s = radius === 0 ? 1 : 1.0 / radius;
  5756. var matrix = new Matrix4();
  5757. matrix.set(s, 0, 0, -s * center.x, 0, s, 0, -s * center.y, 0, 0, s, -s * center.z, 0, 0, 0, 1);
  5758. this.applyMatrix(matrix);
  5759. return this;
  5760. },
  5761. computeFaceNormals: function () {
  5762. var cb = new Vector3(),
  5763. ab = new Vector3();
  5764. for (var f = 0, fl = this.faces.length; f < fl; f++) {
  5765. var face = this.faces[f];
  5766. var vA = this.vertices[face.a];
  5767. var vB = this.vertices[face.b];
  5768. var vC = this.vertices[face.c];
  5769. cb.subVectors(vC, vB);
  5770. ab.subVectors(vA, vB);
  5771. cb.cross(ab);
  5772. cb.normalize();
  5773. face.normal.copy(cb);
  5774. }
  5775. },
  5776. computeVertexNormals: function (areaWeighted) {
  5777. if (areaWeighted === undefined) areaWeighted = true;
  5778. var v, vl, f, fl, face, vertices;
  5779. vertices = new Array(this.vertices.length);
  5780. for (v = 0, vl = this.vertices.length; v < vl; v++) {
  5781. vertices[v] = new Vector3();
  5782. }
  5783. if (areaWeighted) {
  5784. // vertex normals weighted by triangle areas
  5785. // http://www.iquilezles.org/www/articles/normals/normals.htm
  5786. var vA, vB, vC;
  5787. var cb = new Vector3(),
  5788. ab = new Vector3();
  5789. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5790. face = this.faces[f];
  5791. vA = this.vertices[face.a];
  5792. vB = this.vertices[face.b];
  5793. vC = this.vertices[face.c];
  5794. cb.subVectors(vC, vB);
  5795. ab.subVectors(vA, vB);
  5796. cb.cross(ab);
  5797. vertices[face.a].add(cb);
  5798. vertices[face.b].add(cb);
  5799. vertices[face.c].add(cb);
  5800. }
  5801. } else {
  5802. this.computeFaceNormals();
  5803. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5804. face = this.faces[f];
  5805. vertices[face.a].add(face.normal);
  5806. vertices[face.b].add(face.normal);
  5807. vertices[face.c].add(face.normal);
  5808. }
  5809. }
  5810. for (v = 0, vl = this.vertices.length; v < vl; v++) {
  5811. vertices[v].normalize();
  5812. }
  5813. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5814. face = this.faces[f];
  5815. var vertexNormals = face.vertexNormals;
  5816. if (vertexNormals.length === 3) {
  5817. vertexNormals[0].copy(vertices[face.a]);
  5818. vertexNormals[1].copy(vertices[face.b]);
  5819. vertexNormals[2].copy(vertices[face.c]);
  5820. } else {
  5821. vertexNormals[0] = vertices[face.a].clone();
  5822. vertexNormals[1] = vertices[face.b].clone();
  5823. vertexNormals[2] = vertices[face.c].clone();
  5824. }
  5825. }
  5826. if (this.faces.length > 0) {
  5827. this.normalsNeedUpdate = true;
  5828. }
  5829. },
  5830. computeFlatVertexNormals: function () {
  5831. var f, fl, face;
  5832. this.computeFaceNormals();
  5833. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5834. face = this.faces[f];
  5835. var vertexNormals = face.vertexNormals;
  5836. if (vertexNormals.length === 3) {
  5837. vertexNormals[0].copy(face.normal);
  5838. vertexNormals[1].copy(face.normal);
  5839. vertexNormals[2].copy(face.normal);
  5840. } else {
  5841. vertexNormals[0] = face.normal.clone();
  5842. vertexNormals[1] = face.normal.clone();
  5843. vertexNormals[2] = face.normal.clone();
  5844. }
  5845. }
  5846. if (this.faces.length > 0) {
  5847. this.normalsNeedUpdate = true;
  5848. }
  5849. },
  5850. computeMorphNormals: function () {
  5851. var i, il, f, fl, face;
  5852. // save original normals
  5853. // - create temp variables on first access
  5854. // otherwise just copy (for faster repeated calls)
  5855. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5856. face = this.faces[f];
  5857. if (!face.__originalFaceNormal) {
  5858. face.__originalFaceNormal = face.normal.clone();
  5859. } else {
  5860. face.__originalFaceNormal.copy(face.normal);
  5861. }
  5862. if (!face.__originalVertexNormals) face.__originalVertexNormals = [];
  5863. for (i = 0, il = face.vertexNormals.length; i < il; i++) {
  5864. if (!face.__originalVertexNormals[i]) {
  5865. face.__originalVertexNormals[i] = face.vertexNormals[i].clone();
  5866. } else {
  5867. face.__originalVertexNormals[i].copy(face.vertexNormals[i]);
  5868. }
  5869. }
  5870. }
  5871. // use temp geometry to compute face and vertex normals for each morph
  5872. var tmpGeo = new Geometry();
  5873. tmpGeo.faces = this.faces;
  5874. for (i = 0, il = this.morphTargets.length; i < il; i++) {
  5875. // create on first access
  5876. if (!this.morphNormals[i]) {
  5877. this.morphNormals[i] = {};
  5878. this.morphNormals[i].faceNormals = [];
  5879. this.morphNormals[i].vertexNormals = [];
  5880. var dstNormalsFace = this.morphNormals[i].faceNormals;
  5881. var dstNormalsVertex = this.morphNormals[i].vertexNormals;
  5882. var faceNormal, vertexNormals;
  5883. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5884. faceNormal = new Vector3();
  5885. vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
  5886. dstNormalsFace.push(faceNormal);
  5887. dstNormalsVertex.push(vertexNormals);
  5888. }
  5889. }
  5890. var morphNormals = this.morphNormals[i];
  5891. // set vertices to morph target
  5892. tmpGeo.vertices = this.morphTargets[i].vertices;
  5893. // compute morph normals
  5894. tmpGeo.computeFaceNormals();
  5895. tmpGeo.computeVertexNormals();
  5896. // store morph normals
  5897. var faceNormal, vertexNormals;
  5898. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5899. face = this.faces[f];
  5900. faceNormal = morphNormals.faceNormals[f];
  5901. vertexNormals = morphNormals.vertexNormals[f];
  5902. faceNormal.copy(face.normal);
  5903. vertexNormals.a.copy(face.vertexNormals[0]);
  5904. vertexNormals.b.copy(face.vertexNormals[1]);
  5905. vertexNormals.c.copy(face.vertexNormals[2]);
  5906. }
  5907. }
  5908. // restore original normals
  5909. for (f = 0, fl = this.faces.length; f < fl; f++) {
  5910. face = this.faces[f];
  5911. face.normal = face.__originalFaceNormal;
  5912. face.vertexNormals = face.__originalVertexNormals;
  5913. }
  5914. },
  5915. computeBoundingBox: function () {
  5916. if (this.boundingBox === null) {
  5917. this.boundingBox = new Box3();
  5918. }
  5919. this.boundingBox.setFromPoints(this.vertices);
  5920. },
  5921. computeBoundingSphere: function () {
  5922. if (this.boundingSphere === null) {
  5923. this.boundingSphere = new Sphere();
  5924. }
  5925. this.boundingSphere.setFromPoints(this.vertices);
  5926. },
  5927. merge: function (geometry, matrix, materialIndexOffset) {
  5928. if (!(geometry && geometry.isGeometry)) {
  5929. console.error('THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry);
  5930. return;
  5931. }
  5932. var normalMatrix,
  5933. vertexOffset = this.vertices.length,
  5934. vertices1 = this.vertices,
  5935. vertices2 = geometry.vertices,
  5936. faces1 = this.faces,
  5937. faces2 = geometry.faces,
  5938. uvs1 = this.faceVertexUvs[0],
  5939. uvs2 = geometry.faceVertexUvs[0],
  5940. colors1 = this.colors,
  5941. colors2 = geometry.colors;
  5942. if (materialIndexOffset === undefined) materialIndexOffset = 0;
  5943. if (matrix !== undefined) {
  5944. normalMatrix = new Matrix3().getNormalMatrix(matrix);
  5945. }
  5946. // vertices
  5947. for (var i = 0, il = vertices2.length; i < il; i++) {
  5948. var vertex = vertices2[i];
  5949. var vertexCopy = vertex.clone();
  5950. if (matrix !== undefined) vertexCopy.applyMatrix4(matrix);
  5951. vertices1.push(vertexCopy);
  5952. }
  5953. // colors
  5954. for (var i = 0, il = colors2.length; i < il; i++) {
  5955. colors1.push(colors2[i].clone());
  5956. }
  5957. // faces
  5958. for (i = 0, il = faces2.length; i < il; i++) {
  5959. var face = faces2[i],
  5960. faceCopy,
  5961. normal,
  5962. color,
  5963. faceVertexNormals = face.vertexNormals,
  5964. faceVertexColors = face.vertexColors;
  5965. faceCopy = new Face3(face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset);
  5966. faceCopy.normal.copy(face.normal);
  5967. if (normalMatrix !== undefined) {
  5968. faceCopy.normal.applyMatrix3(normalMatrix).normalize();
  5969. }
  5970. for (var j = 0, jl = faceVertexNormals.length; j < jl; j++) {
  5971. normal = faceVertexNormals[j].clone();
  5972. if (normalMatrix !== undefined) {
  5973. normal.applyMatrix3(normalMatrix).normalize();
  5974. }
  5975. faceCopy.vertexNormals.push(normal);
  5976. }
  5977. faceCopy.color.copy(face.color);
  5978. for (var j = 0, jl = faceVertexColors.length; j < jl; j++) {
  5979. color = faceVertexColors[j];
  5980. faceCopy.vertexColors.push(color.clone());
  5981. }
  5982. faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
  5983. faces1.push(faceCopy);
  5984. }
  5985. // uvs
  5986. for (i = 0, il = uvs2.length; i < il; i++) {
  5987. var uv = uvs2[i],
  5988. uvCopy = [];
  5989. if (uv === undefined) {
  5990. continue;
  5991. }
  5992. for (var j = 0, jl = uv.length; j < jl; j++) {
  5993. uvCopy.push(uv[j].clone());
  5994. }
  5995. uvs1.push(uvCopy);
  5996. }
  5997. },
  5998. mergeMesh: function (mesh) {
  5999. if (!(mesh && mesh.isMesh)) {
  6000. console.error('THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh);
  6001. return;
  6002. }
  6003. if (mesh.matrixAutoUpdate) mesh.updateMatrix();
  6004. this.merge(mesh.geometry, mesh.matrix);
  6005. },
  6006. /*
  6007. * Checks for duplicate vertices with hashmap.
  6008. * Duplicated vertices are removed
  6009. * and faces' vertices are updated.
  6010. */
  6011. mergeVertices: function () {
  6012. var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
  6013. var unique = [],
  6014. changes = [];
  6015. var v, key;
  6016. var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
  6017. var precision = Math.pow(10, precisionPoints);
  6018. var i, il, face;
  6019. var indices, j, jl;
  6020. for (i = 0, il = this.vertices.length; i < il; i++) {
  6021. v = this.vertices[i];
  6022. key = Math.round(v.x * precision) + '_' + Math.round(v.y * precision) + '_' + Math.round(v.z * precision);
  6023. if (verticesMap[key] === undefined) {
  6024. verticesMap[key] = i;
  6025. unique.push(this.vertices[i]);
  6026. changes[i] = unique.length - 1;
  6027. } else {
  6028. //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
  6029. changes[i] = changes[verticesMap[key]];
  6030. }
  6031. }
  6032. // if faces are completely degenerate after merging vertices, we
  6033. // have to remove them from the geometry.
  6034. var faceIndicesToRemove = [];
  6035. for (i = 0, il = this.faces.length; i < il; i++) {
  6036. face = this.faces[i];
  6037. face.a = changes[face.a];
  6038. face.b = changes[face.b];
  6039. face.c = changes[face.c];
  6040. indices = [face.a, face.b, face.c];
  6041. // if any duplicate vertices are found in a Face3
  6042. // we have to remove the face as nothing can be saved
  6043. for (var n = 0; n < 3; n++) {
  6044. if (indices[n] === indices[(n + 1) % 3]) {
  6045. faceIndicesToRemove.push(i);
  6046. break;
  6047. }
  6048. }
  6049. }
  6050. for (i = faceIndicesToRemove.length - 1; i >= 0; i--) {
  6051. var idx = faceIndicesToRemove[i];
  6052. this.faces.splice(idx, 1);
  6053. for (j = 0, jl = this.faceVertexUvs.length; j < jl; j++) {
  6054. this.faceVertexUvs[j].splice(idx, 1);
  6055. }
  6056. }
  6057. // Use unique set of vertices
  6058. var diff = this.vertices.length - unique.length;
  6059. this.vertices = unique;
  6060. return diff;
  6061. },
  6062. setFromPoints: function (points) {
  6063. this.vertices = [];
  6064. for (var i = 0, l = points.length; i < l; i++) {
  6065. var point = points[i];
  6066. this.vertices.push(new Vector3(point.x, point.y, point.z || 0));
  6067. }
  6068. return this;
  6069. },
  6070. sortFacesByMaterialIndex: function () {
  6071. var faces = this.faces;
  6072. var length = faces.length;
  6073. // tag faces
  6074. for (var i = 0; i < length; i++) {
  6075. faces[i]._id = i;
  6076. }
  6077. // sort faces
  6078. function materialIndexSort(a, b) {
  6079. return a.materialIndex - b.materialIndex;
  6080. }
  6081. faces.sort(materialIndexSort);
  6082. // sort uvs
  6083. var uvs1 = this.faceVertexUvs[0];
  6084. var uvs2 = this.faceVertexUvs[1];
  6085. var newUvs1, newUvs2;
  6086. if (uvs1 && uvs1.length === length) newUvs1 = [];
  6087. if (uvs2 && uvs2.length === length) newUvs2 = [];
  6088. for (var i = 0; i < length; i++) {
  6089. var id = faces[i]._id;
  6090. if (newUvs1) newUvs1.push(uvs1[id]);
  6091. if (newUvs2) newUvs2.push(uvs2[id]);
  6092. }
  6093. if (newUvs1) this.faceVertexUvs[0] = newUvs1;
  6094. if (newUvs2) this.faceVertexUvs[1] = newUvs2;
  6095. },
  6096. toJSON: function () {
  6097. var data = {
  6098. metadata: {
  6099. version: 4.5,
  6100. type: 'Geometry',
  6101. generator: 'Geometry.toJSON'
  6102. }
  6103. };
  6104. // standard Geometry serialization
  6105. data.uuid = this.uuid;
  6106. data.type = this.type;
  6107. if (this.name !== '') data.name = this.name;
  6108. if (this.parameters !== undefined) {
  6109. var parameters = this.parameters;
  6110. for (var key in parameters) {
  6111. if (parameters[key] !== undefined) data[key] = parameters[key];
  6112. }
  6113. return data;
  6114. }
  6115. var vertices = [];
  6116. for (var i = 0; i < this.vertices.length; i++) {
  6117. var vertex = this.vertices[i];
  6118. vertices.push(vertex.x, vertex.y, vertex.z);
  6119. }
  6120. var faces = [];
  6121. var normals = [];
  6122. var normalsHash = {};
  6123. var colors = [];
  6124. var colorsHash = {};
  6125. var uvs = [];
  6126. var uvsHash = {};
  6127. for (var i = 0; i < this.faces.length; i++) {
  6128. var face = this.faces[i];
  6129. var hasMaterial = true;
  6130. var hasFaceUv = false; // deprecated
  6131. var hasFaceVertexUv = this.faceVertexUvs[0][i] !== undefined;
  6132. var hasFaceNormal = face.normal.length() > 0;
  6133. var hasFaceVertexNormal = face.vertexNormals.length > 0;
  6134. var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
  6135. var hasFaceVertexColor = face.vertexColors.length > 0;
  6136. var faceType = 0;
  6137. faceType = setBit(faceType, 0, 0); // isQuad
  6138. faceType = setBit(faceType, 1, hasMaterial);
  6139. faceType = setBit(faceType, 2, hasFaceUv);
  6140. faceType = setBit(faceType, 3, hasFaceVertexUv);
  6141. faceType = setBit(faceType, 4, hasFaceNormal);
  6142. faceType = setBit(faceType, 5, hasFaceVertexNormal);
  6143. faceType = setBit(faceType, 6, hasFaceColor);
  6144. faceType = setBit(faceType, 7, hasFaceVertexColor);
  6145. faces.push(faceType);
  6146. faces.push(face.a, face.b, face.c);
  6147. faces.push(face.materialIndex);
  6148. if (hasFaceVertexUv) {
  6149. var faceVertexUvs = this.faceVertexUvs[0][i];
  6150. faces.push(getUvIndex(faceVertexUvs[0]), getUvIndex(faceVertexUvs[1]), getUvIndex(faceVertexUvs[2]));
  6151. }
  6152. if (hasFaceNormal) {
  6153. faces.push(getNormalIndex(face.normal));
  6154. }
  6155. if (hasFaceVertexNormal) {
  6156. var vertexNormals = face.vertexNormals;
  6157. faces.push(getNormalIndex(vertexNormals[0]), getNormalIndex(vertexNormals[1]), getNormalIndex(vertexNormals[2]));
  6158. }
  6159. if (hasFaceColor) {
  6160. faces.push(getColorIndex(face.color));
  6161. }
  6162. if (hasFaceVertexColor) {
  6163. var vertexColors = face.vertexColors;
  6164. faces.push(getColorIndex(vertexColors[0]), getColorIndex(vertexColors[1]), getColorIndex(vertexColors[2]));
  6165. }
  6166. }
  6167. function setBit(value, position, enabled) {
  6168. return enabled ? value | 1 << position : value & ~(1 << position);
  6169. }
  6170. function getNormalIndex(normal) {
  6171. var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
  6172. if (normalsHash[hash] !== undefined) {
  6173. return normalsHash[hash];
  6174. }
  6175. normalsHash[hash] = normals.length / 3;
  6176. normals.push(normal.x, normal.y, normal.z);
  6177. return normalsHash[hash];
  6178. }
  6179. function getColorIndex(color) {
  6180. var hash = color.r.toString() + color.g.toString() + color.b.toString();
  6181. if (colorsHash[hash] !== undefined) {
  6182. return colorsHash[hash];
  6183. }
  6184. colorsHash[hash] = colors.length;
  6185. colors.push(color.getHex());
  6186. return colorsHash[hash];
  6187. }
  6188. function getUvIndex(uv) {
  6189. var hash = uv.x.toString() + uv.y.toString();
  6190. if (uvsHash[hash] !== undefined) {
  6191. return uvsHash[hash];
  6192. }
  6193. uvsHash[hash] = uvs.length / 2;
  6194. uvs.push(uv.x, uv.y);
  6195. return uvsHash[hash];
  6196. }
  6197. data.data = {};
  6198. data.data.vertices = vertices;
  6199. data.data.normals = normals;
  6200. if (colors.length > 0) data.data.colors = colors;
  6201. if (uvs.length > 0) data.data.uvs = [uvs]; // temporal backward compatibility
  6202. data.data.faces = faces;
  6203. return data;
  6204. },
  6205. clone: function () {
  6206. /*
  6207. // Handle primitives
  6208. var parameters = this.parameters;
  6209. if ( parameters !== undefined ) {
  6210. var values = [];
  6211. for ( var key in parameters ) {
  6212. values.push( parameters[ key ] );
  6213. }
  6214. var geometry = Object.create( this.constructor.prototype );
  6215. this.constructor.apply( geometry, values );
  6216. return geometry;
  6217. }
  6218. return new this.constructor().copy( this );
  6219. */
  6220. return new Geometry().copy(this);
  6221. },
  6222. copy: function (source) {
  6223. var i, il, j, jl, k, kl;
  6224. // reset
  6225. this.vertices = [];
  6226. this.colors = [];
  6227. this.faces = [];
  6228. this.faceVertexUvs = [[]];
  6229. this.morphTargets = [];
  6230. this.morphNormals = [];
  6231. this.skinWeights = [];
  6232. this.skinIndices = [];
  6233. this.lineDistances = [];
  6234. this.boundingBox = null;
  6235. this.boundingSphere = null;
  6236. // name
  6237. this.name = source.name;
  6238. // vertices
  6239. var vertices = source.vertices;
  6240. for (i = 0, il = vertices.length; i < il; i++) {
  6241. this.vertices.push(vertices[i].clone());
  6242. }
  6243. // colors
  6244. var colors = source.colors;
  6245. for (i = 0, il = colors.length; i < il; i++) {
  6246. this.colors.push(colors[i].clone());
  6247. }
  6248. // faces
  6249. var faces = source.faces;
  6250. for (i = 0, il = faces.length; i < il; i++) {
  6251. this.faces.push(faces[i].clone());
  6252. }
  6253. // face vertex uvs
  6254. for (i = 0, il = source.faceVertexUvs.length; i < il; i++) {
  6255. var faceVertexUvs = source.faceVertexUvs[i];
  6256. if (this.faceVertexUvs[i] === undefined) {
  6257. this.faceVertexUvs[i] = [];
  6258. }
  6259. for (j = 0, jl = faceVertexUvs.length; j < jl; j++) {
  6260. var uvs = faceVertexUvs[j],
  6261. uvsCopy = [];
  6262. for (k = 0, kl = uvs.length; k < kl; k++) {
  6263. var uv = uvs[k];
  6264. uvsCopy.push(uv.clone());
  6265. }
  6266. this.faceVertexUvs[i].push(uvsCopy);
  6267. }
  6268. }
  6269. // morph targets
  6270. var morphTargets = source.morphTargets;
  6271. for (i = 0, il = morphTargets.length; i < il; i++) {
  6272. var morphTarget = {};
  6273. morphTarget.name = morphTargets[i].name;
  6274. // vertices
  6275. if (morphTargets[i].vertices !== undefined) {
  6276. morphTarget.vertices = [];
  6277. for (j = 0, jl = morphTargets[i].vertices.length; j < jl; j++) {
  6278. morphTarget.vertices.push(morphTargets[i].vertices[j].clone());
  6279. }
  6280. }
  6281. // normals
  6282. if (morphTargets[i].normals !== undefined) {
  6283. morphTarget.normals = [];
  6284. for (j = 0, jl = morphTargets[i].normals.length; j < jl; j++) {
  6285. morphTarget.normals.push(morphTargets[i].normals[j].clone());
  6286. }
  6287. }
  6288. this.morphTargets.push(morphTarget);
  6289. }
  6290. // morph normals
  6291. var morphNormals = source.morphNormals;
  6292. for (i = 0, il = morphNormals.length; i < il; i++) {
  6293. var morphNormal = {};
  6294. // vertex normals
  6295. if (morphNormals[i].vertexNormals !== undefined) {
  6296. morphNormal.vertexNormals = [];
  6297. for (j = 0, jl = morphNormals[i].vertexNormals.length; j < jl; j++) {
  6298. var srcVertexNormal = morphNormals[i].vertexNormals[j];
  6299. var destVertexNormal = {};
  6300. destVertexNormal.a = srcVertexNormal.a.clone();
  6301. destVertexNormal.b = srcVertexNormal.b.clone();
  6302. destVertexNormal.c = srcVertexNormal.c.clone();
  6303. morphNormal.vertexNormals.push(destVertexNormal);
  6304. }
  6305. }
  6306. // face normals
  6307. if (morphNormals[i].faceNormals !== undefined) {
  6308. morphNormal.faceNormals = [];
  6309. for (j = 0, jl = morphNormals[i].faceNormals.length; j < jl; j++) {
  6310. morphNormal.faceNormals.push(morphNormals[i].faceNormals[j].clone());
  6311. }
  6312. }
  6313. this.morphNormals.push(morphNormal);
  6314. }
  6315. // skin weights
  6316. var skinWeights = source.skinWeights;
  6317. for (i = 0, il = skinWeights.length; i < il; i++) {
  6318. this.skinWeights.push(skinWeights[i].clone());
  6319. }
  6320. // skin indices
  6321. var skinIndices = source.skinIndices;
  6322. for (i = 0, il = skinIndices.length; i < il; i++) {
  6323. this.skinIndices.push(skinIndices[i].clone());
  6324. }
  6325. // line distances
  6326. var lineDistances = source.lineDistances;
  6327. for (i = 0, il = lineDistances.length; i < il; i++) {
  6328. this.lineDistances.push(lineDistances[i]);
  6329. }
  6330. // bounding box
  6331. var boundingBox = source.boundingBox;
  6332. if (boundingBox !== null) {
  6333. this.boundingBox = boundingBox.clone();
  6334. }
  6335. // bounding sphere
  6336. var boundingSphere = source.boundingSphere;
  6337. if (boundingSphere !== null) {
  6338. this.boundingSphere = boundingSphere.clone();
  6339. }
  6340. // update flags
  6341. this.elementsNeedUpdate = source.elementsNeedUpdate;
  6342. this.verticesNeedUpdate = source.verticesNeedUpdate;
  6343. this.uvsNeedUpdate = source.uvsNeedUpdate;
  6344. this.normalsNeedUpdate = source.normalsNeedUpdate;
  6345. this.colorsNeedUpdate = source.colorsNeedUpdate;
  6346. this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
  6347. this.groupsNeedUpdate = source.groupsNeedUpdate;
  6348. return this;
  6349. },
  6350. dispose: function () {
  6351. this.dispatchEvent({ type: 'dispose' });
  6352. }
  6353. });
  6354. /**
  6355. * @author mrdoob / http://mrdoob.com/
  6356. */
  6357. function BufferAttribute(array, itemSize, normalized) {
  6358. if (Array.isArray(array)) {
  6359. throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.');
  6360. }
  6361. this.name = '';
  6362. this.array = array;
  6363. this.itemSize = itemSize;
  6364. this.count = array !== undefined ? array.length / itemSize : 0;
  6365. this.normalized = normalized === true;
  6366. this.dynamic = false;
  6367. this.updateRange = { offset: 0, count: -1 };
  6368. this.version = 0;
  6369. }
  6370. Object.defineProperty(BufferAttribute.prototype, 'needsUpdate', {
  6371. set: function (value) {
  6372. if (value === true) this.version++;
  6373. }
  6374. });
  6375. Object.assign(BufferAttribute.prototype, {
  6376. isBufferAttribute: true,
  6377. onUploadCallback: function () {},
  6378. setArray: function (array) {
  6379. if (Array.isArray(array)) {
  6380. throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.');
  6381. }
  6382. this.count = array !== undefined ? array.length / this.itemSize : 0;
  6383. this.array = array;
  6384. return this;
  6385. },
  6386. setDynamic: function (value) {
  6387. this.dynamic = value;
  6388. return this;
  6389. },
  6390. copy: function (source) {
  6391. this.name = source.name;
  6392. this.array = new source.array.constructor(source.array);
  6393. this.itemSize = source.itemSize;
  6394. this.count = source.count;
  6395. this.normalized = source.normalized;
  6396. this.dynamic = source.dynamic;
  6397. return this;
  6398. },
  6399. copyAt: function (index1, attribute, index2) {
  6400. index1 *= this.itemSize;
  6401. index2 *= attribute.itemSize;
  6402. for (var i = 0, l = this.itemSize; i < l; i++) {
  6403. this.array[index1 + i] = attribute.array[index2 + i];
  6404. }
  6405. return this;
  6406. },
  6407. copyArray: function (array) {
  6408. this.array.set(array);
  6409. return this;
  6410. },
  6411. copyColorsArray: function (colors) {
  6412. var array = this.array,
  6413. offset = 0;
  6414. for (var i = 0, l = colors.length; i < l; i++) {
  6415. var color = colors[i];
  6416. if (color === undefined) {
  6417. console.warn('THREE.BufferAttribute.copyColorsArray(): color is undefined', i);
  6418. color = new Color();
  6419. }
  6420. array[offset++] = color.r;
  6421. array[offset++] = color.g;
  6422. array[offset++] = color.b;
  6423. }
  6424. return this;
  6425. },
  6426. copyVector2sArray: function (vectors) {
  6427. var array = this.array,
  6428. offset = 0;
  6429. for (var i = 0, l = vectors.length; i < l; i++) {
  6430. var vector = vectors[i];
  6431. if (vector === undefined) {
  6432. console.warn('THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i);
  6433. vector = new Vector2();
  6434. }
  6435. array[offset++] = vector.x;
  6436. array[offset++] = vector.y;
  6437. }
  6438. return this;
  6439. },
  6440. copyVector3sArray: function (vectors) {
  6441. var array = this.array,
  6442. offset = 0;
  6443. for (var i = 0, l = vectors.length; i < l; i++) {
  6444. var vector = vectors[i];
  6445. if (vector === undefined) {
  6446. console.warn('THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i);
  6447. vector = new Vector3();
  6448. }
  6449. array[offset++] = vector.x;
  6450. array[offset++] = vector.y;
  6451. array[offset++] = vector.z;
  6452. }
  6453. return this;
  6454. },
  6455. copyVector4sArray: function (vectors) {
  6456. var array = this.array,
  6457. offset = 0;
  6458. for (var i = 0, l = vectors.length; i < l; i++) {
  6459. var vector = vectors[i];
  6460. if (vector === undefined) {
  6461. console.warn('THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i);
  6462. vector = new Vector4();
  6463. }
  6464. array[offset++] = vector.x;
  6465. array[offset++] = vector.y;
  6466. array[offset++] = vector.z;
  6467. array[offset++] = vector.w;
  6468. }
  6469. return this;
  6470. },
  6471. set: function (value, offset) {
  6472. if (offset === undefined) offset = 0;
  6473. this.array.set(value, offset);
  6474. return this;
  6475. },
  6476. getX: function (index) {
  6477. return this.array[index * this.itemSize];
  6478. },
  6479. setX: function (index, x) {
  6480. this.array[index * this.itemSize] = x;
  6481. return this;
  6482. },
  6483. getY: function (index) {
  6484. return this.array[index * this.itemSize + 1];
  6485. },
  6486. setY: function (index, y) {
  6487. this.array[index * this.itemSize + 1] = y;
  6488. return this;
  6489. },
  6490. getZ: function (index) {
  6491. return this.array[index * this.itemSize + 2];
  6492. },
  6493. setZ: function (index, z) {
  6494. this.array[index * this.itemSize + 2] = z;
  6495. return this;
  6496. },
  6497. getW: function (index) {
  6498. return this.array[index * this.itemSize + 3];
  6499. },
  6500. setW: function (index, w) {
  6501. this.array[index * this.itemSize + 3] = w;
  6502. return this;
  6503. },
  6504. setXY: function (index, x, y) {
  6505. index *= this.itemSize;
  6506. this.array[index + 0] = x;
  6507. this.array[index + 1] = y;
  6508. return this;
  6509. },
  6510. setXYZ: function (index, x, y, z) {
  6511. index *= this.itemSize;
  6512. this.array[index + 0] = x;
  6513. this.array[index + 1] = y;
  6514. this.array[index + 2] = z;
  6515. return this;
  6516. },
  6517. setXYZW: function (index, x, y, z, w) {
  6518. index *= this.itemSize;
  6519. this.array[index + 0] = x;
  6520. this.array[index + 1] = y;
  6521. this.array[index + 2] = z;
  6522. this.array[index + 3] = w;
  6523. return this;
  6524. },
  6525. onUpload: function (callback) {
  6526. this.onUploadCallback = callback;
  6527. return this;
  6528. },
  6529. clone: function () {
  6530. return new this.constructor(this.array, this.itemSize).copy(this);
  6531. }
  6532. });
  6533. //
  6534. function Int8BufferAttribute(array, itemSize, normalized) {
  6535. BufferAttribute.call(this, new Int8Array(array), itemSize, normalized);
  6536. }
  6537. Int8BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6538. Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
  6539. function Uint8BufferAttribute(array, itemSize, normalized) {
  6540. BufferAttribute.call(this, new Uint8Array(array), itemSize, normalized);
  6541. }
  6542. Uint8BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6543. Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
  6544. function Uint8ClampedBufferAttribute(array, itemSize, normalized) {
  6545. BufferAttribute.call(this, new Uint8ClampedArray(array), itemSize, normalized);
  6546. }
  6547. Uint8ClampedBufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6548. Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
  6549. function Int16BufferAttribute(array, itemSize, normalized) {
  6550. BufferAttribute.call(this, new Int16Array(array), itemSize, normalized);
  6551. }
  6552. Int16BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6553. Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
  6554. function Uint16BufferAttribute(array, itemSize, normalized) {
  6555. BufferAttribute.call(this, new Uint16Array(array), itemSize, normalized);
  6556. }
  6557. Uint16BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6558. Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
  6559. function Int32BufferAttribute(array, itemSize, normalized) {
  6560. BufferAttribute.call(this, new Int32Array(array), itemSize, normalized);
  6561. }
  6562. Int32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6563. Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
  6564. function Uint32BufferAttribute(array, itemSize, normalized) {
  6565. BufferAttribute.call(this, new Uint32Array(array), itemSize, normalized);
  6566. }
  6567. Uint32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6568. Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
  6569. function Float32BufferAttribute(array, itemSize, normalized) {
  6570. BufferAttribute.call(this, new Float32Array(array), itemSize, normalized);
  6571. }
  6572. Float32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6573. Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
  6574. function Float64BufferAttribute(array, itemSize, normalized) {
  6575. BufferAttribute.call(this, new Float64Array(array), itemSize, normalized);
  6576. }
  6577. Float64BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
  6578. Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
  6579. /**
  6580. * @author mrdoob / http://mrdoob.com/
  6581. */
  6582. function DirectGeometry() {
  6583. this.vertices = [];
  6584. this.normals = [];
  6585. this.colors = [];
  6586. this.uvs = [];
  6587. this.uvs2 = [];
  6588. this.groups = [];
  6589. this.morphTargets = {};
  6590. this.skinWeights = [];
  6591. this.skinIndices = [];
  6592. // this.lineDistances = [];
  6593. this.boundingBox = null;
  6594. this.boundingSphere = null;
  6595. // update flags
  6596. this.verticesNeedUpdate = false;
  6597. this.normalsNeedUpdate = false;
  6598. this.colorsNeedUpdate = false;
  6599. this.uvsNeedUpdate = false;
  6600. this.groupsNeedUpdate = false;
  6601. }
  6602. Object.assign(DirectGeometry.prototype, {
  6603. computeGroups: function (geometry) {
  6604. var group;
  6605. var groups = [];
  6606. var materialIndex = undefined;
  6607. var faces = geometry.faces;
  6608. for (var i = 0; i < faces.length; i++) {
  6609. var face = faces[i];
  6610. // materials
  6611. if (face.materialIndex !== materialIndex) {
  6612. materialIndex = face.materialIndex;
  6613. if (group !== undefined) {
  6614. group.count = i * 3 - group.start;
  6615. groups.push(group);
  6616. }
  6617. group = {
  6618. start: i * 3,
  6619. materialIndex: materialIndex
  6620. };
  6621. }
  6622. }
  6623. if (group !== undefined) {
  6624. group.count = i * 3 - group.start;
  6625. groups.push(group);
  6626. }
  6627. this.groups = groups;
  6628. },
  6629. fromGeometry: function (geometry) {
  6630. var faces = geometry.faces;
  6631. var vertices = geometry.vertices;
  6632. var faceVertexUvs = geometry.faceVertexUvs;
  6633. var hasFaceVertexUv = faceVertexUvs[0] && faceVertexUvs[0].length > 0;
  6634. var hasFaceVertexUv2 = faceVertexUvs[1] && faceVertexUvs[1].length > 0;
  6635. // morphs
  6636. var morphTargets = geometry.morphTargets;
  6637. var morphTargetsLength = morphTargets.length;
  6638. var morphTargetsPosition;
  6639. if (morphTargetsLength > 0) {
  6640. morphTargetsPosition = [];
  6641. for (var i = 0; i < morphTargetsLength; i++) {
  6642. morphTargetsPosition[i] = [];
  6643. }
  6644. this.morphTargets.position = morphTargetsPosition;
  6645. }
  6646. var morphNormals = geometry.morphNormals;
  6647. var morphNormalsLength = morphNormals.length;
  6648. var morphTargetsNormal;
  6649. if (morphNormalsLength > 0) {
  6650. morphTargetsNormal = [];
  6651. for (var i = 0; i < morphNormalsLength; i++) {
  6652. morphTargetsNormal[i] = [];
  6653. }
  6654. this.morphTargets.normal = morphTargetsNormal;
  6655. }
  6656. // skins
  6657. var skinIndices = geometry.skinIndices;
  6658. var skinWeights = geometry.skinWeights;
  6659. var hasSkinIndices = skinIndices.length === vertices.length;
  6660. var hasSkinWeights = skinWeights.length === vertices.length;
  6661. //
  6662. if (faces.length === 0) {
  6663. console.error('THREE.DirectGeometry: Faceless geometries are not supported.');
  6664. }
  6665. for (var i = 0; i < faces.length; i++) {
  6666. var face = faces[i];
  6667. this.vertices.push(vertices[face.a], vertices[face.b], vertices[face.c]);
  6668. var vertexNormals = face.vertexNormals;
  6669. if (vertexNormals.length === 3) {
  6670. this.normals.push(vertexNormals[0], vertexNormals[1], vertexNormals[2]);
  6671. } else {
  6672. var normal = face.normal;
  6673. this.normals.push(normal, normal, normal);
  6674. }
  6675. var vertexColors = face.vertexColors;
  6676. if (vertexColors.length === 3) {
  6677. this.colors.push(vertexColors[0], vertexColors[1], vertexColors[2]);
  6678. } else {
  6679. var color = face.color;
  6680. this.colors.push(color, color, color);
  6681. }
  6682. if (hasFaceVertexUv === true) {
  6683. var vertexUvs = faceVertexUvs[0][i];
  6684. if (vertexUvs !== undefined) {
  6685. this.uvs.push(vertexUvs[0], vertexUvs[1], vertexUvs[2]);
  6686. } else {
  6687. console.warn('THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i);
  6688. this.uvs.push(new Vector2(), new Vector2(), new Vector2());
  6689. }
  6690. }
  6691. if (hasFaceVertexUv2 === true) {
  6692. var vertexUvs = faceVertexUvs[1][i];
  6693. if (vertexUvs !== undefined) {
  6694. this.uvs2.push(vertexUvs[0], vertexUvs[1], vertexUvs[2]);
  6695. } else {
  6696. console.warn('THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i);
  6697. this.uvs2.push(new Vector2(), new Vector2(), new Vector2());
  6698. }
  6699. }
  6700. // morphs
  6701. for (var j = 0; j < morphTargetsLength; j++) {
  6702. var morphTarget = morphTargets[j].vertices;
  6703. morphTargetsPosition[j].push(morphTarget[face.a], morphTarget[face.b], morphTarget[face.c]);
  6704. }
  6705. for (var j = 0; j < morphNormalsLength; j++) {
  6706. var morphNormal = morphNormals[j].vertexNormals[i];
  6707. morphTargetsNormal[j].push(morphNormal.a, morphNormal.b, morphNormal.c);
  6708. }
  6709. // skins
  6710. if (hasSkinIndices) {
  6711. this.skinIndices.push(skinIndices[face.a], skinIndices[face.b], skinIndices[face.c]);
  6712. }
  6713. if (hasSkinWeights) {
  6714. this.skinWeights.push(skinWeights[face.a], skinWeights[face.b], skinWeights[face.c]);
  6715. }
  6716. }
  6717. this.computeGroups(geometry);
  6718. this.verticesNeedUpdate = geometry.verticesNeedUpdate;
  6719. this.normalsNeedUpdate = geometry.normalsNeedUpdate;
  6720. this.colorsNeedUpdate = geometry.colorsNeedUpdate;
  6721. this.uvsNeedUpdate = geometry.uvsNeedUpdate;
  6722. this.groupsNeedUpdate = geometry.groupsNeedUpdate;
  6723. return this;
  6724. }
  6725. });
  6726. /**
  6727. * @author mrdoob / http://mrdoob.com/
  6728. */
  6729. function arrayMax(array) {
  6730. if (array.length === 0) return -Infinity;
  6731. var max = array[0];
  6732. for (var i = 1, l = array.length; i < l; ++i) {
  6733. if (array[i] > max) max = array[i];
  6734. }
  6735. return max;
  6736. }
  6737. /**
  6738. * @author alteredq / http://alteredqualia.com/
  6739. * @author mrdoob / http://mrdoob.com/
  6740. */
  6741. var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
  6742. function BufferGeometry() {
  6743. Object.defineProperty(this, 'id', { value: bufferGeometryId += 2 });
  6744. this.uuid = _Math.generateUUID();
  6745. this.name = '';
  6746. this.type = 'BufferGeometry';
  6747. this.index = null;
  6748. this.attributes = {};
  6749. this.morphAttributes = {};
  6750. this.groups = [];
  6751. this.boundingBox = null;
  6752. this.boundingSphere = null;
  6753. this.drawRange = { start: 0, count: Infinity };
  6754. this.userData = {};
  6755. }
  6756. BufferGeometry.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  6757. constructor: BufferGeometry,
  6758. isBufferGeometry: true,
  6759. getIndex: function () {
  6760. return this.index;
  6761. },
  6762. setIndex: function (index) {
  6763. if (Array.isArray(index)) {
  6764. this.index = new (arrayMax(index) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute)(index, 1);
  6765. } else {
  6766. this.index = index;
  6767. }
  6768. },
  6769. addAttribute: function (name, attribute) {
  6770. if (!(attribute && attribute.isBufferAttribute) && !(attribute && attribute.isInterleavedBufferAttribute)) {
  6771. console.warn('THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).');
  6772. return this.addAttribute(name, new BufferAttribute(arguments[1], arguments[2]));
  6773. }
  6774. if (name === 'index') {
  6775. console.warn('THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.');
  6776. this.setIndex(attribute);
  6777. return this;
  6778. }
  6779. this.attributes[name] = attribute;
  6780. return this;
  6781. },
  6782. getAttribute: function (name) {
  6783. return this.attributes[name];
  6784. },
  6785. removeAttribute: function (name) {
  6786. delete this.attributes[name];
  6787. return this;
  6788. },
  6789. addGroup: function (start, count, materialIndex) {
  6790. this.groups.push({
  6791. start: start,
  6792. count: count,
  6793. materialIndex: materialIndex !== undefined ? materialIndex : 0
  6794. });
  6795. },
  6796. clearGroups: function () {
  6797. this.groups = [];
  6798. },
  6799. setDrawRange: function (start, count) {
  6800. this.drawRange.start = start;
  6801. this.drawRange.count = count;
  6802. },
  6803. applyMatrix: function (matrix) {
  6804. var position = this.attributes.position;
  6805. if (position !== undefined) {
  6806. matrix.applyToBufferAttribute(position);
  6807. position.needsUpdate = true;
  6808. }
  6809. var normal = this.attributes.normal;
  6810. if (normal !== undefined) {
  6811. var normalMatrix = new Matrix3().getNormalMatrix(matrix);
  6812. normalMatrix.applyToBufferAttribute(normal);
  6813. normal.needsUpdate = true;
  6814. }
  6815. if (this.boundingBox !== null) {
  6816. this.computeBoundingBox();
  6817. }
  6818. if (this.boundingSphere !== null) {
  6819. this.computeBoundingSphere();
  6820. }
  6821. return this;
  6822. },
  6823. rotateX: function () {
  6824. // rotate geometry around world x-axis
  6825. var m1 = new Matrix4();
  6826. return function rotateX(angle) {
  6827. m1.makeRotationX(angle);
  6828. this.applyMatrix(m1);
  6829. return this;
  6830. };
  6831. }(),
  6832. rotateY: function () {
  6833. // rotate geometry around world y-axis
  6834. var m1 = new Matrix4();
  6835. return function rotateY(angle) {
  6836. m1.makeRotationY(angle);
  6837. this.applyMatrix(m1);
  6838. return this;
  6839. };
  6840. }(),
  6841. rotateZ: function () {
  6842. // rotate geometry around world z-axis
  6843. var m1 = new Matrix4();
  6844. return function rotateZ(angle) {
  6845. m1.makeRotationZ(angle);
  6846. this.applyMatrix(m1);
  6847. return this;
  6848. };
  6849. }(),
  6850. translate: function () {
  6851. // translate geometry
  6852. var m1 = new Matrix4();
  6853. return function translate(x, y, z) {
  6854. m1.makeTranslation(x, y, z);
  6855. this.applyMatrix(m1);
  6856. return this;
  6857. };
  6858. }(),
  6859. scale: function () {
  6860. // scale geometry
  6861. var m1 = new Matrix4();
  6862. return function scale(x, y, z) {
  6863. m1.makeScale(x, y, z);
  6864. this.applyMatrix(m1);
  6865. return this;
  6866. };
  6867. }(),
  6868. lookAt: function () {
  6869. var obj = new Object3D();
  6870. return function lookAt(vector) {
  6871. obj.lookAt(vector);
  6872. obj.updateMatrix();
  6873. this.applyMatrix(obj.matrix);
  6874. };
  6875. }(),
  6876. center: function () {
  6877. var offset = new Vector3();
  6878. return function center() {
  6879. this.computeBoundingBox();
  6880. this.boundingBox.getCenter(offset).negate();
  6881. this.translate(offset.x, offset.y, offset.z);
  6882. return this;
  6883. };
  6884. }(),
  6885. setFromObject: function (object) {
  6886. // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
  6887. var geometry = object.geometry;
  6888. if (object.isPoints || object.isLine) {
  6889. var positions = new Float32BufferAttribute(geometry.vertices.length * 3, 3);
  6890. var colors = new Float32BufferAttribute(geometry.colors.length * 3, 3);
  6891. this.addAttribute('position', positions.copyVector3sArray(geometry.vertices));
  6892. this.addAttribute('color', colors.copyColorsArray(geometry.colors));
  6893. if (geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length) {
  6894. var lineDistances = new Float32BufferAttribute(geometry.lineDistances.length, 1);
  6895. this.addAttribute('lineDistance', lineDistances.copyArray(geometry.lineDistances));
  6896. }
  6897. if (geometry.boundingSphere !== null) {
  6898. this.boundingSphere = geometry.boundingSphere.clone();
  6899. }
  6900. if (geometry.boundingBox !== null) {
  6901. this.boundingBox = geometry.boundingBox.clone();
  6902. }
  6903. } else if (object.isMesh) {
  6904. if (geometry && geometry.isGeometry) {
  6905. this.fromGeometry(geometry);
  6906. }
  6907. }
  6908. return this;
  6909. },
  6910. setFromPoints: function (points) {
  6911. var position = [];
  6912. for (var i = 0, l = points.length; i < l; i++) {
  6913. var point = points[i];
  6914. position.push(point.x, point.y, point.z || 0);
  6915. }
  6916. this.addAttribute('position', new Float32BufferAttribute(position, 3));
  6917. return this;
  6918. },
  6919. updateFromObject: function (object) {
  6920. var geometry = object.geometry;
  6921. if (object.isMesh) {
  6922. var direct = geometry.__directGeometry;
  6923. if (geometry.elementsNeedUpdate === true) {
  6924. direct = undefined;
  6925. geometry.elementsNeedUpdate = false;
  6926. }
  6927. if (direct === undefined) {
  6928. return this.fromGeometry(geometry);
  6929. }
  6930. direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
  6931. direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
  6932. direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
  6933. direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
  6934. direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
  6935. geometry.verticesNeedUpdate = false;
  6936. geometry.normalsNeedUpdate = false;
  6937. geometry.colorsNeedUpdate = false;
  6938. geometry.uvsNeedUpdate = false;
  6939. geometry.groupsNeedUpdate = false;
  6940. geometry = direct;
  6941. }
  6942. var attribute;
  6943. if (geometry.verticesNeedUpdate === true) {
  6944. attribute = this.attributes.position;
  6945. if (attribute !== undefined) {
  6946. attribute.copyVector3sArray(geometry.vertices);
  6947. attribute.needsUpdate = true;
  6948. }
  6949. geometry.verticesNeedUpdate = false;
  6950. }
  6951. if (geometry.normalsNeedUpdate === true) {
  6952. attribute = this.attributes.normal;
  6953. if (attribute !== undefined) {
  6954. attribute.copyVector3sArray(geometry.normals);
  6955. attribute.needsUpdate = true;
  6956. }
  6957. geometry.normalsNeedUpdate = false;
  6958. }
  6959. if (geometry.colorsNeedUpdate === true) {
  6960. attribute = this.attributes.color;
  6961. if (attribute !== undefined) {
  6962. attribute.copyColorsArray(geometry.colors);
  6963. attribute.needsUpdate = true;
  6964. }
  6965. geometry.colorsNeedUpdate = false;
  6966. }
  6967. if (geometry.uvsNeedUpdate) {
  6968. attribute = this.attributes.uv;
  6969. if (attribute !== undefined) {
  6970. attribute.copyVector2sArray(geometry.uvs);
  6971. attribute.needsUpdate = true;
  6972. }
  6973. geometry.uvsNeedUpdate = false;
  6974. }
  6975. if (geometry.lineDistancesNeedUpdate) {
  6976. attribute = this.attributes.lineDistance;
  6977. if (attribute !== undefined) {
  6978. attribute.copyArray(geometry.lineDistances);
  6979. attribute.needsUpdate = true;
  6980. }
  6981. geometry.lineDistancesNeedUpdate = false;
  6982. }
  6983. if (geometry.groupsNeedUpdate) {
  6984. geometry.computeGroups(object.geometry);
  6985. this.groups = geometry.groups;
  6986. geometry.groupsNeedUpdate = false;
  6987. }
  6988. return this;
  6989. },
  6990. fromGeometry: function (geometry) {
  6991. geometry.__directGeometry = new DirectGeometry().fromGeometry(geometry);
  6992. return this.fromDirectGeometry(geometry.__directGeometry);
  6993. },
  6994. fromDirectGeometry: function (geometry) {
  6995. var positions = new Float32Array(geometry.vertices.length * 3);
  6996. this.addAttribute('position', new BufferAttribute(positions, 3).copyVector3sArray(geometry.vertices));
  6997. if (geometry.normals.length > 0) {
  6998. var normals = new Float32Array(geometry.normals.length * 3);
  6999. this.addAttribute('normal', new BufferAttribute(normals, 3).copyVector3sArray(geometry.normals));
  7000. }
  7001. if (geometry.colors.length > 0) {
  7002. var colors = new Float32Array(geometry.colors.length * 3);
  7003. this.addAttribute('color', new BufferAttribute(colors, 3).copyColorsArray(geometry.colors));
  7004. }
  7005. if (geometry.uvs.length > 0) {
  7006. var uvs = new Float32Array(geometry.uvs.length * 2);
  7007. this.addAttribute('uv', new BufferAttribute(uvs, 2).copyVector2sArray(geometry.uvs));
  7008. }
  7009. if (geometry.uvs2.length > 0) {
  7010. var uvs2 = new Float32Array(geometry.uvs2.length * 2);
  7011. this.addAttribute('uv2', new BufferAttribute(uvs2, 2).copyVector2sArray(geometry.uvs2));
  7012. }
  7013. // groups
  7014. this.groups = geometry.groups;
  7015. // morphs
  7016. for (var name in geometry.morphTargets) {
  7017. var array = [];
  7018. var morphTargets = geometry.morphTargets[name];
  7019. for (var i = 0, l = morphTargets.length; i < l; i++) {
  7020. var morphTarget = morphTargets[i];
  7021. var attribute = new Float32BufferAttribute(morphTarget.length * 3, 3);
  7022. array.push(attribute.copyVector3sArray(morphTarget));
  7023. }
  7024. this.morphAttributes[name] = array;
  7025. }
  7026. // skinning
  7027. if (geometry.skinIndices.length > 0) {
  7028. var skinIndices = new Float32BufferAttribute(geometry.skinIndices.length * 4, 4);
  7029. this.addAttribute('skinIndex', skinIndices.copyVector4sArray(geometry.skinIndices));
  7030. }
  7031. if (geometry.skinWeights.length > 0) {
  7032. var skinWeights = new Float32BufferAttribute(geometry.skinWeights.length * 4, 4);
  7033. this.addAttribute('skinWeight', skinWeights.copyVector4sArray(geometry.skinWeights));
  7034. }
  7035. //
  7036. if (geometry.boundingSphere !== null) {
  7037. this.boundingSphere = geometry.boundingSphere.clone();
  7038. }
  7039. if (geometry.boundingBox !== null) {
  7040. this.boundingBox = geometry.boundingBox.clone();
  7041. }
  7042. return this;
  7043. },
  7044. computeBoundingBox: function () {
  7045. if (this.boundingBox === null) {
  7046. this.boundingBox = new Box3();
  7047. }
  7048. var position = this.attributes.position;
  7049. if (position !== undefined) {
  7050. this.boundingBox.setFromBufferAttribute(position);
  7051. } else {
  7052. this.boundingBox.makeEmpty();
  7053. }
  7054. if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) {
  7055. console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this);
  7056. }
  7057. },
  7058. computeBoundingSphere: function () {
  7059. var box = new Box3();
  7060. var vector = new Vector3();
  7061. return function computeBoundingSphere() {
  7062. if (this.boundingSphere === null) {
  7063. this.boundingSphere = new Sphere();
  7064. }
  7065. var position = this.attributes.position;
  7066. if (position) {
  7067. var center = this.boundingSphere.center;
  7068. box.setFromBufferAttribute(position);
  7069. box.getCenter(center);
  7070. // hoping to find a boundingSphere with a radius smaller than the
  7071. // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
  7072. var maxRadiusSq = 0;
  7073. for (var i = 0, il = position.count; i < il; i++) {
  7074. vector.x = position.getX(i);
  7075. vector.y = position.getY(i);
  7076. vector.z = position.getZ(i);
  7077. maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector));
  7078. }
  7079. this.boundingSphere.radius = Math.sqrt(maxRadiusSq);
  7080. if (isNaN(this.boundingSphere.radius)) {
  7081. console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this);
  7082. }
  7083. }
  7084. };
  7085. }(),
  7086. computeFaceNormals: function () {
  7087. // backwards compatibility
  7088. },
  7089. computeVertexNormals: function () {
  7090. var index = this.index;
  7091. var attributes = this.attributes;
  7092. var groups = this.groups;
  7093. if (attributes.position) {
  7094. var positions = attributes.position.array;
  7095. if (attributes.normal === undefined) {
  7096. this.addAttribute('normal', new BufferAttribute(new Float32Array(positions.length), 3));
  7097. } else {
  7098. // reset existing normals to zero
  7099. var array = attributes.normal.array;
  7100. for (var i = 0, il = array.length; i < il; i++) {
  7101. array[i] = 0;
  7102. }
  7103. }
  7104. var normals = attributes.normal.array;
  7105. var vA, vB, vC;
  7106. var pA = new Vector3(),
  7107. pB = new Vector3(),
  7108. pC = new Vector3();
  7109. var cb = new Vector3(),
  7110. ab = new Vector3();
  7111. // indexed elements
  7112. if (index) {
  7113. var indices = index.array;
  7114. if (groups.length === 0) {
  7115. this.addGroup(0, indices.length);
  7116. }
  7117. for (var j = 0, jl = groups.length; j < jl; ++j) {
  7118. var group = groups[j];
  7119. var start = group.start;
  7120. var count = group.count;
  7121. for (var i = start, il = start + count; i < il; i += 3) {
  7122. vA = indices[i + 0] * 3;
  7123. vB = indices[i + 1] * 3;
  7124. vC = indices[i + 2] * 3;
  7125. pA.fromArray(positions, vA);
  7126. pB.fromArray(positions, vB);
  7127. pC.fromArray(positions, vC);
  7128. cb.subVectors(pC, pB);
  7129. ab.subVectors(pA, pB);
  7130. cb.cross(ab);
  7131. normals[vA] += cb.x;
  7132. normals[vA + 1] += cb.y;
  7133. normals[vA + 2] += cb.z;
  7134. normals[vB] += cb.x;
  7135. normals[vB + 1] += cb.y;
  7136. normals[vB + 2] += cb.z;
  7137. normals[vC] += cb.x;
  7138. normals[vC + 1] += cb.y;
  7139. normals[vC + 2] += cb.z;
  7140. }
  7141. }
  7142. } else {
  7143. // non-indexed elements (unconnected triangle soup)
  7144. for (var i = 0, il = positions.length; i < il; i += 9) {
  7145. pA.fromArray(positions, i);
  7146. pB.fromArray(positions, i + 3);
  7147. pC.fromArray(positions, i + 6);
  7148. cb.subVectors(pC, pB);
  7149. ab.subVectors(pA, pB);
  7150. cb.cross(ab);
  7151. normals[i] = cb.x;
  7152. normals[i + 1] = cb.y;
  7153. normals[i + 2] = cb.z;
  7154. normals[i + 3] = cb.x;
  7155. normals[i + 4] = cb.y;
  7156. normals[i + 5] = cb.z;
  7157. normals[i + 6] = cb.x;
  7158. normals[i + 7] = cb.y;
  7159. normals[i + 8] = cb.z;
  7160. }
  7161. }
  7162. this.normalizeNormals();
  7163. attributes.normal.needsUpdate = true;
  7164. }
  7165. },
  7166. merge: function (geometry, offset) {
  7167. if (!(geometry && geometry.isBufferGeometry)) {
  7168. console.error('THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry);
  7169. return;
  7170. }
  7171. if (offset === undefined) {
  7172. offset = 0;
  7173. console.warn('THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.');
  7174. }
  7175. var attributes = this.attributes;
  7176. for (var key in attributes) {
  7177. if (geometry.attributes[key] === undefined) continue;
  7178. var attribute1 = attributes[key];
  7179. var attributeArray1 = attribute1.array;
  7180. var attribute2 = geometry.attributes[key];
  7181. var attributeArray2 = attribute2.array;
  7182. var attributeSize = attribute2.itemSize;
  7183. for (var i = 0, j = attributeSize * offset; i < attributeArray2.length; i++, j++) {
  7184. attributeArray1[j] = attributeArray2[i];
  7185. }
  7186. }
  7187. return this;
  7188. },
  7189. normalizeNormals: function () {
  7190. var vector = new Vector3();
  7191. return function normalizeNormals() {
  7192. var normals = this.attributes.normal;
  7193. for (var i = 0, il = normals.count; i < il; i++) {
  7194. vector.x = normals.getX(i);
  7195. vector.y = normals.getY(i);
  7196. vector.z = normals.getZ(i);
  7197. vector.normalize();
  7198. normals.setXYZ(i, vector.x, vector.y, vector.z);
  7199. }
  7200. };
  7201. }(),
  7202. toNonIndexed: function () {
  7203. if (this.index === null) {
  7204. console.warn('THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.');
  7205. return this;
  7206. }
  7207. var geometry2 = new BufferGeometry();
  7208. var indices = this.index.array;
  7209. var attributes = this.attributes;
  7210. for (var name in attributes) {
  7211. var attribute = attributes[name];
  7212. var array = attribute.array;
  7213. var itemSize = attribute.itemSize;
  7214. var array2 = new array.constructor(indices.length * itemSize);
  7215. var index = 0,
  7216. index2 = 0;
  7217. for (var i = 0, l = indices.length; i < l; i++) {
  7218. index = indices[i] * itemSize;
  7219. for (var j = 0; j < itemSize; j++) {
  7220. array2[index2++] = array[index++];
  7221. }
  7222. }
  7223. geometry2.addAttribute(name, new BufferAttribute(array2, itemSize));
  7224. }
  7225. var groups = this.groups;
  7226. for (var i = 0, l = groups.length; i < l; i++) {
  7227. var group = groups[i];
  7228. geometry2.addGroup(group.start, group.count, group.materialIndex);
  7229. }
  7230. return geometry2;
  7231. },
  7232. toJSON: function () {
  7233. var data = {
  7234. metadata: {
  7235. version: 4.5,
  7236. type: 'BufferGeometry',
  7237. generator: 'BufferGeometry.toJSON'
  7238. }
  7239. };
  7240. // standard BufferGeometry serialization
  7241. data.uuid = this.uuid;
  7242. data.type = this.type;
  7243. if (this.name !== '') data.name = this.name;
  7244. if (Object.keys(this.userData).length > 0) data.userData = this.userData;
  7245. if (this.parameters !== undefined) {
  7246. var parameters = this.parameters;
  7247. for (var key in parameters) {
  7248. if (parameters[key] !== undefined) data[key] = parameters[key];
  7249. }
  7250. return data;
  7251. }
  7252. data.data = { attributes: {} };
  7253. var index = this.index;
  7254. if (index !== null) {
  7255. var array = Array.prototype.slice.call(index.array);
  7256. data.data.index = {
  7257. type: index.array.constructor.name,
  7258. array: array
  7259. };
  7260. }
  7261. var attributes = this.attributes;
  7262. for (var key in attributes) {
  7263. var attribute = attributes[key];
  7264. var array = Array.prototype.slice.call(attribute.array);
  7265. data.data.attributes[key] = {
  7266. itemSize: attribute.itemSize,
  7267. type: attribute.array.constructor.name,
  7268. array: array,
  7269. normalized: attribute.normalized
  7270. };
  7271. }
  7272. var groups = this.groups;
  7273. if (groups.length > 0) {
  7274. data.data.groups = JSON.parse(JSON.stringify(groups));
  7275. }
  7276. var boundingSphere = this.boundingSphere;
  7277. if (boundingSphere !== null) {
  7278. data.data.boundingSphere = {
  7279. center: boundingSphere.center.toArray(),
  7280. radius: boundingSphere.radius
  7281. };
  7282. }
  7283. return data;
  7284. },
  7285. clone: function () {
  7286. /*
  7287. // Handle primitives
  7288. var parameters = this.parameters;
  7289. if ( parameters !== undefined ) {
  7290. var values = [];
  7291. for ( var key in parameters ) {
  7292. values.push( parameters[ key ] );
  7293. }
  7294. var geometry = Object.create( this.constructor.prototype );
  7295. this.constructor.apply( geometry, values );
  7296. return geometry;
  7297. }
  7298. return new this.constructor().copy( this );
  7299. */
  7300. return new BufferGeometry().copy(this);
  7301. },
  7302. copy: function (source) {
  7303. var name, i, l;
  7304. // reset
  7305. this.index = null;
  7306. this.attributes = {};
  7307. this.morphAttributes = {};
  7308. this.groups = [];
  7309. this.boundingBox = null;
  7310. this.boundingSphere = null;
  7311. // name
  7312. this.name = source.name;
  7313. // index
  7314. var index = source.index;
  7315. if (index !== null) {
  7316. this.setIndex(index.clone());
  7317. }
  7318. // attributes
  7319. var attributes = source.attributes;
  7320. for (name in attributes) {
  7321. var attribute = attributes[name];
  7322. this.addAttribute(name, attribute.clone());
  7323. }
  7324. // morph attributes
  7325. var morphAttributes = source.morphAttributes;
  7326. for (name in morphAttributes) {
  7327. var array = [];
  7328. var morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes
  7329. for (i = 0, l = morphAttribute.length; i < l; i++) {
  7330. array.push(morphAttribute[i].clone());
  7331. }
  7332. this.morphAttributes[name] = array;
  7333. }
  7334. // groups
  7335. var groups = source.groups;
  7336. for (i = 0, l = groups.length; i < l; i++) {
  7337. var group = groups[i];
  7338. this.addGroup(group.start, group.count, group.materialIndex);
  7339. }
  7340. // bounding box
  7341. var boundingBox = source.boundingBox;
  7342. if (boundingBox !== null) {
  7343. this.boundingBox = boundingBox.clone();
  7344. }
  7345. // bounding sphere
  7346. var boundingSphere = source.boundingSphere;
  7347. if (boundingSphere !== null) {
  7348. this.boundingSphere = boundingSphere.clone();
  7349. }
  7350. // draw range
  7351. this.drawRange.start = source.drawRange.start;
  7352. this.drawRange.count = source.drawRange.count;
  7353. // user data
  7354. this.userData = source.userData;
  7355. return this;
  7356. },
  7357. dispose: function () {
  7358. this.dispatchEvent({ type: 'dispose' });
  7359. }
  7360. });
  7361. /**
  7362. * @author mrdoob / http://mrdoob.com/
  7363. * @author Mugen87 / https://github.com/Mugen87
  7364. */
  7365. // BoxGeometry
  7366. function BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) {
  7367. Geometry.call(this);
  7368. this.type = 'BoxGeometry';
  7369. this.parameters = {
  7370. width: width,
  7371. height: height,
  7372. depth: depth,
  7373. widthSegments: widthSegments,
  7374. heightSegments: heightSegments,
  7375. depthSegments: depthSegments
  7376. };
  7377. this.fromBufferGeometry(new BoxBufferGeometry(width, height, depth, widthSegments, heightSegments, depthSegments));
  7378. this.mergeVertices();
  7379. }
  7380. BoxGeometry.prototype = Object.create(Geometry.prototype);
  7381. BoxGeometry.prototype.constructor = BoxGeometry;
  7382. // BoxBufferGeometry
  7383. function BoxBufferGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) {
  7384. BufferGeometry.call(this);
  7385. this.type = 'BoxBufferGeometry';
  7386. this.parameters = {
  7387. width: width,
  7388. height: height,
  7389. depth: depth,
  7390. widthSegments: widthSegments,
  7391. heightSegments: heightSegments,
  7392. depthSegments: depthSegments
  7393. };
  7394. var scope = this;
  7395. width = width || 1;
  7396. height = height || 1;
  7397. depth = depth || 1;
  7398. // segments
  7399. widthSegments = Math.floor(widthSegments) || 1;
  7400. heightSegments = Math.floor(heightSegments) || 1;
  7401. depthSegments = Math.floor(depthSegments) || 1;
  7402. // buffers
  7403. var indices = [];
  7404. var vertices = [];
  7405. var normals = [];
  7406. var uvs = [];
  7407. // helper variables
  7408. var numberOfVertices = 0;
  7409. var groupStart = 0;
  7410. // build each side of the box geometry
  7411. buildPlane('z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0); // px
  7412. buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1); // nx
  7413. buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2); // py
  7414. buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3); // ny
  7415. buildPlane('x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4); // pz
  7416. buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5); // nz
  7417. // build geometry
  7418. this.setIndex(indices);
  7419. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  7420. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  7421. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  7422. function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex) {
  7423. var segmentWidth = width / gridX;
  7424. var segmentHeight = height / gridY;
  7425. var widthHalf = width / 2;
  7426. var heightHalf = height / 2;
  7427. var depthHalf = depth / 2;
  7428. var gridX1 = gridX + 1;
  7429. var gridY1 = gridY + 1;
  7430. var vertexCounter = 0;
  7431. var groupCount = 0;
  7432. var ix, iy;
  7433. var vector = new Vector3();
  7434. // generate vertices, normals and uvs
  7435. for (iy = 0; iy < gridY1; iy++) {
  7436. var y = iy * segmentHeight - heightHalf;
  7437. for (ix = 0; ix < gridX1; ix++) {
  7438. var x = ix * segmentWidth - widthHalf;
  7439. // set values to correct vector component
  7440. vector[u] = x * udir;
  7441. vector[v] = y * vdir;
  7442. vector[w] = depthHalf;
  7443. // now apply vector to vertex buffer
  7444. vertices.push(vector.x, vector.y, vector.z);
  7445. // set values to correct vector component
  7446. vector[u] = 0;
  7447. vector[v] = 0;
  7448. vector[w] = depth > 0 ? 1 : -1;
  7449. // now apply vector to normal buffer
  7450. normals.push(vector.x, vector.y, vector.z);
  7451. // uvs
  7452. uvs.push(ix / gridX);
  7453. uvs.push(1 - iy / gridY);
  7454. // counters
  7455. vertexCounter += 1;
  7456. }
  7457. }
  7458. // indices
  7459. // 1. you need three indices to draw a single face
  7460. // 2. a single segment consists of two faces
  7461. // 3. so we need to generate six (2*3) indices per segment
  7462. for (iy = 0; iy < gridY; iy++) {
  7463. for (ix = 0; ix < gridX; ix++) {
  7464. var a = numberOfVertices + ix + gridX1 * iy;
  7465. var b = numberOfVertices + ix + gridX1 * (iy + 1);
  7466. var c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1);
  7467. var d = numberOfVertices + (ix + 1) + gridX1 * iy;
  7468. // faces
  7469. indices.push(a, b, d);
  7470. indices.push(b, c, d);
  7471. // increase counter
  7472. groupCount += 6;
  7473. }
  7474. }
  7475. // add a group to the geometry. this will ensure multi material support
  7476. scope.addGroup(groupStart, groupCount, materialIndex);
  7477. // calculate new start value for groups
  7478. groupStart += groupCount;
  7479. // update total number of vertices
  7480. numberOfVertices += vertexCounter;
  7481. }
  7482. }
  7483. BoxBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  7484. BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
  7485. /**
  7486. * @author mrdoob / http://mrdoob.com/
  7487. * @author Mugen87 / https://github.com/Mugen87
  7488. */
  7489. // PlaneGeometry
  7490. function PlaneGeometry(width, height, widthSegments, heightSegments) {
  7491. Geometry.call(this);
  7492. this.type = 'PlaneGeometry';
  7493. this.parameters = {
  7494. width: width,
  7495. height: height,
  7496. widthSegments: widthSegments,
  7497. heightSegments: heightSegments
  7498. };
  7499. this.fromBufferGeometry(new PlaneBufferGeometry(width, height, widthSegments, heightSegments));
  7500. this.mergeVertices();
  7501. }
  7502. PlaneGeometry.prototype = Object.create(Geometry.prototype);
  7503. PlaneGeometry.prototype.constructor = PlaneGeometry;
  7504. // PlaneBufferGeometry
  7505. function PlaneBufferGeometry(width, height, widthSegments, heightSegments) {
  7506. BufferGeometry.call(this);
  7507. this.type = 'PlaneBufferGeometry';
  7508. this.parameters = {
  7509. width: width,
  7510. height: height,
  7511. widthSegments: widthSegments,
  7512. heightSegments: heightSegments
  7513. };
  7514. width = width || 1;
  7515. height = height || 1;
  7516. var width_half = width / 2;
  7517. var height_half = height / 2;
  7518. var gridX = Math.floor(widthSegments) || 1;
  7519. var gridY = Math.floor(heightSegments) || 1;
  7520. var gridX1 = gridX + 1;
  7521. var gridY1 = gridY + 1;
  7522. var segment_width = width / gridX;
  7523. var segment_height = height / gridY;
  7524. var ix, iy;
  7525. // buffers
  7526. var indices = [];
  7527. var vertices = [];
  7528. var normals = [];
  7529. var uvs = [];
  7530. // generate vertices, normals and uvs
  7531. for (iy = 0; iy < gridY1; iy++) {
  7532. var y = iy * segment_height - height_half;
  7533. for (ix = 0; ix < gridX1; ix++) {
  7534. var x = ix * segment_width - width_half;
  7535. vertices.push(x, -y, 0);
  7536. normals.push(0, 0, 1);
  7537. uvs.push(ix / gridX);
  7538. uvs.push(1 - iy / gridY);
  7539. }
  7540. }
  7541. // indices
  7542. for (iy = 0; iy < gridY; iy++) {
  7543. for (ix = 0; ix < gridX; ix++) {
  7544. var a = ix + gridX1 * iy;
  7545. var b = ix + gridX1 * (iy + 1);
  7546. var c = ix + 1 + gridX1 * (iy + 1);
  7547. var d = ix + 1 + gridX1 * iy;
  7548. // faces
  7549. indices.push(a, b, d);
  7550. indices.push(b, c, d);
  7551. }
  7552. }
  7553. // build geometry
  7554. this.setIndex(indices);
  7555. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  7556. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  7557. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  7558. }
  7559. PlaneBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  7560. PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
  7561. /**
  7562. * @author mrdoob / http://mrdoob.com/
  7563. * @author alteredq / http://alteredqualia.com/
  7564. */
  7565. var materialId = 0;
  7566. function Material() {
  7567. Object.defineProperty(this, 'id', { value: materialId++ });
  7568. this.uuid = _Math.generateUUID();
  7569. this.name = '';
  7570. this.type = 'Material';
  7571. this.fog = true;
  7572. this.lights = true;
  7573. this.blending = NormalBlending;
  7574. this.side = FrontSide;
  7575. this.flatShading = false;
  7576. this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors
  7577. this.opacity = 1;
  7578. this.transparent = false;
  7579. this.blendSrc = SrcAlphaFactor;
  7580. this.blendDst = OneMinusSrcAlphaFactor;
  7581. this.blendEquation = AddEquation;
  7582. this.blendSrcAlpha = null;
  7583. this.blendDstAlpha = null;
  7584. this.blendEquationAlpha = null;
  7585. this.depthFunc = LessEqualDepth;
  7586. this.depthTest = true;
  7587. this.depthWrite = true;
  7588. this.clippingPlanes = null;
  7589. this.clipIntersection = false;
  7590. this.clipShadows = false;
  7591. this.shadowSide = null;
  7592. this.colorWrite = true;
  7593. this.precision = null; // override the renderer's default precision for this material
  7594. this.polygonOffset = false;
  7595. this.polygonOffsetFactor = 0;
  7596. this.polygonOffsetUnits = 0;
  7597. this.dithering = false;
  7598. this.alphaTest = 0;
  7599. this.premultipliedAlpha = false;
  7600. this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
  7601. this.visible = true;
  7602. this.userData = {};
  7603. this.needsUpdate = true;
  7604. }
  7605. Material.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  7606. constructor: Material,
  7607. isMaterial: true,
  7608. onBeforeCompile: function () {},
  7609. setValues: function (values) {
  7610. if (values === undefined) return;
  7611. for (var key in values) {
  7612. var newValue = values[key];
  7613. if (newValue === undefined) {
  7614. console.warn("THREE.Material: '" + key + "' parameter is undefined.");
  7615. continue;
  7616. }
  7617. // for backward compatability if shading is set in the constructor
  7618. if (key === 'shading') {
  7619. console.warn('THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.');
  7620. this.flatShading = newValue === FlatShading ? true : false;
  7621. continue;
  7622. }
  7623. var currentValue = this[key];
  7624. if (currentValue === undefined) {
  7625. console.warn("THREE." + this.type + ": '" + key + "' is not a property of this material.");
  7626. continue;
  7627. }
  7628. if (currentValue && currentValue.isColor) {
  7629. currentValue.set(newValue);
  7630. } else if (currentValue && currentValue.isVector3 && newValue && newValue.isVector3) {
  7631. currentValue.copy(newValue);
  7632. } else if (key === 'overdraw') {
  7633. // ensure overdraw is backwards-compatible with legacy boolean type
  7634. this[key] = Number(newValue);
  7635. } else {
  7636. this[key] = newValue;
  7637. }
  7638. }
  7639. },
  7640. toJSON: function (meta) {
  7641. var isRoot = meta === undefined || typeof meta === 'string';
  7642. if (isRoot) {
  7643. meta = {
  7644. textures: {},
  7645. images: {}
  7646. };
  7647. }
  7648. var data = {
  7649. metadata: {
  7650. version: 4.5,
  7651. type: 'Material',
  7652. generator: 'Material.toJSON'
  7653. }
  7654. };
  7655. // standard Material serialization
  7656. data.uuid = this.uuid;
  7657. data.type = this.type;
  7658. if (this.name !== '') data.name = this.name;
  7659. if (this.color && this.color.isColor) data.color = this.color.getHex();
  7660. if (this.roughness !== undefined) data.roughness = this.roughness;
  7661. if (this.metalness !== undefined) data.metalness = this.metalness;
  7662. if (this.emissive && this.emissive.isColor) data.emissive = this.emissive.getHex();
  7663. if (this.emissiveIntensity !== 1) data.emissiveIntensity = this.emissiveIntensity;
  7664. if (this.specular && this.specular.isColor) data.specular = this.specular.getHex();
  7665. if (this.shininess !== undefined) data.shininess = this.shininess;
  7666. if (this.clearCoat !== undefined) data.clearCoat = this.clearCoat;
  7667. if (this.clearCoatRoughness !== undefined) data.clearCoatRoughness = this.clearCoatRoughness;
  7668. if (this.map && this.map.isTexture) data.map = this.map.toJSON(meta).uuid;
  7669. if (this.alphaMap && this.alphaMap.isTexture) data.alphaMap = this.alphaMap.toJSON(meta).uuid;
  7670. if (this.lightMap && this.lightMap.isTexture) data.lightMap = this.lightMap.toJSON(meta).uuid;
  7671. if (this.aoMap && this.aoMap.isTexture) {
  7672. data.aoMap = this.aoMap.toJSON(meta).uuid;
  7673. data.aoMapIntensity = this.aoMapIntensity;
  7674. }
  7675. if (this.bumpMap && this.bumpMap.isTexture) {
  7676. data.bumpMap = this.bumpMap.toJSON(meta).uuid;
  7677. data.bumpScale = this.bumpScale;
  7678. }
  7679. if (this.normalMap && this.normalMap.isTexture) {
  7680. data.normalMap = this.normalMap.toJSON(meta).uuid;
  7681. data.normalScale = this.normalScale.toArray();
  7682. }
  7683. if (this.displacementMap && this.displacementMap.isTexture) {
  7684. data.displacementMap = this.displacementMap.toJSON(meta).uuid;
  7685. data.displacementScale = this.displacementScale;
  7686. data.displacementBias = this.displacementBias;
  7687. }
  7688. if (this.roughnessMap && this.roughnessMap.isTexture) data.roughnessMap = this.roughnessMap.toJSON(meta).uuid;
  7689. if (this.metalnessMap && this.metalnessMap.isTexture) data.metalnessMap = this.metalnessMap.toJSON(meta).uuid;
  7690. if (this.emissiveMap && this.emissiveMap.isTexture) data.emissiveMap = this.emissiveMap.toJSON(meta).uuid;
  7691. if (this.specularMap && this.specularMap.isTexture) data.specularMap = this.specularMap.toJSON(meta).uuid;
  7692. if (this.envMap && this.envMap.isTexture) {
  7693. data.envMap = this.envMap.toJSON(meta).uuid;
  7694. data.reflectivity = this.reflectivity; // Scale behind envMap
  7695. }
  7696. if (this.gradientMap && this.gradientMap.isTexture) {
  7697. data.gradientMap = this.gradientMap.toJSON(meta).uuid;
  7698. }
  7699. if (this.size !== undefined) data.size = this.size;
  7700. if (this.sizeAttenuation !== undefined) data.sizeAttenuation = this.sizeAttenuation;
  7701. if (this.blending !== NormalBlending) data.blending = this.blending;
  7702. if (this.flatShading === true) data.flatShading = this.flatShading;
  7703. if (this.side !== FrontSide) data.side = this.side;
  7704. if (this.vertexColors !== NoColors) data.vertexColors = this.vertexColors;
  7705. if (this.opacity < 1) data.opacity = this.opacity;
  7706. if (this.transparent === true) data.transparent = this.transparent;
  7707. data.depthFunc = this.depthFunc;
  7708. data.depthTest = this.depthTest;
  7709. data.depthWrite = this.depthWrite;
  7710. // rotation (SpriteMaterial)
  7711. if (this.rotation !== 0) data.rotation = this.rotation;
  7712. if (this.linewidth !== 1) data.linewidth = this.linewidth;
  7713. if (this.dashSize !== undefined) data.dashSize = this.dashSize;
  7714. if (this.gapSize !== undefined) data.gapSize = this.gapSize;
  7715. if (this.scale !== undefined) data.scale = this.scale;
  7716. if (this.dithering === true) data.dithering = true;
  7717. if (this.alphaTest > 0) data.alphaTest = this.alphaTest;
  7718. if (this.premultipliedAlpha === true) data.premultipliedAlpha = this.premultipliedAlpha;
  7719. if (this.wireframe === true) data.wireframe = this.wireframe;
  7720. if (this.wireframeLinewidth > 1) data.wireframeLinewidth = this.wireframeLinewidth;
  7721. if (this.wireframeLinecap !== 'round') data.wireframeLinecap = this.wireframeLinecap;
  7722. if (this.wireframeLinejoin !== 'round') data.wireframeLinejoin = this.wireframeLinejoin;
  7723. if (this.morphTargets === true) data.morphTargets = true;
  7724. if (this.skinning === true) data.skinning = true;
  7725. if (this.visible === false) data.visible = false;
  7726. if (JSON.stringify(this.userData) !== '{}') data.userData = this.userData;
  7727. // TODO: Copied from Object3D.toJSON
  7728. function extractFromCache(cache) {
  7729. var values = [];
  7730. for (var key in cache) {
  7731. var data = cache[key];
  7732. delete data.metadata;
  7733. values.push(data);
  7734. }
  7735. return values;
  7736. }
  7737. if (isRoot) {
  7738. var textures = extractFromCache(meta.textures);
  7739. var images = extractFromCache(meta.images);
  7740. if (textures.length > 0) data.textures = textures;
  7741. if (images.length > 0) data.images = images;
  7742. }
  7743. return data;
  7744. },
  7745. clone: function () {
  7746. return new this.constructor().copy(this);
  7747. },
  7748. copy: function (source) {
  7749. this.name = source.name;
  7750. this.fog = source.fog;
  7751. this.lights = source.lights;
  7752. this.blending = source.blending;
  7753. this.side = source.side;
  7754. this.flatShading = source.flatShading;
  7755. this.vertexColors = source.vertexColors;
  7756. this.opacity = source.opacity;
  7757. this.transparent = source.transparent;
  7758. this.blendSrc = source.blendSrc;
  7759. this.blendDst = source.blendDst;
  7760. this.blendEquation = source.blendEquation;
  7761. this.blendSrcAlpha = source.blendSrcAlpha;
  7762. this.blendDstAlpha = source.blendDstAlpha;
  7763. this.blendEquationAlpha = source.blendEquationAlpha;
  7764. this.depthFunc = source.depthFunc;
  7765. this.depthTest = source.depthTest;
  7766. this.depthWrite = source.depthWrite;
  7767. this.colorWrite = source.colorWrite;
  7768. this.precision = source.precision;
  7769. this.polygonOffset = source.polygonOffset;
  7770. this.polygonOffsetFactor = source.polygonOffsetFactor;
  7771. this.polygonOffsetUnits = source.polygonOffsetUnits;
  7772. this.dithering = source.dithering;
  7773. this.alphaTest = source.alphaTest;
  7774. this.premultipliedAlpha = source.premultipliedAlpha;
  7775. this.overdraw = source.overdraw;
  7776. this.visible = source.visible;
  7777. this.userData = JSON.parse(JSON.stringify(source.userData));
  7778. this.clipShadows = source.clipShadows;
  7779. this.clipIntersection = source.clipIntersection;
  7780. var srcPlanes = source.clippingPlanes,
  7781. dstPlanes = null;
  7782. if (srcPlanes !== null) {
  7783. var n = srcPlanes.length;
  7784. dstPlanes = new Array(n);
  7785. for (var i = 0; i !== n; ++i) dstPlanes[i] = srcPlanes[i].clone();
  7786. }
  7787. this.clippingPlanes = dstPlanes;
  7788. this.shadowSide = source.shadowSide;
  7789. return this;
  7790. },
  7791. dispose: function () {
  7792. this.dispatchEvent({ type: 'dispose' });
  7793. }
  7794. });
  7795. /**
  7796. * @author mrdoob / http://mrdoob.com/
  7797. * @author alteredq / http://alteredqualia.com/
  7798. *
  7799. * parameters = {
  7800. * color: <hex>,
  7801. * opacity: <float>,
  7802. * map: new THREE.Texture( <Image> ),
  7803. *
  7804. * lightMap: new THREE.Texture( <Image> ),
  7805. * lightMapIntensity: <float>
  7806. *
  7807. * aoMap: new THREE.Texture( <Image> ),
  7808. * aoMapIntensity: <float>
  7809. *
  7810. * specularMap: new THREE.Texture( <Image> ),
  7811. *
  7812. * alphaMap: new THREE.Texture( <Image> ),
  7813. *
  7814. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  7815. * combine: THREE.Multiply,
  7816. * reflectivity: <float>,
  7817. * refractionRatio: <float>,
  7818. *
  7819. * depthTest: <bool>,
  7820. * depthWrite: <bool>,
  7821. *
  7822. * wireframe: <boolean>,
  7823. * wireframeLinewidth: <float>,
  7824. *
  7825. * skinning: <bool>,
  7826. * morphTargets: <bool>
  7827. * }
  7828. */
  7829. function MeshBasicMaterial(parameters) {
  7830. Material.call(this);
  7831. this.type = 'MeshBasicMaterial';
  7832. this.color = new Color(0xffffff); // emissive
  7833. this.map = null;
  7834. this.lightMap = null;
  7835. this.lightMapIntensity = 1.0;
  7836. this.aoMap = null;
  7837. this.aoMapIntensity = 1.0;
  7838. this.specularMap = null;
  7839. this.alphaMap = null;
  7840. this.envMap = null;
  7841. this.combine = MultiplyOperation;
  7842. this.reflectivity = 1;
  7843. this.refractionRatio = 0.98;
  7844. this.wireframe = false;
  7845. this.wireframeLinewidth = 1;
  7846. this.wireframeLinecap = 'round';
  7847. this.wireframeLinejoin = 'round';
  7848. this.skinning = false;
  7849. this.morphTargets = false;
  7850. this.lights = false;
  7851. this.setValues(parameters);
  7852. }
  7853. MeshBasicMaterial.prototype = Object.create(Material.prototype);
  7854. MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
  7855. MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
  7856. MeshBasicMaterial.prototype.copy = function (source) {
  7857. Material.prototype.copy.call(this, source);
  7858. this.color.copy(source.color);
  7859. this.map = source.map;
  7860. this.lightMap = source.lightMap;
  7861. this.lightMapIntensity = source.lightMapIntensity;
  7862. this.aoMap = source.aoMap;
  7863. this.aoMapIntensity = source.aoMapIntensity;
  7864. this.specularMap = source.specularMap;
  7865. this.alphaMap = source.alphaMap;
  7866. this.envMap = source.envMap;
  7867. this.combine = source.combine;
  7868. this.reflectivity = source.reflectivity;
  7869. this.refractionRatio = source.refractionRatio;
  7870. this.wireframe = source.wireframe;
  7871. this.wireframeLinewidth = source.wireframeLinewidth;
  7872. this.wireframeLinecap = source.wireframeLinecap;
  7873. this.wireframeLinejoin = source.wireframeLinejoin;
  7874. this.skinning = source.skinning;
  7875. this.morphTargets = source.morphTargets;
  7876. return this;
  7877. };
  7878. /**
  7879. * @author alteredq / http://alteredqualia.com/
  7880. *
  7881. * parameters = {
  7882. * defines: { "label" : "value" },
  7883. * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
  7884. *
  7885. * fragmentShader: <string>,
  7886. * vertexShader: <string>,
  7887. *
  7888. * wireframe: <boolean>,
  7889. * wireframeLinewidth: <float>,
  7890. *
  7891. * lights: <bool>,
  7892. *
  7893. * skinning: <bool>,
  7894. * morphTargets: <bool>,
  7895. * morphNormals: <bool>
  7896. * }
  7897. */
  7898. function ShaderMaterial(parameters) {
  7899. Material.call(this);
  7900. this.type = 'ShaderMaterial';
  7901. this.defines = {};
  7902. this.uniforms = {};
  7903. this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
  7904. this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
  7905. this.linewidth = 1;
  7906. this.wireframe = false;
  7907. this.wireframeLinewidth = 1;
  7908. this.fog = false; // set to use scene fog
  7909. this.lights = false; // set to use scene lights
  7910. this.clipping = false; // set to use user-defined clipping planes
  7911. this.skinning = false; // set to use skinning attribute streams
  7912. this.morphTargets = false; // set to use morph targets
  7913. this.morphNormals = false; // set to use morph normals
  7914. this.extensions = {
  7915. derivatives: false, // set to use derivatives
  7916. fragDepth: false, // set to use fragment depth values
  7917. drawBuffers: false, // set to use draw buffers
  7918. shaderTextureLOD: false // set to use shader texture LOD
  7919. };
  7920. // When rendered geometry doesn't include these attributes but the material does,
  7921. // use these default values in WebGL. This avoids errors when buffer data is missing.
  7922. this.defaultAttributeValues = {
  7923. 'color': [1, 1, 1],
  7924. 'uv': [0, 0],
  7925. 'uv2': [0, 0]
  7926. };
  7927. this.index0AttributeName = undefined;
  7928. this.uniformsNeedUpdate = false;
  7929. if (parameters !== undefined) {
  7930. if (parameters.attributes !== undefined) {
  7931. console.error('THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.');
  7932. }
  7933. this.setValues(parameters);
  7934. }
  7935. }
  7936. ShaderMaterial.prototype = Object.create(Material.prototype);
  7937. ShaderMaterial.prototype.constructor = ShaderMaterial;
  7938. ShaderMaterial.prototype.isShaderMaterial = true;
  7939. ShaderMaterial.prototype.copy = function (source) {
  7940. Material.prototype.copy.call(this, source);
  7941. this.fragmentShader = source.fragmentShader;
  7942. this.vertexShader = source.vertexShader;
  7943. this.uniforms = UniformsUtils.clone(source.uniforms);
  7944. this.defines = Object.assign({}, source.defines);
  7945. this.wireframe = source.wireframe;
  7946. this.wireframeLinewidth = source.wireframeLinewidth;
  7947. this.lights = source.lights;
  7948. this.clipping = source.clipping;
  7949. this.skinning = source.skinning;
  7950. this.morphTargets = source.morphTargets;
  7951. this.morphNormals = source.morphNormals;
  7952. this.extensions = source.extensions;
  7953. return this;
  7954. };
  7955. ShaderMaterial.prototype.toJSON = function (meta) {
  7956. var data = Material.prototype.toJSON.call(this, meta);
  7957. data.uniforms = this.uniforms;
  7958. data.vertexShader = this.vertexShader;
  7959. data.fragmentShader = this.fragmentShader;
  7960. return data;
  7961. };
  7962. /**
  7963. * @author bhouston / http://clara.io
  7964. */
  7965. function Ray(origin, direction) {
  7966. this.origin = origin !== undefined ? origin : new Vector3();
  7967. this.direction = direction !== undefined ? direction : new Vector3();
  7968. }
  7969. Object.assign(Ray.prototype, {
  7970. set: function (origin, direction) {
  7971. this.origin.copy(origin);
  7972. this.direction.copy(direction);
  7973. return this;
  7974. },
  7975. clone: function () {
  7976. return new this.constructor().copy(this);
  7977. },
  7978. copy: function (ray) {
  7979. this.origin.copy(ray.origin);
  7980. this.direction.copy(ray.direction);
  7981. return this;
  7982. },
  7983. at: function (t, target) {
  7984. if (target === undefined) {
  7985. console.warn('THREE.Ray: .at() target is now required');
  7986. target = new Vector3();
  7987. }
  7988. return target.copy(this.direction).multiplyScalar(t).add(this.origin);
  7989. },
  7990. lookAt: function (v) {
  7991. this.direction.copy(v).sub(this.origin).normalize();
  7992. return this;
  7993. },
  7994. recast: function () {
  7995. var v1 = new Vector3();
  7996. return function recast(t) {
  7997. this.origin.copy(this.at(t, v1));
  7998. return this;
  7999. };
  8000. }(),
  8001. closestPointToPoint: function (point, target) {
  8002. if (target === undefined) {
  8003. console.warn('THREE.Ray: .closestPointToPoint() target is now required');
  8004. target = new Vector3();
  8005. }
  8006. target.subVectors(point, this.origin);
  8007. var directionDistance = target.dot(this.direction);
  8008. if (directionDistance < 0) {
  8009. return target.copy(this.origin);
  8010. }
  8011. return target.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
  8012. },
  8013. distanceToPoint: function (point) {
  8014. return Math.sqrt(this.distanceSqToPoint(point));
  8015. },
  8016. distanceSqToPoint: function () {
  8017. var v1 = new Vector3();
  8018. return function distanceSqToPoint(point) {
  8019. var directionDistance = v1.subVectors(point, this.origin).dot(this.direction);
  8020. // point behind the ray
  8021. if (directionDistance < 0) {
  8022. return this.origin.distanceToSquared(point);
  8023. }
  8024. v1.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
  8025. return v1.distanceToSquared(point);
  8026. };
  8027. }(),
  8028. distanceSqToSegment: function () {
  8029. var segCenter = new Vector3();
  8030. var segDir = new Vector3();
  8031. var diff = new Vector3();
  8032. return function distanceSqToSegment(v0, v1, optionalPointOnRay, optionalPointOnSegment) {
  8033. // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
  8034. // It returns the min distance between the ray and the segment
  8035. // defined by v0 and v1
  8036. // It can also set two optional targets :
  8037. // - The closest point on the ray
  8038. // - The closest point on the segment
  8039. segCenter.copy(v0).add(v1).multiplyScalar(0.5);
  8040. segDir.copy(v1).sub(v0).normalize();
  8041. diff.copy(this.origin).sub(segCenter);
  8042. var segExtent = v0.distanceTo(v1) * 0.5;
  8043. var a01 = -this.direction.dot(segDir);
  8044. var b0 = diff.dot(this.direction);
  8045. var b1 = -diff.dot(segDir);
  8046. var c = diff.lengthSq();
  8047. var det = Math.abs(1 - a01 * a01);
  8048. var s0, s1, sqrDist, extDet;
  8049. if (det > 0) {
  8050. // The ray and segment are not parallel.
  8051. s0 = a01 * b1 - b0;
  8052. s1 = a01 * b0 - b1;
  8053. extDet = segExtent * det;
  8054. if (s0 >= 0) {
  8055. if (s1 >= -extDet) {
  8056. if (s1 <= extDet) {
  8057. // region 0
  8058. // Minimum at interior points of ray and segment.
  8059. var invDet = 1 / det;
  8060. s0 *= invDet;
  8061. s1 *= invDet;
  8062. sqrDist = s0 * (s0 + a01 * s1 + 2 * b0) + s1 * (a01 * s0 + s1 + 2 * b1) + c;
  8063. } else {
  8064. // region 1
  8065. s1 = segExtent;
  8066. s0 = Math.max(0, -(a01 * s1 + b0));
  8067. sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
  8068. }
  8069. } else {
  8070. // region 5
  8071. s1 = -segExtent;
  8072. s0 = Math.max(0, -(a01 * s1 + b0));
  8073. sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
  8074. }
  8075. } else {
  8076. if (s1 <= -extDet) {
  8077. // region 4
  8078. s0 = Math.max(0, -(-a01 * segExtent + b0));
  8079. s1 = s0 > 0 ? -segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
  8080. sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
  8081. } else if (s1 <= extDet) {
  8082. // region 3
  8083. s0 = 0;
  8084. s1 = Math.min(Math.max(-segExtent, -b1), segExtent);
  8085. sqrDist = s1 * (s1 + 2 * b1) + c;
  8086. } else {
  8087. // region 2
  8088. s0 = Math.max(0, -(a01 * segExtent + b0));
  8089. s1 = s0 > 0 ? segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
  8090. sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
  8091. }
  8092. }
  8093. } else {
  8094. // Ray and segment are parallel.
  8095. s1 = a01 > 0 ? -segExtent : segExtent;
  8096. s0 = Math.max(0, -(a01 * s1 + b0));
  8097. sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
  8098. }
  8099. if (optionalPointOnRay) {
  8100. optionalPointOnRay.copy(this.direction).multiplyScalar(s0).add(this.origin);
  8101. }
  8102. if (optionalPointOnSegment) {
  8103. optionalPointOnSegment.copy(segDir).multiplyScalar(s1).add(segCenter);
  8104. }
  8105. return sqrDist;
  8106. };
  8107. }(),
  8108. intersectSphere: function () {
  8109. var v1 = new Vector3();
  8110. return function intersectSphere(sphere, target) {
  8111. v1.subVectors(sphere.center, this.origin);
  8112. var tca = v1.dot(this.direction);
  8113. var d2 = v1.dot(v1) - tca * tca;
  8114. var radius2 = sphere.radius * sphere.radius;
  8115. if (d2 > radius2) return null;
  8116. var thc = Math.sqrt(radius2 - d2);
  8117. // t0 = first intersect point - entrance on front of sphere
  8118. var t0 = tca - thc;
  8119. // t1 = second intersect point - exit point on back of sphere
  8120. var t1 = tca + thc;
  8121. // test to see if both t0 and t1 are behind the ray - if so, return null
  8122. if (t0 < 0 && t1 < 0) return null;
  8123. // test to see if t0 is behind the ray:
  8124. // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
  8125. // in order to always return an intersect point that is in front of the ray.
  8126. if (t0 < 0) return this.at(t1, target);
  8127. // else t0 is in front of the ray, so return the first collision point scaled by t0
  8128. return this.at(t0, target);
  8129. };
  8130. }(),
  8131. intersectsSphere: function (sphere) {
  8132. return this.distanceToPoint(sphere.center) <= sphere.radius;
  8133. },
  8134. distanceToPlane: function (plane) {
  8135. var denominator = plane.normal.dot(this.direction);
  8136. if (denominator === 0) {
  8137. // line is coplanar, return origin
  8138. if (plane.distanceToPoint(this.origin) === 0) {
  8139. return 0;
  8140. }
  8141. // Null is preferable to undefined since undefined means.... it is undefined
  8142. return null;
  8143. }
  8144. var t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
  8145. // Return if the ray never intersects the plane
  8146. return t >= 0 ? t : null;
  8147. },
  8148. intersectPlane: function (plane, target) {
  8149. var t = this.distanceToPlane(plane);
  8150. if (t === null) {
  8151. return null;
  8152. }
  8153. return this.at(t, target);
  8154. },
  8155. intersectsPlane: function (plane) {
  8156. // check if the ray lies on the plane first
  8157. var distToPoint = plane.distanceToPoint(this.origin);
  8158. if (distToPoint === 0) {
  8159. return true;
  8160. }
  8161. var denominator = plane.normal.dot(this.direction);
  8162. if (denominator * distToPoint < 0) {
  8163. return true;
  8164. }
  8165. // ray origin is behind the plane (and is pointing behind it)
  8166. return false;
  8167. },
  8168. intersectBox: function (box, target) {
  8169. var tmin, tmax, tymin, tymax, tzmin, tzmax;
  8170. var invdirx = 1 / this.direction.x,
  8171. invdiry = 1 / this.direction.y,
  8172. invdirz = 1 / this.direction.z;
  8173. var origin = this.origin;
  8174. if (invdirx >= 0) {
  8175. tmin = (box.min.x - origin.x) * invdirx;
  8176. tmax = (box.max.x - origin.x) * invdirx;
  8177. } else {
  8178. tmin = (box.max.x - origin.x) * invdirx;
  8179. tmax = (box.min.x - origin.x) * invdirx;
  8180. }
  8181. if (invdiry >= 0) {
  8182. tymin = (box.min.y - origin.y) * invdiry;
  8183. tymax = (box.max.y - origin.y) * invdiry;
  8184. } else {
  8185. tymin = (box.max.y - origin.y) * invdiry;
  8186. tymax = (box.min.y - origin.y) * invdiry;
  8187. }
  8188. if (tmin > tymax || tymin > tmax) return null;
  8189. // These lines also handle the case where tmin or tmax is NaN
  8190. // (result of 0 * Infinity). x !== x returns true if x is NaN
  8191. if (tymin > tmin || tmin !== tmin) tmin = tymin;
  8192. if (tymax < tmax || tmax !== tmax) tmax = tymax;
  8193. if (invdirz >= 0) {
  8194. tzmin = (box.min.z - origin.z) * invdirz;
  8195. tzmax = (box.max.z - origin.z) * invdirz;
  8196. } else {
  8197. tzmin = (box.max.z - origin.z) * invdirz;
  8198. tzmax = (box.min.z - origin.z) * invdirz;
  8199. }
  8200. if (tmin > tzmax || tzmin > tmax) return null;
  8201. if (tzmin > tmin || tmin !== tmin) tmin = tzmin;
  8202. if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
  8203. //return point closest to the ray (positive side)
  8204. if (tmax < 0) return null;
  8205. return this.at(tmin >= 0 ? tmin : tmax, target);
  8206. },
  8207. intersectsBox: function () {
  8208. var v = new Vector3();
  8209. return function intersectsBox(box) {
  8210. return this.intersectBox(box, v) !== null;
  8211. };
  8212. }(),
  8213. intersectTriangle: function () {
  8214. // Compute the offset origin, edges, and normal.
  8215. var diff = new Vector3();
  8216. var edge1 = new Vector3();
  8217. var edge2 = new Vector3();
  8218. var normal = new Vector3();
  8219. return function intersectTriangle(a, b, c, backfaceCulling, target) {
  8220. // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
  8221. edge1.subVectors(b, a);
  8222. edge2.subVectors(c, a);
  8223. normal.crossVectors(edge1, edge2);
  8224. // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
  8225. // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
  8226. // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  8227. // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  8228. // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  8229. var DdN = this.direction.dot(normal);
  8230. var sign;
  8231. if (DdN > 0) {
  8232. if (backfaceCulling) return null;
  8233. sign = 1;
  8234. } else if (DdN < 0) {
  8235. sign = -1;
  8236. DdN = -DdN;
  8237. } else {
  8238. return null;
  8239. }
  8240. diff.subVectors(this.origin, a);
  8241. var DdQxE2 = sign * this.direction.dot(edge2.crossVectors(diff, edge2));
  8242. // b1 < 0, no intersection
  8243. if (DdQxE2 < 0) {
  8244. return null;
  8245. }
  8246. var DdE1xQ = sign * this.direction.dot(edge1.cross(diff));
  8247. // b2 < 0, no intersection
  8248. if (DdE1xQ < 0) {
  8249. return null;
  8250. }
  8251. // b1+b2 > 1, no intersection
  8252. if (DdQxE2 + DdE1xQ > DdN) {
  8253. return null;
  8254. }
  8255. // Line intersects triangle, check if ray does.
  8256. var QdN = -sign * diff.dot(normal);
  8257. // t < 0, no intersection
  8258. if (QdN < 0) {
  8259. return null;
  8260. }
  8261. // Ray intersects triangle.
  8262. return this.at(QdN / DdN, target);
  8263. };
  8264. }(),
  8265. applyMatrix4: function (matrix4) {
  8266. this.origin.applyMatrix4(matrix4);
  8267. this.direction.transformDirection(matrix4);
  8268. return this;
  8269. },
  8270. equals: function (ray) {
  8271. return ray.origin.equals(this.origin) && ray.direction.equals(this.direction);
  8272. }
  8273. });
  8274. /**
  8275. * @author bhouston / http://clara.io
  8276. */
  8277. function Line3(start, end) {
  8278. this.start = start !== undefined ? start : new Vector3();
  8279. this.end = end !== undefined ? end : new Vector3();
  8280. }
  8281. Object.assign(Line3.prototype, {
  8282. set: function (start, end) {
  8283. this.start.copy(start);
  8284. this.end.copy(end);
  8285. return this;
  8286. },
  8287. clone: function () {
  8288. return new this.constructor().copy(this);
  8289. },
  8290. copy: function (line) {
  8291. this.start.copy(line.start);
  8292. this.end.copy(line.end);
  8293. return this;
  8294. },
  8295. getCenter: function (target) {
  8296. if (target === undefined) {
  8297. console.warn('THREE.Line3: .getCenter() target is now required');
  8298. target = new Vector3();
  8299. }
  8300. return target.addVectors(this.start, this.end).multiplyScalar(0.5);
  8301. },
  8302. delta: function (target) {
  8303. if (target === undefined) {
  8304. console.warn('THREE.Line3: .delta() target is now required');
  8305. target = new Vector3();
  8306. }
  8307. return target.subVectors(this.end, this.start);
  8308. },
  8309. distanceSq: function () {
  8310. return this.start.distanceToSquared(this.end);
  8311. },
  8312. distance: function () {
  8313. return this.start.distanceTo(this.end);
  8314. },
  8315. at: function (t, target) {
  8316. if (target === undefined) {
  8317. console.warn('THREE.Line3: .at() target is now required');
  8318. target = new Vector3();
  8319. }
  8320. return this.delta(target).multiplyScalar(t).add(this.start);
  8321. },
  8322. closestPointToPointParameter: function () {
  8323. var startP = new Vector3();
  8324. var startEnd = new Vector3();
  8325. return function closestPointToPointParameter(point, clampToLine) {
  8326. startP.subVectors(point, this.start);
  8327. startEnd.subVectors(this.end, this.start);
  8328. var startEnd2 = startEnd.dot(startEnd);
  8329. var startEnd_startP = startEnd.dot(startP);
  8330. var t = startEnd_startP / startEnd2;
  8331. if (clampToLine) {
  8332. t = _Math.clamp(t, 0, 1);
  8333. }
  8334. return t;
  8335. };
  8336. }(),
  8337. closestPointToPoint: function (point, clampToLine, target) {
  8338. var t = this.closestPointToPointParameter(point, clampToLine);
  8339. if (target === undefined) {
  8340. console.warn('THREE.Line3: .closestPointToPoint() target is now required');
  8341. target = new Vector3();
  8342. }
  8343. return this.delta(target).multiplyScalar(t).add(this.start);
  8344. },
  8345. applyMatrix4: function (matrix) {
  8346. this.start.applyMatrix4(matrix);
  8347. this.end.applyMatrix4(matrix);
  8348. return this;
  8349. },
  8350. equals: function (line) {
  8351. return line.start.equals(this.start) && line.end.equals(this.end);
  8352. }
  8353. });
  8354. /**
  8355. * @author bhouston / http://clara.io
  8356. * @author mrdoob / http://mrdoob.com/
  8357. */
  8358. function Triangle(a, b, c) {
  8359. this.a = a !== undefined ? a : new Vector3();
  8360. this.b = b !== undefined ? b : new Vector3();
  8361. this.c = c !== undefined ? c : new Vector3();
  8362. }
  8363. Object.assign(Triangle, {
  8364. getNormal: function () {
  8365. var v0 = new Vector3();
  8366. return function getNormal(a, b, c, target) {
  8367. if (target === undefined) {
  8368. console.warn('THREE.Triangle: .getNormal() target is now required');
  8369. target = new Vector3();
  8370. }
  8371. target.subVectors(c, b);
  8372. v0.subVectors(a, b);
  8373. target.cross(v0);
  8374. var targetLengthSq = target.lengthSq();
  8375. if (targetLengthSq > 0) {
  8376. return target.multiplyScalar(1 / Math.sqrt(targetLengthSq));
  8377. }
  8378. return target.set(0, 0, 0);
  8379. };
  8380. }(),
  8381. // static/instance method to calculate barycentric coordinates
  8382. // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
  8383. getBarycoord: function () {
  8384. var v0 = new Vector3();
  8385. var v1 = new Vector3();
  8386. var v2 = new Vector3();
  8387. return function getBarycoord(point, a, b, c, target) {
  8388. v0.subVectors(c, a);
  8389. v1.subVectors(b, a);
  8390. v2.subVectors(point, a);
  8391. var dot00 = v0.dot(v0);
  8392. var dot01 = v0.dot(v1);
  8393. var dot02 = v0.dot(v2);
  8394. var dot11 = v1.dot(v1);
  8395. var dot12 = v1.dot(v2);
  8396. var denom = dot00 * dot11 - dot01 * dot01;
  8397. if (target === undefined) {
  8398. console.warn('THREE.Triangle: .getBarycoord() target is now required');
  8399. target = new Vector3();
  8400. }
  8401. // collinear or singular triangle
  8402. if (denom === 0) {
  8403. // arbitrary location outside of triangle?
  8404. // not sure if this is the best idea, maybe should be returning undefined
  8405. return target.set(-2, -1, -1);
  8406. }
  8407. var invDenom = 1 / denom;
  8408. var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  8409. var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  8410. // barycentric coordinates must always sum to 1
  8411. return target.set(1 - u - v, v, u);
  8412. };
  8413. }(),
  8414. containsPoint: function () {
  8415. var v1 = new Vector3();
  8416. return function containsPoint(point, a, b, c) {
  8417. Triangle.getBarycoord(point, a, b, c, v1);
  8418. return v1.x >= 0 && v1.y >= 0 && v1.x + v1.y <= 1;
  8419. };
  8420. }()
  8421. });
  8422. Object.assign(Triangle.prototype, {
  8423. set: function (a, b, c) {
  8424. this.a.copy(a);
  8425. this.b.copy(b);
  8426. this.c.copy(c);
  8427. return this;
  8428. },
  8429. setFromPointsAndIndices: function (points, i0, i1, i2) {
  8430. this.a.copy(points[i0]);
  8431. this.b.copy(points[i1]);
  8432. this.c.copy(points[i2]);
  8433. return this;
  8434. },
  8435. clone: function () {
  8436. return new this.constructor().copy(this);
  8437. },
  8438. copy: function (triangle) {
  8439. this.a.copy(triangle.a);
  8440. this.b.copy(triangle.b);
  8441. this.c.copy(triangle.c);
  8442. return this;
  8443. },
  8444. getArea: function () {
  8445. var v0 = new Vector3();
  8446. var v1 = new Vector3();
  8447. return function getArea() {
  8448. v0.subVectors(this.c, this.b);
  8449. v1.subVectors(this.a, this.b);
  8450. return v0.cross(v1).length() * 0.5;
  8451. };
  8452. }(),
  8453. getMidpoint: function (target) {
  8454. if (target === undefined) {
  8455. console.warn('THREE.Triangle: .getMidpoint() target is now required');
  8456. target = new Vector3();
  8457. }
  8458. return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3);
  8459. },
  8460. getNormal: function (target) {
  8461. return Triangle.getNormal(this.a, this.b, this.c, target);
  8462. },
  8463. getPlane: function (target) {
  8464. if (target === undefined) {
  8465. console.warn('THREE.Triangle: .getPlane() target is now required');
  8466. target = new Vector3();
  8467. }
  8468. return target.setFromCoplanarPoints(this.a, this.b, this.c);
  8469. },
  8470. getBarycoord: function (point, target) {
  8471. return Triangle.getBarycoord(point, this.a, this.b, this.c, target);
  8472. },
  8473. containsPoint: function (point) {
  8474. return Triangle.containsPoint(point, this.a, this.b, this.c);
  8475. },
  8476. intersectsBox: function (box) {
  8477. return box.intersectsTriangle(this);
  8478. },
  8479. closestPointToPoint: function () {
  8480. var plane = new Plane();
  8481. var edgeList = [new Line3(), new Line3(), new Line3()];
  8482. var projectedPoint = new Vector3();
  8483. var closestPoint = new Vector3();
  8484. return function closestPointToPoint(point, target) {
  8485. if (target === undefined) {
  8486. console.warn('THREE.Triangle: .closestPointToPoint() target is now required');
  8487. target = new Vector3();
  8488. }
  8489. var minDistance = Infinity;
  8490. // project the point onto the plane of the triangle
  8491. plane.setFromCoplanarPoints(this.a, this.b, this.c);
  8492. plane.projectPoint(point, projectedPoint);
  8493. // check if the projection lies within the triangle
  8494. if (this.containsPoint(projectedPoint) === true) {
  8495. // if so, this is the closest point
  8496. target.copy(projectedPoint);
  8497. } else {
  8498. // if not, the point falls outside the triangle. the target is the closest point to the triangle's edges or vertices
  8499. edgeList[0].set(this.a, this.b);
  8500. edgeList[1].set(this.b, this.c);
  8501. edgeList[2].set(this.c, this.a);
  8502. for (var i = 0; i < edgeList.length; i++) {
  8503. edgeList[i].closestPointToPoint(projectedPoint, true, closestPoint);
  8504. var distance = projectedPoint.distanceToSquared(closestPoint);
  8505. if (distance < minDistance) {
  8506. minDistance = distance;
  8507. target.copy(closestPoint);
  8508. }
  8509. }
  8510. }
  8511. return target;
  8512. };
  8513. }(),
  8514. equals: function (triangle) {
  8515. return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c);
  8516. }
  8517. });
  8518. /**
  8519. * @author mrdoob / http://mrdoob.com/
  8520. * @author alteredq / http://alteredqualia.com/
  8521. * @author mikael emtinger / http://gomo.se/
  8522. * @author jonobr1 / http://jonobr1.com/
  8523. */
  8524. function Mesh(geometry, material) {
  8525. Object3D.call(this);
  8526. this.type = 'Mesh';
  8527. this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
  8528. this.material = material !== undefined ? material : new MeshBasicMaterial({ color: Math.random() * 0xffffff });
  8529. this.drawMode = TrianglesDrawMode;
  8530. this.updateMorphTargets();
  8531. }
  8532. Mesh.prototype = Object.assign(Object.create(Object3D.prototype), {
  8533. constructor: Mesh,
  8534. isMesh: true,
  8535. setDrawMode: function (value) {
  8536. this.drawMode = value;
  8537. },
  8538. copy: function (source) {
  8539. Object3D.prototype.copy.call(this, source);
  8540. this.drawMode = source.drawMode;
  8541. if (source.morphTargetInfluences !== undefined) {
  8542. this.morphTargetInfluences = source.morphTargetInfluences.slice();
  8543. }
  8544. if (source.morphTargetDictionary !== undefined) {
  8545. this.morphTargetDictionary = Object.assign({}, source.morphTargetDictionary);
  8546. }
  8547. return this;
  8548. },
  8549. updateMorphTargets: function () {
  8550. var geometry = this.geometry;
  8551. var m, ml, name;
  8552. if (geometry.isBufferGeometry) {
  8553. var morphAttributes = geometry.morphAttributes;
  8554. var keys = Object.keys(morphAttributes);
  8555. if (keys.length > 0) {
  8556. var morphAttribute = morphAttributes[keys[0]];
  8557. if (morphAttribute !== undefined) {
  8558. this.morphTargetInfluences = [];
  8559. this.morphTargetDictionary = {};
  8560. for (m = 0, ml = morphAttribute.length; m < ml; m++) {
  8561. name = morphAttribute[m].name || String(m);
  8562. this.morphTargetInfluences.push(0);
  8563. this.morphTargetDictionary[name] = m;
  8564. }
  8565. }
  8566. }
  8567. } else {
  8568. var morphTargets = geometry.morphTargets;
  8569. if (morphTargets !== undefined && morphTargets.length > 0) {
  8570. this.morphTargetInfluences = [];
  8571. this.morphTargetDictionary = {};
  8572. for (m = 0, ml = morphTargets.length; m < ml; m++) {
  8573. name = morphTargets[m].name || String(m);
  8574. this.morphTargetInfluences.push(0);
  8575. this.morphTargetDictionary[name] = m;
  8576. }
  8577. }
  8578. }
  8579. },
  8580. raycast: function () {
  8581. var inverseMatrix = new Matrix4();
  8582. var ray = new Ray();
  8583. var sphere = new Sphere();
  8584. var vA = new Vector3();
  8585. var vB = new Vector3();
  8586. var vC = new Vector3();
  8587. var tempA = new Vector3();
  8588. var tempB = new Vector3();
  8589. var tempC = new Vector3();
  8590. var uvA = new Vector2();
  8591. var uvB = new Vector2();
  8592. var uvC = new Vector2();
  8593. var barycoord = new Vector3();
  8594. var intersectionPoint = new Vector3();
  8595. var intersectionPointWorld = new Vector3();
  8596. function uvIntersection(point, p1, p2, p3, uv1, uv2, uv3) {
  8597. Triangle.getBarycoord(point, p1, p2, p3, barycoord);
  8598. uv1.multiplyScalar(barycoord.x);
  8599. uv2.multiplyScalar(barycoord.y);
  8600. uv3.multiplyScalar(barycoord.z);
  8601. uv1.add(uv2).add(uv3);
  8602. return uv1.clone();
  8603. }
  8604. function checkIntersection(object, material, raycaster, ray, pA, pB, pC, point) {
  8605. var intersect;
  8606. if (material.side === BackSide) {
  8607. intersect = ray.intersectTriangle(pC, pB, pA, true, point);
  8608. } else {
  8609. intersect = ray.intersectTriangle(pA, pB, pC, material.side !== DoubleSide, point);
  8610. }
  8611. if (intersect === null) return null;
  8612. intersectionPointWorld.copy(point);
  8613. intersectionPointWorld.applyMatrix4(object.matrixWorld);
  8614. var distance = raycaster.ray.origin.distanceTo(intersectionPointWorld);
  8615. if (distance < raycaster.near || distance > raycaster.far) return null;
  8616. return {
  8617. distance: distance,
  8618. point: intersectionPointWorld.clone(),
  8619. object: object
  8620. };
  8621. }
  8622. function checkBufferGeometryIntersection(object, raycaster, ray, position, uv, a, b, c) {
  8623. vA.fromBufferAttribute(position, a);
  8624. vB.fromBufferAttribute(position, b);
  8625. vC.fromBufferAttribute(position, c);
  8626. var intersection = checkIntersection(object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint);
  8627. if (intersection) {
  8628. if (uv) {
  8629. uvA.fromBufferAttribute(uv, a);
  8630. uvB.fromBufferAttribute(uv, b);
  8631. uvC.fromBufferAttribute(uv, c);
  8632. intersection.uv = uvIntersection(intersectionPoint, vA, vB, vC, uvA, uvB, uvC);
  8633. }
  8634. var face = new Face3(a, b, c);
  8635. Triangle.getNormal(vA, vB, vC, face.normal);
  8636. intersection.face = face;
  8637. }
  8638. return intersection;
  8639. }
  8640. return function raycast(raycaster, intersects) {
  8641. var geometry = this.geometry;
  8642. var material = this.material;
  8643. var matrixWorld = this.matrixWorld;
  8644. if (material === undefined) return;
  8645. // Checking boundingSphere distance to ray
  8646. if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
  8647. sphere.copy(geometry.boundingSphere);
  8648. sphere.applyMatrix4(matrixWorld);
  8649. if (raycaster.ray.intersectsSphere(sphere) === false) return;
  8650. //
  8651. inverseMatrix.getInverse(matrixWorld);
  8652. ray.copy(raycaster.ray).applyMatrix4(inverseMatrix);
  8653. // Check boundingBox before continuing
  8654. if (geometry.boundingBox !== null) {
  8655. if (ray.intersectsBox(geometry.boundingBox) === false) return;
  8656. }
  8657. var intersection;
  8658. if (geometry.isBufferGeometry) {
  8659. var a, b, c;
  8660. var index = geometry.index;
  8661. var position = geometry.attributes.position;
  8662. var uv = geometry.attributes.uv;
  8663. var i, l;
  8664. if (index !== null) {
  8665. // indexed buffer geometry
  8666. for (i = 0, l = index.count; i < l; i += 3) {
  8667. a = index.getX(i);
  8668. b = index.getX(i + 1);
  8669. c = index.getX(i + 2);
  8670. intersection = checkBufferGeometryIntersection(this, raycaster, ray, position, uv, a, b, c);
  8671. if (intersection) {
  8672. intersection.faceIndex = Math.floor(i / 3); // triangle number in indexed buffer semantics
  8673. intersects.push(intersection);
  8674. }
  8675. }
  8676. } else if (position !== undefined) {
  8677. // non-indexed buffer geometry
  8678. for (i = 0, l = position.count; i < l; i += 3) {
  8679. a = i;
  8680. b = i + 1;
  8681. c = i + 2;
  8682. intersection = checkBufferGeometryIntersection(this, raycaster, ray, position, uv, a, b, c);
  8683. if (intersection) {
  8684. intersection.faceIndex = Math.floor(i / 3); // triangle number in non-indexed buffer semantics
  8685. intersects.push(intersection);
  8686. }
  8687. }
  8688. }
  8689. } else if (geometry.isGeometry) {
  8690. var fvA, fvB, fvC;
  8691. var isMultiMaterial = Array.isArray(material);
  8692. var vertices = geometry.vertices;
  8693. var faces = geometry.faces;
  8694. var uvs;
  8695. var faceVertexUvs = geometry.faceVertexUvs[0];
  8696. if (faceVertexUvs.length > 0) uvs = faceVertexUvs;
  8697. for (var f = 0, fl = faces.length; f < fl; f++) {
  8698. var face = faces[f];
  8699. var faceMaterial = isMultiMaterial ? material[face.materialIndex] : material;
  8700. if (faceMaterial === undefined) continue;
  8701. fvA = vertices[face.a];
  8702. fvB = vertices[face.b];
  8703. fvC = vertices[face.c];
  8704. if (faceMaterial.morphTargets === true) {
  8705. var morphTargets = geometry.morphTargets;
  8706. var morphInfluences = this.morphTargetInfluences;
  8707. vA.set(0, 0, 0);
  8708. vB.set(0, 0, 0);
  8709. vC.set(0, 0, 0);
  8710. for (var t = 0, tl = morphTargets.length; t < tl; t++) {
  8711. var influence = morphInfluences[t];
  8712. if (influence === 0) continue;
  8713. var targets = morphTargets[t].vertices;
  8714. vA.addScaledVector(tempA.subVectors(targets[face.a], fvA), influence);
  8715. vB.addScaledVector(tempB.subVectors(targets[face.b], fvB), influence);
  8716. vC.addScaledVector(tempC.subVectors(targets[face.c], fvC), influence);
  8717. }
  8718. vA.add(fvA);
  8719. vB.add(fvB);
  8720. vC.add(fvC);
  8721. fvA = vA;
  8722. fvB = vB;
  8723. fvC = vC;
  8724. }
  8725. intersection = checkIntersection(this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint);
  8726. if (intersection) {
  8727. if (uvs && uvs[f]) {
  8728. var uvs_f = uvs[f];
  8729. uvA.copy(uvs_f[0]);
  8730. uvB.copy(uvs_f[1]);
  8731. uvC.copy(uvs_f[2]);
  8732. intersection.uv = uvIntersection(intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC);
  8733. }
  8734. intersection.face = face;
  8735. intersection.faceIndex = f;
  8736. intersects.push(intersection);
  8737. }
  8738. }
  8739. }
  8740. };
  8741. }(),
  8742. clone: function () {
  8743. return new this.constructor(this.geometry, this.material).copy(this);
  8744. }
  8745. });
  8746. /**
  8747. * @author mrdoob / http://mrdoob.com/
  8748. */
  8749. function WebGLBackground(renderer, state, objects, premultipliedAlpha) {
  8750. var clearColor = new Color(0x000000);
  8751. var clearAlpha = 0;
  8752. var planeCamera, planeMesh;
  8753. var boxMesh;
  8754. function render(renderList, scene, camera, forceClear) {
  8755. var background = scene.background;
  8756. if (background === null) {
  8757. setClear(clearColor, clearAlpha);
  8758. } else if (background && background.isColor) {
  8759. setClear(background, 1);
  8760. forceClear = true;
  8761. }
  8762. if (renderer.autoClear || forceClear) {
  8763. renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil);
  8764. }
  8765. if (background && background.isCubeTexture) {
  8766. if (boxMesh === undefined) {
  8767. boxMesh = new Mesh(new BoxBufferGeometry(1, 1, 1), new ShaderMaterial({
  8768. uniforms: ShaderLib.cube.uniforms,
  8769. vertexShader: ShaderLib.cube.vertexShader,
  8770. fragmentShader: ShaderLib.cube.fragmentShader,
  8771. side: BackSide,
  8772. depthTest: true,
  8773. depthWrite: false,
  8774. fog: false
  8775. }));
  8776. boxMesh.geometry.removeAttribute('normal');
  8777. boxMesh.geometry.removeAttribute('uv');
  8778. boxMesh.onBeforeRender = function (renderer, scene, camera) {
  8779. this.matrixWorld.copyPosition(camera.matrixWorld);
  8780. };
  8781. objects.update(boxMesh);
  8782. }
  8783. boxMesh.material.uniforms.tCube.value = background;
  8784. renderList.push(boxMesh, boxMesh.geometry, boxMesh.material, 0, null);
  8785. } else if (background && background.isTexture) {
  8786. if (planeCamera === undefined) {
  8787. planeCamera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
  8788. planeMesh = new Mesh(new PlaneBufferGeometry(2, 2), new MeshBasicMaterial({ depthTest: false, depthWrite: false, fog: false }));
  8789. objects.update(planeMesh);
  8790. }
  8791. planeMesh.material.map = background;
  8792. // TODO Push this to renderList
  8793. renderer.renderBufferDirect(planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null);
  8794. }
  8795. }
  8796. function setClear(color, alpha) {
  8797. state.buffers.color.setClear(color.r, color.g, color.b, alpha, premultipliedAlpha);
  8798. }
  8799. return {
  8800. getClearColor: function () {
  8801. return clearColor;
  8802. },
  8803. setClearColor: function (color, alpha) {
  8804. clearColor.set(color);
  8805. clearAlpha = alpha !== undefined ? alpha : 1;
  8806. setClear(clearColor, clearAlpha);
  8807. },
  8808. getClearAlpha: function () {
  8809. return clearAlpha;
  8810. },
  8811. setClearAlpha: function (alpha) {
  8812. clearAlpha = alpha;
  8813. setClear(clearColor, clearAlpha);
  8814. },
  8815. render: render
  8816. };
  8817. }
  8818. /**
  8819. * @author mrdoob / http://mrdoob.com/
  8820. */
  8821. function WebGLBufferRenderer(gl, extensions, info) {
  8822. var mode;
  8823. function setMode(value) {
  8824. mode = value;
  8825. }
  8826. function render(start, count) {
  8827. gl.drawArrays(mode, start, count);
  8828. info.update(count, mode);
  8829. }
  8830. function renderInstances(geometry, start, count) {
  8831. var extension = extensions.get('ANGLE_instanced_arrays');
  8832. if (extension === null) {
  8833. console.error('THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.');
  8834. return;
  8835. }
  8836. extension.drawArraysInstancedANGLE(mode, start, count, geometry.maxInstancedCount);
  8837. info.update(count, mode, geometry.maxInstancedCount);
  8838. }
  8839. //
  8840. this.setMode = setMode;
  8841. this.render = render;
  8842. this.renderInstances = renderInstances;
  8843. }
  8844. /**
  8845. * @author mrdoob / http://mrdoob.com/
  8846. */
  8847. function WebGLCapabilities(gl, extensions, parameters) {
  8848. var maxAnisotropy;
  8849. function getMaxAnisotropy() {
  8850. if (maxAnisotropy !== undefined) return maxAnisotropy;
  8851. var extension = extensions.get('EXT_texture_filter_anisotropic');
  8852. if (extension !== null) {
  8853. maxAnisotropy = gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
  8854. } else {
  8855. maxAnisotropy = 0;
  8856. }
  8857. return maxAnisotropy;
  8858. }
  8859. function getMaxPrecision(precision) {
  8860. if (precision === 'highp') {
  8861. if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 && gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) {
  8862. return 'highp';
  8863. }
  8864. precision = 'mediump';
  8865. }
  8866. if (precision === 'mediump') {
  8867. if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 && gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) {
  8868. return 'mediump';
  8869. }
  8870. }
  8871. return 'lowp';
  8872. }
  8873. var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
  8874. var maxPrecision = getMaxPrecision(precision);
  8875. if (maxPrecision !== precision) {
  8876. console.warn('THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.');
  8877. precision = maxPrecision;
  8878. }
  8879. var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
  8880. var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  8881. var maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
  8882. var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
  8883. var maxCubemapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);
  8884. var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
  8885. var maxVertexUniforms = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);
  8886. var maxVaryings = gl.getParameter(gl.MAX_VARYING_VECTORS);
  8887. var maxFragmentUniforms = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
  8888. var vertexTextures = maxVertexTextures > 0;
  8889. var floatFragmentTextures = !!extensions.get('OES_texture_float');
  8890. var floatVertexTextures = vertexTextures && floatFragmentTextures;
  8891. return {
  8892. getMaxAnisotropy: getMaxAnisotropy,
  8893. getMaxPrecision: getMaxPrecision,
  8894. precision: precision,
  8895. logarithmicDepthBuffer: logarithmicDepthBuffer,
  8896. maxTextures: maxTextures,
  8897. maxVertexTextures: maxVertexTextures,
  8898. maxTextureSize: maxTextureSize,
  8899. maxCubemapSize: maxCubemapSize,
  8900. maxAttributes: maxAttributes,
  8901. maxVertexUniforms: maxVertexUniforms,
  8902. maxVaryings: maxVaryings,
  8903. maxFragmentUniforms: maxFragmentUniforms,
  8904. vertexTextures: vertexTextures,
  8905. floatFragmentTextures: floatFragmentTextures,
  8906. floatVertexTextures: floatVertexTextures
  8907. };
  8908. }
  8909. /**
  8910. * @author tschw
  8911. */
  8912. function WebGLClipping() {
  8913. var scope = this,
  8914. globalState = null,
  8915. numGlobalPlanes = 0,
  8916. localClippingEnabled = false,
  8917. renderingShadows = false,
  8918. plane = new Plane(),
  8919. viewNormalMatrix = new Matrix3(),
  8920. uniform = { value: null, needsUpdate: false };
  8921. this.uniform = uniform;
  8922. this.numPlanes = 0;
  8923. this.numIntersection = 0;
  8924. this.init = function (planes, enableLocalClipping, camera) {
  8925. var enabled = planes.length !== 0 || enableLocalClipping ||
  8926. // enable state of previous frame - the clipping code has to
  8927. // run another frame in order to reset the state:
  8928. numGlobalPlanes !== 0 || localClippingEnabled;
  8929. localClippingEnabled = enableLocalClipping;
  8930. globalState = projectPlanes(planes, camera, 0);
  8931. numGlobalPlanes = planes.length;
  8932. return enabled;
  8933. };
  8934. this.beginShadows = function () {
  8935. renderingShadows = true;
  8936. projectPlanes(null);
  8937. };
  8938. this.endShadows = function () {
  8939. renderingShadows = false;
  8940. resetGlobalState();
  8941. };
  8942. this.setState = function (planes, clipIntersection, clipShadows, camera, cache, fromCache) {
  8943. if (!localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && !clipShadows) {
  8944. // there's no local clipping
  8945. if (renderingShadows) {
  8946. // there's no global clipping
  8947. projectPlanes(null);
  8948. } else {
  8949. resetGlobalState();
  8950. }
  8951. } else {
  8952. var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
  8953. lGlobal = nGlobal * 4,
  8954. dstArray = cache.clippingState || null;
  8955. uniform.value = dstArray; // ensure unique state
  8956. dstArray = projectPlanes(planes, camera, lGlobal, fromCache);
  8957. for (var i = 0; i !== lGlobal; ++i) {
  8958. dstArray[i] = globalState[i];
  8959. }
  8960. cache.clippingState = dstArray;
  8961. this.numIntersection = clipIntersection ? this.numPlanes : 0;
  8962. this.numPlanes += nGlobal;
  8963. }
  8964. };
  8965. function resetGlobalState() {
  8966. if (uniform.value !== globalState) {
  8967. uniform.value = globalState;
  8968. uniform.needsUpdate = numGlobalPlanes > 0;
  8969. }
  8970. scope.numPlanes = numGlobalPlanes;
  8971. scope.numIntersection = 0;
  8972. }
  8973. function projectPlanes(planes, camera, dstOffset, skipTransform) {
  8974. var nPlanes = planes !== null ? planes.length : 0,
  8975. dstArray = null;
  8976. if (nPlanes !== 0) {
  8977. dstArray = uniform.value;
  8978. if (skipTransform !== true || dstArray === null) {
  8979. var flatSize = dstOffset + nPlanes * 4,
  8980. viewMatrix = camera.matrixWorldInverse;
  8981. viewNormalMatrix.getNormalMatrix(viewMatrix);
  8982. if (dstArray === null || dstArray.length < flatSize) {
  8983. dstArray = new Float32Array(flatSize);
  8984. }
  8985. for (var i = 0, i4 = dstOffset; i !== nPlanes; ++i, i4 += 4) {
  8986. plane.copy(planes[i]).applyMatrix4(viewMatrix, viewNormalMatrix);
  8987. plane.normal.toArray(dstArray, i4);
  8988. dstArray[i4 + 3] = plane.constant;
  8989. }
  8990. }
  8991. uniform.value = dstArray;
  8992. uniform.needsUpdate = true;
  8993. }
  8994. scope.numPlanes = nPlanes;
  8995. return dstArray;
  8996. }
  8997. }
  8998. /**
  8999. * @author mrdoob / http://mrdoob.com/
  9000. */
  9001. function WebGLExtensions(gl) {
  9002. var extensions = {};
  9003. return {
  9004. get: function (name) {
  9005. if (extensions[name] !== undefined) {
  9006. return extensions[name];
  9007. }
  9008. var extension;
  9009. switch (name) {
  9010. case 'WEBGL_depth_texture':
  9011. extension = gl.getExtension('WEBGL_depth_texture') || gl.getExtension('MOZ_WEBGL_depth_texture') || gl.getExtension('WEBKIT_WEBGL_depth_texture');
  9012. break;
  9013. case 'EXT_texture_filter_anisotropic':
  9014. extension = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic');
  9015. break;
  9016. case 'WEBGL_compressed_texture_s3tc':
  9017. extension = gl.getExtension('WEBGL_compressed_texture_s3tc') || gl.getExtension('MOZ_WEBGL_compressed_texture_s3tc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
  9018. break;
  9019. case 'WEBGL_compressed_texture_pvrtc':
  9020. extension = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
  9021. break;
  9022. default:
  9023. extension = gl.getExtension(name);
  9024. }
  9025. if (extension === null) {
  9026. console.warn('THREE.WebGLRenderer: ' + name + ' extension not supported.');
  9027. }
  9028. extensions[name] = extension;
  9029. return extension;
  9030. }
  9031. };
  9032. }
  9033. /**
  9034. * @author mrdoob / http://mrdoob.com/
  9035. */
  9036. function WebGLGeometries(gl, attributes, info) {
  9037. var geometries = {};
  9038. var wireframeAttributes = {};
  9039. function onGeometryDispose(event) {
  9040. var geometry = event.target;
  9041. var buffergeometry = geometries[geometry.id];
  9042. if (buffergeometry.index !== null) {
  9043. attributes.remove(buffergeometry.index);
  9044. }
  9045. for (var name in buffergeometry.attributes) {
  9046. attributes.remove(buffergeometry.attributes[name]);
  9047. }
  9048. geometry.removeEventListener('dispose', onGeometryDispose);
  9049. delete geometries[geometry.id];
  9050. // TODO Remove duplicate code
  9051. var attribute = wireframeAttributes[geometry.id];
  9052. if (attribute) {
  9053. attributes.remove(attribute);
  9054. delete wireframeAttributes[geometry.id];
  9055. }
  9056. attribute = wireframeAttributes[buffergeometry.id];
  9057. if (attribute) {
  9058. attributes.remove(attribute);
  9059. delete wireframeAttributes[buffergeometry.id];
  9060. }
  9061. //
  9062. info.memory.geometries--;
  9063. }
  9064. function get(object, geometry) {
  9065. var buffergeometry = geometries[geometry.id];
  9066. if (buffergeometry) return buffergeometry;
  9067. geometry.addEventListener('dispose', onGeometryDispose);
  9068. if (geometry.isBufferGeometry) {
  9069. buffergeometry = geometry;
  9070. } else if (geometry.isGeometry) {
  9071. if (geometry._bufferGeometry === undefined) {
  9072. geometry._bufferGeometry = new BufferGeometry().setFromObject(object);
  9073. }
  9074. buffergeometry = geometry._bufferGeometry;
  9075. }
  9076. geometries[geometry.id] = buffergeometry;
  9077. info.memory.geometries++;
  9078. return buffergeometry;
  9079. }
  9080. function update(geometry) {
  9081. var index = geometry.index;
  9082. var geometryAttributes = geometry.attributes;
  9083. if (index !== null) {
  9084. attributes.update(index, gl.ELEMENT_ARRAY_BUFFER);
  9085. }
  9086. for (var name in geometryAttributes) {
  9087. attributes.update(geometryAttributes[name], gl.ARRAY_BUFFER);
  9088. }
  9089. // morph targets
  9090. var morphAttributes = geometry.morphAttributes;
  9091. for (var name in morphAttributes) {
  9092. var array = morphAttributes[name];
  9093. for (var i = 0, l = array.length; i < l; i++) {
  9094. attributes.update(array[i], gl.ARRAY_BUFFER);
  9095. }
  9096. }
  9097. }
  9098. function getWireframeAttribute(geometry) {
  9099. var attribute = wireframeAttributes[geometry.id];
  9100. if (attribute) return attribute;
  9101. var indices = [];
  9102. var geometryIndex = geometry.index;
  9103. var geometryAttributes = geometry.attributes;
  9104. // console.time( 'wireframe' );
  9105. if (geometryIndex !== null) {
  9106. var array = geometryIndex.array;
  9107. for (var i = 0, l = array.length; i < l; i += 3) {
  9108. var a = array[i + 0];
  9109. var b = array[i + 1];
  9110. var c = array[i + 2];
  9111. indices.push(a, b, b, c, c, a);
  9112. }
  9113. } else {
  9114. var array = geometryAttributes.position.array;
  9115. for (var i = 0, l = array.length / 3 - 1; i < l; i += 3) {
  9116. var a = i + 0;
  9117. var b = i + 1;
  9118. var c = i + 2;
  9119. indices.push(a, b, b, c, c, a);
  9120. }
  9121. }
  9122. // console.timeEnd( 'wireframe' );
  9123. attribute = new (arrayMax(indices) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute)(indices, 1);
  9124. attributes.update(attribute, gl.ELEMENT_ARRAY_BUFFER);
  9125. wireframeAttributes[geometry.id] = attribute;
  9126. return attribute;
  9127. }
  9128. return {
  9129. get: get,
  9130. update: update,
  9131. getWireframeAttribute: getWireframeAttribute
  9132. };
  9133. }
  9134. /**
  9135. * @author mrdoob / http://mrdoob.com/
  9136. */
  9137. function WebGLIndexedBufferRenderer(gl, extensions, info) {
  9138. var mode;
  9139. function setMode(value) {
  9140. mode = value;
  9141. }
  9142. var type, bytesPerElement;
  9143. function setIndex(value) {
  9144. type = value.type;
  9145. bytesPerElement = value.bytesPerElement;
  9146. }
  9147. function render(start, count) {
  9148. gl.drawElements(mode, count, type, start * bytesPerElement);
  9149. info.update(count, mode);
  9150. }
  9151. function renderInstances(geometry, start, count) {
  9152. var extension = extensions.get('ANGLE_instanced_arrays');
  9153. if (extension === null) {
  9154. console.error('THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.');
  9155. return;
  9156. }
  9157. extension.drawElementsInstancedANGLE(mode, count, type, start * bytesPerElement, geometry.maxInstancedCount);
  9158. info.update(count, mode, geometry.maxInstancedCount);
  9159. }
  9160. //
  9161. this.setMode = setMode;
  9162. this.setIndex = setIndex;
  9163. this.render = render;
  9164. this.renderInstances = renderInstances;
  9165. }
  9166. /**
  9167. * @author Mugen87 / https://github.com/Mugen87
  9168. */
  9169. function WebGLInfo(gl) {
  9170. var memory = {
  9171. geometries: 0,
  9172. textures: 0
  9173. };
  9174. var render = {
  9175. frame: 0,
  9176. calls: 0,
  9177. triangles: 0,
  9178. points: 0,
  9179. lines: 0
  9180. };
  9181. function update(count, mode, instanceCount) {
  9182. instanceCount = instanceCount || 1;
  9183. render.calls++;
  9184. switch (mode) {
  9185. case gl.TRIANGLES:
  9186. render.triangles += instanceCount * (count / 3);
  9187. break;
  9188. case gl.TRIANGLE_STRIP:
  9189. case gl.TRIANGLE_FAN:
  9190. render.triangles += instanceCount * (count - 2);
  9191. break;
  9192. case gl.LINES:
  9193. render.lines += instanceCount * (count / 2);
  9194. break;
  9195. case gl.LINE_STRIP:
  9196. render.lines += instanceCount * (count - 1);
  9197. break;
  9198. case gl.LINE_LOOP:
  9199. render.lines += instanceCount * count;
  9200. break;
  9201. case gl.POINTS:
  9202. render.points += instanceCount * count;
  9203. break;
  9204. default:
  9205. console.error('THREE.WebGLInfo: Unknown draw mode:', mode);
  9206. break;
  9207. }
  9208. }
  9209. function reset() {
  9210. render.frame++;
  9211. render.calls = 0;
  9212. render.triangles = 0;
  9213. render.points = 0;
  9214. render.lines = 0;
  9215. }
  9216. return {
  9217. memory: memory,
  9218. render: render,
  9219. programs: null,
  9220. autoReset: true,
  9221. reset: reset,
  9222. update: update
  9223. };
  9224. }
  9225. /**
  9226. * @author mrdoob / http://mrdoob.com/
  9227. */
  9228. function absNumericalSort(a, b) {
  9229. return Math.abs(b[1]) - Math.abs(a[1]);
  9230. }
  9231. function WebGLMorphtargets(gl) {
  9232. var influencesList = {};
  9233. var morphInfluences = new Float32Array(8);
  9234. function update(object, geometry, material, program) {
  9235. var objectInfluences = object.morphTargetInfluences;
  9236. var length = objectInfluences.length;
  9237. var influences = influencesList[geometry.id];
  9238. if (influences === undefined) {
  9239. // initialise list
  9240. influences = [];
  9241. for (var i = 0; i < length; i++) {
  9242. influences[i] = [i, 0];
  9243. }
  9244. influencesList[geometry.id] = influences;
  9245. }
  9246. var morphTargets = material.morphTargets && geometry.morphAttributes.position;
  9247. var morphNormals = material.morphNormals && geometry.morphAttributes.normal;
  9248. // Remove current morphAttributes
  9249. for (var i = 0; i < length; i++) {
  9250. var influence = influences[i];
  9251. if (influence[1] !== 0) {
  9252. if (morphTargets) geometry.removeAttribute('morphTarget' + i);
  9253. if (morphNormals) geometry.removeAttribute('morphNormal' + i);
  9254. }
  9255. }
  9256. // Collect influences
  9257. for (var i = 0; i < length; i++) {
  9258. var influence = influences[i];
  9259. influence[0] = i;
  9260. influence[1] = objectInfluences[i];
  9261. }
  9262. influences.sort(absNumericalSort);
  9263. // Add morphAttributes
  9264. for (var i = 0; i < 8; i++) {
  9265. var influence = influences[i];
  9266. if (influence) {
  9267. var index = influence[0];
  9268. var value = influence[1];
  9269. if (value) {
  9270. if (morphTargets) geometry.addAttribute('morphTarget' + i, morphTargets[index]);
  9271. if (morphNormals) geometry.addAttribute('morphNormal' + i, morphNormals[index]);
  9272. morphInfluences[i] = value;
  9273. continue;
  9274. }
  9275. }
  9276. morphInfluences[i] = 0;
  9277. }
  9278. program.getUniforms().setValue(gl, 'morphTargetInfluences', morphInfluences);
  9279. }
  9280. return {
  9281. update: update
  9282. };
  9283. }
  9284. /**
  9285. * @author mrdoob / http://mrdoob.com/
  9286. */
  9287. function WebGLObjects(geometries, info) {
  9288. var updateList = {};
  9289. function update(object) {
  9290. var frame = info.render.frame;
  9291. var geometry = object.geometry;
  9292. var buffergeometry = geometries.get(object, geometry);
  9293. // Update once per frame
  9294. if (updateList[buffergeometry.id] !== frame) {
  9295. if (geometry.isGeometry) {
  9296. buffergeometry.updateFromObject(object);
  9297. }
  9298. geometries.update(buffergeometry);
  9299. updateList[buffergeometry.id] = frame;
  9300. }
  9301. return buffergeometry;
  9302. }
  9303. function dispose() {
  9304. updateList = {};
  9305. }
  9306. return {
  9307. update: update,
  9308. dispose: dispose
  9309. };
  9310. }
  9311. /**
  9312. * @author mrdoob / http://mrdoob.com/
  9313. */
  9314. function CubeTexture(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding) {
  9315. images = images !== undefined ? images : [];
  9316. mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
  9317. Texture.call(this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding);
  9318. this.flipY = false;
  9319. }
  9320. CubeTexture.prototype = Object.create(Texture.prototype);
  9321. CubeTexture.prototype.constructor = CubeTexture;
  9322. CubeTexture.prototype.isCubeTexture = true;
  9323. Object.defineProperty(CubeTexture.prototype, 'images', {
  9324. get: function () {
  9325. return this.image;
  9326. },
  9327. set: function (value) {
  9328. this.image = value;
  9329. }
  9330. });
  9331. /**
  9332. * @author tschw
  9333. *
  9334. * Uniforms of a program.
  9335. * Those form a tree structure with a special top-level container for the root,
  9336. * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
  9337. *
  9338. *
  9339. * Properties of inner nodes including the top-level container:
  9340. *
  9341. * .seq - array of nested uniforms
  9342. * .map - nested uniforms by name
  9343. *
  9344. *
  9345. * Methods of all nodes except the top-level container:
  9346. *
  9347. * .setValue( gl, value, [renderer] )
  9348. *
  9349. * uploads a uniform value(s)
  9350. * the 'renderer' parameter is needed for sampler uniforms
  9351. *
  9352. *
  9353. * Static methods of the top-level container (renderer factorizations):
  9354. *
  9355. * .upload( gl, seq, values, renderer )
  9356. *
  9357. * sets uniforms in 'seq' to 'values[id].value'
  9358. *
  9359. * .seqWithValue( seq, values ) : filteredSeq
  9360. *
  9361. * filters 'seq' entries with corresponding entry in values
  9362. *
  9363. *
  9364. * Methods of the top-level container (renderer factorizations):
  9365. *
  9366. * .setValue( gl, name, value )
  9367. *
  9368. * sets uniform with name 'name' to 'value'
  9369. *
  9370. * .set( gl, obj, prop )
  9371. *
  9372. * sets uniform from object and property with same name than uniform
  9373. *
  9374. * .setOptional( gl, obj, prop )
  9375. *
  9376. * like .set for an optional property of the object
  9377. *
  9378. */
  9379. var emptyTexture = new Texture();
  9380. var emptyCubeTexture = new CubeTexture();
  9381. // --- Base for inner nodes (including the root) ---
  9382. function UniformContainer() {
  9383. this.seq = [];
  9384. this.map = {};
  9385. }
  9386. // --- Utilities ---
  9387. // Array Caches (provide typed arrays for temporary by size)
  9388. var arrayCacheF32 = [];
  9389. var arrayCacheI32 = [];
  9390. // Float32Array caches used for uploading Matrix uniforms
  9391. var mat4array = new Float32Array(16);
  9392. var mat3array = new Float32Array(9);
  9393. var mat2array = new Float32Array(4);
  9394. // Flattening for arrays of vectors and matrices
  9395. function flatten(array, nBlocks, blockSize) {
  9396. var firstElem = array[0];
  9397. if (firstElem <= 0 || firstElem > 0) return array;
  9398. // unoptimized: ! isNaN( firstElem )
  9399. // see http://jacksondunstan.com/articles/983
  9400. var n = nBlocks * blockSize,
  9401. r = arrayCacheF32[n];
  9402. if (r === undefined) {
  9403. r = new Float32Array(n);
  9404. arrayCacheF32[n] = r;
  9405. }
  9406. if (nBlocks !== 0) {
  9407. firstElem.toArray(r, 0);
  9408. for (var i = 1, offset = 0; i !== nBlocks; ++i) {
  9409. offset += blockSize;
  9410. array[i].toArray(r, offset);
  9411. }
  9412. }
  9413. return r;
  9414. }
  9415. function arraysEqual(a, b) {
  9416. if (a.length !== b.length) return false;
  9417. for (var i = 0, l = a.length; i < l; i++) {
  9418. if (a[i] !== b[i]) return false;
  9419. }
  9420. return true;
  9421. }
  9422. function copyArray(a, b) {
  9423. for (var i = 0, l = b.length; i < l; i++) {
  9424. a[i] = b[i];
  9425. }
  9426. }
  9427. // Texture unit allocation
  9428. function allocTexUnits(renderer, n) {
  9429. var r = arrayCacheI32[n];
  9430. if (r === undefined) {
  9431. r = new Int32Array(n);
  9432. arrayCacheI32[n] = r;
  9433. }
  9434. for (var i = 0; i !== n; ++i) r[i] = renderer.allocTextureUnit();
  9435. return r;
  9436. }
  9437. // --- Setters ---
  9438. // Note: Defining these methods externally, because they come in a bunch
  9439. // and this way their names minify.
  9440. // Single scalar
  9441. function setValue1f(gl, v) {
  9442. var cache = this.cache;
  9443. if (cache[0] === v) return;
  9444. gl.uniform1f(this.addr, v);
  9445. cache[0] = v;
  9446. }
  9447. function setValue1i(gl, v) {
  9448. var cache = this.cache;
  9449. if (cache[0] === v) return;
  9450. gl.uniform1i(this.addr, v);
  9451. cache[0] = v;
  9452. }
  9453. // Single float vector (from flat array or THREE.VectorN)
  9454. function setValue2fv(gl, v) {
  9455. var cache = this.cache;
  9456. if (v.x !== undefined) {
  9457. if (cache[0] !== v.x || cache[1] !== v.y) {
  9458. gl.uniform2f(this.addr, v.x, v.y);
  9459. cache[0] = v.x;
  9460. cache[1] = v.y;
  9461. }
  9462. } else {
  9463. if (arraysEqual(cache, v)) return;
  9464. gl.uniform2fv(this.addr, v);
  9465. copyArray(cache, v);
  9466. }
  9467. }
  9468. function setValue3fv(gl, v) {
  9469. var cache = this.cache;
  9470. if (v.x !== undefined) {
  9471. if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) {
  9472. gl.uniform3f(this.addr, v.x, v.y, v.z);
  9473. cache[0] = v.x;
  9474. cache[1] = v.y;
  9475. cache[2] = v.z;
  9476. }
  9477. } else if (v.r !== undefined) {
  9478. if (cache[0] !== v.r || cache[1] !== v.g || cache[2] !== v.b) {
  9479. gl.uniform3f(this.addr, v.r, v.g, v.b);
  9480. cache[0] = v.r;
  9481. cache[1] = v.g;
  9482. cache[2] = v.b;
  9483. }
  9484. } else {
  9485. if (arraysEqual(cache, v)) return;
  9486. gl.uniform3fv(this.addr, v);
  9487. copyArray(cache, v);
  9488. }
  9489. }
  9490. function setValue4fv(gl, v) {
  9491. var cache = this.cache;
  9492. if (v.x !== undefined) {
  9493. if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) {
  9494. gl.uniform4f(this.addr, v.x, v.y, v.z, v.w);
  9495. cache[0] = v.x;
  9496. cache[1] = v.y;
  9497. cache[2] = v.z;
  9498. cache[3] = v.w;
  9499. }
  9500. } else {
  9501. if (arraysEqual(cache, v)) return;
  9502. gl.uniform4fv(this.addr, v);
  9503. copyArray(cache, v);
  9504. }
  9505. }
  9506. // Single matrix (from flat array or MatrixN)
  9507. function setValue2fm(gl, v) {
  9508. var cache = this.cache;
  9509. var elements = v.elements;
  9510. if (elements === undefined) {
  9511. if (arraysEqual(cache, v)) return;
  9512. gl.uniformMatrix2fv(this.addr, false, v);
  9513. copyArray(cache, v);
  9514. } else {
  9515. if (arraysEqual(cache, elements)) return;
  9516. mat2array.set(elements);
  9517. gl.uniformMatrix2fv(this.addr, false, mat2array);
  9518. copyArray(cache, elements);
  9519. }
  9520. }
  9521. function setValue3fm(gl, v) {
  9522. var cache = this.cache;
  9523. var elements = v.elements;
  9524. if (elements === undefined) {
  9525. if (arraysEqual(cache, v)) return;
  9526. gl.uniformMatrix3fv(this.addr, false, v);
  9527. copyArray(cache, v);
  9528. } else {
  9529. if (arraysEqual(cache, elements)) return;
  9530. mat3array.set(elements);
  9531. gl.uniformMatrix3fv(this.addr, false, mat3array);
  9532. copyArray(cache, elements);
  9533. }
  9534. }
  9535. function setValue4fm(gl, v) {
  9536. var cache = this.cache;
  9537. var elements = v.elements;
  9538. if (elements === undefined) {
  9539. if (arraysEqual(cache, v)) return;
  9540. gl.uniformMatrix4fv(this.addr, false, v);
  9541. copyArray(cache, v);
  9542. } else {
  9543. if (arraysEqual(cache, elements)) return;
  9544. mat4array.set(elements);
  9545. gl.uniformMatrix4fv(this.addr, false, mat4array);
  9546. copyArray(cache, elements);
  9547. }
  9548. }
  9549. // Single texture (2D / Cube)
  9550. function setValueT1(gl, v, renderer) {
  9551. var cache = this.cache;
  9552. var unit = renderer.allocTextureUnit();
  9553. if (cache[0] !== unit) {
  9554. gl.uniform1i(this.addr, unit);
  9555. cache[0] = unit;
  9556. }
  9557. renderer.setTexture2D(v || emptyTexture, unit);
  9558. }
  9559. function setValueT6(gl, v, renderer) {
  9560. var cache = this.cache;
  9561. var unit = renderer.allocTextureUnit();
  9562. if (cache[0] !== unit) {
  9563. gl.uniform1i(this.addr, unit);
  9564. cache[0] = unit;
  9565. }
  9566. renderer.setTextureCube(v || emptyCubeTexture, unit);
  9567. }
  9568. // Integer / Boolean vectors or arrays thereof (always flat arrays)
  9569. function setValue2iv(gl, v) {
  9570. var cache = this.cache;
  9571. if (arraysEqual(cache, v)) return;
  9572. gl.uniform2iv(this.addr, v);
  9573. copyArray(cache, v);
  9574. }
  9575. function setValue3iv(gl, v) {
  9576. var cache = this.cache;
  9577. if (arraysEqual(cache, v)) return;
  9578. gl.uniform3iv(this.addr, v);
  9579. copyArray(cache, v);
  9580. }
  9581. function setValue4iv(gl, v) {
  9582. var cache = this.cache;
  9583. if (arraysEqual(cache, v)) return;
  9584. gl.uniform4iv(this.addr, v);
  9585. copyArray(cache, v);
  9586. }
  9587. // Helper to pick the right setter for the singular case
  9588. function getSingularSetter(type) {
  9589. switch (type) {
  9590. case 0x1406:
  9591. return setValue1f; // FLOAT
  9592. case 0x8b50:
  9593. return setValue2fv; // _VEC2
  9594. case 0x8b51:
  9595. return setValue3fv; // _VEC3
  9596. case 0x8b52:
  9597. return setValue4fv; // _VEC4
  9598. case 0x8b5a:
  9599. return setValue2fm; // _MAT2
  9600. case 0x8b5b:
  9601. return setValue3fm; // _MAT3
  9602. case 0x8b5c:
  9603. return setValue4fm; // _MAT4
  9604. case 0x8b5e:case 0x8d66:
  9605. return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
  9606. case 0x8b60:
  9607. return setValueT6; // SAMPLER_CUBE
  9608. case 0x1404:case 0x8b56:
  9609. return setValue1i; // INT, BOOL
  9610. case 0x8b53:case 0x8b57:
  9611. return setValue2iv; // _VEC2
  9612. case 0x8b54:case 0x8b58:
  9613. return setValue3iv; // _VEC3
  9614. case 0x8b55:case 0x8b59:
  9615. return setValue4iv; // _VEC4
  9616. }
  9617. }
  9618. // Array of scalars
  9619. function setValue1fv(gl, v) {
  9620. var cache = this.cache;
  9621. if (arraysEqual(cache, v)) return;
  9622. gl.uniform1fv(this.addr, v);
  9623. copyArray(cache, v);
  9624. }
  9625. function setValue1iv(gl, v) {
  9626. var cache = this.cache;
  9627. if (arraysEqual(cache, v)) return;
  9628. gl.uniform1iv(this.addr, v);
  9629. copyArray(cache, v);
  9630. }
  9631. // Array of vectors (flat or from THREE classes)
  9632. function setValueV2a(gl, v) {
  9633. var cache = this.cache;
  9634. var data = flatten(v, this.size, 2);
  9635. if (arraysEqual(cache, data)) return;
  9636. gl.uniform2fv(this.addr, data);
  9637. this.updateCache(data);
  9638. }
  9639. function setValueV3a(gl, v) {
  9640. var cache = this.cache;
  9641. var data = flatten(v, this.size, 3);
  9642. if (arraysEqual(cache, data)) return;
  9643. gl.uniform3fv(this.addr, data);
  9644. this.updateCache(data);
  9645. }
  9646. function setValueV4a(gl, v) {
  9647. var cache = this.cache;
  9648. var data = flatten(v, this.size, 4);
  9649. if (arraysEqual(cache, data)) return;
  9650. gl.uniform4fv(this.addr, data);
  9651. this.updateCache(data);
  9652. }
  9653. // Array of matrices (flat or from THREE clases)
  9654. function setValueM2a(gl, v) {
  9655. var cache = this.cache;
  9656. var data = flatten(v, this.size, 4);
  9657. if (arraysEqual(cache, data)) return;
  9658. gl.uniformMatrix2fv(this.addr, false, data);
  9659. this.updateCache(data);
  9660. }
  9661. function setValueM3a(gl, v) {
  9662. var cache = this.cache;
  9663. var data = flatten(v, this.size, 9);
  9664. if (arraysEqual(cache, data)) return;
  9665. gl.uniformMatrix3fv(this.addr, false, data);
  9666. this.updateCache(data);
  9667. }
  9668. function setValueM4a(gl, v) {
  9669. var cache = this.cache;
  9670. var data = flatten(v, this.size, 16);
  9671. if (arraysEqual(cache, data)) return;
  9672. gl.uniformMatrix4fv(this.addr, false, data);
  9673. this.updateCache(data);
  9674. }
  9675. // Array of textures (2D / Cube)
  9676. function setValueT1a(gl, v, renderer) {
  9677. var cache = this.cache;
  9678. var n = v.length;
  9679. var units = allocTexUnits(renderer, n);
  9680. if (arraysEqual(cache, units) === false) {
  9681. gl.uniform1iv(this.addr, units);
  9682. copyArray(cache, units);
  9683. }
  9684. for (var i = 0; i !== n; ++i) {
  9685. renderer.setTexture2D(v[i] || emptyTexture, units[i]);
  9686. }
  9687. }
  9688. function setValueT6a(gl, v, renderer) {
  9689. var cache = this.cache;
  9690. var n = v.length;
  9691. var units = allocTexUnits(renderer, n);
  9692. if (arraysEqual(cache, units) === false) {
  9693. gl.uniform1iv(this.addr, units);
  9694. copyArray(cache, units);
  9695. }
  9696. for (var i = 0; i !== n; ++i) {
  9697. renderer.setTextureCube(v[i] || emptyCubeTexture, units[i]);
  9698. }
  9699. }
  9700. // Helper to pick the right setter for a pure (bottom-level) array
  9701. function getPureArraySetter(type) {
  9702. switch (type) {
  9703. case 0x1406:
  9704. return setValue1fv; // FLOAT
  9705. case 0x8b50:
  9706. return setValueV2a; // _VEC2
  9707. case 0x8b51:
  9708. return setValueV3a; // _VEC3
  9709. case 0x8b52:
  9710. return setValueV4a; // _VEC4
  9711. case 0x8b5a:
  9712. return setValueM2a; // _MAT2
  9713. case 0x8b5b:
  9714. return setValueM3a; // _MAT3
  9715. case 0x8b5c:
  9716. return setValueM4a; // _MAT4
  9717. case 0x8b5e:
  9718. return setValueT1a; // SAMPLER_2D
  9719. case 0x8b60:
  9720. return setValueT6a; // SAMPLER_CUBE
  9721. case 0x1404:case 0x8b56:
  9722. return setValue1iv; // INT, BOOL
  9723. case 0x8b53:case 0x8b57:
  9724. return setValue2iv; // _VEC2
  9725. case 0x8b54:case 0x8b58:
  9726. return setValue3iv; // _VEC3
  9727. case 0x8b55:case 0x8b59:
  9728. return setValue4iv; // _VEC4
  9729. }
  9730. }
  9731. // --- Uniform Classes ---
  9732. function SingleUniform(id, activeInfo, addr) {
  9733. this.id = id;
  9734. this.addr = addr;
  9735. this.cache = [];
  9736. this.setValue = getSingularSetter(activeInfo.type);
  9737. // this.path = activeInfo.name; // DEBUG
  9738. }
  9739. function PureArrayUniform(id, activeInfo, addr) {
  9740. this.id = id;
  9741. this.addr = addr;
  9742. this.cache = [];
  9743. this.size = activeInfo.size;
  9744. this.setValue = getPureArraySetter(activeInfo.type);
  9745. // this.path = activeInfo.name; // DEBUG
  9746. }
  9747. PureArrayUniform.prototype.updateCache = function (data) {
  9748. var cache = this.cache;
  9749. if (data instanceof Float32Array && cache.length !== data.length) {
  9750. this.cache = new Float32Array(data.length);
  9751. }
  9752. copyArray(cache, data);
  9753. };
  9754. function StructuredUniform(id) {
  9755. this.id = id;
  9756. UniformContainer.call(this); // mix-in
  9757. }
  9758. StructuredUniform.prototype.setValue = function (gl, value) {
  9759. // Note: Don't need an extra 'renderer' parameter, since samplers
  9760. // are not allowed in structured uniforms.
  9761. var seq = this.seq;
  9762. for (var i = 0, n = seq.length; i !== n; ++i) {
  9763. var u = seq[i];
  9764. u.setValue(gl, value[u.id]);
  9765. }
  9766. };
  9767. // --- Top-level ---
  9768. // Parser - builds up the property tree from the path strings
  9769. var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
  9770. // extracts
  9771. // - the identifier (member name or array index)
  9772. // - followed by an optional right bracket (found when array index)
  9773. // - followed by an optional left bracket or dot (type of subscript)
  9774. //
  9775. // Note: These portions can be read in a non-overlapping fashion and
  9776. // allow straightforward parsing of the hierarchy that WebGL encodes
  9777. // in the uniform names.
  9778. function addUniform(container, uniformObject) {
  9779. container.seq.push(uniformObject);
  9780. container.map[uniformObject.id] = uniformObject;
  9781. }
  9782. function parseUniform(activeInfo, addr, container) {
  9783. var path = activeInfo.name,
  9784. pathLength = path.length;
  9785. // reset RegExp object, because of the early exit of a previous run
  9786. RePathPart.lastIndex = 0;
  9787. while (true) {
  9788. var match = RePathPart.exec(path),
  9789. matchEnd = RePathPart.lastIndex,
  9790. id = match[1],
  9791. idIsIndex = match[2] === ']',
  9792. subscript = match[3];
  9793. if (idIsIndex) id = id | 0; // convert to integer
  9794. if (subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength) {
  9795. // bare name or "pure" bottom-level array "[0]" suffix
  9796. addUniform(container, subscript === undefined ? new SingleUniform(id, activeInfo, addr) : new PureArrayUniform(id, activeInfo, addr));
  9797. break;
  9798. } else {
  9799. // step into inner node / create it in case it doesn't exist
  9800. var map = container.map,
  9801. next = map[id];
  9802. if (next === undefined) {
  9803. next = new StructuredUniform(id);
  9804. addUniform(container, next);
  9805. }
  9806. container = next;
  9807. }
  9808. }
  9809. }
  9810. // Root Container
  9811. function WebGLUniforms(gl, program, renderer) {
  9812. UniformContainer.call(this);
  9813. this.renderer = renderer;
  9814. var n = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  9815. for (var i = 0; i < n; ++i) {
  9816. var info = gl.getActiveUniform(program, i),
  9817. addr = gl.getUniformLocation(program, info.name);
  9818. parseUniform(info, addr, this);
  9819. }
  9820. }
  9821. WebGLUniforms.prototype.setValue = function (gl, name, value) {
  9822. var u = this.map[name];
  9823. if (u !== undefined) u.setValue(gl, value, this.renderer);
  9824. };
  9825. WebGLUniforms.prototype.setOptional = function (gl, object, name) {
  9826. var v = object[name];
  9827. if (v !== undefined) this.setValue(gl, name, v);
  9828. };
  9829. // Static interface
  9830. WebGLUniforms.upload = function (gl, seq, values, renderer) {
  9831. for (var i = 0, n = seq.length; i !== n; ++i) {
  9832. var u = seq[i],
  9833. v = values[u.id];
  9834. if (v.needsUpdate !== false) {
  9835. // note: always updating when .needsUpdate is undefined
  9836. u.setValue(gl, v.value, renderer);
  9837. }
  9838. }
  9839. };
  9840. WebGLUniforms.seqWithValue = function (seq, values) {
  9841. var r = [];
  9842. for (var i = 0, n = seq.length; i !== n; ++i) {
  9843. var u = seq[i];
  9844. if (u.id in values) r.push(u);
  9845. }
  9846. return r;
  9847. };
  9848. /**
  9849. * @author mrdoob / http://mrdoob.com/
  9850. */
  9851. function addLineNumbers(string) {
  9852. var lines = string.split('\n');
  9853. for (var i = 0; i < lines.length; i++) {
  9854. lines[i] = i + 1 + ': ' + lines[i];
  9855. }
  9856. return lines.join('\n');
  9857. }
  9858. function WebGLShader(gl, type, string) {
  9859. var shader = gl.createShader(type);
  9860. gl.shaderSource(shader, string);
  9861. gl.compileShader(shader);
  9862. if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === false) {
  9863. console.error('THREE.WebGLShader: Shader couldn\'t compile.');
  9864. }
  9865. if (gl.getShaderInfoLog(shader) !== '') {
  9866. console.warn('THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog(shader), addLineNumbers(string));
  9867. }
  9868. // --enable-privileged-webgl-extension
  9869. // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
  9870. return shader;
  9871. }
  9872. /**
  9873. * @author mrdoob / http://mrdoob.com/
  9874. */
  9875. var programIdCount = 0;
  9876. function getEncodingComponents(encoding) {
  9877. switch (encoding) {
  9878. case LinearEncoding:
  9879. return ['Linear', '( value )'];
  9880. case sRGBEncoding:
  9881. return ['sRGB', '( value )'];
  9882. case RGBEEncoding:
  9883. return ['RGBE', '( value )'];
  9884. case RGBM7Encoding:
  9885. return ['RGBM', '( value, 7.0 )'];
  9886. case RGBM16Encoding:
  9887. return ['RGBM', '( value, 16.0 )'];
  9888. case RGBDEncoding:
  9889. return ['RGBD', '( value, 256.0 )'];
  9890. case GammaEncoding:
  9891. return ['Gamma', '( value, float( GAMMA_FACTOR ) )'];
  9892. default:
  9893. throw new Error('unsupported encoding: ' + encoding);
  9894. }
  9895. }
  9896. function getTexelDecodingFunction(functionName, encoding) {
  9897. var components = getEncodingComponents(encoding);
  9898. return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[0] + 'ToLinear' + components[1] + '; }';
  9899. }
  9900. function getTexelEncodingFunction(functionName, encoding) {
  9901. var components = getEncodingComponents(encoding);
  9902. return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[0] + components[1] + '; }';
  9903. }
  9904. function getToneMappingFunction(functionName, toneMapping) {
  9905. var toneMappingName;
  9906. switch (toneMapping) {
  9907. case LinearToneMapping:
  9908. toneMappingName = 'Linear';
  9909. break;
  9910. case ReinhardToneMapping:
  9911. toneMappingName = 'Reinhard';
  9912. break;
  9913. case Uncharted2ToneMapping:
  9914. toneMappingName = 'Uncharted2';
  9915. break;
  9916. case CineonToneMapping:
  9917. toneMappingName = 'OptimizedCineon';
  9918. break;
  9919. default:
  9920. throw new Error('unsupported toneMapping: ' + toneMapping);
  9921. }
  9922. return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
  9923. }
  9924. function generateExtensions(extensions, parameters, rendererExtensions) {
  9925. extensions = extensions || {};
  9926. 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' : ''];
  9927. return chunks.filter(filterEmptyLine).join('\n');
  9928. }
  9929. function generateDefines(defines) {
  9930. var chunks = [];
  9931. for (var name in defines) {
  9932. var value = defines[name];
  9933. if (value === false) continue;
  9934. chunks.push('#define ' + name + ' ' + value);
  9935. }
  9936. return chunks.join('\n');
  9937. }
  9938. function fetchAttributeLocations(gl, program) {
  9939. var attributes = {};
  9940. var n = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
  9941. for (var i = 0; i < n; i++) {
  9942. var info = gl.getActiveAttrib(program, i);
  9943. var name = info.name;
  9944. // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
  9945. attributes[name] = gl.getAttribLocation(program, name);
  9946. }
  9947. return attributes;
  9948. }
  9949. function filterEmptyLine(string) {
  9950. return string !== '';
  9951. }
  9952. function replaceLightNums(string, parameters) {
  9953. 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);
  9954. }
  9955. function replaceClippingPlaneNums(string, parameters) {
  9956. return string.replace(/NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g, parameters.numClippingPlanes - parameters.numClipIntersection);
  9957. }
  9958. function parseIncludes(string) {
  9959. var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;
  9960. function replace(match, include) {
  9961. var replace = ShaderChunk[include];
  9962. if (replace === undefined) {
  9963. throw new Error('Can not resolve #include <' + include + '>');
  9964. }
  9965. return parseIncludes(replace);
  9966. }
  9967. return string.replace(pattern, replace);
  9968. }
  9969. function unrollLoops(string) {
  9970. var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
  9971. function replace(match, start, end, snippet) {
  9972. var unroll = '';
  9973. for (var i = parseInt(start); i < parseInt(end); i++) {
  9974. unroll += snippet.replace(/\[ i \]/g, '[ ' + i + ' ]');
  9975. }
  9976. return unroll;
  9977. }
  9978. return string.replace(pattern, replace);
  9979. }
  9980. function WebGLProgram(renderer, extensions, code, material, shader, parameters) {
  9981. var gl = renderer.context;
  9982. var defines = material.defines;
  9983. var vertexShader = shader.vertexShader;
  9984. var fragmentShader = shader.fragmentShader;
  9985. var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
  9986. if (parameters.shadowMapType === PCFShadowMap) {
  9987. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
  9988. } else if (parameters.shadowMapType === PCFSoftShadowMap) {
  9989. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
  9990. }
  9991. var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  9992. var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
  9993. var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
  9994. if (parameters.envMap) {
  9995. switch (material.envMap.mapping) {
  9996. case CubeReflectionMapping:
  9997. case CubeRefractionMapping:
  9998. envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  9999. break;
  10000. case CubeUVReflectionMapping:
  10001. case CubeUVRefractionMapping:
  10002. envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
  10003. break;
  10004. case EquirectangularReflectionMapping:
  10005. case EquirectangularRefractionMapping:
  10006. envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
  10007. break;
  10008. case SphericalReflectionMapping:
  10009. envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
  10010. break;
  10011. }
  10012. switch (material.envMap.mapping) {
  10013. case CubeRefractionMapping:
  10014. case EquirectangularRefractionMapping:
  10015. envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
  10016. break;
  10017. }
  10018. switch (material.combine) {
  10019. case MultiplyOperation:
  10020. envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
  10021. break;
  10022. case MixOperation:
  10023. envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
  10024. break;
  10025. case AddOperation:
  10026. envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
  10027. break;
  10028. }
  10029. }
  10030. var gammaFactorDefine = renderer.gammaFactor > 0 ? renderer.gammaFactor : 1.0;
  10031. // console.log( 'building new program ' );
  10032. //
  10033. var customExtensions = generateExtensions(material.extensions, parameters, extensions);
  10034. var customDefines = generateDefines(defines);
  10035. //
  10036. var program = gl.createProgram();
  10037. var prefixVertex, prefixFragment;
  10038. if (material.isRawShaderMaterial) {
  10039. prefixVertex = [customDefines].filter(filterEmptyLine).join('\n');
  10040. if (prefixVertex.length > 0) {
  10041. prefixVertex += '\n';
  10042. }
  10043. prefixFragment = [customExtensions, customDefines].filter(filterEmptyLine).join('\n');
  10044. if (prefixFragment.length > 0) {
  10045. prefixFragment += '\n';
  10046. }
  10047. } else {
  10048. 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' : '', parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', parameters.logarithmicDepthBuffer && 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');
  10049. prefixFragment = [customExtensions, 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', '#define SHADER_NAME ' + shader.name, customDefines, parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + (parameters.alphaTest % 1 ? '' : '.0') : '', // add '.0' if integer
  10050. '#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' : '', 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 && extensions.get('EXT_frag_depth') ? '#define USE_LOGDEPTHBUF_EXT' : '', parameters.envMap && 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
  10051. 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
  10052. 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');
  10053. }
  10054. vertexShader = parseIncludes(vertexShader);
  10055. vertexShader = replaceLightNums(vertexShader, parameters);
  10056. vertexShader = replaceClippingPlaneNums(vertexShader, parameters);
  10057. fragmentShader = parseIncludes(fragmentShader);
  10058. fragmentShader = replaceLightNums(fragmentShader, parameters);
  10059. fragmentShader = replaceClippingPlaneNums(fragmentShader, parameters);
  10060. vertexShader = unrollLoops(vertexShader);
  10061. fragmentShader = unrollLoops(fragmentShader);
  10062. var vertexGlsl = prefixVertex + vertexShader;
  10063. var fragmentGlsl = prefixFragment + fragmentShader;
  10064. // console.log( '*VERTEX*', vertexGlsl );
  10065. // console.log( '*FRAGMENT*', fragmentGlsl );
  10066. var glVertexShader = WebGLShader(gl, gl.VERTEX_SHADER, vertexGlsl);
  10067. var glFragmentShader = WebGLShader(gl, gl.FRAGMENT_SHADER, fragmentGlsl);
  10068. gl.attachShader(program, glVertexShader);
  10069. gl.attachShader(program, glFragmentShader);
  10070. // Force a particular attribute to index 0.
  10071. if (material.index0AttributeName !== undefined) {
  10072. gl.bindAttribLocation(program, 0, material.index0AttributeName);
  10073. } else if (parameters.morphTargets === true) {
  10074. // programs with morphTargets displace position out of attribute 0
  10075. gl.bindAttribLocation(program, 0, 'position');
  10076. }
  10077. gl.linkProgram(program);
  10078. var programLog = gl.getProgramInfoLog(program).trim();
  10079. var vertexLog = gl.getShaderInfoLog(glVertexShader).trim();
  10080. var fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim();
  10081. var runnable = true;
  10082. var haveDiagnostics = true;
  10083. // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
  10084. // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
  10085. if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) {
  10086. runnable = false;
  10087. console.error('THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter(program, gl.VALIDATE_STATUS), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog);
  10088. } else if (programLog !== '') {
  10089. console.warn('THREE.WebGLProgram: gl.getProgramInfoLog()', programLog);
  10090. } else if (vertexLog === '' || fragmentLog === '') {
  10091. haveDiagnostics = false;
  10092. }
  10093. if (haveDiagnostics) {
  10094. this.diagnostics = {
  10095. runnable: runnable,
  10096. material: material,
  10097. programLog: programLog,
  10098. vertexShader: {
  10099. log: vertexLog,
  10100. prefix: prefixVertex
  10101. },
  10102. fragmentShader: {
  10103. log: fragmentLog,
  10104. prefix: prefixFragment
  10105. }
  10106. };
  10107. }
  10108. // clean up
  10109. gl.deleteShader(glVertexShader);
  10110. gl.deleteShader(glFragmentShader);
  10111. // set up caching for uniform locations
  10112. var cachedUniforms;
  10113. this.getUniforms = function () {
  10114. if (cachedUniforms === undefined) {
  10115. cachedUniforms = new WebGLUniforms(gl, program, renderer);
  10116. }
  10117. return cachedUniforms;
  10118. };
  10119. // set up caching for attribute locations
  10120. var cachedAttributes;
  10121. this.getAttributes = function () {
  10122. if (cachedAttributes === undefined) {
  10123. cachedAttributes = fetchAttributeLocations(gl, program);
  10124. }
  10125. return cachedAttributes;
  10126. };
  10127. // free resource
  10128. this.destroy = function () {
  10129. gl.deleteProgram(program);
  10130. this.program = undefined;
  10131. };
  10132. // DEPRECATED
  10133. Object.defineProperties(this, {
  10134. uniforms: {
  10135. get: function () {
  10136. console.warn('THREE.WebGLProgram: .uniforms is now .getUniforms().');
  10137. return this.getUniforms();
  10138. }
  10139. },
  10140. attributes: {
  10141. get: function () {
  10142. console.warn('THREE.WebGLProgram: .attributes is now .getAttributes().');
  10143. return this.getAttributes();
  10144. }
  10145. }
  10146. });
  10147. //
  10148. this.name = shader.name;
  10149. this.id = programIdCount++;
  10150. this.code = code;
  10151. this.usedTimes = 1;
  10152. this.program = program;
  10153. this.vertexShader = glVertexShader;
  10154. this.fragmentShader = glFragmentShader;
  10155. return this;
  10156. }
  10157. /**
  10158. * @author mrdoob / http://mrdoob.com/
  10159. */
  10160. function WebGLPrograms(renderer, extensions, capabilities) {
  10161. var programs = [];
  10162. var shaderIDs = {
  10163. MeshDepthMaterial: 'depth',
  10164. MeshDistanceMaterial: 'distanceRGBA',
  10165. MeshNormalMaterial: 'normal',
  10166. MeshBasicMaterial: 'basic',
  10167. MeshLambertMaterial: 'lambert',
  10168. MeshPhongMaterial: 'phong',
  10169. MeshToonMaterial: 'phong',
  10170. MeshStandardMaterial: 'physical',
  10171. MeshPhysicalMaterial: 'physical',
  10172. LineBasicMaterial: 'basic',
  10173. LineDashedMaterial: 'dashed',
  10174. PointsMaterial: 'points',
  10175. ShadowMaterial: 'shadow'
  10176. };
  10177. 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"];
  10178. function allocateBones(object) {
  10179. var skeleton = object.skeleton;
  10180. var bones = skeleton.bones;
  10181. if (capabilities.floatVertexTextures) {
  10182. return 1024;
  10183. } else {
  10184. // default for when object is not specified
  10185. // ( for example when prebuilding shader to be used with multiple objects )
  10186. //
  10187. // - leave some extra space for other uniforms
  10188. // - limit here is ANGLE's 254 max uniform vectors
  10189. // (up to 54 should be safe)
  10190. var nVertexUniforms = capabilities.maxVertexUniforms;
  10191. var nVertexMatrices = Math.floor((nVertexUniforms - 20) / 4);
  10192. var maxBones = Math.min(nVertexMatrices, bones.length);
  10193. if (maxBones < bones.length) {
  10194. console.warn('THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.');
  10195. return 0;
  10196. }
  10197. return maxBones;
  10198. }
  10199. }
  10200. function getTextureEncodingFromMap(map, gammaOverrideLinear) {
  10201. var encoding;
  10202. if (!map) {
  10203. encoding = LinearEncoding;
  10204. } else if (map.isTexture) {
  10205. encoding = map.encoding;
  10206. } else if (map.isWebGLRenderTarget) {
  10207. console.warn("THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead.");
  10208. encoding = map.texture.encoding;
  10209. }
  10210. // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
  10211. if (encoding === LinearEncoding && gammaOverrideLinear) {
  10212. encoding = GammaEncoding;
  10213. }
  10214. return encoding;
  10215. }
  10216. this.getParameters = function (material, lights, shadows, fog, nClipPlanes, nClipIntersection, object) {
  10217. var shaderID = shaderIDs[material.type];
  10218. // heuristics to create shader parameters according to lights in the scene
  10219. // (not to blow over maxLights budget)
  10220. var maxBones = object.isSkinnedMesh ? allocateBones(object) : 0;
  10221. var precision = capabilities.precision;
  10222. if (material.precision !== null) {
  10223. precision = capabilities.getMaxPrecision(material.precision);
  10224. if (precision !== material.precision) {
  10225. console.warn('THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.');
  10226. }
  10227. }
  10228. var currentRenderTarget = renderer.getRenderTarget();
  10229. var parameters = {
  10230. shaderID: shaderID,
  10231. precision: precision,
  10232. supportsVertexTextures: capabilities.vertexTextures,
  10233. outputEncoding: getTextureEncodingFromMap(!currentRenderTarget ? null : currentRenderTarget.texture, renderer.gammaOutput),
  10234. map: !!material.map,
  10235. mapEncoding: getTextureEncodingFromMap(material.map, renderer.gammaInput),
  10236. envMap: !!material.envMap,
  10237. envMapMode: material.envMap && material.envMap.mapping,
  10238. envMapEncoding: getTextureEncodingFromMap(material.envMap, renderer.gammaInput),
  10239. envMapCubeUV: !!material.envMap && (material.envMap.mapping === CubeUVReflectionMapping || material.envMap.mapping === CubeUVRefractionMapping),
  10240. lightMap: !!material.lightMap,
  10241. aoMap: !!material.aoMap,
  10242. emissiveMap: !!material.emissiveMap,
  10243. emissiveMapEncoding: getTextureEncodingFromMap(material.emissiveMap, renderer.gammaInput),
  10244. bumpMap: !!material.bumpMap,
  10245. normalMap: !!material.normalMap,
  10246. displacementMap: !!material.displacementMap,
  10247. roughnessMap: !!material.roughnessMap,
  10248. metalnessMap: !!material.metalnessMap,
  10249. specularMap: !!material.specularMap,
  10250. alphaMap: !!material.alphaMap,
  10251. gradientMap: !!material.gradientMap,
  10252. combine: material.combine,
  10253. vertexColors: material.vertexColors,
  10254. fog: !!fog,
  10255. useFog: material.fog,
  10256. fogExp: fog && fog.isFogExp2,
  10257. flatShading: material.flatShading,
  10258. sizeAttenuation: material.sizeAttenuation,
  10259. logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
  10260. skinning: material.skinning && maxBones > 0,
  10261. maxBones: maxBones,
  10262. useVertexTexture: capabilities.floatVertexTextures,
  10263. morphTargets: material.morphTargets,
  10264. morphNormals: material.morphNormals,
  10265. maxMorphTargets: renderer.maxMorphTargets,
  10266. maxMorphNormals: renderer.maxMorphNormals,
  10267. numDirLights: lights.directional.length,
  10268. numPointLights: lights.point.length,
  10269. numSpotLights: lights.spot.length,
  10270. numRectAreaLights: lights.rectArea.length,
  10271. numHemiLights: lights.hemi.length,
  10272. numClippingPlanes: nClipPlanes,
  10273. numClipIntersection: nClipIntersection,
  10274. dithering: material.dithering,
  10275. shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,
  10276. shadowMapType: renderer.shadowMap.type,
  10277. toneMapping: renderer.toneMapping,
  10278. physicallyCorrectLights: renderer.physicallyCorrectLights,
  10279. premultipliedAlpha: material.premultipliedAlpha,
  10280. alphaTest: material.alphaTest,
  10281. doubleSided: material.side === DoubleSide,
  10282. flipSided: material.side === BackSide,
  10283. depthPacking: material.depthPacking !== undefined ? material.depthPacking : false
  10284. };
  10285. return parameters;
  10286. };
  10287. this.getProgramCode = function (material, parameters) {
  10288. var array = [];
  10289. if (parameters.shaderID) {
  10290. array.push(parameters.shaderID);
  10291. } else {
  10292. array.push(material.fragmentShader);
  10293. array.push(material.vertexShader);
  10294. }
  10295. if (material.defines !== undefined) {
  10296. for (var name in material.defines) {
  10297. array.push(name);
  10298. array.push(material.defines[name]);
  10299. }
  10300. }
  10301. for (var i = 0; i < parameterNames.length; i++) {
  10302. array.push(parameters[parameterNames[i]]);
  10303. }
  10304. array.push(material.onBeforeCompile.toString());
  10305. array.push(renderer.gammaOutput);
  10306. return array.join();
  10307. };
  10308. this.acquireProgram = function (material, shader, parameters, code) {
  10309. var program;
  10310. // Check if code has been already compiled
  10311. for (var p = 0, pl = programs.length; p < pl; p++) {
  10312. var programInfo = programs[p];
  10313. if (programInfo.code === code) {
  10314. program = programInfo;
  10315. ++program.usedTimes;
  10316. break;
  10317. }
  10318. }
  10319. if (program === undefined) {
  10320. program = new WebGLProgram(renderer, extensions, code, material, shader, parameters);
  10321. programs.push(program);
  10322. }
  10323. return program;
  10324. };
  10325. this.releaseProgram = function (program) {
  10326. if (--program.usedTimes === 0) {
  10327. // Remove from unordered set
  10328. var i = programs.indexOf(program);
  10329. programs[i] = programs[programs.length - 1];
  10330. programs.pop();
  10331. // Free WebGL resources
  10332. program.destroy();
  10333. }
  10334. };
  10335. // Exposed for resource monitoring & error feedback via renderer.info:
  10336. this.programs = programs;
  10337. }
  10338. /**
  10339. * @author fordacious / fordacious.github.io
  10340. */
  10341. function WebGLProperties() {
  10342. var properties = new WeakMap();
  10343. function get(object) {
  10344. var map = properties.get(object);
  10345. if (map === undefined) {
  10346. map = {};
  10347. properties.set(object, map);
  10348. }
  10349. return map;
  10350. }
  10351. function remove(object) {
  10352. properties.delete(object);
  10353. }
  10354. function update(object, key, value) {
  10355. properties.get(object)[key] = value;
  10356. }
  10357. function dispose() {
  10358. properties = new WeakMap();
  10359. }
  10360. return {
  10361. get: get,
  10362. remove: remove,
  10363. update: update,
  10364. dispose: dispose
  10365. };
  10366. }
  10367. /**
  10368. * @author mrdoob / http://mrdoob.com/
  10369. */
  10370. function painterSortStable(a, b) {
  10371. if (a.renderOrder !== b.renderOrder) {
  10372. return a.renderOrder - b.renderOrder;
  10373. } else if (a.program && b.program && a.program !== b.program) {
  10374. return a.program.id - b.program.id;
  10375. } else if (a.material.id !== b.material.id) {
  10376. return a.material.id - b.material.id;
  10377. } else if (a.z !== b.z) {
  10378. return a.z - b.z;
  10379. } else {
  10380. return a.id - b.id;
  10381. }
  10382. }
  10383. function reversePainterSortStable(a, b) {
  10384. if (a.renderOrder !== b.renderOrder) {
  10385. return a.renderOrder - b.renderOrder;
  10386. }if (a.z !== b.z) {
  10387. return b.z - a.z;
  10388. } else {
  10389. return a.id - b.id;
  10390. }
  10391. }
  10392. function WebGLRenderList() {
  10393. var renderItems = [];
  10394. var renderItemsIndex = 0;
  10395. var opaque = [];
  10396. var transparent = [];
  10397. function init() {
  10398. renderItemsIndex = 0;
  10399. opaque.length = 0;
  10400. transparent.length = 0;
  10401. }
  10402. function push(object, geometry, material, z, group) {
  10403. var renderItem = renderItems[renderItemsIndex];
  10404. if (renderItem === undefined) {
  10405. renderItem = {
  10406. id: object.id,
  10407. object: object,
  10408. geometry: geometry,
  10409. material: material,
  10410. program: material.program,
  10411. renderOrder: object.renderOrder,
  10412. z: z,
  10413. group: group
  10414. };
  10415. renderItems[renderItemsIndex] = renderItem;
  10416. } else {
  10417. renderItem.id = object.id;
  10418. renderItem.object = object;
  10419. renderItem.geometry = geometry;
  10420. renderItem.material = material;
  10421. renderItem.program = material.program;
  10422. renderItem.renderOrder = object.renderOrder;
  10423. renderItem.z = z;
  10424. renderItem.group = group;
  10425. }
  10426. (material.transparent === true ? transparent : opaque).push(renderItem);
  10427. renderItemsIndex++;
  10428. }
  10429. function sort() {
  10430. if (opaque.length > 1) opaque.sort(painterSortStable);
  10431. if (transparent.length > 1) transparent.sort(reversePainterSortStable);
  10432. }
  10433. return {
  10434. opaque: opaque,
  10435. transparent: transparent,
  10436. init: init,
  10437. push: push,
  10438. sort: sort
  10439. };
  10440. }
  10441. function WebGLRenderLists() {
  10442. var lists = {};
  10443. function get(scene, camera) {
  10444. var hash = scene.id + ',' + camera.id;
  10445. var list = lists[hash];
  10446. if (list === undefined) {
  10447. // console.log( 'THREE.WebGLRenderLists:', hash );
  10448. list = new WebGLRenderList();
  10449. lists[hash] = list;
  10450. }
  10451. return list;
  10452. }
  10453. function dispose() {
  10454. lists = {};
  10455. }
  10456. return {
  10457. get: get,
  10458. dispose: dispose
  10459. };
  10460. }
  10461. /**
  10462. * @author mrdoob / http://mrdoob.com/
  10463. */
  10464. function UniformsCache() {
  10465. var lights = {};
  10466. return {
  10467. get: function (light) {
  10468. if (lights[light.id] !== undefined) {
  10469. return lights[light.id];
  10470. }
  10471. var uniforms;
  10472. switch (light.type) {
  10473. case 'DirectionalLight':
  10474. uniforms = {
  10475. direction: new Vector3(),
  10476. color: new Color(),
  10477. shadow: false,
  10478. shadowBias: 0,
  10479. shadowRadius: 1,
  10480. shadowMapSize: new Vector2()
  10481. };
  10482. break;
  10483. case 'SpotLight':
  10484. uniforms = {
  10485. position: new Vector3(),
  10486. direction: new Vector3(),
  10487. color: new Color(),
  10488. distance: 0,
  10489. coneCos: 0,
  10490. penumbraCos: 0,
  10491. decay: 0,
  10492. shadow: false,
  10493. shadowBias: 0,
  10494. shadowRadius: 1,
  10495. shadowMapSize: new Vector2()
  10496. };
  10497. break;
  10498. case 'PointLight':
  10499. uniforms = {
  10500. position: new Vector3(),
  10501. color: new Color(),
  10502. distance: 0,
  10503. decay: 0,
  10504. shadow: false,
  10505. shadowBias: 0,
  10506. shadowRadius: 1,
  10507. shadowMapSize: new Vector2(),
  10508. shadowCameraNear: 1,
  10509. shadowCameraFar: 1000
  10510. };
  10511. break;
  10512. case 'HemisphereLight':
  10513. uniforms = {
  10514. direction: new Vector3(),
  10515. skyColor: new Color(),
  10516. groundColor: new Color()
  10517. };
  10518. break;
  10519. case 'RectAreaLight':
  10520. uniforms = {
  10521. color: new Color(),
  10522. position: new Vector3(),
  10523. halfWidth: new Vector3(),
  10524. halfHeight: new Vector3()
  10525. // TODO (abelnation): set RectAreaLight shadow uniforms
  10526. };
  10527. break;
  10528. }
  10529. lights[light.id] = uniforms;
  10530. return uniforms;
  10531. }
  10532. };
  10533. }
  10534. var count = 0;
  10535. function WebGLLights() {
  10536. var cache = new UniformsCache();
  10537. var state = {
  10538. id: count++,
  10539. hash: '',
  10540. ambient: [0, 0, 0],
  10541. directional: [],
  10542. directionalShadowMap: [],
  10543. directionalShadowMatrix: [],
  10544. spot: [],
  10545. spotShadowMap: [],
  10546. spotShadowMatrix: [],
  10547. rectArea: [],
  10548. point: [],
  10549. pointShadowMap: [],
  10550. pointShadowMatrix: [],
  10551. hemi: []
  10552. };
  10553. var vector3 = new Vector3();
  10554. var matrix4 = new Matrix4();
  10555. var matrix42 = new Matrix4();
  10556. function setup(lights, shadows, camera) {
  10557. var r = 0,
  10558. g = 0,
  10559. b = 0;
  10560. var directionalLength = 0;
  10561. var pointLength = 0;
  10562. var spotLength = 0;
  10563. var rectAreaLength = 0;
  10564. var hemiLength = 0;
  10565. var viewMatrix = camera.matrixWorldInverse;
  10566. for (var i = 0, l = lights.length; i < l; i++) {
  10567. var light = lights[i];
  10568. var color = light.color;
  10569. var intensity = light.intensity;
  10570. var distance = light.distance;
  10571. var shadowMap = light.shadow && light.shadow.map ? light.shadow.map.texture : null;
  10572. if (light.isAmbientLight) {
  10573. r += color.r * intensity;
  10574. g += color.g * intensity;
  10575. b += color.b * intensity;
  10576. } else if (light.isDirectionalLight) {
  10577. var uniforms = cache.get(light);
  10578. uniforms.color.copy(light.color).multiplyScalar(light.intensity);
  10579. uniforms.direction.setFromMatrixPosition(light.matrixWorld);
  10580. vector3.setFromMatrixPosition(light.target.matrixWorld);
  10581. uniforms.direction.sub(vector3);
  10582. uniforms.direction.transformDirection(viewMatrix);
  10583. uniforms.shadow = light.castShadow;
  10584. if (light.castShadow) {
  10585. var shadow = light.shadow;
  10586. uniforms.shadowBias = shadow.bias;
  10587. uniforms.shadowRadius = shadow.radius;
  10588. uniforms.shadowMapSize = shadow.mapSize;
  10589. }
  10590. state.directionalShadowMap[directionalLength] = shadowMap;
  10591. state.directionalShadowMatrix[directionalLength] = light.shadow.matrix;
  10592. state.directional[directionalLength] = uniforms;
  10593. directionalLength++;
  10594. } else if (light.isSpotLight) {
  10595. var uniforms = cache.get(light);
  10596. uniforms.position.setFromMatrixPosition(light.matrixWorld);
  10597. uniforms.position.applyMatrix4(viewMatrix);
  10598. uniforms.color.copy(color).multiplyScalar(intensity);
  10599. uniforms.distance = distance;
  10600. uniforms.direction.setFromMatrixPosition(light.matrixWorld);
  10601. vector3.setFromMatrixPosition(light.target.matrixWorld);
  10602. uniforms.direction.sub(vector3);
  10603. uniforms.direction.transformDirection(viewMatrix);
  10604. uniforms.coneCos = Math.cos(light.angle);
  10605. uniforms.penumbraCos = Math.cos(light.angle * (1 - light.penumbra));
  10606. uniforms.decay = light.distance === 0 ? 0.0 : light.decay;
  10607. uniforms.shadow = light.castShadow;
  10608. if (light.castShadow) {
  10609. var shadow = light.shadow;
  10610. uniforms.shadowBias = shadow.bias;
  10611. uniforms.shadowRadius = shadow.radius;
  10612. uniforms.shadowMapSize = shadow.mapSize;
  10613. }
  10614. state.spotShadowMap[spotLength] = shadowMap;
  10615. state.spotShadowMatrix[spotLength] = light.shadow.matrix;
  10616. state.spot[spotLength] = uniforms;
  10617. spotLength++;
  10618. } else if (light.isRectAreaLight) {
  10619. var uniforms = cache.get(light);
  10620. // (a) intensity is the total visible light emitted
  10621. //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
  10622. // (b) intensity is the brightness of the light
  10623. uniforms.color.copy(color).multiplyScalar(intensity);
  10624. uniforms.position.setFromMatrixPosition(light.matrixWorld);
  10625. uniforms.position.applyMatrix4(viewMatrix);
  10626. // extract local rotation of light to derive width/height half vectors
  10627. matrix42.identity();
  10628. matrix4.copy(light.matrixWorld);
  10629. matrix4.premultiply(viewMatrix);
  10630. matrix42.extractRotation(matrix4);
  10631. uniforms.halfWidth.set(light.width * 0.5, 0.0, 0.0);
  10632. uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0);
  10633. uniforms.halfWidth.applyMatrix4(matrix42);
  10634. uniforms.halfHeight.applyMatrix4(matrix42);
  10635. // TODO (abelnation): RectAreaLight distance?
  10636. // uniforms.distance = distance;
  10637. state.rectArea[rectAreaLength] = uniforms;
  10638. rectAreaLength++;
  10639. } else if (light.isPointLight) {
  10640. var uniforms = cache.get(light);
  10641. uniforms.position.setFromMatrixPosition(light.matrixWorld);
  10642. uniforms.position.applyMatrix4(viewMatrix);
  10643. uniforms.color.copy(light.color).multiplyScalar(light.intensity);
  10644. uniforms.distance = light.distance;
  10645. uniforms.decay = light.distance === 0 ? 0.0 : light.decay;
  10646. uniforms.shadow = light.castShadow;
  10647. if (light.castShadow) {
  10648. var shadow = light.shadow;
  10649. uniforms.shadowBias = shadow.bias;
  10650. uniforms.shadowRadius = shadow.radius;
  10651. uniforms.shadowMapSize = shadow.mapSize;
  10652. uniforms.shadowCameraNear = shadow.camera.near;
  10653. uniforms.shadowCameraFar = shadow.camera.far;
  10654. }
  10655. state.pointShadowMap[pointLength] = shadowMap;
  10656. state.pointShadowMatrix[pointLength] = light.shadow.matrix;
  10657. state.point[pointLength] = uniforms;
  10658. pointLength++;
  10659. } else if (light.isHemisphereLight) {
  10660. var uniforms = cache.get(light);
  10661. uniforms.direction.setFromMatrixPosition(light.matrixWorld);
  10662. uniforms.direction.transformDirection(viewMatrix);
  10663. uniforms.direction.normalize();
  10664. uniforms.skyColor.copy(light.color).multiplyScalar(intensity);
  10665. uniforms.groundColor.copy(light.groundColor).multiplyScalar(intensity);
  10666. state.hemi[hemiLength] = uniforms;
  10667. hemiLength++;
  10668. }
  10669. }
  10670. state.ambient[0] = r;
  10671. state.ambient[1] = g;
  10672. state.ambient[2] = b;
  10673. state.directional.length = directionalLength;
  10674. state.spot.length = spotLength;
  10675. state.rectArea.length = rectAreaLength;
  10676. state.point.length = pointLength;
  10677. state.hemi.length = hemiLength;
  10678. state.hash = state.id + ',' + directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length;
  10679. }
  10680. return {
  10681. setup: setup,
  10682. state: state
  10683. };
  10684. }
  10685. /**
  10686. * @author Mugen87 / https://github.com/Mugen87
  10687. */
  10688. function WebGLRenderState() {
  10689. var lights = new WebGLLights();
  10690. var lightsArray = [];
  10691. var shadowsArray = [];
  10692. var spritesArray = [];
  10693. function init() {
  10694. lightsArray.length = 0;
  10695. shadowsArray.length = 0;
  10696. spritesArray.length = 0;
  10697. }
  10698. function pushLight(light) {
  10699. lightsArray.push(light);
  10700. }
  10701. function pushShadow(shadowLight) {
  10702. shadowsArray.push(shadowLight);
  10703. }
  10704. function pushSprite(shadowLight) {
  10705. spritesArray.push(shadowLight);
  10706. }
  10707. function setupLights(camera) {
  10708. lights.setup(lightsArray, shadowsArray, camera);
  10709. }
  10710. var state = {
  10711. lightsArray: lightsArray,
  10712. shadowsArray: shadowsArray,
  10713. spritesArray: spritesArray,
  10714. lights: lights
  10715. };
  10716. return {
  10717. init: init,
  10718. state: state,
  10719. setupLights: setupLights,
  10720. pushLight: pushLight,
  10721. pushShadow: pushShadow,
  10722. pushSprite: pushSprite
  10723. };
  10724. }
  10725. function WebGLRenderStates() {
  10726. var renderStates = {};
  10727. function get(scene, camera) {
  10728. var hash = scene.id + ',' + camera.id;
  10729. var renderState = renderStates[hash];
  10730. if (renderState === undefined) {
  10731. renderState = new WebGLRenderState();
  10732. renderStates[hash] = renderState;
  10733. }
  10734. return renderState;
  10735. }
  10736. function dispose() {
  10737. renderStates = {};
  10738. }
  10739. return {
  10740. get: get,
  10741. dispose: dispose
  10742. };
  10743. }
  10744. /**
  10745. * @author mrdoob / http://mrdoob.com/
  10746. * @author alteredq / http://alteredqualia.com/
  10747. * @author bhouston / https://clara.io
  10748. * @author WestLangley / http://github.com/WestLangley
  10749. *
  10750. * parameters = {
  10751. *
  10752. * opacity: <float>,
  10753. *
  10754. * map: new THREE.Texture( <Image> ),
  10755. *
  10756. * alphaMap: new THREE.Texture( <Image> ),
  10757. *
  10758. * displacementMap: new THREE.Texture( <Image> ),
  10759. * displacementScale: <float>,
  10760. * displacementBias: <float>,
  10761. *
  10762. * wireframe: <boolean>,
  10763. * wireframeLinewidth: <float>
  10764. * }
  10765. */
  10766. function MeshDepthMaterial(parameters) {
  10767. Material.call(this);
  10768. this.type = 'MeshDepthMaterial';
  10769. this.depthPacking = BasicDepthPacking;
  10770. this.skinning = false;
  10771. this.morphTargets = false;
  10772. this.map = null;
  10773. this.alphaMap = null;
  10774. this.displacementMap = null;
  10775. this.displacementScale = 1;
  10776. this.displacementBias = 0;
  10777. this.wireframe = false;
  10778. this.wireframeLinewidth = 1;
  10779. this.fog = false;
  10780. this.lights = false;
  10781. this.setValues(parameters);
  10782. }
  10783. MeshDepthMaterial.prototype = Object.create(Material.prototype);
  10784. MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
  10785. MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
  10786. MeshDepthMaterial.prototype.copy = function (source) {
  10787. Material.prototype.copy.call(this, source);
  10788. this.depthPacking = source.depthPacking;
  10789. this.skinning = source.skinning;
  10790. this.morphTargets = source.morphTargets;
  10791. this.map = source.map;
  10792. this.alphaMap = source.alphaMap;
  10793. this.displacementMap = source.displacementMap;
  10794. this.displacementScale = source.displacementScale;
  10795. this.displacementBias = source.displacementBias;
  10796. this.wireframe = source.wireframe;
  10797. this.wireframeLinewidth = source.wireframeLinewidth;
  10798. return this;
  10799. };
  10800. /**
  10801. * @author WestLangley / http://github.com/WestLangley
  10802. *
  10803. * parameters = {
  10804. *
  10805. * referencePosition: <float>,
  10806. * nearDistance: <float>,
  10807. * farDistance: <float>,
  10808. *
  10809. * skinning: <bool>,
  10810. * morphTargets: <bool>,
  10811. *
  10812. * map: new THREE.Texture( <Image> ),
  10813. *
  10814. * alphaMap: new THREE.Texture( <Image> ),
  10815. *
  10816. * displacementMap: new THREE.Texture( <Image> ),
  10817. * displacementScale: <float>,
  10818. * displacementBias: <float>
  10819. *
  10820. * }
  10821. */
  10822. function MeshDistanceMaterial(parameters) {
  10823. Material.call(this);
  10824. this.type = 'MeshDistanceMaterial';
  10825. this.referencePosition = new Vector3();
  10826. this.nearDistance = 1;
  10827. this.farDistance = 1000;
  10828. this.skinning = false;
  10829. this.morphTargets = false;
  10830. this.map = null;
  10831. this.alphaMap = null;
  10832. this.displacementMap = null;
  10833. this.displacementScale = 1;
  10834. this.displacementBias = 0;
  10835. this.fog = false;
  10836. this.lights = false;
  10837. this.setValues(parameters);
  10838. }
  10839. MeshDistanceMaterial.prototype = Object.create(Material.prototype);
  10840. MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
  10841. MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
  10842. MeshDistanceMaterial.prototype.copy = function (source) {
  10843. Material.prototype.copy.call(this, source);
  10844. this.referencePosition.copy(source.referencePosition);
  10845. this.nearDistance = source.nearDistance;
  10846. this.farDistance = source.farDistance;
  10847. this.skinning = source.skinning;
  10848. this.morphTargets = source.morphTargets;
  10849. this.map = source.map;
  10850. this.alphaMap = source.alphaMap;
  10851. this.displacementMap = source.displacementMap;
  10852. this.displacementScale = source.displacementScale;
  10853. this.displacementBias = source.displacementBias;
  10854. return this;
  10855. };
  10856. /**
  10857. * @author alteredq / http://alteredqualia.com/
  10858. * @author mrdoob / http://mrdoob.com/
  10859. */
  10860. function WebGLShadowMap(_renderer, _objects, maxTextureSize) {
  10861. var _frustum = new Frustum(),
  10862. _projScreenMatrix = new Matrix4(),
  10863. _shadowMapSize = new Vector2(),
  10864. _maxShadowMapSize = new Vector2(maxTextureSize, maxTextureSize),
  10865. _lookTarget = new Vector3(),
  10866. _lightPositionWorld = new Vector3(),
  10867. _MorphingFlag = 1,
  10868. _SkinningFlag = 2,
  10869. _NumberOfMaterialVariants = (_MorphingFlag | _SkinningFlag) + 1,
  10870. _depthMaterials = new Array(_NumberOfMaterialVariants),
  10871. _distanceMaterials = new Array(_NumberOfMaterialVariants),
  10872. _materialCache = {};
  10873. var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
  10874. 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)];
  10875. 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)];
  10876. var cube2DViewPorts = [new Vector4(), new Vector4(), new Vector4(), new Vector4(), new Vector4(), new Vector4()];
  10877. // init
  10878. for (var i = 0; i !== _NumberOfMaterialVariants; ++i) {
  10879. var useMorphing = (i & _MorphingFlag) !== 0;
  10880. var useSkinning = (i & _SkinningFlag) !== 0;
  10881. var depthMaterial = new MeshDepthMaterial({
  10882. depthPacking: RGBADepthPacking,
  10883. morphTargets: useMorphing,
  10884. skinning: useSkinning
  10885. });
  10886. _depthMaterials[i] = depthMaterial;
  10887. //
  10888. var distanceMaterial = new MeshDistanceMaterial({
  10889. morphTargets: useMorphing,
  10890. skinning: useSkinning
  10891. });
  10892. _distanceMaterials[i] = distanceMaterial;
  10893. }
  10894. //
  10895. var scope = this;
  10896. this.enabled = false;
  10897. this.autoUpdate = true;
  10898. this.needsUpdate = false;
  10899. this.type = PCFShadowMap;
  10900. this.render = function (lights, scene, camera) {
  10901. if (scope.enabled === false) return;
  10902. if (scope.autoUpdate === false && scope.needsUpdate === false) return;
  10903. if (lights.length === 0) return;
  10904. // TODO Clean up (needed in case of contextlost)
  10905. var _gl = _renderer.context;
  10906. var _state = _renderer.state;
  10907. // Set GL state for depth map.
  10908. _state.disable(_gl.BLEND);
  10909. _state.buffers.color.setClear(1, 1, 1, 1);
  10910. _state.buffers.depth.setTest(true);
  10911. _state.setScissorTest(false);
  10912. // render depth map
  10913. var faceCount;
  10914. for (var i = 0, il = lights.length; i < il; i++) {
  10915. var light = lights[i];
  10916. var shadow = light.shadow;
  10917. var isPointLight = light && light.isPointLight;
  10918. if (shadow === undefined) {
  10919. console.warn('THREE.WebGLShadowMap:', light, 'has no shadow.');
  10920. continue;
  10921. }
  10922. var shadowCamera = shadow.camera;
  10923. _shadowMapSize.copy(shadow.mapSize);
  10924. _shadowMapSize.min(_maxShadowMapSize);
  10925. if (isPointLight) {
  10926. var vpWidth = _shadowMapSize.x;
  10927. var vpHeight = _shadowMapSize.y;
  10928. // These viewports map a cube-map onto a 2D texture with the
  10929. // following orientation:
  10930. //
  10931. // xzXZ
  10932. // y Y
  10933. //
  10934. // X - Positive x direction
  10935. // x - Negative x direction
  10936. // Y - Positive y direction
  10937. // y - Negative y direction
  10938. // Z - Positive z direction
  10939. // z - Negative z direction
  10940. // positive X
  10941. cube2DViewPorts[0].set(vpWidth * 2, vpHeight, vpWidth, vpHeight);
  10942. // negative X
  10943. cube2DViewPorts[1].set(0, vpHeight, vpWidth, vpHeight);
  10944. // positive Z
  10945. cube2DViewPorts[2].set(vpWidth * 3, vpHeight, vpWidth, vpHeight);
  10946. // negative Z
  10947. cube2DViewPorts[3].set(vpWidth, vpHeight, vpWidth, vpHeight);
  10948. // positive Y
  10949. cube2DViewPorts[4].set(vpWidth * 3, 0, vpWidth, vpHeight);
  10950. // negative Y
  10951. cube2DViewPorts[5].set(vpWidth, 0, vpWidth, vpHeight);
  10952. _shadowMapSize.x *= 4.0;
  10953. _shadowMapSize.y *= 2.0;
  10954. }
  10955. if (shadow.map === null) {
  10956. var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
  10957. shadow.map = new WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y, pars);
  10958. shadow.map.texture.name = light.name + ".shadowMap";
  10959. shadowCamera.updateProjectionMatrix();
  10960. }
  10961. if (shadow.isSpotLightShadow) {
  10962. shadow.update(light);
  10963. }
  10964. var shadowMap = shadow.map;
  10965. var shadowMatrix = shadow.matrix;
  10966. _lightPositionWorld.setFromMatrixPosition(light.matrixWorld);
  10967. shadowCamera.position.copy(_lightPositionWorld);
  10968. if (isPointLight) {
  10969. faceCount = 6;
  10970. // for point lights we set the shadow matrix to be a translation-only matrix
  10971. // equal to inverse of the light's position
  10972. shadowMatrix.makeTranslation(-_lightPositionWorld.x, -_lightPositionWorld.y, -_lightPositionWorld.z);
  10973. } else {
  10974. faceCount = 1;
  10975. _lookTarget.setFromMatrixPosition(light.target.matrixWorld);
  10976. shadowCamera.lookAt(_lookTarget);
  10977. shadowCamera.updateMatrixWorld();
  10978. // compute shadow matrix
  10979. 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);
  10980. shadowMatrix.multiply(shadowCamera.projectionMatrix);
  10981. shadowMatrix.multiply(shadowCamera.matrixWorldInverse);
  10982. }
  10983. _renderer.setRenderTarget(shadowMap);
  10984. _renderer.clear();
  10985. // render shadow map for each cube face (if omni-directional) or
  10986. // run a single pass if not
  10987. for (var face = 0; face < faceCount; face++) {
  10988. if (isPointLight) {
  10989. _lookTarget.copy(shadowCamera.position);
  10990. _lookTarget.add(cubeDirections[face]);
  10991. shadowCamera.up.copy(cubeUps[face]);
  10992. shadowCamera.lookAt(_lookTarget);
  10993. shadowCamera.updateMatrixWorld();
  10994. var vpDimensions = cube2DViewPorts[face];
  10995. _state.viewport(vpDimensions);
  10996. }
  10997. // update camera matrices and frustum
  10998. _projScreenMatrix.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse);
  10999. _frustum.setFromMatrix(_projScreenMatrix);
  11000. // set object matrices & frustum culling
  11001. renderObject(scene, camera, shadowCamera, isPointLight);
  11002. }
  11003. }
  11004. scope.needsUpdate = false;
  11005. };
  11006. function getDepthMaterial(object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar) {
  11007. var geometry = object.geometry;
  11008. var result = null;
  11009. var materialVariants = _depthMaterials;
  11010. var customMaterial = object.customDepthMaterial;
  11011. if (isPointLight) {
  11012. materialVariants = _distanceMaterials;
  11013. customMaterial = object.customDistanceMaterial;
  11014. }
  11015. if (!customMaterial) {
  11016. var useMorphing = false;
  11017. if (material.morphTargets) {
  11018. if (geometry && geometry.isBufferGeometry) {
  11019. useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
  11020. } else if (geometry && geometry.isGeometry) {
  11021. useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
  11022. }
  11023. }
  11024. if (object.isSkinnedMesh && material.skinning === false) {
  11025. console.warn('THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object);
  11026. }
  11027. var useSkinning = object.isSkinnedMesh && material.skinning;
  11028. var variantIndex = 0;
  11029. if (useMorphing) variantIndex |= _MorphingFlag;
  11030. if (useSkinning) variantIndex |= _SkinningFlag;
  11031. result = materialVariants[variantIndex];
  11032. } else {
  11033. result = customMaterial;
  11034. }
  11035. if (_renderer.localClippingEnabled && material.clipShadows === true && material.clippingPlanes.length !== 0) {
  11036. // in this case we need a unique material instance reflecting the
  11037. // appropriate state
  11038. var keyA = result.uuid,
  11039. keyB = material.uuid;
  11040. var materialsForVariant = _materialCache[keyA];
  11041. if (materialsForVariant === undefined) {
  11042. materialsForVariant = {};
  11043. _materialCache[keyA] = materialsForVariant;
  11044. }
  11045. var cachedMaterial = materialsForVariant[keyB];
  11046. if (cachedMaterial === undefined) {
  11047. cachedMaterial = result.clone();
  11048. materialsForVariant[keyB] = cachedMaterial;
  11049. }
  11050. result = cachedMaterial;
  11051. }
  11052. result.visible = material.visible;
  11053. result.wireframe = material.wireframe;
  11054. result.side = material.shadowSide != null ? material.shadowSide : shadowSide[material.side];
  11055. result.clipShadows = material.clipShadows;
  11056. result.clippingPlanes = material.clippingPlanes;
  11057. result.clipIntersection = material.clipIntersection;
  11058. result.wireframeLinewidth = material.wireframeLinewidth;
  11059. result.linewidth = material.linewidth;
  11060. if (isPointLight && result.isMeshDistanceMaterial) {
  11061. result.referencePosition.copy(lightPositionWorld);
  11062. result.nearDistance = shadowCameraNear;
  11063. result.farDistance = shadowCameraFar;
  11064. }
  11065. return result;
  11066. }
  11067. function renderObject(object, camera, shadowCamera, isPointLight) {
  11068. if (object.visible === false) return;
  11069. var visible = object.layers.test(camera.layers);
  11070. if (visible && (object.isMesh || object.isLine || object.isPoints)) {
  11071. if (object.castShadow && (!object.frustumCulled || _frustum.intersectsObject(object))) {
  11072. object.modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld);
  11073. var geometry = _objects.update(object);
  11074. var material = object.material;
  11075. if (Array.isArray(material)) {
  11076. var groups = geometry.groups;
  11077. for (var k = 0, kl = groups.length; k < kl; k++) {
  11078. var group = groups[k];
  11079. var groupMaterial = material[group.materialIndex];
  11080. if (groupMaterial && groupMaterial.visible) {
  11081. var depthMaterial = getDepthMaterial(object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far);
  11082. _renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, group);
  11083. }
  11084. }
  11085. } else if (material.visible) {
  11086. var depthMaterial = getDepthMaterial(object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far);
  11087. _renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, null);
  11088. }
  11089. }
  11090. }
  11091. var children = object.children;
  11092. for (var i = 0, l = children.length; i < l; i++) {
  11093. renderObject(children[i], camera, shadowCamera, isPointLight);
  11094. }
  11095. }
  11096. }
  11097. /**
  11098. * @author mrdoob / http://mrdoob.com/
  11099. */
  11100. function CanvasTexture(canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) {
  11101. Texture.call(this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy);
  11102. this.needsUpdate = true;
  11103. }
  11104. CanvasTexture.prototype = Object.create(Texture.prototype);
  11105. CanvasTexture.prototype.constructor = CanvasTexture;
  11106. CanvasTexture.prototype.isCanvasTexture = true;
  11107. /**
  11108. * @author mikael emtinger / http://gomo.se/
  11109. * @author alteredq / http://alteredqualia.com/
  11110. */
  11111. function WebGLSpriteRenderer(renderer, gl, state, textures, capabilities) {
  11112. var vertexBuffer, elementBuffer;
  11113. var program, attributes, uniforms;
  11114. var texture;
  11115. // decompose matrixWorld
  11116. var spritePosition = new Vector3();
  11117. var spriteRotation = new Quaternion();
  11118. var spriteScale = new Vector3();
  11119. function init() {
  11120. 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]);
  11121. var faces = new Uint16Array([0, 1, 2, 0, 2, 3]);
  11122. vertexBuffer = gl.createBuffer();
  11123. elementBuffer = gl.createBuffer();
  11124. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  11125. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  11126. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
  11127. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW);
  11128. program = createProgram();
  11129. attributes = {
  11130. position: gl.getAttribLocation(program, 'position'),
  11131. uv: gl.getAttribLocation(program, 'uv')
  11132. };
  11133. uniforms = {
  11134. uvOffset: gl.getUniformLocation(program, 'uvOffset'),
  11135. uvScale: gl.getUniformLocation(program, 'uvScale'),
  11136. rotation: gl.getUniformLocation(program, 'rotation'),
  11137. center: gl.getUniformLocation(program, 'center'),
  11138. scale: gl.getUniformLocation(program, 'scale'),
  11139. color: gl.getUniformLocation(program, 'color'),
  11140. map: gl.getUniformLocation(program, 'map'),
  11141. opacity: gl.getUniformLocation(program, 'opacity'),
  11142. modelViewMatrix: gl.getUniformLocation(program, 'modelViewMatrix'),
  11143. projectionMatrix: gl.getUniformLocation(program, 'projectionMatrix'),
  11144. fogType: gl.getUniformLocation(program, 'fogType'),
  11145. fogDensity: gl.getUniformLocation(program, 'fogDensity'),
  11146. fogNear: gl.getUniformLocation(program, 'fogNear'),
  11147. fogFar: gl.getUniformLocation(program, 'fogFar'),
  11148. fogColor: gl.getUniformLocation(program, 'fogColor'),
  11149. fogDepth: gl.getUniformLocation(program, 'fogDepth'),
  11150. alphaTest: gl.getUniformLocation(program, 'alphaTest')
  11151. };
  11152. var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
  11153. canvas.width = 8;
  11154. canvas.height = 8;
  11155. var context = canvas.getContext('2d');
  11156. context.fillStyle = 'white';
  11157. context.fillRect(0, 0, 8, 8);
  11158. texture = new CanvasTexture(canvas);
  11159. }
  11160. this.render = function (sprites, scene, camera) {
  11161. if (sprites.length === 0) return;
  11162. // setup gl
  11163. if (program === undefined) {
  11164. init();
  11165. }
  11166. state.useProgram(program);
  11167. state.initAttributes();
  11168. state.enableAttribute(attributes.position);
  11169. state.enableAttribute(attributes.uv);
  11170. state.disableUnusedAttributes();
  11171. state.disable(gl.CULL_FACE);
  11172. state.enable(gl.BLEND);
  11173. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  11174. gl.vertexAttribPointer(attributes.position, 2, gl.FLOAT, false, 2 * 8, 0);
  11175. gl.vertexAttribPointer(attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8);
  11176. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
  11177. gl.uniformMatrix4fv(uniforms.projectionMatrix, false, camera.projectionMatrix.elements);
  11178. state.activeTexture(gl.TEXTURE0);
  11179. gl.uniform1i(uniforms.map, 0);
  11180. var oldFogType = 0;
  11181. var sceneFogType = 0;
  11182. var fog = scene.fog;
  11183. if (fog) {
  11184. gl.uniform3f(uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b);
  11185. if (fog.isFog) {
  11186. gl.uniform1f(uniforms.fogNear, fog.near);
  11187. gl.uniform1f(uniforms.fogFar, fog.far);
  11188. gl.uniform1i(uniforms.fogType, 1);
  11189. oldFogType = 1;
  11190. sceneFogType = 1;
  11191. } else if (fog.isFogExp2) {
  11192. gl.uniform1f(uniforms.fogDensity, fog.density);
  11193. gl.uniform1i(uniforms.fogType, 2);
  11194. oldFogType = 2;
  11195. sceneFogType = 2;
  11196. }
  11197. } else {
  11198. gl.uniform1i(uniforms.fogType, 0);
  11199. oldFogType = 0;
  11200. sceneFogType = 0;
  11201. }
  11202. // update positions and sort
  11203. for (var i = 0, l = sprites.length; i < l; i++) {
  11204. var sprite = sprites[i];
  11205. sprite.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, sprite.matrixWorld);
  11206. sprite.z = -sprite.modelViewMatrix.elements[14];
  11207. }
  11208. sprites.sort(painterSortStable);
  11209. // render all sprites
  11210. var scale = [];
  11211. var center = [];
  11212. for (var i = 0, l = sprites.length; i < l; i++) {
  11213. var sprite = sprites[i];
  11214. var material = sprite.material;
  11215. if (material.visible === false) continue;
  11216. sprite.onBeforeRender(renderer, scene, camera, undefined, material, undefined);
  11217. gl.uniform1f(uniforms.alphaTest, material.alphaTest);
  11218. gl.uniformMatrix4fv(uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements);
  11219. sprite.matrixWorld.decompose(spritePosition, spriteRotation, spriteScale);
  11220. scale[0] = spriteScale.x;
  11221. scale[1] = spriteScale.y;
  11222. center[0] = sprite.center.x - 0.5;
  11223. center[1] = sprite.center.y - 0.5;
  11224. var fogType = 0;
  11225. if (scene.fog && material.fog) {
  11226. fogType = sceneFogType;
  11227. }
  11228. if (oldFogType !== fogType) {
  11229. gl.uniform1i(uniforms.fogType, fogType);
  11230. oldFogType = fogType;
  11231. }
  11232. if (material.map !== null) {
  11233. gl.uniform2f(uniforms.uvOffset, material.map.offset.x, material.map.offset.y);
  11234. gl.uniform2f(uniforms.uvScale, material.map.repeat.x, material.map.repeat.y);
  11235. } else {
  11236. gl.uniform2f(uniforms.uvOffset, 0, 0);
  11237. gl.uniform2f(uniforms.uvScale, 1, 1);
  11238. }
  11239. gl.uniform1f(uniforms.opacity, material.opacity);
  11240. gl.uniform3f(uniforms.color, material.color.r, material.color.g, material.color.b);
  11241. gl.uniform1f(uniforms.rotation, material.rotation);
  11242. gl.uniform2fv(uniforms.center, center);
  11243. gl.uniform2fv(uniforms.scale, scale);
  11244. state.setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha);
  11245. state.buffers.depth.setTest(material.depthTest);
  11246. state.buffers.depth.setMask(material.depthWrite);
  11247. state.buffers.color.setMask(material.colorWrite);
  11248. textures.setTexture2D(material.map || texture, 0);
  11249. gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
  11250. sprite.onAfterRender(renderer, scene, camera, undefined, material, undefined);
  11251. }
  11252. // restore gl
  11253. state.enable(gl.CULL_FACE);
  11254. state.reset();
  11255. };
  11256. function createProgram() {
  11257. var program = gl.createProgram();
  11258. var vertexShader = gl.createShader(gl.VERTEX_SHADER);
  11259. var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  11260. gl.shaderSource(vertexShader, ['precision ' + capabilities.precision + ' float;', '#define SHADER_NAME ' + 'SpriteMaterial', 'uniform mat4 modelViewMatrix;', 'uniform mat4 projectionMatrix;', 'uniform float rotation;', 'uniform vec2 center;', 'uniform vec2 scale;', 'uniform vec2 uvOffset;', 'uniform vec2 uvScale;', 'attribute vec2 position;', 'attribute vec2 uv;', 'varying vec2 vUV;', 'varying float fogDepth;', 'void main() {', ' vUV = uvOffset + uv * uvScale;', ' vec2 alignedPosition = ( position - center ) * scale;', ' vec2 rotatedPosition;', ' rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', ' rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', ' vec4 mvPosition;', ' mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', ' mvPosition.xy += rotatedPosition;', ' gl_Position = projectionMatrix * mvPosition;', ' fogDepth = - mvPosition.z;', '}'].join('\n'));
  11261. gl.shaderSource(fragmentShader, ['precision ' + capabilities.precision + ' 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;', 'varying float fogDepth;', 'void main() {', ' vec4 texture = texture2D( map, vUV );', ' gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', ' if ( gl_FragColor.a < alphaTest ) discard;', ' if ( fogType > 0 ) {', ' float fogFactor = 0.0;', ' if ( fogType == 1 ) {', ' fogFactor = smoothstep( fogNear, fogFar, fogDepth );', ' } else {', ' const float LOG2 = 1.442695;', ' fogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );', ' fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', ' }', ' gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );', ' }', '}'].join('\n'));
  11262. gl.compileShader(vertexShader);
  11263. gl.compileShader(fragmentShader);
  11264. gl.attachShader(program, vertexShader);
  11265. gl.attachShader(program, fragmentShader);
  11266. gl.linkProgram(program);
  11267. return program;
  11268. }
  11269. function painterSortStable(a, b) {
  11270. if (a.renderOrder !== b.renderOrder) {
  11271. return a.renderOrder - b.renderOrder;
  11272. } else if (a.z !== b.z) {
  11273. return b.z - a.z;
  11274. } else {
  11275. return b.id - a.id;
  11276. }
  11277. }
  11278. }
  11279. /**
  11280. * @author mrdoob / http://mrdoob.com/
  11281. */
  11282. function WebGLState(gl, extensions, utils) {
  11283. function ColorBuffer() {
  11284. var locked = false;
  11285. var color = new Vector4();
  11286. var currentColorMask = null;
  11287. var currentColorClear = new Vector4(0, 0, 0, 0);
  11288. return {
  11289. setMask: function (colorMask) {
  11290. if (currentColorMask !== colorMask && !locked) {
  11291. gl.colorMask(colorMask, colorMask, colorMask, colorMask);
  11292. currentColorMask = colorMask;
  11293. }
  11294. },
  11295. setLocked: function (lock) {
  11296. locked = lock;
  11297. },
  11298. setClear: function (r, g, b, a, premultipliedAlpha) {
  11299. if (premultipliedAlpha === true) {
  11300. r *= a;g *= a;b *= a;
  11301. }
  11302. color.set(r, g, b, a);
  11303. if (currentColorClear.equals(color) === false) {
  11304. gl.clearColor(r, g, b, a);
  11305. currentColorClear.copy(color);
  11306. }
  11307. },
  11308. reset: function () {
  11309. locked = false;
  11310. currentColorMask = null;
  11311. currentColorClear.set(-1, 0, 0, 0); // set to invalid state
  11312. }
  11313. };
  11314. }
  11315. function DepthBuffer() {
  11316. var locked = false;
  11317. var currentDepthMask = null;
  11318. var currentDepthFunc = null;
  11319. var currentDepthClear = null;
  11320. return {
  11321. setTest: function (depthTest) {
  11322. if (depthTest) {
  11323. enable(gl.DEPTH_TEST);
  11324. } else {
  11325. disable(gl.DEPTH_TEST);
  11326. }
  11327. },
  11328. setMask: function (depthMask) {
  11329. if (currentDepthMask !== depthMask && !locked) {
  11330. gl.depthMask(depthMask);
  11331. currentDepthMask = depthMask;
  11332. }
  11333. },
  11334. setFunc: function (depthFunc) {
  11335. if (currentDepthFunc !== depthFunc) {
  11336. if (depthFunc) {
  11337. switch (depthFunc) {
  11338. case NeverDepth:
  11339. gl.depthFunc(gl.NEVER);
  11340. break;
  11341. case AlwaysDepth:
  11342. gl.depthFunc(gl.ALWAYS);
  11343. break;
  11344. case LessDepth:
  11345. gl.depthFunc(gl.LESS);
  11346. break;
  11347. case LessEqualDepth:
  11348. gl.depthFunc(gl.LEQUAL);
  11349. break;
  11350. case EqualDepth:
  11351. gl.depthFunc(gl.EQUAL);
  11352. break;
  11353. case GreaterEqualDepth:
  11354. gl.depthFunc(gl.GEQUAL);
  11355. break;
  11356. case GreaterDepth:
  11357. gl.depthFunc(gl.GREATER);
  11358. break;
  11359. case NotEqualDepth:
  11360. gl.depthFunc(gl.NOTEQUAL);
  11361. break;
  11362. default:
  11363. gl.depthFunc(gl.LEQUAL);
  11364. }
  11365. } else {
  11366. gl.depthFunc(gl.LEQUAL);
  11367. }
  11368. currentDepthFunc = depthFunc;
  11369. }
  11370. },
  11371. setLocked: function (lock) {
  11372. locked = lock;
  11373. },
  11374. setClear: function (depth) {
  11375. if (currentDepthClear !== depth) {
  11376. gl.clearDepth(depth);
  11377. currentDepthClear = depth;
  11378. }
  11379. },
  11380. reset: function () {
  11381. locked = false;
  11382. currentDepthMask = null;
  11383. currentDepthFunc = null;
  11384. currentDepthClear = null;
  11385. }
  11386. };
  11387. }
  11388. function StencilBuffer() {
  11389. var locked = false;
  11390. var currentStencilMask = null;
  11391. var currentStencilFunc = null;
  11392. var currentStencilRef = null;
  11393. var currentStencilFuncMask = null;
  11394. var currentStencilFail = null;
  11395. var currentStencilZFail = null;
  11396. var currentStencilZPass = null;
  11397. var currentStencilClear = null;
  11398. return {
  11399. setTest: function (stencilTest) {
  11400. if (stencilTest) {
  11401. enable(gl.STENCIL_TEST);
  11402. } else {
  11403. disable(gl.STENCIL_TEST);
  11404. }
  11405. },
  11406. setMask: function (stencilMask) {
  11407. if (currentStencilMask !== stencilMask && !locked) {
  11408. gl.stencilMask(stencilMask);
  11409. currentStencilMask = stencilMask;
  11410. }
  11411. },
  11412. setFunc: function (stencilFunc, stencilRef, stencilMask) {
  11413. if (currentStencilFunc !== stencilFunc || currentStencilRef !== stencilRef || currentStencilFuncMask !== stencilMask) {
  11414. gl.stencilFunc(stencilFunc, stencilRef, stencilMask);
  11415. currentStencilFunc = stencilFunc;
  11416. currentStencilRef = stencilRef;
  11417. currentStencilFuncMask = stencilMask;
  11418. }
  11419. },
  11420. setOp: function (stencilFail, stencilZFail, stencilZPass) {
  11421. if (currentStencilFail !== stencilFail || currentStencilZFail !== stencilZFail || currentStencilZPass !== stencilZPass) {
  11422. gl.stencilOp(stencilFail, stencilZFail, stencilZPass);
  11423. currentStencilFail = stencilFail;
  11424. currentStencilZFail = stencilZFail;
  11425. currentStencilZPass = stencilZPass;
  11426. }
  11427. },
  11428. setLocked: function (lock) {
  11429. locked = lock;
  11430. },
  11431. setClear: function (stencil) {
  11432. if (currentStencilClear !== stencil) {
  11433. gl.clearStencil(stencil);
  11434. currentStencilClear = stencil;
  11435. }
  11436. },
  11437. reset: function () {
  11438. locked = false;
  11439. currentStencilMask = null;
  11440. currentStencilFunc = null;
  11441. currentStencilRef = null;
  11442. currentStencilFuncMask = null;
  11443. currentStencilFail = null;
  11444. currentStencilZFail = null;
  11445. currentStencilZPass = null;
  11446. currentStencilClear = null;
  11447. }
  11448. };
  11449. }
  11450. //
  11451. var colorBuffer = new ColorBuffer();
  11452. var depthBuffer = new DepthBuffer();
  11453. var stencilBuffer = new StencilBuffer();
  11454. var maxVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
  11455. var newAttributes = new Uint8Array(maxVertexAttributes);
  11456. var enabledAttributes = new Uint8Array(maxVertexAttributes);
  11457. var attributeDivisors = new Uint8Array(maxVertexAttributes);
  11458. var capabilities = {};
  11459. var compressedTextureFormats = null;
  11460. var currentProgram = null;
  11461. var currentBlending = null;
  11462. var currentBlendEquation = null;
  11463. var currentBlendSrc = null;
  11464. var currentBlendDst = null;
  11465. var currentBlendEquationAlpha = null;
  11466. var currentBlendSrcAlpha = null;
  11467. var currentBlendDstAlpha = null;
  11468. var currentPremultipledAlpha = false;
  11469. var currentFlipSided = null;
  11470. var currentCullFace = null;
  11471. var currentLineWidth = null;
  11472. var currentPolygonOffsetFactor = null;
  11473. var currentPolygonOffsetUnits = null;
  11474. var maxTextures = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
  11475. var lineWidthAvailable = false;
  11476. var version = 0;
  11477. var glVersion = gl.getParameter(gl.VERSION);
  11478. if (glVersion.indexOf('WebGL') !== -1) {
  11479. version = parseFloat(/^WebGL\ ([0-9])/.exec(glVersion)[1]);
  11480. lineWidthAvailable = version >= 1.0;
  11481. } else if (glVersion.indexOf('OpenGL ES') !== -1) {
  11482. version = parseFloat(/^OpenGL\ ES\ ([0-9])/.exec(glVersion)[1]);
  11483. lineWidthAvailable = version >= 2.0;
  11484. }
  11485. var currentTextureSlot = null;
  11486. var currentBoundTextures = {};
  11487. var currentScissor = new Vector4();
  11488. var currentViewport = new Vector4();
  11489. function createTexture(type, target, count) {
  11490. var data = new Uint8Array(4); // 4 is required to match default unpack alignment of 4.
  11491. var texture = gl.createTexture();
  11492. gl.bindTexture(type, texture);
  11493. gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  11494. gl.texParameteri(type, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  11495. for (var i = 0; i < count; i++) {
  11496. gl.texImage2D(target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
  11497. }
  11498. return texture;
  11499. }
  11500. var emptyTextures = {};
  11501. emptyTextures[gl.TEXTURE_2D] = createTexture(gl.TEXTURE_2D, gl.TEXTURE_2D, 1);
  11502. emptyTextures[gl.TEXTURE_CUBE_MAP] = createTexture(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6);
  11503. // init
  11504. colorBuffer.setClear(0, 0, 0, 1);
  11505. depthBuffer.setClear(1);
  11506. stencilBuffer.setClear(0);
  11507. enable(gl.DEPTH_TEST);
  11508. depthBuffer.setFunc(LessEqualDepth);
  11509. setFlipSided(false);
  11510. setCullFace(CullFaceBack);
  11511. enable(gl.CULL_FACE);
  11512. enable(gl.BLEND);
  11513. setBlending(NormalBlending);
  11514. //
  11515. function initAttributes() {
  11516. for (var i = 0, l = newAttributes.length; i < l; i++) {
  11517. newAttributes[i] = 0;
  11518. }
  11519. }
  11520. function enableAttribute(attribute) {
  11521. enableAttributeAndDivisor(attribute, 0);
  11522. }
  11523. function enableAttributeAndDivisor(attribute, meshPerAttribute) {
  11524. newAttributes[attribute] = 1;
  11525. if (enabledAttributes[attribute] === 0) {
  11526. gl.enableVertexAttribArray(attribute);
  11527. enabledAttributes[attribute] = 1;
  11528. }
  11529. if (attributeDivisors[attribute] !== meshPerAttribute) {
  11530. var extension = extensions.get('ANGLE_instanced_arrays');
  11531. extension.vertexAttribDivisorANGLE(attribute, meshPerAttribute);
  11532. attributeDivisors[attribute] = meshPerAttribute;
  11533. }
  11534. }
  11535. function disableUnusedAttributes() {
  11536. for (var i = 0, l = enabledAttributes.length; i !== l; ++i) {
  11537. if (enabledAttributes[i] !== newAttributes[i]) {
  11538. gl.disableVertexAttribArray(i);
  11539. enabledAttributes[i] = 0;
  11540. }
  11541. }
  11542. }
  11543. function enable(id) {
  11544. if (capabilities[id] !== true) {
  11545. gl.enable(id);
  11546. capabilities[id] = true;
  11547. }
  11548. }
  11549. function disable(id) {
  11550. if (capabilities[id] !== false) {
  11551. gl.disable(id);
  11552. capabilities[id] = false;
  11553. }
  11554. }
  11555. function getCompressedTextureFormats() {
  11556. if (compressedTextureFormats === null) {
  11557. compressedTextureFormats = [];
  11558. if (extensions.get('WEBGL_compressed_texture_pvrtc') || extensions.get('WEBGL_compressed_texture_s3tc') || extensions.get('WEBGL_compressed_texture_etc1') || extensions.get('WEBGL_compressed_texture_astc')) {
  11559. var formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
  11560. for (var i = 0; i < formats.length; i++) {
  11561. compressedTextureFormats.push(formats[i]);
  11562. }
  11563. }
  11564. }
  11565. return compressedTextureFormats;
  11566. }
  11567. function useProgram(program) {
  11568. if (currentProgram !== program) {
  11569. gl.useProgram(program);
  11570. currentProgram = program;
  11571. return true;
  11572. }
  11573. return false;
  11574. }
  11575. function setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha) {
  11576. if (blending !== NoBlending) {
  11577. enable(gl.BLEND);
  11578. } else {
  11579. disable(gl.BLEND);
  11580. }
  11581. if (blending !== CustomBlending) {
  11582. if (blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha) {
  11583. switch (blending) {
  11584. case AdditiveBlending:
  11585. if (premultipliedAlpha) {
  11586. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  11587. gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE);
  11588. } else {
  11589. gl.blendEquation(gl.FUNC_ADD);
  11590. gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  11591. }
  11592. break;
  11593. case SubtractiveBlending:
  11594. if (premultipliedAlpha) {
  11595. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  11596. gl.blendFuncSeparate(gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA);
  11597. } else {
  11598. gl.blendEquation(gl.FUNC_ADD);
  11599. gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR);
  11600. }
  11601. break;
  11602. case MultiplyBlending:
  11603. if (premultipliedAlpha) {
  11604. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  11605. gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA);
  11606. } else {
  11607. gl.blendEquation(gl.FUNC_ADD);
  11608. gl.blendFunc(gl.ZERO, gl.SRC_COLOR);
  11609. }
  11610. break;
  11611. default:
  11612. if (premultipliedAlpha) {
  11613. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  11614. gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  11615. } else {
  11616. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  11617. gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  11618. }
  11619. }
  11620. }
  11621. currentBlendEquation = null;
  11622. currentBlendSrc = null;
  11623. currentBlendDst = null;
  11624. currentBlendEquationAlpha = null;
  11625. currentBlendSrcAlpha = null;
  11626. currentBlendDstAlpha = null;
  11627. } else {
  11628. blendEquationAlpha = blendEquationAlpha || blendEquation;
  11629. blendSrcAlpha = blendSrcAlpha || blendSrc;
  11630. blendDstAlpha = blendDstAlpha || blendDst;
  11631. if (blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha) {
  11632. gl.blendEquationSeparate(utils.convert(blendEquation), utils.convert(blendEquationAlpha));
  11633. currentBlendEquation = blendEquation;
  11634. currentBlendEquationAlpha = blendEquationAlpha;
  11635. }
  11636. if (blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha) {
  11637. gl.blendFuncSeparate(utils.convert(blendSrc), utils.convert(blendDst), utils.convert(blendSrcAlpha), utils.convert(blendDstAlpha));
  11638. currentBlendSrc = blendSrc;
  11639. currentBlendDst = blendDst;
  11640. currentBlendSrcAlpha = blendSrcAlpha;
  11641. currentBlendDstAlpha = blendDstAlpha;
  11642. }
  11643. }
  11644. currentBlending = blending;
  11645. currentPremultipledAlpha = premultipliedAlpha;
  11646. }
  11647. function setMaterial(material, frontFaceCW) {
  11648. material.side === DoubleSide ? disable(gl.CULL_FACE) : enable(gl.CULL_FACE);
  11649. var flipSided = material.side === BackSide;
  11650. if (frontFaceCW) flipSided = !flipSided;
  11651. setFlipSided(flipSided);
  11652. material.transparent === true ? setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha) : setBlending(NoBlending);
  11653. depthBuffer.setFunc(material.depthFunc);
  11654. depthBuffer.setTest(material.depthTest);
  11655. depthBuffer.setMask(material.depthWrite);
  11656. colorBuffer.setMask(material.colorWrite);
  11657. setPolygonOffset(material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits);
  11658. }
  11659. //
  11660. function setFlipSided(flipSided) {
  11661. if (currentFlipSided !== flipSided) {
  11662. if (flipSided) {
  11663. gl.frontFace(gl.CW);
  11664. } else {
  11665. gl.frontFace(gl.CCW);
  11666. }
  11667. currentFlipSided = flipSided;
  11668. }
  11669. }
  11670. function setCullFace(cullFace) {
  11671. if (cullFace !== CullFaceNone) {
  11672. enable(gl.CULL_FACE);
  11673. if (cullFace !== currentCullFace) {
  11674. if (cullFace === CullFaceBack) {
  11675. gl.cullFace(gl.BACK);
  11676. } else if (cullFace === CullFaceFront) {
  11677. gl.cullFace(gl.FRONT);
  11678. } else {
  11679. gl.cullFace(gl.FRONT_AND_BACK);
  11680. }
  11681. }
  11682. } else {
  11683. disable(gl.CULL_FACE);
  11684. }
  11685. currentCullFace = cullFace;
  11686. }
  11687. function setLineWidth(width) {
  11688. if (width !== currentLineWidth) {
  11689. if (lineWidthAvailable) gl.lineWidth(width);
  11690. currentLineWidth = width;
  11691. }
  11692. }
  11693. function setPolygonOffset(polygonOffset, factor, units) {
  11694. if (polygonOffset) {
  11695. enable(gl.POLYGON_OFFSET_FILL);
  11696. if (currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units) {
  11697. gl.polygonOffset(factor, units);
  11698. currentPolygonOffsetFactor = factor;
  11699. currentPolygonOffsetUnits = units;
  11700. }
  11701. } else {
  11702. disable(gl.POLYGON_OFFSET_FILL);
  11703. }
  11704. }
  11705. function setScissorTest(scissorTest) {
  11706. if (scissorTest) {
  11707. enable(gl.SCISSOR_TEST);
  11708. } else {
  11709. disable(gl.SCISSOR_TEST);
  11710. }
  11711. }
  11712. // texture
  11713. function activeTexture(webglSlot) {
  11714. if (webglSlot === undefined) webglSlot = gl.TEXTURE0 + maxTextures - 1;
  11715. if (currentTextureSlot !== webglSlot) {
  11716. gl.activeTexture(webglSlot);
  11717. currentTextureSlot = webglSlot;
  11718. }
  11719. }
  11720. function bindTexture(webglType, webglTexture) {
  11721. if (currentTextureSlot === null) {
  11722. activeTexture();
  11723. }
  11724. var boundTexture = currentBoundTextures[currentTextureSlot];
  11725. if (boundTexture === undefined) {
  11726. boundTexture = { type: undefined, texture: undefined };
  11727. currentBoundTextures[currentTextureSlot] = boundTexture;
  11728. }
  11729. if (boundTexture.type !== webglType || boundTexture.texture !== webglTexture) {
  11730. gl.bindTexture(webglType, webglTexture || emptyTextures[webglType]);
  11731. boundTexture.type = webglType;
  11732. boundTexture.texture = webglTexture;
  11733. }
  11734. }
  11735. function compressedTexImage2D() {
  11736. try {
  11737. gl.compressedTexImage2D.apply(gl, arguments);
  11738. } catch (error) {
  11739. console.error('THREE.WebGLState:', error);
  11740. }
  11741. }
  11742. function texImage2D() {
  11743. try {
  11744. gl.texImage2D.apply(gl, arguments);
  11745. } catch (error) {
  11746. console.error('THREE.WebGLState:', error);
  11747. }
  11748. }
  11749. //
  11750. function scissor(scissor) {
  11751. if (currentScissor.equals(scissor) === false) {
  11752. gl.scissor(scissor.x, scissor.y, scissor.z, scissor.w);
  11753. currentScissor.copy(scissor);
  11754. }
  11755. }
  11756. function viewport(viewport) {
  11757. if (currentViewport.equals(viewport) === false) {
  11758. gl.viewport(viewport.x, viewport.y, viewport.z, viewport.w);
  11759. currentViewport.copy(viewport);
  11760. }
  11761. }
  11762. //
  11763. function reset() {
  11764. for (var i = 0; i < enabledAttributes.length; i++) {
  11765. if (enabledAttributes[i] === 1) {
  11766. gl.disableVertexAttribArray(i);
  11767. enabledAttributes[i] = 0;
  11768. }
  11769. }
  11770. capabilities = {};
  11771. compressedTextureFormats = null;
  11772. currentTextureSlot = null;
  11773. currentBoundTextures = {};
  11774. currentProgram = null;
  11775. currentBlending = null;
  11776. currentFlipSided = null;
  11777. currentCullFace = null;
  11778. colorBuffer.reset();
  11779. depthBuffer.reset();
  11780. stencilBuffer.reset();
  11781. }
  11782. return {
  11783. buffers: {
  11784. color: colorBuffer,
  11785. depth: depthBuffer,
  11786. stencil: stencilBuffer
  11787. },
  11788. initAttributes: initAttributes,
  11789. enableAttribute: enableAttribute,
  11790. enableAttributeAndDivisor: enableAttributeAndDivisor,
  11791. disableUnusedAttributes: disableUnusedAttributes,
  11792. enable: enable,
  11793. disable: disable,
  11794. getCompressedTextureFormats: getCompressedTextureFormats,
  11795. useProgram: useProgram,
  11796. setBlending: setBlending,
  11797. setMaterial: setMaterial,
  11798. setFlipSided: setFlipSided,
  11799. setCullFace: setCullFace,
  11800. setLineWidth: setLineWidth,
  11801. setPolygonOffset: setPolygonOffset,
  11802. setScissorTest: setScissorTest,
  11803. activeTexture: activeTexture,
  11804. bindTexture: bindTexture,
  11805. compressedTexImage2D: compressedTexImage2D,
  11806. texImage2D: texImage2D,
  11807. scissor: scissor,
  11808. viewport: viewport,
  11809. reset: reset
  11810. };
  11811. }
  11812. /**
  11813. * @author mrdoob / http://mrdoob.com/
  11814. */
  11815. function WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info) {
  11816. var _isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext; /* global WebGL2RenderingContext */
  11817. var _videoTextures = {};
  11818. var _canvas;
  11819. //
  11820. function clampToMaxSize(image, maxSize) {
  11821. if (image.width > maxSize || image.height > maxSize) {
  11822. if ('data' in image) {
  11823. console.warn('THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').');
  11824. return;
  11825. }
  11826. // Warning: Scaling through the canvas will only work with images that use
  11827. // premultiplied alpha.
  11828. var scale = maxSize / Math.max(image.width, image.height);
  11829. var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
  11830. canvas.width = Math.floor(image.width * scale);
  11831. canvas.height = Math.floor(image.height * scale);
  11832. var context = canvas.getContext('2d');
  11833. context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
  11834. console.warn('THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image);
  11835. return canvas;
  11836. }
  11837. return image;
  11838. }
  11839. function isPowerOfTwo(image) {
  11840. return _Math.isPowerOfTwo(image.width) && _Math.isPowerOfTwo(image.height);
  11841. }
  11842. function makePowerOfTwo(image) {
  11843. if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap) {
  11844. if (_canvas === undefined) _canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
  11845. _canvas.width = _Math.floorPowerOfTwo(image.width);
  11846. _canvas.height = _Math.floorPowerOfTwo(image.height);
  11847. var context = _canvas.getContext('2d');
  11848. context.drawImage(image, 0, 0, _canvas.width, _canvas.height);
  11849. console.warn('THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height, image);
  11850. return _canvas;
  11851. }
  11852. return image;
  11853. }
  11854. function textureNeedsPowerOfTwo(texture) {
  11855. return texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping || texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
  11856. }
  11857. function textureNeedsGenerateMipmaps(texture, isPowerOfTwo) {
  11858. return texture.generateMipmaps && isPowerOfTwo && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
  11859. }
  11860. function generateMipmap(target, texture, width, height) {
  11861. _gl.generateMipmap(target);
  11862. var textureProperties = properties.get(texture);
  11863. // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
  11864. textureProperties.__maxMipLevel = Math.log(Math.max(width, height)) * Math.LOG2E;
  11865. }
  11866. // Fallback filters for non-power-of-2 textures
  11867. function filterFallback(f) {
  11868. if (f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter) {
  11869. return _gl.NEAREST;
  11870. }
  11871. return _gl.LINEAR;
  11872. }
  11873. //
  11874. function onTextureDispose(event) {
  11875. var texture = event.target;
  11876. texture.removeEventListener('dispose', onTextureDispose);
  11877. deallocateTexture(texture);
  11878. if (texture.isVideoTexture) {
  11879. delete _videoTextures[texture.id];
  11880. }
  11881. info.memory.textures--;
  11882. }
  11883. function onRenderTargetDispose(event) {
  11884. var renderTarget = event.target;
  11885. renderTarget.removeEventListener('dispose', onRenderTargetDispose);
  11886. deallocateRenderTarget(renderTarget);
  11887. info.memory.textures--;
  11888. }
  11889. //
  11890. function deallocateTexture(texture) {
  11891. var textureProperties = properties.get(texture);
  11892. if (texture.image && textureProperties.__image__webglTextureCube) {
  11893. // cube texture
  11894. _gl.deleteTexture(textureProperties.__image__webglTextureCube);
  11895. } else {
  11896. // 2D texture
  11897. if (textureProperties.__webglInit === undefined) return;
  11898. _gl.deleteTexture(textureProperties.__webglTexture);
  11899. }
  11900. // remove all webgl properties
  11901. properties.remove(texture);
  11902. }
  11903. function deallocateRenderTarget(renderTarget) {
  11904. var renderTargetProperties = properties.get(renderTarget);
  11905. var textureProperties = properties.get(renderTarget.texture);
  11906. if (!renderTarget) return;
  11907. if (textureProperties.__webglTexture !== undefined) {
  11908. _gl.deleteTexture(textureProperties.__webglTexture);
  11909. }
  11910. if (renderTarget.depthTexture) {
  11911. renderTarget.depthTexture.dispose();
  11912. }
  11913. if (renderTarget.isWebGLRenderTargetCube) {
  11914. for (var i = 0; i < 6; i++) {
  11915. _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[i]);
  11916. if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer[i]);
  11917. }
  11918. } else {
  11919. _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer);
  11920. if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer);
  11921. }
  11922. properties.remove(renderTarget.texture);
  11923. properties.remove(renderTarget);
  11924. }
  11925. //
  11926. function setTexture2D(texture, slot) {
  11927. var textureProperties = properties.get(texture);
  11928. if (texture.isVideoTexture) updateVideoTexture(texture);
  11929. if (texture.version > 0 && textureProperties.__version !== texture.version) {
  11930. var image = texture.image;
  11931. if (image === undefined) {
  11932. console.warn('THREE.WebGLRenderer: Texture marked for update but image is undefined', texture);
  11933. } else if (image.complete === false) {
  11934. console.warn('THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture);
  11935. } else {
  11936. uploadTexture(textureProperties, texture, slot);
  11937. return;
  11938. }
  11939. }
  11940. state.activeTexture(_gl.TEXTURE0 + slot);
  11941. state.bindTexture(_gl.TEXTURE_2D, textureProperties.__webglTexture);
  11942. }
  11943. function setTextureCube(texture, slot) {
  11944. var textureProperties = properties.get(texture);
  11945. if (texture.image.length === 6) {
  11946. if (texture.version > 0 && textureProperties.__version !== texture.version) {
  11947. if (!textureProperties.__image__webglTextureCube) {
  11948. texture.addEventListener('dispose', onTextureDispose);
  11949. textureProperties.__image__webglTextureCube = _gl.createTexture();
  11950. info.memory.textures++;
  11951. }
  11952. state.activeTexture(_gl.TEXTURE0 + slot);
  11953. state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube);
  11954. _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY);
  11955. var isCompressed = texture && texture.isCompressedTexture;
  11956. var isDataTexture = texture.image[0] && texture.image[0].isDataTexture;
  11957. var cubeImage = [];
  11958. for (var i = 0; i < 6; i++) {
  11959. if (!isCompressed && !isDataTexture) {
  11960. cubeImage[i] = clampToMaxSize(texture.image[i], capabilities.maxCubemapSize);
  11961. } else {
  11962. cubeImage[i] = isDataTexture ? texture.image[i].image : texture.image[i];
  11963. }
  11964. }
  11965. var image = cubeImage[0],
  11966. isPowerOfTwoImage = isPowerOfTwo(image),
  11967. glFormat = utils.convert(texture.format),
  11968. glType = utils.convert(texture.type);
  11969. setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage);
  11970. for (var i = 0; i < 6; i++) {
  11971. if (!isCompressed) {
  11972. if (isDataTexture) {
  11973. state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[i].width, cubeImage[i].height, 0, glFormat, glType, cubeImage[i].data);
  11974. } else {
  11975. state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[i]);
  11976. }
  11977. } else {
  11978. var mipmap,
  11979. mipmaps = cubeImage[i].mipmaps;
  11980. for (var j = 0, jl = mipmaps.length; j < jl; j++) {
  11981. mipmap = mipmaps[j];
  11982. if (texture.format !== RGBAFormat && texture.format !== RGBFormat) {
  11983. if (state.getCompressedTextureFormats().indexOf(glFormat) > -1) {
  11984. state.compressedTexImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data);
  11985. } else {
  11986. console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()');
  11987. }
  11988. } else {
  11989. state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data);
  11990. }
  11991. }
  11992. }
  11993. }
  11994. if (!isCompressed) {
  11995. textureProperties.__maxMipLevel = 0;
  11996. } else {
  11997. textureProperties.__maxMipLevel = mipmaps.length - 1;
  11998. }
  11999. if (textureNeedsGenerateMipmaps(texture, isPowerOfTwoImage)) {
  12000. // We assume images for cube map have the same size.
  12001. generateMipmap(_gl.TEXTURE_CUBE_MAP, texture, image.width, image.height);
  12002. }
  12003. textureProperties.__version = texture.version;
  12004. if (texture.onUpdate) texture.onUpdate(texture);
  12005. } else {
  12006. state.activeTexture(_gl.TEXTURE0 + slot);
  12007. state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube);
  12008. }
  12009. }
  12010. }
  12011. function setTextureCubeDynamic(texture, slot) {
  12012. state.activeTexture(_gl.TEXTURE0 + slot);
  12013. state.bindTexture(_gl.TEXTURE_CUBE_MAP, properties.get(texture).__webglTexture);
  12014. }
  12015. function setTextureParameters(textureType, texture, isPowerOfTwoImage) {
  12016. var extension;
  12017. if (isPowerOfTwoImage) {
  12018. _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, utils.convert(texture.wrapS));
  12019. _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, utils.convert(texture.wrapT));
  12020. _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, utils.convert(texture.magFilter));
  12021. _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, utils.convert(texture.minFilter));
  12022. } else {
  12023. _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE);
  12024. _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE);
  12025. if (texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping) {
  12026. console.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture);
  12027. }
  12028. _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, filterFallback(texture.magFilter));
  12029. _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, filterFallback(texture.minFilter));
  12030. if (texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter) {
  12031. console.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture);
  12032. }
  12033. }
  12034. extension = extensions.get('EXT_texture_filter_anisotropic');
  12035. if (extension) {
  12036. if (texture.type === FloatType && extensions.get('OES_texture_float_linear') === null) return;
  12037. if (texture.type === HalfFloatType && extensions.get('OES_texture_half_float_linear') === null) return;
  12038. if (texture.anisotropy > 1 || properties.get(texture).__currentAnisotropy) {
  12039. _gl.texParameterf(textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropy, capabilities.getMaxAnisotropy()));
  12040. properties.get(texture).__currentAnisotropy = texture.anisotropy;
  12041. }
  12042. }
  12043. }
  12044. function uploadTexture(textureProperties, texture, slot) {
  12045. if (textureProperties.__webglInit === undefined) {
  12046. textureProperties.__webglInit = true;
  12047. texture.addEventListener('dispose', onTextureDispose);
  12048. textureProperties.__webglTexture = _gl.createTexture();
  12049. info.memory.textures++;
  12050. }
  12051. state.activeTexture(_gl.TEXTURE0 + slot);
  12052. state.bindTexture(_gl.TEXTURE_2D, textureProperties.__webglTexture);
  12053. _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY);
  12054. _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha);
  12055. _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment);
  12056. var image = clampToMaxSize(texture.image, capabilities.maxTextureSize);
  12057. if (textureNeedsPowerOfTwo(texture) && isPowerOfTwo(image) === false) {
  12058. image = makePowerOfTwo(image);
  12059. }
  12060. var isPowerOfTwoImage = isPowerOfTwo(image),
  12061. glFormat = utils.convert(texture.format),
  12062. glType = utils.convert(texture.type);
  12063. setTextureParameters(_gl.TEXTURE_2D, texture, isPowerOfTwoImage);
  12064. var mipmap,
  12065. mipmaps = texture.mipmaps;
  12066. if (texture.isDepthTexture) {
  12067. // populate depth texture with dummy data
  12068. var internalFormat = _gl.DEPTH_COMPONENT;
  12069. if (texture.type === FloatType) {
  12070. if (!_isWebGL2) throw new Error('Float Depth Texture only supported in WebGL2.0');
  12071. internalFormat = _gl.DEPTH_COMPONENT32F;
  12072. } else if (_isWebGL2) {
  12073. // WebGL 2.0 requires signed internalformat for glTexImage2D
  12074. internalFormat = _gl.DEPTH_COMPONENT16;
  12075. }
  12076. if (texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT) {
  12077. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  12078. // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
  12079. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  12080. if (texture.type !== UnsignedShortType && texture.type !== UnsignedIntType) {
  12081. console.warn('THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.');
  12082. texture.type = UnsignedShortType;
  12083. glType = utils.convert(texture.type);
  12084. }
  12085. }
  12086. // Depth stencil textures need the DEPTH_STENCIL internal format
  12087. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  12088. if (texture.format === DepthStencilFormat) {
  12089. internalFormat = _gl.DEPTH_STENCIL;
  12090. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  12091. // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
  12092. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  12093. if (texture.type !== UnsignedInt248Type) {
  12094. console.warn('THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.');
  12095. texture.type = UnsignedInt248Type;
  12096. glType = utils.convert(texture.type);
  12097. }
  12098. }
  12099. state.texImage2D(_gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null);
  12100. } else if (texture.isDataTexture) {
  12101. // use manually created mipmaps if available
  12102. // if there are no manual mipmaps
  12103. // set 0 level mipmap and then use GL to generate other mipmap levels
  12104. if (mipmaps.length > 0 && isPowerOfTwoImage) {
  12105. for (var i = 0, il = mipmaps.length; i < il; i++) {
  12106. mipmap = mipmaps[i];
  12107. state.texImage2D(_gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data);
  12108. }
  12109. texture.generateMipmaps = false;
  12110. textureProperties.__maxMipLevel = mipmaps.length - 1;
  12111. } else {
  12112. state.texImage2D(_gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data);
  12113. textureProperties.__maxMipLevel = 0;
  12114. }
  12115. } else if (texture.isCompressedTexture) {
  12116. for (var i = 0, il = mipmaps.length; i < il; i++) {
  12117. mipmap = mipmaps[i];
  12118. if (texture.format !== RGBAFormat && texture.format !== RGBFormat) {
  12119. if (state.getCompressedTextureFormats().indexOf(glFormat) > -1) {
  12120. state.compressedTexImage2D(_gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data);
  12121. } else {
  12122. console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()');
  12123. }
  12124. } else {
  12125. state.texImage2D(_gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data);
  12126. }
  12127. }
  12128. textureProperties.__maxMipLevel = mipmaps.length - 1;
  12129. } else {
  12130. // regular Texture (image, video, canvas)
  12131. // use manually created mipmaps if available
  12132. // if there are no manual mipmaps
  12133. // set 0 level mipmap and then use GL to generate other mipmap levels
  12134. if (mipmaps.length > 0 && isPowerOfTwoImage) {
  12135. for (var i = 0, il = mipmaps.length; i < il; i++) {
  12136. mipmap = mipmaps[i];
  12137. state.texImage2D(_gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap);
  12138. }
  12139. texture.generateMipmaps = false;
  12140. textureProperties.__maxMipLevel = mipmaps.length - 1;
  12141. } else {
  12142. state.texImage2D(_gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image);
  12143. textureProperties.__maxMipLevel = 0;
  12144. }
  12145. }
  12146. if (textureNeedsGenerateMipmaps(texture, isPowerOfTwoImage)) {
  12147. generateMipmap(_gl.TEXTURE_2D, texture, image.width, image.height);
  12148. }
  12149. textureProperties.__version = texture.version;
  12150. if (texture.onUpdate) texture.onUpdate(texture);
  12151. }
  12152. // Render targets
  12153. // Setup storage for target texture and bind it to correct framebuffer
  12154. function setupFrameBufferTexture(framebuffer, renderTarget, attachment, textureTarget) {
  12155. var glFormat = utils.convert(renderTarget.texture.format);
  12156. var glType = utils.convert(renderTarget.texture.type);
  12157. state.texImage2D(textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null);
  12158. _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer);
  12159. _gl.framebufferTexture2D(_gl.FRAMEBUFFER, attachment, textureTarget, properties.get(renderTarget.texture).__webglTexture, 0);
  12160. _gl.bindFramebuffer(_gl.FRAMEBUFFER, null);
  12161. }
  12162. // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
  12163. function setupRenderBufferStorage(renderbuffer, renderTarget) {
  12164. _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer);
  12165. if (renderTarget.depthBuffer && !renderTarget.stencilBuffer) {
  12166. _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height);
  12167. _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer);
  12168. } else if (renderTarget.depthBuffer && renderTarget.stencilBuffer) {
  12169. _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height);
  12170. _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer);
  12171. } else {
  12172. // FIXME: We don't support !depth !stencil
  12173. _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height);
  12174. }
  12175. _gl.bindRenderbuffer(_gl.RENDERBUFFER, null);
  12176. }
  12177. // Setup resources for a Depth Texture for a FBO (needs an extension)
  12178. function setupDepthTexture(framebuffer, renderTarget) {
  12179. var isCube = renderTarget && renderTarget.isWebGLRenderTargetCube;
  12180. if (isCube) throw new Error('Depth Texture with cube render targets is not supported');
  12181. _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer);
  12182. if (!(renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture)) {
  12183. throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture');
  12184. }
  12185. // upload an empty depth texture with framebuffer size
  12186. if (!properties.get(renderTarget.depthTexture).__webglTexture || renderTarget.depthTexture.image.width !== renderTarget.width || renderTarget.depthTexture.image.height !== renderTarget.height) {
  12187. renderTarget.depthTexture.image.width = renderTarget.width;
  12188. renderTarget.depthTexture.image.height = renderTarget.height;
  12189. renderTarget.depthTexture.needsUpdate = true;
  12190. }
  12191. setTexture2D(renderTarget.depthTexture, 0);
  12192. var webglDepthTexture = properties.get(renderTarget.depthTexture).__webglTexture;
  12193. if (renderTarget.depthTexture.format === DepthFormat) {
  12194. _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0);
  12195. } else if (renderTarget.depthTexture.format === DepthStencilFormat) {
  12196. _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0);
  12197. } else {
  12198. throw new Error('Unknown depthTexture format');
  12199. }
  12200. }
  12201. // Setup GL resources for a non-texture depth buffer
  12202. function setupDepthRenderbuffer(renderTarget) {
  12203. var renderTargetProperties = properties.get(renderTarget);
  12204. var isCube = renderTarget.isWebGLRenderTargetCube === true;
  12205. if (renderTarget.depthTexture) {
  12206. if (isCube) throw new Error('target.depthTexture not supported in Cube render targets');
  12207. setupDepthTexture(renderTargetProperties.__webglFramebuffer, renderTarget);
  12208. } else {
  12209. if (isCube) {
  12210. renderTargetProperties.__webglDepthbuffer = [];
  12211. for (var i = 0; i < 6; i++) {
  12212. _gl.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[i]);
  12213. renderTargetProperties.__webglDepthbuffer[i] = _gl.createRenderbuffer();
  12214. setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer[i], renderTarget);
  12215. }
  12216. } else {
  12217. _gl.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer);
  12218. renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
  12219. setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer, renderTarget);
  12220. }
  12221. }
  12222. _gl.bindFramebuffer(_gl.FRAMEBUFFER, null);
  12223. }
  12224. // Set up GL resources for the render target
  12225. function setupRenderTarget(renderTarget) {
  12226. var renderTargetProperties = properties.get(renderTarget);
  12227. var textureProperties = properties.get(renderTarget.texture);
  12228. renderTarget.addEventListener('dispose', onRenderTargetDispose);
  12229. textureProperties.__webglTexture = _gl.createTexture();
  12230. info.memory.textures++;
  12231. var isCube = renderTarget.isWebGLRenderTargetCube === true;
  12232. var isTargetPowerOfTwo = isPowerOfTwo(renderTarget);
  12233. // Setup framebuffer
  12234. if (isCube) {
  12235. renderTargetProperties.__webglFramebuffer = [];
  12236. for (var i = 0; i < 6; i++) {
  12237. renderTargetProperties.__webglFramebuffer[i] = _gl.createFramebuffer();
  12238. }
  12239. } else {
  12240. renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
  12241. }
  12242. // Setup color buffer
  12243. if (isCube) {
  12244. state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture);
  12245. setTextureParameters(_gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo);
  12246. for (var i = 0; i < 6; i++) {
  12247. setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[i], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i);
  12248. }
  12249. if (textureNeedsGenerateMipmaps(renderTarget.texture, isTargetPowerOfTwo)) {
  12250. generateMipmap(_gl.TEXTURE_CUBE_MAP, renderTarget.texture, renderTarget.width, renderTarget.height);
  12251. }
  12252. state.bindTexture(_gl.TEXTURE_CUBE_MAP, null);
  12253. } else {
  12254. state.bindTexture(_gl.TEXTURE_2D, textureProperties.__webglTexture);
  12255. setTextureParameters(_gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo);
  12256. setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D);
  12257. if (textureNeedsGenerateMipmaps(renderTarget.texture, isTargetPowerOfTwo)) {
  12258. generateMipmap(_gl.TEXTURE_2D, renderTarget.texture, renderTarget.width, renderTarget.height);
  12259. }
  12260. state.bindTexture(_gl.TEXTURE_2D, null);
  12261. }
  12262. // Setup depth and stencil buffers
  12263. if (renderTarget.depthBuffer) {
  12264. setupDepthRenderbuffer(renderTarget);
  12265. }
  12266. }
  12267. function updateRenderTargetMipmap(renderTarget) {
  12268. var texture = renderTarget.texture;
  12269. var isTargetPowerOfTwo = isPowerOfTwo(renderTarget);
  12270. if (textureNeedsGenerateMipmaps(texture, isTargetPowerOfTwo)) {
  12271. var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
  12272. var webglTexture = properties.get(texture).__webglTexture;
  12273. state.bindTexture(target, webglTexture);
  12274. generateMipmap(target, texture, renderTarget.width, renderTarget.height);
  12275. state.bindTexture(target, null);
  12276. }
  12277. }
  12278. function updateVideoTexture(texture) {
  12279. var id = texture.id;
  12280. var frame = info.render.frame;
  12281. // Check the last frame we updated the VideoTexture
  12282. if (_videoTextures[id] !== frame) {
  12283. _videoTextures[id] = frame;
  12284. texture.update();
  12285. }
  12286. }
  12287. this.setTexture2D = setTexture2D;
  12288. this.setTextureCube = setTextureCube;
  12289. this.setTextureCubeDynamic = setTextureCubeDynamic;
  12290. this.setupRenderTarget = setupRenderTarget;
  12291. this.updateRenderTargetMipmap = updateRenderTargetMipmap;
  12292. }
  12293. /**
  12294. * @author thespite / http://www.twitter.com/thespite
  12295. */
  12296. function WebGLUtils(gl, extensions) {
  12297. function convert(p) {
  12298. var extension;
  12299. if (p === RepeatWrapping) return gl.REPEAT;
  12300. if (p === ClampToEdgeWrapping) return gl.CLAMP_TO_EDGE;
  12301. if (p === MirroredRepeatWrapping) return gl.MIRRORED_REPEAT;
  12302. if (p === NearestFilter) return gl.NEAREST;
  12303. if (p === NearestMipMapNearestFilter) return gl.NEAREST_MIPMAP_NEAREST;
  12304. if (p === NearestMipMapLinearFilter) return gl.NEAREST_MIPMAP_LINEAR;
  12305. if (p === LinearFilter) return gl.LINEAR;
  12306. if (p === LinearMipMapNearestFilter) return gl.LINEAR_MIPMAP_NEAREST;
  12307. if (p === LinearMipMapLinearFilter) return gl.LINEAR_MIPMAP_LINEAR;
  12308. if (p === UnsignedByteType) return gl.UNSIGNED_BYTE;
  12309. if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4;
  12310. if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1;
  12311. if (p === UnsignedShort565Type) return gl.UNSIGNED_SHORT_5_6_5;
  12312. if (p === ByteType) return gl.BYTE;
  12313. if (p === ShortType) return gl.SHORT;
  12314. if (p === UnsignedShortType) return gl.UNSIGNED_SHORT;
  12315. if (p === IntType) return gl.INT;
  12316. if (p === UnsignedIntType) return gl.UNSIGNED_INT;
  12317. if (p === FloatType) return gl.FLOAT;
  12318. if (p === HalfFloatType) {
  12319. extension = extensions.get('OES_texture_half_float');
  12320. if (extension !== null) return extension.HALF_FLOAT_OES;
  12321. }
  12322. if (p === AlphaFormat) return gl.ALPHA;
  12323. if (p === RGBFormat) return gl.RGB;
  12324. if (p === RGBAFormat) return gl.RGBA;
  12325. if (p === LuminanceFormat) return gl.LUMINANCE;
  12326. if (p === LuminanceAlphaFormat) return gl.LUMINANCE_ALPHA;
  12327. if (p === DepthFormat) return gl.DEPTH_COMPONENT;
  12328. if (p === DepthStencilFormat) return gl.DEPTH_STENCIL;
  12329. if (p === AddEquation) return gl.FUNC_ADD;
  12330. if (p === SubtractEquation) return gl.FUNC_SUBTRACT;
  12331. if (p === ReverseSubtractEquation) return gl.FUNC_REVERSE_SUBTRACT;
  12332. if (p === ZeroFactor) return gl.ZERO;
  12333. if (p === OneFactor) return gl.ONE;
  12334. if (p === SrcColorFactor) return gl.SRC_COLOR;
  12335. if (p === OneMinusSrcColorFactor) return gl.ONE_MINUS_SRC_COLOR;
  12336. if (p === SrcAlphaFactor) return gl.SRC_ALPHA;
  12337. if (p === OneMinusSrcAlphaFactor) return gl.ONE_MINUS_SRC_ALPHA;
  12338. if (p === DstAlphaFactor) return gl.DST_ALPHA;
  12339. if (p === OneMinusDstAlphaFactor) return gl.ONE_MINUS_DST_ALPHA;
  12340. if (p === DstColorFactor) return gl.DST_COLOR;
  12341. if (p === OneMinusDstColorFactor) return gl.ONE_MINUS_DST_COLOR;
  12342. if (p === SrcAlphaSaturateFactor) return gl.SRC_ALPHA_SATURATE;
  12343. if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) {
  12344. extension = extensions.get('WEBGL_compressed_texture_s3tc');
  12345. if (extension !== null) {
  12346. if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
  12347. if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
  12348. if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
  12349. if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
  12350. }
  12351. }
  12352. if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) {
  12353. extension = extensions.get('WEBGL_compressed_texture_pvrtc');
  12354. if (extension !== null) {
  12355. if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
  12356. if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  12357. if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  12358. if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
  12359. }
  12360. }
  12361. if (p === RGB_ETC1_Format) {
  12362. extension = extensions.get('WEBGL_compressed_texture_etc1');
  12363. if (extension !== null) return extension.COMPRESSED_RGB_ETC1_WEBGL;
  12364. }
  12365. if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) {
  12366. extension = extensions.get('WEBGL_compressed_texture_astc');
  12367. if (extension !== null) {
  12368. return p;
  12369. }
  12370. }
  12371. if (p === MinEquation || p === MaxEquation) {
  12372. extension = extensions.get('EXT_blend_minmax');
  12373. if (extension !== null) {
  12374. if (p === MinEquation) return extension.MIN_EXT;
  12375. if (p === MaxEquation) return extension.MAX_EXT;
  12376. }
  12377. }
  12378. if (p === UnsignedInt248Type) {
  12379. extension = extensions.get('WEBGL_depth_texture');
  12380. if (extension !== null) return extension.UNSIGNED_INT_24_8_WEBGL;
  12381. }
  12382. return 0;
  12383. }
  12384. return { convert: convert };
  12385. }
  12386. /**
  12387. * @author mrdoob / http://mrdoob.com/
  12388. * @author greggman / http://games.greggman.com/
  12389. * @author zz85 / http://www.lab4games.net/zz85/blog
  12390. * @author tschw
  12391. */
  12392. function PerspectiveCamera(fov, aspect, near, far) {
  12393. Camera.call(this);
  12394. this.type = 'PerspectiveCamera';
  12395. this.fov = fov !== undefined ? fov : 50;
  12396. this.zoom = 1;
  12397. this.near = near !== undefined ? near : 0.1;
  12398. this.far = far !== undefined ? far : 2000;
  12399. this.focus = 10;
  12400. this.aspect = aspect !== undefined ? aspect : 1;
  12401. this.view = null;
  12402. this.filmGauge = 35; // width of the film (default in millimeters)
  12403. this.filmOffset = 0; // horizontal film offset (same unit as gauge)
  12404. this.updateProjectionMatrix();
  12405. }
  12406. PerspectiveCamera.prototype = Object.assign(Object.create(Camera.prototype), {
  12407. constructor: PerspectiveCamera,
  12408. isPerspectiveCamera: true,
  12409. copy: function (source, recursive) {
  12410. Camera.prototype.copy.call(this, source, recursive);
  12411. this.fov = source.fov;
  12412. this.zoom = source.zoom;
  12413. this.near = source.near;
  12414. this.far = source.far;
  12415. this.focus = source.focus;
  12416. this.aspect = source.aspect;
  12417. this.view = source.view === null ? null : Object.assign({}, source.view);
  12418. this.filmGauge = source.filmGauge;
  12419. this.filmOffset = source.filmOffset;
  12420. return this;
  12421. },
  12422. /**
  12423. * Sets the FOV by focal length in respect to the current .filmGauge.
  12424. *
  12425. * The default film gauge is 35, so that the focal length can be specified for
  12426. * a 35mm (full frame) camera.
  12427. *
  12428. * Values for focal length and film gauge must have the same unit.
  12429. */
  12430. setFocalLength: function (focalLength) {
  12431. // see http://www.bobatkins.com/photography/technical/field_of_view.html
  12432. var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
  12433. this.fov = _Math.RAD2DEG * 2 * Math.atan(vExtentSlope);
  12434. this.updateProjectionMatrix();
  12435. },
  12436. /**
  12437. * Calculates the focal length from the current .fov and .filmGauge.
  12438. */
  12439. getFocalLength: function () {
  12440. var vExtentSlope = Math.tan(_Math.DEG2RAD * 0.5 * this.fov);
  12441. return 0.5 * this.getFilmHeight() / vExtentSlope;
  12442. },
  12443. getEffectiveFOV: function () {
  12444. return _Math.RAD2DEG * 2 * Math.atan(Math.tan(_Math.DEG2RAD * 0.5 * this.fov) / this.zoom);
  12445. },
  12446. getFilmWidth: function () {
  12447. // film not completely covered in portrait format (aspect < 1)
  12448. return this.filmGauge * Math.min(this.aspect, 1);
  12449. },
  12450. getFilmHeight: function () {
  12451. // film not completely covered in landscape format (aspect > 1)
  12452. return this.filmGauge / Math.max(this.aspect, 1);
  12453. },
  12454. /**
  12455. * Sets an offset in a larger frustum. This is useful for multi-window or
  12456. * multi-monitor/multi-machine setups.
  12457. *
  12458. * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
  12459. * the monitors are in grid like this
  12460. *
  12461. * +---+---+---+
  12462. * | A | B | C |
  12463. * +---+---+---+
  12464. * | D | E | F |
  12465. * +---+---+---+
  12466. *
  12467. * then for each monitor you would call it like this
  12468. *
  12469. * var w = 1920;
  12470. * var h = 1080;
  12471. * var fullWidth = w * 3;
  12472. * var fullHeight = h * 2;
  12473. *
  12474. * --A--
  12475. * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
  12476. * --B--
  12477. * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
  12478. * --C--
  12479. * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
  12480. * --D--
  12481. * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
  12482. * --E--
  12483. * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
  12484. * --F--
  12485. * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
  12486. *
  12487. * Note there is no reason monitors have to be the same size or in a grid.
  12488. */
  12489. setViewOffset: function (fullWidth, fullHeight, x, y, width, height) {
  12490. this.aspect = fullWidth / fullHeight;
  12491. if (this.view === null) {
  12492. this.view = {
  12493. enabled: true,
  12494. fullWidth: 1,
  12495. fullHeight: 1,
  12496. offsetX: 0,
  12497. offsetY: 0,
  12498. width: 1,
  12499. height: 1
  12500. };
  12501. }
  12502. this.view.enabled = true;
  12503. this.view.fullWidth = fullWidth;
  12504. this.view.fullHeight = fullHeight;
  12505. this.view.offsetX = x;
  12506. this.view.offsetY = y;
  12507. this.view.width = width;
  12508. this.view.height = height;
  12509. this.updateProjectionMatrix();
  12510. },
  12511. clearViewOffset: function () {
  12512. if (this.view !== null) {
  12513. this.view.enabled = false;
  12514. }
  12515. this.updateProjectionMatrix();
  12516. },
  12517. updateProjectionMatrix: function () {
  12518. var near = this.near,
  12519. top = near * Math.tan(_Math.DEG2RAD * 0.5 * this.fov) / this.zoom,
  12520. height = 2 * top,
  12521. width = this.aspect * height,
  12522. left = -0.5 * width,
  12523. view = this.view;
  12524. if (this.view !== null && this.view.enabled) {
  12525. var fullWidth = view.fullWidth,
  12526. fullHeight = view.fullHeight;
  12527. left += view.offsetX * width / fullWidth;
  12528. top -= view.offsetY * height / fullHeight;
  12529. width *= view.width / fullWidth;
  12530. height *= view.height / fullHeight;
  12531. }
  12532. var skew = this.filmOffset;
  12533. if (skew !== 0) left += near * skew / this.getFilmWidth();
  12534. this.projectionMatrix.makePerspective(left, left + width, top, top - height, near, this.far);
  12535. },
  12536. toJSON: function (meta) {
  12537. var data = Object3D.prototype.toJSON.call(this, meta);
  12538. data.object.fov = this.fov;
  12539. data.object.zoom = this.zoom;
  12540. data.object.near = this.near;
  12541. data.object.far = this.far;
  12542. data.object.focus = this.focus;
  12543. data.object.aspect = this.aspect;
  12544. if (this.view !== null) data.object.view = Object.assign({}, this.view);
  12545. data.object.filmGauge = this.filmGauge;
  12546. data.object.filmOffset = this.filmOffset;
  12547. return data;
  12548. }
  12549. });
  12550. /**
  12551. * @author mrdoob / http://mrdoob.com/
  12552. */
  12553. function ArrayCamera(array) {
  12554. PerspectiveCamera.call(this);
  12555. this.cameras = array || [];
  12556. }
  12557. ArrayCamera.prototype = Object.assign(Object.create(PerspectiveCamera.prototype), {
  12558. constructor: ArrayCamera,
  12559. isArrayCamera: true
  12560. });
  12561. /**
  12562. * @author mrdoob / http://mrdoob.com/
  12563. */
  12564. function WebVRManager(renderer) {
  12565. var scope = this;
  12566. var device = null;
  12567. var frameData = null;
  12568. var poseTarget = null;
  12569. var standingMatrix = new Matrix4();
  12570. var standingMatrixInverse = new Matrix4();
  12571. if (typeof window !== 'undefined' && 'VRFrameData' in window) {
  12572. frameData = new window.VRFrameData();
  12573. window.addEventListener('vrdisplaypresentchange', onVRDisplayPresentChange, false);
  12574. }
  12575. var matrixWorldInverse = new Matrix4();
  12576. var tempQuaternion = new Quaternion();
  12577. var tempPosition = new Vector3();
  12578. var cameraL = new PerspectiveCamera();
  12579. cameraL.bounds = new Vector4(0.0, 0.0, 0.5, 1.0);
  12580. cameraL.layers.enable(1);
  12581. var cameraR = new PerspectiveCamera();
  12582. cameraR.bounds = new Vector4(0.5, 0.0, 0.5, 1.0);
  12583. cameraR.layers.enable(2);
  12584. var cameraVR = new ArrayCamera([cameraL, cameraR]);
  12585. cameraVR.layers.enable(1);
  12586. cameraVR.layers.enable(2);
  12587. //
  12588. function isPresenting() {
  12589. return device !== null && device.isPresenting === true;
  12590. }
  12591. var currentSize, currentPixelRatio;
  12592. function onVRDisplayPresentChange() {
  12593. if (isPresenting()) {
  12594. var eyeParameters = device.getEyeParameters('left');
  12595. var renderWidth = eyeParameters.renderWidth;
  12596. var renderHeight = eyeParameters.renderHeight;
  12597. currentPixelRatio = renderer.getPixelRatio();
  12598. currentSize = renderer.getSize();
  12599. renderer.setDrawingBufferSize(renderWidth * 2, renderHeight, 1);
  12600. animation.start();
  12601. } else if (scope.enabled) {
  12602. renderer.setDrawingBufferSize(currentSize.width, currentSize.height, currentPixelRatio);
  12603. animation.stop();
  12604. }
  12605. }
  12606. //
  12607. this.enabled = false;
  12608. this.userHeight = 1.6;
  12609. this.getDevice = function () {
  12610. return device;
  12611. };
  12612. this.setDevice = function (value) {
  12613. if (value !== undefined) device = value;
  12614. animation.setContext(value);
  12615. };
  12616. this.setPoseTarget = function (object) {
  12617. if (object !== undefined) poseTarget = object;
  12618. };
  12619. this.getCamera = function (camera) {
  12620. if (device === null) return camera;
  12621. device.depthNear = camera.near;
  12622. device.depthFar = camera.far;
  12623. device.getFrameData(frameData);
  12624. //
  12625. var stageParameters = device.stageParameters;
  12626. if (stageParameters) {
  12627. standingMatrix.fromArray(stageParameters.sittingToStandingTransform);
  12628. } else {
  12629. standingMatrix.makeTranslation(0, scope.userHeight, 0);
  12630. }
  12631. var pose = frameData.pose;
  12632. var poseObject = poseTarget !== null ? poseTarget : camera;
  12633. // We want to manipulate poseObject by its position and quaternion components since users may rely on them.
  12634. poseObject.matrix.copy(standingMatrix);
  12635. poseObject.matrix.decompose(poseObject.position, poseObject.quaternion, poseObject.scale);
  12636. if (pose.orientation !== null) {
  12637. tempQuaternion.fromArray(pose.orientation);
  12638. poseObject.quaternion.multiply(tempQuaternion);
  12639. }
  12640. if (pose.position !== null) {
  12641. tempQuaternion.setFromRotationMatrix(standingMatrix);
  12642. tempPosition.fromArray(pose.position);
  12643. tempPosition.applyQuaternion(tempQuaternion);
  12644. poseObject.position.add(tempPosition);
  12645. }
  12646. poseObject.updateMatrixWorld();
  12647. if (device.isPresenting === false) return camera;
  12648. //
  12649. cameraL.near = camera.near;
  12650. cameraR.near = camera.near;
  12651. cameraL.far = camera.far;
  12652. cameraR.far = camera.far;
  12653. cameraVR.matrixWorld.copy(camera.matrixWorld);
  12654. cameraVR.matrixWorldInverse.copy(camera.matrixWorldInverse);
  12655. cameraL.matrixWorldInverse.fromArray(frameData.leftViewMatrix);
  12656. cameraR.matrixWorldInverse.fromArray(frameData.rightViewMatrix);
  12657. // TODO (mrdoob) Double check this code
  12658. standingMatrixInverse.getInverse(standingMatrix);
  12659. cameraL.matrixWorldInverse.multiply(standingMatrixInverse);
  12660. cameraR.matrixWorldInverse.multiply(standingMatrixInverse);
  12661. var parent = poseObject.parent;
  12662. if (parent !== null) {
  12663. matrixWorldInverse.getInverse(parent.matrixWorld);
  12664. cameraL.matrixWorldInverse.multiply(matrixWorldInverse);
  12665. cameraR.matrixWorldInverse.multiply(matrixWorldInverse);
  12666. }
  12667. // envMap and Mirror needs camera.matrixWorld
  12668. cameraL.matrixWorld.getInverse(cameraL.matrixWorldInverse);
  12669. cameraR.matrixWorld.getInverse(cameraR.matrixWorldInverse);
  12670. cameraL.projectionMatrix.fromArray(frameData.leftProjectionMatrix);
  12671. cameraR.projectionMatrix.fromArray(frameData.rightProjectionMatrix);
  12672. // HACK (mrdoob)
  12673. // https://github.com/w3c/webvr/issues/203
  12674. cameraVR.projectionMatrix.copy(cameraL.projectionMatrix);
  12675. //
  12676. var layers = device.getLayers();
  12677. if (layers.length) {
  12678. var layer = layers[0];
  12679. if (layer.leftBounds !== null && layer.leftBounds.length === 4) {
  12680. cameraL.bounds.fromArray(layer.leftBounds);
  12681. }
  12682. if (layer.rightBounds !== null && layer.rightBounds.length === 4) {
  12683. cameraR.bounds.fromArray(layer.rightBounds);
  12684. }
  12685. }
  12686. return cameraVR;
  12687. };
  12688. this.getStandingMatrix = function () {
  12689. return standingMatrix;
  12690. };
  12691. this.isPresenting = isPresenting;
  12692. // Animation Loop
  12693. var animation = new WebGLAnimation();
  12694. this.setAnimationLoop = function (callback) {
  12695. animation.setAnimationLoop(callback);
  12696. };
  12697. this.submitFrame = function () {
  12698. if (isPresenting()) device.submitFrame();
  12699. };
  12700. this.dispose = function () {
  12701. if (typeof window !== 'undefined') {
  12702. window.removeEventListener('vrdisplaypresentchange', onVRDisplayPresentChange);
  12703. }
  12704. };
  12705. }
  12706. /**
  12707. * @author mrdoob / http://mrdoob.com/
  12708. */
  12709. function WebXRManager(renderer) {
  12710. var gl = renderer.context;
  12711. var device = null;
  12712. var session = null;
  12713. var frameOfRef = null;
  12714. var pose = null;
  12715. function isPresenting() {
  12716. return session !== null && frameOfRef !== null;
  12717. }
  12718. //
  12719. var cameraL = new PerspectiveCamera();
  12720. cameraL.layers.enable(1);
  12721. cameraL.viewport = new Vector4();
  12722. var cameraR = new PerspectiveCamera();
  12723. cameraR.layers.enable(2);
  12724. cameraR.viewport = new Vector4();
  12725. var cameraVR = new ArrayCamera([cameraL, cameraR]);
  12726. cameraVR.layers.enable(1);
  12727. cameraVR.layers.enable(2);
  12728. //
  12729. this.enabled = false;
  12730. this.getDevice = function () {
  12731. return device;
  12732. };
  12733. this.setDevice = function (value) {
  12734. if (value !== undefined) device = value;
  12735. gl.setCompatibleXRDevice(value);
  12736. };
  12737. //
  12738. this.setSession = function (value, options) {
  12739. session = value;
  12740. if (session !== null) {
  12741. session.addEventListener('end', function () {
  12742. renderer.setFramebuffer(null);
  12743. animation.stop();
  12744. });
  12745. session.baseLayer = new XRWebGLLayer(session, gl);
  12746. session.requestFrameOfReference(options.frameOfReferenceType).then(function (value) {
  12747. frameOfRef = value;
  12748. renderer.setFramebuffer(session.baseLayer.framebuffer);
  12749. animation.setContext(session);
  12750. animation.start();
  12751. });
  12752. }
  12753. };
  12754. function updateCamera(camera, parent) {
  12755. if (parent === null) {
  12756. camera.matrixWorld.copy(camera.matrix);
  12757. } else {
  12758. camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix);
  12759. }
  12760. camera.matrixWorldInverse.getInverse(camera.matrixWorld);
  12761. }
  12762. this.getCamera = function (camera) {
  12763. if (isPresenting()) {
  12764. var parent = camera.parent;
  12765. var cameras = cameraVR.cameras;
  12766. // apply camera.parent to cameraVR
  12767. updateCamera(cameraVR, parent);
  12768. for (var i = 0; i < cameras.length; i++) {
  12769. updateCamera(cameras[i], parent);
  12770. }
  12771. // update camera and its children
  12772. camera.matrixWorld.copy(cameraVR.matrixWorld);
  12773. var children = camera.children;
  12774. for (var i = 0, l = children.length; i < l; i++) {
  12775. children[i].updateMatrixWorld(true);
  12776. }
  12777. return cameraVR;
  12778. }
  12779. return camera;
  12780. };
  12781. this.isPresenting = isPresenting;
  12782. // Animation Loop
  12783. var onAnimationFrameCallback = null;
  12784. function onAnimationFrame(time, frame) {
  12785. pose = frame.getDevicePose(frameOfRef);
  12786. var layer = session.baseLayer;
  12787. var views = frame.views;
  12788. for (var i = 0; i < views.length; i++) {
  12789. var view = views[i];
  12790. var viewport = layer.getViewport(view);
  12791. var viewMatrix = pose.getViewMatrix(view);
  12792. var camera = cameraVR.cameras[i];
  12793. camera.matrix.fromArray(viewMatrix).getInverse(camera.matrix);
  12794. camera.projectionMatrix.fromArray(view.projectionMatrix);
  12795. camera.viewport.set(viewport.x, viewport.y, viewport.width, viewport.height);
  12796. if (i === 0) {
  12797. cameraVR.matrix.copy(camera.matrix);
  12798. // HACK (mrdoob)
  12799. // https://github.com/w3c/webvr/issues/203
  12800. cameraVR.projectionMatrix.copy(camera.projectionMatrix);
  12801. }
  12802. }
  12803. if (onAnimationFrameCallback) onAnimationFrameCallback();
  12804. }
  12805. var animation = new WebGLAnimation();
  12806. animation.setAnimationLoop(onAnimationFrame);
  12807. this.setAnimationLoop = function (callback) {
  12808. onAnimationFrameCallback = callback;
  12809. };
  12810. // DEPRECATED
  12811. this.getStandingMatrix = function () {
  12812. console.warn('THREE.WebXRManager: getStandingMatrix() is no longer needed.');
  12813. return new THREE.Matrix4();
  12814. };
  12815. this.submitFrame = function () {};
  12816. }
  12817. /**
  12818. * @author supereggbert / http://www.paulbrunt.co.uk/
  12819. * @author mrdoob / http://mrdoob.com/
  12820. * @author alteredq / http://alteredqualia.com/
  12821. * @author szimek / https://github.com/szimek/
  12822. * @author tschw
  12823. */
  12824. function WebGLRenderer(parameters) {
  12825. console.log('THREE.WebGLRenderer', REVISION);
  12826. parameters = parameters || {};
  12827. var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'),
  12828. _context = parameters.context !== undefined ? parameters.context : null,
  12829. _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
  12830. _depth = parameters.depth !== undefined ? parameters.depth : true,
  12831. _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
  12832. _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
  12833. _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
  12834. _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
  12835. _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default';
  12836. var currentRenderList = null;
  12837. var currentRenderState = null;
  12838. // public properties
  12839. this.domElement = _canvas;
  12840. this.context = null;
  12841. // clearing
  12842. this.autoClear = true;
  12843. this.autoClearColor = true;
  12844. this.autoClearDepth = true;
  12845. this.autoClearStencil = true;
  12846. // scene graph
  12847. this.sortObjects = true;
  12848. // user-defined clipping
  12849. this.clippingPlanes = [];
  12850. this.localClippingEnabled = false;
  12851. // physically based shading
  12852. this.gammaFactor = 2.0; // for backwards compatibility
  12853. this.gammaInput = false;
  12854. this.gammaOutput = false;
  12855. // physical lights
  12856. this.physicallyCorrectLights = false;
  12857. // tone mapping
  12858. this.toneMapping = LinearToneMapping;
  12859. this.toneMappingExposure = 1.0;
  12860. this.toneMappingWhitePoint = 1.0;
  12861. // morphs
  12862. this.maxMorphTargets = 8;
  12863. this.maxMorphNormals = 4;
  12864. // internal properties
  12865. var _this = this,
  12866. _isContextLost = false,
  12867. // internal state cache
  12868. _framebuffer = null,
  12869. _currentRenderTarget = null,
  12870. _currentFramebuffer = null,
  12871. _currentMaterialId = -1,
  12872. _currentGeometryProgram = '',
  12873. _currentCamera = null,
  12874. _currentArrayCamera = null,
  12875. _currentViewport = new Vector4(),
  12876. _currentScissor = new Vector4(),
  12877. _currentScissorTest = null,
  12878. //
  12879. _usedTextureUnits = 0,
  12880. //
  12881. _width = _canvas.width,
  12882. _height = _canvas.height,
  12883. _pixelRatio = 1,
  12884. _viewport = new Vector4(0, 0, _width, _height),
  12885. _scissor = new Vector4(0, 0, _width, _height),
  12886. _scissorTest = false,
  12887. // frustum
  12888. _frustum = new Frustum(),
  12889. // clipping
  12890. _clipping = new WebGLClipping(),
  12891. _clippingEnabled = false,
  12892. _localClippingEnabled = false,
  12893. // camera matrices cache
  12894. _projScreenMatrix = new Matrix4(),
  12895. _vector3 = new Vector3();
  12896. function getTargetPixelRatio() {
  12897. return _currentRenderTarget === null ? _pixelRatio : 1;
  12898. }
  12899. // initialize
  12900. var _gl;
  12901. try {
  12902. var contextAttributes = {
  12903. alpha: _alpha,
  12904. depth: _depth,
  12905. stencil: _stencil,
  12906. antialias: _antialias,
  12907. premultipliedAlpha: _premultipliedAlpha,
  12908. preserveDrawingBuffer: _preserveDrawingBuffer,
  12909. powerPreference: _powerPreference
  12910. };
  12911. // event listeners must be registered before WebGL context is created, see #12753
  12912. _canvas.addEventListener('webglcontextlost', onContextLost, false);
  12913. _canvas.addEventListener('webglcontextrestored', onContextRestore, false);
  12914. _gl = _context || _canvas.getContext('webgl', contextAttributes) || _canvas.getContext('experimental-webgl', contextAttributes);
  12915. if (_gl === null) {
  12916. if (_canvas.getContext('webgl') !== null) {
  12917. throw new Error('Error creating WebGL context with your selected attributes.');
  12918. } else {
  12919. throw new Error('Error creating WebGL context.');
  12920. }
  12921. }
  12922. // Some experimental-webgl implementations do not have getShaderPrecisionFormat
  12923. if (_gl.getShaderPrecisionFormat === undefined) {
  12924. _gl.getShaderPrecisionFormat = function () {
  12925. return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
  12926. };
  12927. }
  12928. } catch (error) {
  12929. console.error('THREE.WebGLRenderer: ' + error.message);
  12930. }
  12931. var extensions, capabilities, state, info;
  12932. var properties, textures, attributes, geometries, objects;
  12933. var programCache, renderLists, renderStates;
  12934. var background, morphtargets, bufferRenderer, indexedBufferRenderer;
  12935. var spriteRenderer;
  12936. var utils;
  12937. function initGLContext() {
  12938. extensions = new WebGLExtensions(_gl);
  12939. extensions.get('WEBGL_depth_texture');
  12940. extensions.get('OES_texture_float');
  12941. extensions.get('OES_texture_float_linear');
  12942. extensions.get('OES_texture_half_float');
  12943. extensions.get('OES_texture_half_float_linear');
  12944. extensions.get('OES_standard_derivatives');
  12945. extensions.get('OES_element_index_uint');
  12946. extensions.get('ANGLE_instanced_arrays');
  12947. utils = new WebGLUtils(_gl, extensions);
  12948. capabilities = new WebGLCapabilities(_gl, extensions, parameters);
  12949. state = new WebGLState(_gl, extensions, utils);
  12950. state.scissor(_currentScissor.copy(_scissor).multiplyScalar(_pixelRatio));
  12951. state.viewport(_currentViewport.copy(_viewport).multiplyScalar(_pixelRatio));
  12952. info = new WebGLInfo(_gl);
  12953. properties = new WebGLProperties();
  12954. textures = new WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info);
  12955. attributes = new WebGLAttributes(_gl);
  12956. geometries = new WebGLGeometries(_gl, attributes, info);
  12957. objects = new WebGLObjects(geometries, info);
  12958. morphtargets = new WebGLMorphtargets(_gl);
  12959. programCache = new WebGLPrograms(_this, extensions, capabilities);
  12960. renderLists = new WebGLRenderLists();
  12961. renderStates = new WebGLRenderStates();
  12962. background = new WebGLBackground(_this, state, objects, _premultipliedAlpha);
  12963. bufferRenderer = new WebGLBufferRenderer(_gl, extensions, info);
  12964. indexedBufferRenderer = new WebGLIndexedBufferRenderer(_gl, extensions, info);
  12965. spriteRenderer = new WebGLSpriteRenderer(_this, _gl, state, textures, capabilities);
  12966. info.programs = programCache.programs;
  12967. _this.context = _gl;
  12968. _this.capabilities = capabilities;
  12969. _this.extensions = extensions;
  12970. _this.properties = properties;
  12971. _this.renderLists = renderLists;
  12972. _this.state = state;
  12973. _this.info = info;
  12974. }
  12975. initGLContext();
  12976. // vr
  12977. var vr = 'xr' in navigator ? new WebXRManager(_this) : new WebVRManager(_this);
  12978. this.vr = vr;
  12979. // shadow map
  12980. var shadowMap = new WebGLShadowMap(_this, objects, capabilities.maxTextureSize);
  12981. this.shadowMap = shadowMap;
  12982. // API
  12983. this.getContext = function () {
  12984. return _gl;
  12985. };
  12986. this.getContextAttributes = function () {
  12987. return _gl.getContextAttributes();
  12988. };
  12989. this.forceContextLoss = function () {
  12990. var extension = extensions.get('WEBGL_lose_context');
  12991. if (extension) extension.loseContext();
  12992. };
  12993. this.forceContextRestore = function () {
  12994. var extension = extensions.get('WEBGL_lose_context');
  12995. if (extension) extension.restoreContext();
  12996. };
  12997. this.getPixelRatio = function () {
  12998. return _pixelRatio;
  12999. };
  13000. this.setPixelRatio = function (value) {
  13001. if (value === undefined) return;
  13002. _pixelRatio = value;
  13003. this.setSize(_width, _height, false);
  13004. };
  13005. this.getSize = function () {
  13006. return {
  13007. width: _width,
  13008. height: _height
  13009. };
  13010. };
  13011. this.setSize = function (width, height, updateStyle) {
  13012. if (vr.isPresenting()) {
  13013. console.warn('THREE.WebGLRenderer: Can\'t change size while VR device is presenting.');
  13014. return;
  13015. }
  13016. _width = width;
  13017. _height = height;
  13018. _canvas.width = width * _pixelRatio;
  13019. _canvas.height = height * _pixelRatio;
  13020. if (updateStyle !== false) {
  13021. _canvas.style.width = width + 'px';
  13022. _canvas.style.height = height + 'px';
  13023. }
  13024. this.setViewport(0, 0, width, height);
  13025. };
  13026. this.getDrawingBufferSize = function () {
  13027. return {
  13028. width: _width * _pixelRatio,
  13029. height: _height * _pixelRatio
  13030. };
  13031. };
  13032. this.setDrawingBufferSize = function (width, height, pixelRatio) {
  13033. _width = width;
  13034. _height = height;
  13035. _pixelRatio = pixelRatio;
  13036. _canvas.width = width * pixelRatio;
  13037. _canvas.height = height * pixelRatio;
  13038. this.setViewport(0, 0, width, height);
  13039. };
  13040. this.getCurrentViewport = function () {
  13041. return _currentViewport;
  13042. };
  13043. this.setViewport = function (x, y, width, height) {
  13044. _viewport.set(x, _height - y - height, width, height);
  13045. state.viewport(_currentViewport.copy(_viewport).multiplyScalar(_pixelRatio));
  13046. };
  13047. this.setScissor = function (x, y, width, height) {
  13048. _scissor.set(x, _height - y - height, width, height);
  13049. state.scissor(_currentScissor.copy(_scissor).multiplyScalar(_pixelRatio));
  13050. };
  13051. this.setScissorTest = function (boolean) {
  13052. state.setScissorTest(_scissorTest = boolean);
  13053. };
  13054. // Clearing
  13055. this.getClearColor = function () {
  13056. return background.getClearColor();
  13057. };
  13058. this.setClearColor = function () {
  13059. background.setClearColor.apply(background, arguments);
  13060. };
  13061. this.getClearAlpha = function () {
  13062. return background.getClearAlpha();
  13063. };
  13064. this.setClearAlpha = function () {
  13065. background.setClearAlpha.apply(background, arguments);
  13066. };
  13067. this.clear = function (color, depth, stencil) {
  13068. var bits = 0;
  13069. if (color === undefined || color) bits |= _gl.COLOR_BUFFER_BIT;
  13070. if (depth === undefined || depth) bits |= _gl.DEPTH_BUFFER_BIT;
  13071. if (stencil === undefined || stencil) bits |= _gl.STENCIL_BUFFER_BIT;
  13072. _gl.clear(bits);
  13073. };
  13074. this.clearColor = function () {
  13075. this.clear(true, false, false);
  13076. };
  13077. this.clearDepth = function () {
  13078. this.clear(false, true, false);
  13079. };
  13080. this.clearStencil = function () {
  13081. this.clear(false, false, true);
  13082. };
  13083. this.clearTarget = function (renderTarget, color, depth, stencil) {
  13084. this.setRenderTarget(renderTarget);
  13085. this.clear(color, depth, stencil);
  13086. };
  13087. //
  13088. this.dispose = function () {
  13089. _canvas.removeEventListener('webglcontextlost', onContextLost, false);
  13090. _canvas.removeEventListener('webglcontextrestored', onContextRestore, false);
  13091. renderLists.dispose();
  13092. renderStates.dispose();
  13093. properties.dispose();
  13094. objects.dispose();
  13095. vr.dispose();
  13096. animation.stop();
  13097. };
  13098. // Events
  13099. function onContextLost(event) {
  13100. event.preventDefault();
  13101. console.log('THREE.WebGLRenderer: Context Lost.');
  13102. _isContextLost = true;
  13103. }
  13104. function onContextRestore() /* event */{
  13105. console.log('THREE.WebGLRenderer: Context Restored.');
  13106. _isContextLost = false;
  13107. initGLContext();
  13108. }
  13109. function onMaterialDispose(event) {
  13110. var material = event.target;
  13111. material.removeEventListener('dispose', onMaterialDispose);
  13112. deallocateMaterial(material);
  13113. }
  13114. // Buffer deallocation
  13115. function deallocateMaterial(material) {
  13116. releaseMaterialProgramReference(material);
  13117. properties.remove(material);
  13118. }
  13119. function releaseMaterialProgramReference(material) {
  13120. var programInfo = properties.get(material).program;
  13121. material.program = undefined;
  13122. if (programInfo !== undefined) {
  13123. programCache.releaseProgram(programInfo);
  13124. }
  13125. }
  13126. // Buffer rendering
  13127. function renderObjectImmediate(object, program, material) {
  13128. object.render(function (object) {
  13129. _this.renderBufferImmediate(object, program, material);
  13130. });
  13131. }
  13132. this.renderBufferImmediate = function (object, program, material) {
  13133. state.initAttributes();
  13134. var buffers = properties.get(object);
  13135. if (object.hasPositions && !buffers.position) buffers.position = _gl.createBuffer();
  13136. if (object.hasNormals && !buffers.normal) buffers.normal = _gl.createBuffer();
  13137. if (object.hasUvs && !buffers.uv) buffers.uv = _gl.createBuffer();
  13138. if (object.hasColors && !buffers.color) buffers.color = _gl.createBuffer();
  13139. var programAttributes = program.getAttributes();
  13140. if (object.hasPositions) {
  13141. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffers.position);
  13142. _gl.bufferData(_gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW);
  13143. state.enableAttribute(programAttributes.position);
  13144. _gl.vertexAttribPointer(programAttributes.position, 3, _gl.FLOAT, false, 0, 0);
  13145. }
  13146. if (object.hasNormals) {
  13147. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffers.normal);
  13148. if (!material.isMeshPhongMaterial && !material.isMeshStandardMaterial && !material.isMeshNormalMaterial && material.flatShading === true) {
  13149. for (var i = 0, l = object.count * 3; i < l; i += 9) {
  13150. var array = object.normalArray;
  13151. var nx = (array[i + 0] + array[i + 3] + array[i + 6]) / 3;
  13152. var ny = (array[i + 1] + array[i + 4] + array[i + 7]) / 3;
  13153. var nz = (array[i + 2] + array[i + 5] + array[i + 8]) / 3;
  13154. array[i + 0] = nx;
  13155. array[i + 1] = ny;
  13156. array[i + 2] = nz;
  13157. array[i + 3] = nx;
  13158. array[i + 4] = ny;
  13159. array[i + 5] = nz;
  13160. array[i + 6] = nx;
  13161. array[i + 7] = ny;
  13162. array[i + 8] = nz;
  13163. }
  13164. }
  13165. _gl.bufferData(_gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW);
  13166. state.enableAttribute(programAttributes.normal);
  13167. _gl.vertexAttribPointer(programAttributes.normal, 3, _gl.FLOAT, false, 0, 0);
  13168. }
  13169. if (object.hasUvs && material.map) {
  13170. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffers.uv);
  13171. _gl.bufferData(_gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW);
  13172. state.enableAttribute(programAttributes.uv);
  13173. _gl.vertexAttribPointer(programAttributes.uv, 2, _gl.FLOAT, false, 0, 0);
  13174. }
  13175. if (object.hasColors && material.vertexColors !== NoColors) {
  13176. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffers.color);
  13177. _gl.bufferData(_gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW);
  13178. state.enableAttribute(programAttributes.color);
  13179. _gl.vertexAttribPointer(programAttributes.color, 3, _gl.FLOAT, false, 0, 0);
  13180. }
  13181. state.disableUnusedAttributes();
  13182. _gl.drawArrays(_gl.TRIANGLES, 0, object.count);
  13183. object.count = 0;
  13184. };
  13185. this.renderBufferDirect = function (camera, fog, geometry, material, object, group) {
  13186. var frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0;
  13187. state.setMaterial(material, frontFaceCW);
  13188. var program = setProgram(camera, fog, material, object);
  13189. var geometryProgram = geometry.id + '_' + program.id + '_' + (material.wireframe === true);
  13190. var updateBuffers = false;
  13191. if (geometryProgram !== _currentGeometryProgram) {
  13192. _currentGeometryProgram = geometryProgram;
  13193. updateBuffers = true;
  13194. }
  13195. if (object.morphTargetInfluences) {
  13196. morphtargets.update(object, geometry, material, program);
  13197. updateBuffers = true;
  13198. }
  13199. //
  13200. var index = geometry.index;
  13201. var position = geometry.attributes.position;
  13202. var rangeFactor = 1;
  13203. if (material.wireframe === true) {
  13204. index = geometries.getWireframeAttribute(geometry);
  13205. rangeFactor = 2;
  13206. }
  13207. var attribute;
  13208. var renderer = bufferRenderer;
  13209. if (index !== null) {
  13210. attribute = attributes.get(index);
  13211. renderer = indexedBufferRenderer;
  13212. renderer.setIndex(attribute);
  13213. }
  13214. if (updateBuffers) {
  13215. setupVertexAttributes(material, program, geometry);
  13216. if (index !== null) {
  13217. _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, attribute.buffer);
  13218. }
  13219. }
  13220. //
  13221. var dataCount = Infinity;
  13222. if (index !== null) {
  13223. dataCount = index.count;
  13224. } else if (position !== undefined) {
  13225. dataCount = position.count;
  13226. }
  13227. var rangeStart = geometry.drawRange.start * rangeFactor;
  13228. var rangeCount = geometry.drawRange.count * rangeFactor;
  13229. var groupStart = group !== null ? group.start * rangeFactor : 0;
  13230. var groupCount = group !== null ? group.count * rangeFactor : Infinity;
  13231. var drawStart = Math.max(rangeStart, groupStart);
  13232. var drawEnd = Math.min(dataCount, rangeStart + rangeCount, groupStart + groupCount) - 1;
  13233. var drawCount = Math.max(0, drawEnd - drawStart + 1);
  13234. if (drawCount === 0) return;
  13235. //
  13236. if (object.isMesh) {
  13237. if (material.wireframe === true) {
  13238. state.setLineWidth(material.wireframeLinewidth * getTargetPixelRatio());
  13239. renderer.setMode(_gl.LINES);
  13240. } else {
  13241. switch (object.drawMode) {
  13242. case TrianglesDrawMode:
  13243. renderer.setMode(_gl.TRIANGLES);
  13244. break;
  13245. case TriangleStripDrawMode:
  13246. renderer.setMode(_gl.TRIANGLE_STRIP);
  13247. break;
  13248. case TriangleFanDrawMode:
  13249. renderer.setMode(_gl.TRIANGLE_FAN);
  13250. break;
  13251. }
  13252. }
  13253. } else if (object.isLine) {
  13254. var lineWidth = material.linewidth;
  13255. if (lineWidth === undefined) lineWidth = 1; // Not using Line*Material
  13256. state.setLineWidth(lineWidth * getTargetPixelRatio());
  13257. if (object.isLineSegments) {
  13258. renderer.setMode(_gl.LINES);
  13259. } else if (object.isLineLoop) {
  13260. renderer.setMode(_gl.LINE_LOOP);
  13261. } else {
  13262. renderer.setMode(_gl.LINE_STRIP);
  13263. }
  13264. } else if (object.isPoints) {
  13265. renderer.setMode(_gl.POINTS);
  13266. }
  13267. if (geometry && geometry.isInstancedBufferGeometry) {
  13268. if (geometry.maxInstancedCount > 0) {
  13269. renderer.renderInstances(geometry, drawStart, drawCount);
  13270. }
  13271. } else {
  13272. renderer.render(drawStart, drawCount);
  13273. }
  13274. };
  13275. function setupVertexAttributes(material, program, geometry) {
  13276. if (geometry && geometry.isInstancedBufferGeometry) {
  13277. if (extensions.get('ANGLE_instanced_arrays') === null) {
  13278. console.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.');
  13279. return;
  13280. }
  13281. }
  13282. state.initAttributes();
  13283. var geometryAttributes = geometry.attributes;
  13284. var programAttributes = program.getAttributes();
  13285. var materialDefaultAttributeValues = material.defaultAttributeValues;
  13286. for (var name in programAttributes) {
  13287. var programAttribute = programAttributes[name];
  13288. if (programAttribute >= 0) {
  13289. var geometryAttribute = geometryAttributes[name];
  13290. if (geometryAttribute !== undefined) {
  13291. var normalized = geometryAttribute.normalized;
  13292. var size = geometryAttribute.itemSize;
  13293. var attribute = attributes.get(geometryAttribute);
  13294. // TODO Attribute may not be available on context restore
  13295. if (attribute === undefined) continue;
  13296. var buffer = attribute.buffer;
  13297. var type = attribute.type;
  13298. var bytesPerElement = attribute.bytesPerElement;
  13299. if (geometryAttribute.isInterleavedBufferAttribute) {
  13300. var data = geometryAttribute.data;
  13301. var stride = data.stride;
  13302. var offset = geometryAttribute.offset;
  13303. if (data && data.isInstancedInterleavedBuffer) {
  13304. state.enableAttributeAndDivisor(programAttribute, data.meshPerAttribute);
  13305. if (geometry.maxInstancedCount === undefined) {
  13306. geometry.maxInstancedCount = data.meshPerAttribute * data.count;
  13307. }
  13308. } else {
  13309. state.enableAttribute(programAttribute);
  13310. }
  13311. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
  13312. _gl.vertexAttribPointer(programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement);
  13313. } else {
  13314. if (geometryAttribute.isInstancedBufferAttribute) {
  13315. state.enableAttributeAndDivisor(programAttribute, geometryAttribute.meshPerAttribute);
  13316. if (geometry.maxInstancedCount === undefined) {
  13317. geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
  13318. }
  13319. } else {
  13320. state.enableAttribute(programAttribute);
  13321. }
  13322. _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
  13323. _gl.vertexAttribPointer(programAttribute, size, type, normalized, 0, 0);
  13324. }
  13325. } else if (materialDefaultAttributeValues !== undefined) {
  13326. var value = materialDefaultAttributeValues[name];
  13327. if (value !== undefined) {
  13328. switch (value.length) {
  13329. case 2:
  13330. _gl.vertexAttrib2fv(programAttribute, value);
  13331. break;
  13332. case 3:
  13333. _gl.vertexAttrib3fv(programAttribute, value);
  13334. break;
  13335. case 4:
  13336. _gl.vertexAttrib4fv(programAttribute, value);
  13337. break;
  13338. default:
  13339. _gl.vertexAttrib1fv(programAttribute, value);
  13340. }
  13341. }
  13342. }
  13343. }
  13344. }
  13345. state.disableUnusedAttributes();
  13346. }
  13347. // Compile
  13348. this.compile = function (scene, camera) {
  13349. currentRenderState = renderStates.get(scene, camera);
  13350. currentRenderState.init();
  13351. scene.traverse(function (object) {
  13352. if (object.isLight) {
  13353. currentRenderState.pushLight(object);
  13354. if (object.castShadow) {
  13355. currentRenderState.pushShadow(object);
  13356. }
  13357. }
  13358. });
  13359. currentRenderState.setupLights(camera);
  13360. scene.traverse(function (object) {
  13361. if (object.material) {
  13362. if (Array.isArray(object.material)) {
  13363. for (var i = 0; i < object.material.length; i++) {
  13364. initMaterial(object.material[i], scene.fog, object);
  13365. }
  13366. } else {
  13367. initMaterial(object.material, scene.fog, object);
  13368. }
  13369. }
  13370. });
  13371. };
  13372. // Animation Loop
  13373. var onAnimationFrameCallback = null;
  13374. function onAnimationFrame() {
  13375. if (vr.isPresenting()) return;
  13376. if (onAnimationFrameCallback) onAnimationFrameCallback();
  13377. }
  13378. var animation = new WebGLAnimation();
  13379. animation.setAnimationLoop(onAnimationFrame);
  13380. animation.setContext(window);
  13381. this.setAnimationLoop = function (callback) {
  13382. onAnimationFrameCallback = callback;
  13383. vr.setAnimationLoop(callback);
  13384. animation.start();
  13385. };
  13386. // Rendering
  13387. this.render = function (scene, camera, renderTarget, forceClear) {
  13388. if (!(camera && camera.isCamera)) {
  13389. console.error('THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.');
  13390. return;
  13391. }
  13392. if (_isContextLost) return;
  13393. // reset caching for this frame
  13394. _currentGeometryProgram = '';
  13395. _currentMaterialId = -1;
  13396. _currentCamera = null;
  13397. // update scene graph
  13398. if (scene.autoUpdate === true) scene.updateMatrixWorld();
  13399. // update camera matrices and frustum
  13400. if (camera.parent === null) camera.updateMatrixWorld();
  13401. if (vr.enabled) {
  13402. camera = vr.getCamera(camera);
  13403. }
  13404. //
  13405. currentRenderState = renderStates.get(scene, camera);
  13406. currentRenderState.init();
  13407. scene.onBeforeRender(_this, scene, camera, renderTarget);
  13408. _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
  13409. _frustum.setFromMatrix(_projScreenMatrix);
  13410. _localClippingEnabled = this.localClippingEnabled;
  13411. _clippingEnabled = _clipping.init(this.clippingPlanes, _localClippingEnabled, camera);
  13412. currentRenderList = renderLists.get(scene, camera);
  13413. currentRenderList.init();
  13414. projectObject(scene, camera, _this.sortObjects);
  13415. if (_this.sortObjects === true) {
  13416. currentRenderList.sort();
  13417. }
  13418. //
  13419. if (_clippingEnabled) _clipping.beginShadows();
  13420. var shadowsArray = currentRenderState.state.shadowsArray;
  13421. shadowMap.render(shadowsArray, scene, camera);
  13422. currentRenderState.setupLights(camera);
  13423. if (_clippingEnabled) _clipping.endShadows();
  13424. //
  13425. if (this.info.autoReset) this.info.reset();
  13426. if (renderTarget === undefined) {
  13427. renderTarget = null;
  13428. }
  13429. this.setRenderTarget(renderTarget);
  13430. //
  13431. background.render(currentRenderList, scene, camera, forceClear);
  13432. // render scene
  13433. var opaqueObjects = currentRenderList.opaque;
  13434. var transparentObjects = currentRenderList.transparent;
  13435. if (scene.overrideMaterial) {
  13436. var overrideMaterial = scene.overrideMaterial;
  13437. if (opaqueObjects.length) renderObjects(opaqueObjects, scene, camera, overrideMaterial);
  13438. if (transparentObjects.length) renderObjects(transparentObjects, scene, camera, overrideMaterial);
  13439. } else {
  13440. // opaque pass (front-to-back order)
  13441. if (opaqueObjects.length) renderObjects(opaqueObjects, scene, camera);
  13442. // transparent pass (back-to-front order)
  13443. if (transparentObjects.length) renderObjects(transparentObjects, scene, camera);
  13444. }
  13445. // custom renderers
  13446. var spritesArray = currentRenderState.state.spritesArray;
  13447. spriteRenderer.render(spritesArray, scene, camera);
  13448. // Generate mipmap if we're using any kind of mipmap filtering
  13449. if (renderTarget) {
  13450. textures.updateRenderTargetMipmap(renderTarget);
  13451. }
  13452. // Ensure depth buffer writing is enabled so it can be cleared on next render
  13453. state.buffers.depth.setTest(true);
  13454. state.buffers.depth.setMask(true);
  13455. state.buffers.color.setMask(true);
  13456. state.setPolygonOffset(false);
  13457. scene.onAfterRender(_this, scene, camera);
  13458. if (vr.enabled) {
  13459. vr.submitFrame();
  13460. }
  13461. // _gl.finish();
  13462. currentRenderList = null;
  13463. currentRenderState = null;
  13464. };
  13465. /*
  13466. // TODO Duplicated code (Frustum)
  13467. var _sphere = new Sphere();
  13468. function isObjectViewable( object ) {
  13469. var geometry = object.geometry;
  13470. if ( geometry.boundingSphere === null )
  13471. geometry.computeBoundingSphere();
  13472. _sphere.copy( geometry.boundingSphere ).
  13473. applyMatrix4( object.matrixWorld );
  13474. return isSphereViewable( _sphere );
  13475. }
  13476. function isSpriteViewable( sprite ) {
  13477. _sphere.center.set( 0, 0, 0 );
  13478. _sphere.radius = 0.7071067811865476;
  13479. _sphere.applyMatrix4( sprite.matrixWorld );
  13480. return isSphereViewable( _sphere );
  13481. }
  13482. function isSphereViewable( sphere ) {
  13483. if ( ! _frustum.intersectsSphere( sphere ) ) return false;
  13484. var numPlanes = _clipping.numPlanes;
  13485. if ( numPlanes === 0 ) return true;
  13486. var planes = _this.clippingPlanes,
  13487. center = sphere.center,
  13488. negRad = - sphere.radius,
  13489. i = 0;
  13490. do {
  13491. // out when deeper than radius in the negative halfspace
  13492. if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
  13493. } while ( ++ i !== numPlanes );
  13494. return true;
  13495. }
  13496. */
  13497. function projectObject(object, camera, sortObjects) {
  13498. if (object.visible === false) return;
  13499. var visible = object.layers.test(camera.layers);
  13500. if (visible) {
  13501. if (object.isLight) {
  13502. currentRenderState.pushLight(object);
  13503. if (object.castShadow) {
  13504. currentRenderState.pushShadow(object);
  13505. }
  13506. } else if (object.isSprite) {
  13507. if (!object.frustumCulled || _frustum.intersectsSprite(object)) {
  13508. currentRenderState.pushSprite(object);
  13509. }
  13510. } else if (object.isImmediateRenderObject) {
  13511. if (sortObjects) {
  13512. _vector3.setFromMatrixPosition(object.matrixWorld).applyMatrix4(_projScreenMatrix);
  13513. }
  13514. currentRenderList.push(object, null, object.material, _vector3.z, null);
  13515. } else if (object.isMesh || object.isLine || object.isPoints) {
  13516. if (object.isSkinnedMesh) {
  13517. object.skeleton.update();
  13518. }
  13519. if (!object.frustumCulled || _frustum.intersectsObject(object)) {
  13520. if (sortObjects) {
  13521. _vector3.setFromMatrixPosition(object.matrixWorld).applyMatrix4(_projScreenMatrix);
  13522. }
  13523. var geometry = objects.update(object);
  13524. var material = object.material;
  13525. if (Array.isArray(material)) {
  13526. var groups = geometry.groups;
  13527. for (var i = 0, l = groups.length; i < l; i++) {
  13528. var group = groups[i];
  13529. var groupMaterial = material[group.materialIndex];
  13530. if (groupMaterial && groupMaterial.visible) {
  13531. currentRenderList.push(object, geometry, groupMaterial, _vector3.z, group);
  13532. }
  13533. }
  13534. } else if (material.visible) {
  13535. currentRenderList.push(object, geometry, material, _vector3.z, null);
  13536. }
  13537. }
  13538. }
  13539. }
  13540. var children = object.children;
  13541. for (var i = 0, l = children.length; i < l; i++) {
  13542. projectObject(children[i], camera, sortObjects);
  13543. }
  13544. }
  13545. function renderObjects(renderList, scene, camera, overrideMaterial) {
  13546. for (var i = 0, l = renderList.length; i < l; i++) {
  13547. var renderItem = renderList[i];
  13548. var object = renderItem.object;
  13549. var geometry = renderItem.geometry;
  13550. var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
  13551. var group = renderItem.group;
  13552. if (camera.isArrayCamera) {
  13553. _currentArrayCamera = camera;
  13554. var cameras = camera.cameras;
  13555. for (var j = 0, jl = cameras.length; j < jl; j++) {
  13556. var camera2 = cameras[j];
  13557. if (object.layers.test(camera2.layers)) {
  13558. if ('viewport' in camera2) {
  13559. // XR
  13560. state.viewport(_currentViewport.copy(camera2.viewport));
  13561. } else {
  13562. var bounds = camera2.bounds;
  13563. var x = bounds.x * _width;
  13564. var y = bounds.y * _height;
  13565. var width = bounds.z * _width;
  13566. var height = bounds.w * _height;
  13567. state.viewport(_currentViewport.set(x, y, width, height).multiplyScalar(_pixelRatio));
  13568. }
  13569. renderObject(object, scene, camera2, geometry, material, group);
  13570. }
  13571. }
  13572. } else {
  13573. _currentArrayCamera = null;
  13574. renderObject(object, scene, camera, geometry, material, group);
  13575. }
  13576. }
  13577. }
  13578. function renderObject(object, scene, camera, geometry, material, group) {
  13579. object.onBeforeRender(_this, scene, camera, geometry, material, group);
  13580. currentRenderState = renderStates.get(scene, _currentArrayCamera || camera);
  13581. object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld);
  13582. object.normalMatrix.getNormalMatrix(object.modelViewMatrix);
  13583. if (object.isImmediateRenderObject) {
  13584. var frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0;
  13585. state.setMaterial(material, frontFaceCW);
  13586. var program = setProgram(camera, scene.fog, material, object);
  13587. _currentGeometryProgram = '';
  13588. renderObjectImmediate(object, program, material);
  13589. } else {
  13590. _this.renderBufferDirect(camera, scene.fog, geometry, material, object, group);
  13591. }
  13592. object.onAfterRender(_this, scene, camera, geometry, material, group);
  13593. currentRenderState = renderStates.get(scene, _currentArrayCamera || camera);
  13594. }
  13595. function initMaterial(material, fog, object) {
  13596. var materialProperties = properties.get(material);
  13597. var lights = currentRenderState.state.lights;
  13598. var shadowsArray = currentRenderState.state.shadowsArray;
  13599. var parameters = programCache.getParameters(material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object);
  13600. var code = programCache.getProgramCode(material, parameters);
  13601. var program = materialProperties.program;
  13602. var programChange = true;
  13603. if (program === undefined) {
  13604. // new material
  13605. material.addEventListener('dispose', onMaterialDispose);
  13606. } else if (program.code !== code) {
  13607. // changed glsl or parameters
  13608. releaseMaterialProgramReference(material);
  13609. } else if (materialProperties.lightsHash !== lights.state.hash) {
  13610. properties.update(material, 'lightsHash', lights.state.hash);
  13611. programChange = false;
  13612. } else if (parameters.shaderID !== undefined) {
  13613. // same glsl and uniform list
  13614. return;
  13615. } else {
  13616. // only rebuild uniform list
  13617. programChange = false;
  13618. }
  13619. if (programChange) {
  13620. if (parameters.shaderID) {
  13621. var shader = ShaderLib[parameters.shaderID];
  13622. materialProperties.shader = {
  13623. name: material.type,
  13624. uniforms: UniformsUtils.clone(shader.uniforms),
  13625. vertexShader: shader.vertexShader,
  13626. fragmentShader: shader.fragmentShader
  13627. };
  13628. } else {
  13629. materialProperties.shader = {
  13630. name: material.type,
  13631. uniforms: material.uniforms,
  13632. vertexShader: material.vertexShader,
  13633. fragmentShader: material.fragmentShader
  13634. };
  13635. }
  13636. material.onBeforeCompile(materialProperties.shader, _this);
  13637. program = programCache.acquireProgram(material, materialProperties.shader, parameters, code);
  13638. materialProperties.program = program;
  13639. material.program = program;
  13640. }
  13641. var programAttributes = program.getAttributes();
  13642. if (material.morphTargets) {
  13643. material.numSupportedMorphTargets = 0;
  13644. for (var i = 0; i < _this.maxMorphTargets; i++) {
  13645. if (programAttributes['morphTarget' + i] >= 0) {
  13646. material.numSupportedMorphTargets++;
  13647. }
  13648. }
  13649. }
  13650. if (material.morphNormals) {
  13651. material.numSupportedMorphNormals = 0;
  13652. for (var i = 0; i < _this.maxMorphNormals; i++) {
  13653. if (programAttributes['morphNormal' + i] >= 0) {
  13654. material.numSupportedMorphNormals++;
  13655. }
  13656. }
  13657. }
  13658. var uniforms = materialProperties.shader.uniforms;
  13659. if (!material.isShaderMaterial && !material.isRawShaderMaterial || material.clipping === true) {
  13660. materialProperties.numClippingPlanes = _clipping.numPlanes;
  13661. materialProperties.numIntersection = _clipping.numIntersection;
  13662. uniforms.clippingPlanes = _clipping.uniform;
  13663. }
  13664. materialProperties.fog = fog;
  13665. // store the light setup it was created for
  13666. materialProperties.lightsHash = lights.state.hash;
  13667. if (material.lights) {
  13668. // wire up the material to this renderer's lighting state
  13669. uniforms.ambientLightColor.value = lights.state.ambient;
  13670. uniforms.directionalLights.value = lights.state.directional;
  13671. uniforms.spotLights.value = lights.state.spot;
  13672. uniforms.rectAreaLights.value = lights.state.rectArea;
  13673. uniforms.pointLights.value = lights.state.point;
  13674. uniforms.hemisphereLights.value = lights.state.hemi;
  13675. uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
  13676. uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
  13677. uniforms.spotShadowMap.value = lights.state.spotShadowMap;
  13678. uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
  13679. uniforms.pointShadowMap.value = lights.state.pointShadowMap;
  13680. uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
  13681. // TODO (abelnation): add area lights shadow info to uniforms
  13682. }
  13683. var progUniforms = materialProperties.program.getUniforms(),
  13684. uniformsList = WebGLUniforms.seqWithValue(progUniforms.seq, uniforms);
  13685. materialProperties.uniformsList = uniformsList;
  13686. }
  13687. function setProgram(camera, fog, material, object) {
  13688. _usedTextureUnits = 0;
  13689. var materialProperties = properties.get(material);
  13690. var lights = currentRenderState.state.lights;
  13691. if (_clippingEnabled) {
  13692. if (_localClippingEnabled || camera !== _currentCamera) {
  13693. var useCache = camera === _currentCamera && material.id === _currentMaterialId;
  13694. // we might want to call this function with some ClippingGroup
  13695. // object instead of the material, once it becomes feasible
  13696. // (#8465, #8379)
  13697. _clipping.setState(material.clippingPlanes, material.clipIntersection, material.clipShadows, camera, materialProperties, useCache);
  13698. }
  13699. }
  13700. if (material.needsUpdate === false) {
  13701. if (materialProperties.program === undefined) {
  13702. material.needsUpdate = true;
  13703. } else if (material.fog && materialProperties.fog !== fog) {
  13704. material.needsUpdate = true;
  13705. } else if (material.lights && materialProperties.lightsHash !== lights.state.hash) {
  13706. material.needsUpdate = true;
  13707. } else if (materialProperties.numClippingPlanes !== undefined && (materialProperties.numClippingPlanes !== _clipping.numPlanes || materialProperties.numIntersection !== _clipping.numIntersection)) {
  13708. material.needsUpdate = true;
  13709. }
  13710. }
  13711. if (material.needsUpdate) {
  13712. initMaterial(material, fog, object);
  13713. material.needsUpdate = false;
  13714. }
  13715. var refreshProgram = false;
  13716. var refreshMaterial = false;
  13717. var refreshLights = false;
  13718. var program = materialProperties.program,
  13719. p_uniforms = program.getUniforms(),
  13720. m_uniforms = materialProperties.shader.uniforms;
  13721. if (state.useProgram(program.program)) {
  13722. refreshProgram = true;
  13723. refreshMaterial = true;
  13724. refreshLights = true;
  13725. }
  13726. if (material.id !== _currentMaterialId) {
  13727. _currentMaterialId = material.id;
  13728. refreshMaterial = true;
  13729. }
  13730. if (refreshProgram || camera !== _currentCamera) {
  13731. p_uniforms.setValue(_gl, 'projectionMatrix', camera.projectionMatrix);
  13732. if (capabilities.logarithmicDepthBuffer) {
  13733. p_uniforms.setValue(_gl, 'logDepthBufFC', 2.0 / (Math.log(camera.far + 1.0) / Math.LN2));
  13734. }
  13735. // Avoid unneeded uniform updates per ArrayCamera's sub-camera
  13736. if (_currentCamera !== (_currentArrayCamera || camera)) {
  13737. _currentCamera = _currentArrayCamera || camera;
  13738. // lighting uniforms depend on the camera so enforce an update
  13739. // now, in case this material supports lights - or later, when
  13740. // the next material that does gets activated:
  13741. refreshMaterial = true; // set to true on material change
  13742. refreshLights = true; // remains set until update done
  13743. }
  13744. // load material specific uniforms
  13745. // (shader material also gets them for the sake of genericity)
  13746. if (material.isShaderMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial || material.envMap) {
  13747. var uCamPos = p_uniforms.map.cameraPosition;
  13748. if (uCamPos !== undefined) {
  13749. uCamPos.setValue(_gl, _vector3.setFromMatrixPosition(camera.matrixWorld));
  13750. }
  13751. }
  13752. if (material.isMeshPhongMaterial || material.isMeshLambertMaterial || material.isMeshBasicMaterial || material.isMeshStandardMaterial || material.isShaderMaterial || material.skinning) {
  13753. p_uniforms.setValue(_gl, 'viewMatrix', camera.matrixWorldInverse);
  13754. }
  13755. }
  13756. // skinning uniforms must be set even if material didn't change
  13757. // auto-setting of texture unit for bone texture must go before other textures
  13758. // not sure why, but otherwise weird things happen
  13759. if (material.skinning) {
  13760. p_uniforms.setOptional(_gl, object, 'bindMatrix');
  13761. p_uniforms.setOptional(_gl, object, 'bindMatrixInverse');
  13762. var skeleton = object.skeleton;
  13763. if (skeleton) {
  13764. var bones = skeleton.bones;
  13765. if (capabilities.floatVertexTextures) {
  13766. if (skeleton.boneTexture === undefined) {
  13767. // layout (1 matrix = 4 pixels)
  13768. // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
  13769. // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
  13770. // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
  13771. // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
  13772. // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
  13773. var size = Math.sqrt(bones.length * 4); // 4 pixels needed for 1 matrix
  13774. size = _Math.ceilPowerOfTwo(size);
  13775. size = Math.max(size, 4);
  13776. var boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel
  13777. boneMatrices.set(skeleton.boneMatrices); // copy current values
  13778. var boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType);
  13779. boneTexture.needsUpdate = true;
  13780. skeleton.boneMatrices = boneMatrices;
  13781. skeleton.boneTexture = boneTexture;
  13782. skeleton.boneTextureSize = size;
  13783. }
  13784. p_uniforms.setValue(_gl, 'boneTexture', skeleton.boneTexture);
  13785. p_uniforms.setValue(_gl, 'boneTextureSize', skeleton.boneTextureSize);
  13786. } else {
  13787. p_uniforms.setOptional(_gl, skeleton, 'boneMatrices');
  13788. }
  13789. }
  13790. }
  13791. if (refreshMaterial) {
  13792. p_uniforms.setValue(_gl, 'toneMappingExposure', _this.toneMappingExposure);
  13793. p_uniforms.setValue(_gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint);
  13794. if (material.lights) {
  13795. // the current material requires lighting info
  13796. // note: all lighting uniforms are always set correctly
  13797. // they simply reference the renderer's state for their
  13798. // values
  13799. //
  13800. // use the current material's .needsUpdate flags to set
  13801. // the GL state when required
  13802. markUniformsLightsNeedsUpdate(m_uniforms, refreshLights);
  13803. }
  13804. // refresh uniforms common to several materials
  13805. if (fog && material.fog) {
  13806. refreshUniformsFog(m_uniforms, fog);
  13807. }
  13808. if (material.isMeshBasicMaterial) {
  13809. refreshUniformsCommon(m_uniforms, material);
  13810. } else if (material.isMeshLambertMaterial) {
  13811. refreshUniformsCommon(m_uniforms, material);
  13812. refreshUniformsLambert(m_uniforms, material);
  13813. } else if (material.isMeshPhongMaterial) {
  13814. refreshUniformsCommon(m_uniforms, material);
  13815. if (material.isMeshToonMaterial) {
  13816. refreshUniformsToon(m_uniforms, material);
  13817. } else {
  13818. refreshUniformsPhong(m_uniforms, material);
  13819. }
  13820. } else if (material.isMeshStandardMaterial) {
  13821. refreshUniformsCommon(m_uniforms, material);
  13822. if (material.isMeshPhysicalMaterial) {
  13823. refreshUniformsPhysical(m_uniforms, material);
  13824. } else {
  13825. refreshUniformsStandard(m_uniforms, material);
  13826. }
  13827. } else if (material.isMeshDepthMaterial) {
  13828. refreshUniformsCommon(m_uniforms, material);
  13829. refreshUniformsDepth(m_uniforms, material);
  13830. } else if (material.isMeshDistanceMaterial) {
  13831. refreshUniformsCommon(m_uniforms, material);
  13832. refreshUniformsDistance(m_uniforms, material);
  13833. } else if (material.isMeshNormalMaterial) {
  13834. refreshUniformsCommon(m_uniforms, material);
  13835. refreshUniformsNormal(m_uniforms, material);
  13836. } else if (material.isLineBasicMaterial) {
  13837. refreshUniformsLine(m_uniforms, material);
  13838. if (material.isLineDashedMaterial) {
  13839. refreshUniformsDash(m_uniforms, material);
  13840. }
  13841. } else if (material.isPointsMaterial) {
  13842. refreshUniformsPoints(m_uniforms, material);
  13843. } else if (material.isShadowMaterial) {
  13844. m_uniforms.color.value = material.color;
  13845. m_uniforms.opacity.value = material.opacity;
  13846. }
  13847. // RectAreaLight Texture
  13848. // TODO (mrdoob): Find a nicer implementation
  13849. if (m_uniforms.ltc_1 !== undefined) m_uniforms.ltc_1.value = UniformsLib.LTC_1;
  13850. if (m_uniforms.ltc_2 !== undefined) m_uniforms.ltc_2.value = UniformsLib.LTC_2;
  13851. WebGLUniforms.upload(_gl, materialProperties.uniformsList, m_uniforms, _this);
  13852. }
  13853. if (material.isShaderMaterial && material.uniformsNeedUpdate === true) {
  13854. WebGLUniforms.upload(_gl, materialProperties.uniformsList, m_uniforms, _this);
  13855. material.uniformsNeedUpdate = false;
  13856. }
  13857. // common matrices
  13858. p_uniforms.setValue(_gl, 'modelViewMatrix', object.modelViewMatrix);
  13859. p_uniforms.setValue(_gl, 'normalMatrix', object.normalMatrix);
  13860. p_uniforms.setValue(_gl, 'modelMatrix', object.matrixWorld);
  13861. return program;
  13862. }
  13863. // Uniforms (refresh uniforms objects)
  13864. function refreshUniformsCommon(uniforms, material) {
  13865. uniforms.opacity.value = material.opacity;
  13866. if (material.color) {
  13867. uniforms.diffuse.value = material.color;
  13868. }
  13869. if (material.emissive) {
  13870. uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity);
  13871. }
  13872. if (material.map) {
  13873. uniforms.map.value = material.map;
  13874. }
  13875. if (material.alphaMap) {
  13876. uniforms.alphaMap.value = material.alphaMap;
  13877. }
  13878. if (material.specularMap) {
  13879. uniforms.specularMap.value = material.specularMap;
  13880. }
  13881. if (material.envMap) {
  13882. uniforms.envMap.value = material.envMap;
  13883. // don't flip CubeTexture envMaps, flip everything else:
  13884. // WebGLRenderTargetCube will be flipped for backwards compatibility
  13885. // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
  13886. // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
  13887. uniforms.flipEnvMap.value = !(material.envMap && material.envMap.isCubeTexture) ? 1 : -1;
  13888. uniforms.reflectivity.value = material.reflectivity;
  13889. uniforms.refractionRatio.value = material.refractionRatio;
  13890. uniforms.maxMipLevel.value = properties.get(material.envMap).__maxMipLevel;
  13891. }
  13892. if (material.lightMap) {
  13893. uniforms.lightMap.value = material.lightMap;
  13894. uniforms.lightMapIntensity.value = material.lightMapIntensity;
  13895. }
  13896. if (material.aoMap) {
  13897. uniforms.aoMap.value = material.aoMap;
  13898. uniforms.aoMapIntensity.value = material.aoMapIntensity;
  13899. }
  13900. // uv repeat and offset setting priorities
  13901. // 1. color map
  13902. // 2. specular map
  13903. // 3. normal map
  13904. // 4. bump map
  13905. // 5. alpha map
  13906. // 6. emissive map
  13907. var uvScaleMap;
  13908. if (material.map) {
  13909. uvScaleMap = material.map;
  13910. } else if (material.specularMap) {
  13911. uvScaleMap = material.specularMap;
  13912. } else if (material.displacementMap) {
  13913. uvScaleMap = material.displacementMap;
  13914. } else if (material.normalMap) {
  13915. uvScaleMap = material.normalMap;
  13916. } else if (material.bumpMap) {
  13917. uvScaleMap = material.bumpMap;
  13918. } else if (material.roughnessMap) {
  13919. uvScaleMap = material.roughnessMap;
  13920. } else if (material.metalnessMap) {
  13921. uvScaleMap = material.metalnessMap;
  13922. } else if (material.alphaMap) {
  13923. uvScaleMap = material.alphaMap;
  13924. } else if (material.emissiveMap) {
  13925. uvScaleMap = material.emissiveMap;
  13926. }
  13927. if (uvScaleMap !== undefined) {
  13928. // backwards compatibility
  13929. if (uvScaleMap.isWebGLRenderTarget) {
  13930. uvScaleMap = uvScaleMap.texture;
  13931. }
  13932. if (uvScaleMap.matrixAutoUpdate === true) {
  13933. uvScaleMap.updateMatrix();
  13934. }
  13935. uniforms.uvTransform.value.copy(uvScaleMap.matrix);
  13936. }
  13937. }
  13938. function refreshUniformsLine(uniforms, material) {
  13939. uniforms.diffuse.value = material.color;
  13940. uniforms.opacity.value = material.opacity;
  13941. }
  13942. function refreshUniformsDash(uniforms, material) {
  13943. uniforms.dashSize.value = material.dashSize;
  13944. uniforms.totalSize.value = material.dashSize + material.gapSize;
  13945. uniforms.scale.value = material.scale;
  13946. }
  13947. function refreshUniformsPoints(uniforms, material) {
  13948. uniforms.diffuse.value = material.color;
  13949. uniforms.opacity.value = material.opacity;
  13950. uniforms.size.value = material.size * _pixelRatio;
  13951. uniforms.scale.value = _height * 0.5;
  13952. uniforms.map.value = material.map;
  13953. if (material.map !== null) {
  13954. if (material.map.matrixAutoUpdate === true) {
  13955. material.map.updateMatrix();
  13956. }
  13957. uniforms.uvTransform.value.copy(material.map.matrix);
  13958. }
  13959. }
  13960. function refreshUniformsFog(uniforms, fog) {
  13961. uniforms.fogColor.value = fog.color;
  13962. if (fog.isFog) {
  13963. uniforms.fogNear.value = fog.near;
  13964. uniforms.fogFar.value = fog.far;
  13965. } else if (fog.isFogExp2) {
  13966. uniforms.fogDensity.value = fog.density;
  13967. }
  13968. }
  13969. function refreshUniformsLambert(uniforms, material) {
  13970. if (material.emissiveMap) {
  13971. uniforms.emissiveMap.value = material.emissiveMap;
  13972. }
  13973. }
  13974. function refreshUniformsPhong(uniforms, material) {
  13975. uniforms.specular.value = material.specular;
  13976. uniforms.shininess.value = Math.max(material.shininess, 1e-4); // to prevent pow( 0.0, 0.0 )
  13977. if (material.emissiveMap) {
  13978. uniforms.emissiveMap.value = material.emissiveMap;
  13979. }
  13980. if (material.bumpMap) {
  13981. uniforms.bumpMap.value = material.bumpMap;
  13982. uniforms.bumpScale.value = material.bumpScale;
  13983. if (material.side === BackSide) uniforms.bumpScale.value *= -1;
  13984. }
  13985. if (material.normalMap) {
  13986. uniforms.normalMap.value = material.normalMap;
  13987. uniforms.normalScale.value.copy(material.normalScale);
  13988. if (material.side === BackSide) uniforms.normalScale.value.negate();
  13989. }
  13990. if (material.displacementMap) {
  13991. uniforms.displacementMap.value = material.displacementMap;
  13992. uniforms.displacementScale.value = material.displacementScale;
  13993. uniforms.displacementBias.value = material.displacementBias;
  13994. }
  13995. }
  13996. function refreshUniformsToon(uniforms, material) {
  13997. refreshUniformsPhong(uniforms, material);
  13998. if (material.gradientMap) {
  13999. uniforms.gradientMap.value = material.gradientMap;
  14000. }
  14001. }
  14002. function refreshUniformsStandard(uniforms, material) {
  14003. uniforms.roughness.value = material.roughness;
  14004. uniforms.metalness.value = material.metalness;
  14005. if (material.roughnessMap) {
  14006. uniforms.roughnessMap.value = material.roughnessMap;
  14007. }
  14008. if (material.metalnessMap) {
  14009. uniforms.metalnessMap.value = material.metalnessMap;
  14010. }
  14011. if (material.emissiveMap) {
  14012. uniforms.emissiveMap.value = material.emissiveMap;
  14013. }
  14014. if (material.bumpMap) {
  14015. uniforms.bumpMap.value = material.bumpMap;
  14016. uniforms.bumpScale.value = material.bumpScale;
  14017. if (material.side === BackSide) uniforms.bumpScale.value *= -1;
  14018. }
  14019. if (material.normalMap) {
  14020. uniforms.normalMap.value = material.normalMap;
  14021. uniforms.normalScale.value.copy(material.normalScale);
  14022. if (material.side === BackSide) uniforms.normalScale.value.negate();
  14023. }
  14024. if (material.displacementMap) {
  14025. uniforms.displacementMap.value = material.displacementMap;
  14026. uniforms.displacementScale.value = material.displacementScale;
  14027. uniforms.displacementBias.value = material.displacementBias;
  14028. }
  14029. if (material.envMap) {
  14030. //uniforms.envMap.value = material.envMap; // part of uniforms common
  14031. uniforms.envMapIntensity.value = material.envMapIntensity;
  14032. }
  14033. }
  14034. function refreshUniformsPhysical(uniforms, material) {
  14035. uniforms.clearCoat.value = material.clearCoat;
  14036. uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
  14037. refreshUniformsStandard(uniforms, material);
  14038. }
  14039. function refreshUniformsDepth(uniforms, material) {
  14040. if (material.displacementMap) {
  14041. uniforms.displacementMap.value = material.displacementMap;
  14042. uniforms.displacementScale.value = material.displacementScale;
  14043. uniforms.displacementBias.value = material.displacementBias;
  14044. }
  14045. }
  14046. function refreshUniformsDistance(uniforms, material) {
  14047. if (material.displacementMap) {
  14048. uniforms.displacementMap.value = material.displacementMap;
  14049. uniforms.displacementScale.value = material.displacementScale;
  14050. uniforms.displacementBias.value = material.displacementBias;
  14051. }
  14052. uniforms.referencePosition.value.copy(material.referencePosition);
  14053. uniforms.nearDistance.value = material.nearDistance;
  14054. uniforms.farDistance.value = material.farDistance;
  14055. }
  14056. function refreshUniformsNormal(uniforms, material) {
  14057. if (material.bumpMap) {
  14058. uniforms.bumpMap.value = material.bumpMap;
  14059. uniforms.bumpScale.value = material.bumpScale;
  14060. if (material.side === BackSide) uniforms.bumpScale.value *= -1;
  14061. }
  14062. if (material.normalMap) {
  14063. uniforms.normalMap.value = material.normalMap;
  14064. uniforms.normalScale.value.copy(material.normalScale);
  14065. if (material.side === BackSide) uniforms.normalScale.value.negate();
  14066. }
  14067. if (material.displacementMap) {
  14068. uniforms.displacementMap.value = material.displacementMap;
  14069. uniforms.displacementScale.value = material.displacementScale;
  14070. uniforms.displacementBias.value = material.displacementBias;
  14071. }
  14072. }
  14073. // If uniforms are marked as clean, they don't need to be loaded to the GPU.
  14074. function markUniformsLightsNeedsUpdate(uniforms, value) {
  14075. uniforms.ambientLightColor.needsUpdate = value;
  14076. uniforms.directionalLights.needsUpdate = value;
  14077. uniforms.pointLights.needsUpdate = value;
  14078. uniforms.spotLights.needsUpdate = value;
  14079. uniforms.rectAreaLights.needsUpdate = value;
  14080. uniforms.hemisphereLights.needsUpdate = value;
  14081. }
  14082. // Textures
  14083. function allocTextureUnit() {
  14084. var textureUnit = _usedTextureUnits;
  14085. if (textureUnit >= capabilities.maxTextures) {
  14086. console.warn('THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures);
  14087. }
  14088. _usedTextureUnits += 1;
  14089. return textureUnit;
  14090. }
  14091. this.allocTextureUnit = allocTextureUnit;
  14092. // this.setTexture2D = setTexture2D;
  14093. this.setTexture2D = function () {
  14094. var warned = false;
  14095. // backwards compatibility: peel texture.texture
  14096. return function setTexture2D(texture, slot) {
  14097. if (texture && texture.isWebGLRenderTarget) {
  14098. if (!warned) {
  14099. console.warn("THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead.");
  14100. warned = true;
  14101. }
  14102. texture = texture.texture;
  14103. }
  14104. textures.setTexture2D(texture, slot);
  14105. };
  14106. }();
  14107. this.setTexture = function () {
  14108. var warned = false;
  14109. return function setTexture(texture, slot) {
  14110. if (!warned) {
  14111. console.warn("THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead.");
  14112. warned = true;
  14113. }
  14114. textures.setTexture2D(texture, slot);
  14115. };
  14116. }();
  14117. this.setTextureCube = function () {
  14118. var warned = false;
  14119. return function setTextureCube(texture, slot) {
  14120. // backwards compatibility: peel texture.texture
  14121. if (texture && texture.isWebGLRenderTargetCube) {
  14122. if (!warned) {
  14123. console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead.");
  14124. warned = true;
  14125. }
  14126. texture = texture.texture;
  14127. }
  14128. // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
  14129. // TODO: unify these code paths
  14130. if (texture && texture.isCubeTexture || Array.isArray(texture.image) && texture.image.length === 6) {
  14131. // CompressedTexture can have Array in image :/
  14132. // this function alone should take care of cube textures
  14133. textures.setTextureCube(texture, slot);
  14134. } else {
  14135. // assumed: texture property of THREE.WebGLRenderTargetCube
  14136. textures.setTextureCubeDynamic(texture, slot);
  14137. }
  14138. };
  14139. }();
  14140. //
  14141. this.setFramebuffer = function (value) {
  14142. _framebuffer = value;
  14143. };
  14144. this.getRenderTarget = function () {
  14145. return _currentRenderTarget;
  14146. };
  14147. this.setRenderTarget = function (renderTarget) {
  14148. _currentRenderTarget = renderTarget;
  14149. if (renderTarget && properties.get(renderTarget).__webglFramebuffer === undefined) {
  14150. textures.setupRenderTarget(renderTarget);
  14151. }
  14152. var framebuffer = _framebuffer;
  14153. var isCube = false;
  14154. if (renderTarget) {
  14155. var __webglFramebuffer = properties.get(renderTarget).__webglFramebuffer;
  14156. if (renderTarget.isWebGLRenderTargetCube) {
  14157. framebuffer = __webglFramebuffer[renderTarget.activeCubeFace];
  14158. isCube = true;
  14159. } else {
  14160. framebuffer = __webglFramebuffer;
  14161. }
  14162. _currentViewport.copy(renderTarget.viewport);
  14163. _currentScissor.copy(renderTarget.scissor);
  14164. _currentScissorTest = renderTarget.scissorTest;
  14165. } else {
  14166. _currentViewport.copy(_viewport).multiplyScalar(_pixelRatio);
  14167. _currentScissor.copy(_scissor).multiplyScalar(_pixelRatio);
  14168. _currentScissorTest = _scissorTest;
  14169. }
  14170. if (_currentFramebuffer !== framebuffer) {
  14171. _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer);
  14172. _currentFramebuffer = framebuffer;
  14173. }
  14174. state.viewport(_currentViewport);
  14175. state.scissor(_currentScissor);
  14176. state.setScissorTest(_currentScissorTest);
  14177. if (isCube) {
  14178. var textureProperties = properties.get(renderTarget.texture);
  14179. _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel);
  14180. }
  14181. };
  14182. this.readRenderTargetPixels = function (renderTarget, x, y, width, height, buffer) {
  14183. if (!(renderTarget && renderTarget.isWebGLRenderTarget)) {
  14184. console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.');
  14185. return;
  14186. }
  14187. var framebuffer = properties.get(renderTarget).__webglFramebuffer;
  14188. if (framebuffer) {
  14189. var restore = false;
  14190. if (framebuffer !== _currentFramebuffer) {
  14191. _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer);
  14192. restore = true;
  14193. }
  14194. try {
  14195. var texture = renderTarget.texture;
  14196. var textureFormat = texture.format;
  14197. var textureType = texture.type;
  14198. if (textureFormat !== RGBAFormat && utils.convert(textureFormat) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_FORMAT)) {
  14199. console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.');
  14200. return;
  14201. }
  14202. if (textureType !== UnsignedByteType && utils.convert(textureType) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_TYPE) && // IE11, Edge and Chrome Mac < 52 (#9513)
  14203. !(textureType === FloatType && (extensions.get('OES_texture_float') || extensions.get('WEBGL_color_buffer_float'))) && // Chrome Mac >= 52 and Firefox
  14204. !(textureType === HalfFloatType && extensions.get('EXT_color_buffer_half_float'))) {
  14205. console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.');
  14206. return;
  14207. }
  14208. if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) === _gl.FRAMEBUFFER_COMPLETE) {
  14209. // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
  14210. if (x >= 0 && x <= renderTarget.width - width && y >= 0 && y <= renderTarget.height - height) {
  14211. _gl.readPixels(x, y, width, height, utils.convert(textureFormat), utils.convert(textureType), buffer);
  14212. }
  14213. } else {
  14214. console.error('THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.');
  14215. }
  14216. } finally {
  14217. if (restore) {
  14218. _gl.bindFramebuffer(_gl.FRAMEBUFFER, _currentFramebuffer);
  14219. }
  14220. }
  14221. }
  14222. };
  14223. this.copyFramebufferToTexture = function (position, texture, level) {
  14224. var width = texture.image.width;
  14225. var height = texture.image.height;
  14226. var glFormat = utils.convert(texture.format);
  14227. this.setTexture2D(texture, 0);
  14228. _gl.copyTexImage2D(_gl.TEXTURE_2D, level || 0, glFormat, position.x, position.y, width, height, 0);
  14229. };
  14230. this.copyTextureToTexture = function (position, srcTexture, dstTexture, level) {
  14231. var width = srcTexture.image.width;
  14232. var height = srcTexture.image.height;
  14233. var glFormat = utils.convert(dstTexture.format);
  14234. var glType = utils.convert(dstTexture.type);
  14235. this.setTexture2D(dstTexture, 0);
  14236. if (srcTexture.isDataTexture) {
  14237. _gl.texSubImage2D(_gl.TEXTURE_2D, level || 0, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data);
  14238. } else {
  14239. _gl.texSubImage2D(_gl.TEXTURE_2D, level || 0, position.x, position.y, glFormat, glType, srcTexture.image);
  14240. }
  14241. };
  14242. }
  14243. /**
  14244. * @author mrdoob / http://mrdoob.com/
  14245. * @author alteredq / http://alteredqualia.com/
  14246. */
  14247. function FogExp2(color, density) {
  14248. this.name = '';
  14249. this.color = new Color(color);
  14250. this.density = density !== undefined ? density : 0.00025;
  14251. }
  14252. FogExp2.prototype.isFogExp2 = true;
  14253. FogExp2.prototype.clone = function () {
  14254. return new FogExp2(this.color, this.density);
  14255. };
  14256. FogExp2.prototype.toJSON = function () /* meta */{
  14257. return {
  14258. type: 'FogExp2',
  14259. color: this.color.getHex(),
  14260. density: this.density
  14261. };
  14262. };
  14263. /**
  14264. * @author mrdoob / http://mrdoob.com/
  14265. * @author alteredq / http://alteredqualia.com/
  14266. */
  14267. function Fog(color, near, far) {
  14268. this.name = '';
  14269. this.color = new Color(color);
  14270. this.near = near !== undefined ? near : 1;
  14271. this.far = far !== undefined ? far : 1000;
  14272. }
  14273. Fog.prototype.isFog = true;
  14274. Fog.prototype.clone = function () {
  14275. return new Fog(this.color, this.near, this.far);
  14276. };
  14277. Fog.prototype.toJSON = function () /* meta */{
  14278. return {
  14279. type: 'Fog',
  14280. color: this.color.getHex(),
  14281. near: this.near,
  14282. far: this.far
  14283. };
  14284. };
  14285. /**
  14286. * @author mrdoob / http://mrdoob.com/
  14287. */
  14288. function Scene() {
  14289. Object3D.call(this);
  14290. this.type = 'Scene';
  14291. this.background = null;
  14292. this.fog = null;
  14293. this.overrideMaterial = null;
  14294. this.autoUpdate = true; // checked by the renderer
  14295. }
  14296. Scene.prototype = Object.assign(Object.create(Object3D.prototype), {
  14297. constructor: Scene,
  14298. copy: function (source, recursive) {
  14299. Object3D.prototype.copy.call(this, source, recursive);
  14300. if (source.background !== null) this.background = source.background.clone();
  14301. if (source.fog !== null) this.fog = source.fog.clone();
  14302. if (source.overrideMaterial !== null) this.overrideMaterial = source.overrideMaterial.clone();
  14303. this.autoUpdate = source.autoUpdate;
  14304. this.matrixAutoUpdate = source.matrixAutoUpdate;
  14305. return this;
  14306. },
  14307. toJSON: function (meta) {
  14308. var data = Object3D.prototype.toJSON.call(this, meta);
  14309. if (this.background !== null) data.object.background = this.background.toJSON(meta);
  14310. if (this.fog !== null) data.object.fog = this.fog.toJSON();
  14311. return data;
  14312. }
  14313. });
  14314. /**
  14315. * @author alteredq / http://alteredqualia.com/
  14316. *
  14317. * parameters = {
  14318. * color: <hex>,
  14319. * opacity: <float>,
  14320. * map: new THREE.Texture( <Image> ),
  14321. *
  14322. * uvOffset: new THREE.Vector2(),
  14323. * uvScale: new THREE.Vector2()
  14324. * }
  14325. */
  14326. function SpriteMaterial(parameters) {
  14327. Material.call(this);
  14328. this.type = 'SpriteMaterial';
  14329. this.color = new Color(0xffffff);
  14330. this.map = null;
  14331. this.rotation = 0;
  14332. this.fog = false;
  14333. this.lights = false;
  14334. this.setValues(parameters);
  14335. }
  14336. SpriteMaterial.prototype = Object.create(Material.prototype);
  14337. SpriteMaterial.prototype.constructor = SpriteMaterial;
  14338. SpriteMaterial.prototype.isSpriteMaterial = true;
  14339. SpriteMaterial.prototype.copy = function (source) {
  14340. Material.prototype.copy.call(this, source);
  14341. this.color.copy(source.color);
  14342. this.map = source.map;
  14343. this.rotation = source.rotation;
  14344. return this;
  14345. };
  14346. /**
  14347. * @author mikael emtinger / http://gomo.se/
  14348. * @author alteredq / http://alteredqualia.com/
  14349. */
  14350. function Sprite(material) {
  14351. Object3D.call(this);
  14352. this.type = 'Sprite';
  14353. this.material = material !== undefined ? material : new SpriteMaterial();
  14354. this.center = new Vector2(0.5, 0.5);
  14355. }
  14356. Sprite.prototype = Object.assign(Object.create(Object3D.prototype), {
  14357. constructor: Sprite,
  14358. isSprite: true,
  14359. raycast: function () {
  14360. var intersectPoint = new Vector3();
  14361. var worldPosition = new Vector3();
  14362. var worldScale = new Vector3();
  14363. return function raycast(raycaster, intersects) {
  14364. worldPosition.setFromMatrixPosition(this.matrixWorld);
  14365. raycaster.ray.closestPointToPoint(worldPosition, intersectPoint);
  14366. worldScale.setFromMatrixScale(this.matrixWorld);
  14367. var guessSizeSq = worldScale.x * worldScale.y / 4;
  14368. if (worldPosition.distanceToSquared(intersectPoint) > guessSizeSq) return;
  14369. var distance = raycaster.ray.origin.distanceTo(intersectPoint);
  14370. if (distance < raycaster.near || distance > raycaster.far) return;
  14371. intersects.push({
  14372. distance: distance,
  14373. point: intersectPoint.clone(),
  14374. face: null,
  14375. object: this
  14376. });
  14377. };
  14378. }(),
  14379. clone: function () {
  14380. return new this.constructor(this.material).copy(this);
  14381. },
  14382. copy: function (source) {
  14383. Object3D.prototype.copy.call(this, source);
  14384. if (source.center !== undefined) this.center.copy(source.center);
  14385. return this;
  14386. }
  14387. });
  14388. /**
  14389. * @author mikael emtinger / http://gomo.se/
  14390. * @author alteredq / http://alteredqualia.com/
  14391. * @author mrdoob / http://mrdoob.com/
  14392. */
  14393. function LOD() {
  14394. Object3D.call(this);
  14395. this.type = 'LOD';
  14396. Object.defineProperties(this, {
  14397. levels: {
  14398. enumerable: true,
  14399. value: []
  14400. }
  14401. });
  14402. }
  14403. LOD.prototype = Object.assign(Object.create(Object3D.prototype), {
  14404. constructor: LOD,
  14405. copy: function (source) {
  14406. Object3D.prototype.copy.call(this, source, false);
  14407. var levels = source.levels;
  14408. for (var i = 0, l = levels.length; i < l; i++) {
  14409. var level = levels[i];
  14410. this.addLevel(level.object.clone(), level.distance);
  14411. }
  14412. return this;
  14413. },
  14414. addLevel: function (object, distance) {
  14415. if (distance === undefined) distance = 0;
  14416. distance = Math.abs(distance);
  14417. var levels = this.levels;
  14418. for (var l = 0; l < levels.length; l++) {
  14419. if (distance < levels[l].distance) {
  14420. break;
  14421. }
  14422. }
  14423. levels.splice(l, 0, { distance: distance, object: object });
  14424. this.add(object);
  14425. },
  14426. getObjectForDistance: function (distance) {
  14427. var levels = this.levels;
  14428. for (var i = 1, l = levels.length; i < l; i++) {
  14429. if (distance < levels[i].distance) {
  14430. break;
  14431. }
  14432. }
  14433. return levels[i - 1].object;
  14434. },
  14435. raycast: function () {
  14436. var matrixPosition = new Vector3();
  14437. return function raycast(raycaster, intersects) {
  14438. matrixPosition.setFromMatrixPosition(this.matrixWorld);
  14439. var distance = raycaster.ray.origin.distanceTo(matrixPosition);
  14440. this.getObjectForDistance(distance).raycast(raycaster, intersects);
  14441. };
  14442. }(),
  14443. update: function () {
  14444. var v1 = new Vector3();
  14445. var v2 = new Vector3();
  14446. return function update(camera) {
  14447. var levels = this.levels;
  14448. if (levels.length > 1) {
  14449. v1.setFromMatrixPosition(camera.matrixWorld);
  14450. v2.setFromMatrixPosition(this.matrixWorld);
  14451. var distance = v1.distanceTo(v2);
  14452. levels[0].object.visible = true;
  14453. for (var i = 1, l = levels.length; i < l; i++) {
  14454. if (distance >= levels[i].distance) {
  14455. levels[i - 1].object.visible = false;
  14456. levels[i].object.visible = true;
  14457. } else {
  14458. break;
  14459. }
  14460. }
  14461. for (; i < l; i++) {
  14462. levels[i].object.visible = false;
  14463. }
  14464. }
  14465. };
  14466. }(),
  14467. toJSON: function (meta) {
  14468. var data = Object3D.prototype.toJSON.call(this, meta);
  14469. data.object.levels = [];
  14470. var levels = this.levels;
  14471. for (var i = 0, l = levels.length; i < l; i++) {
  14472. var level = levels[i];
  14473. data.object.levels.push({
  14474. object: level.object.uuid,
  14475. distance: level.distance
  14476. });
  14477. }
  14478. return data;
  14479. }
  14480. });
  14481. /**
  14482. * @author mikael emtinger / http://gomo.se/
  14483. * @author alteredq / http://alteredqualia.com/
  14484. * @author michael guerrero / http://realitymeltdown.com
  14485. * @author ikerr / http://verold.com
  14486. */
  14487. function Skeleton(bones, boneInverses) {
  14488. // copy the bone array
  14489. bones = bones || [];
  14490. this.bones = bones.slice(0);
  14491. this.boneMatrices = new Float32Array(this.bones.length * 16);
  14492. // use the supplied bone inverses or calculate the inverses
  14493. if (boneInverses === undefined) {
  14494. this.calculateInverses();
  14495. } else {
  14496. if (this.bones.length === boneInverses.length) {
  14497. this.boneInverses = boneInverses.slice(0);
  14498. } else {
  14499. console.warn('THREE.Skeleton boneInverses is the wrong length.');
  14500. this.boneInverses = [];
  14501. for (var i = 0, il = this.bones.length; i < il; i++) {
  14502. this.boneInverses.push(new Matrix4());
  14503. }
  14504. }
  14505. }
  14506. }
  14507. Object.assign(Skeleton.prototype, {
  14508. calculateInverses: function () {
  14509. this.boneInverses = [];
  14510. for (var i = 0, il = this.bones.length; i < il; i++) {
  14511. var inverse = new Matrix4();
  14512. if (this.bones[i]) {
  14513. inverse.getInverse(this.bones[i].matrixWorld);
  14514. }
  14515. this.boneInverses.push(inverse);
  14516. }
  14517. },
  14518. pose: function () {
  14519. var bone, i, il;
  14520. // recover the bind-time world matrices
  14521. for (i = 0, il = this.bones.length; i < il; i++) {
  14522. bone = this.bones[i];
  14523. if (bone) {
  14524. bone.matrixWorld.getInverse(this.boneInverses[i]);
  14525. }
  14526. }
  14527. // compute the local matrices, positions, rotations and scales
  14528. for (i = 0, il = this.bones.length; i < il; i++) {
  14529. bone = this.bones[i];
  14530. if (bone) {
  14531. if (bone.parent && bone.parent.isBone) {
  14532. bone.matrix.getInverse(bone.parent.matrixWorld);
  14533. bone.matrix.multiply(bone.matrixWorld);
  14534. } else {
  14535. bone.matrix.copy(bone.matrixWorld);
  14536. }
  14537. bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
  14538. }
  14539. }
  14540. },
  14541. update: function () {
  14542. var offsetMatrix = new Matrix4();
  14543. var identityMatrix = new Matrix4();
  14544. return function update() {
  14545. var bones = this.bones;
  14546. var boneInverses = this.boneInverses;
  14547. var boneMatrices = this.boneMatrices;
  14548. var boneTexture = this.boneTexture;
  14549. // flatten bone matrices to array
  14550. for (var i = 0, il = bones.length; i < il; i++) {
  14551. // compute the offset between the current and the original transform
  14552. var matrix = bones[i] ? bones[i].matrixWorld : identityMatrix;
  14553. offsetMatrix.multiplyMatrices(matrix, boneInverses[i]);
  14554. offsetMatrix.toArray(boneMatrices, i * 16);
  14555. }
  14556. if (boneTexture !== undefined) {
  14557. boneTexture.needsUpdate = true;
  14558. }
  14559. };
  14560. }(),
  14561. clone: function () {
  14562. return new Skeleton(this.bones, this.boneInverses);
  14563. },
  14564. getBoneByName: function (name) {
  14565. for (var i = 0, il = this.bones.length; i < il; i++) {
  14566. var bone = this.bones[i];
  14567. if (bone.name === name) {
  14568. return bone;
  14569. }
  14570. }
  14571. return undefined;
  14572. }
  14573. });
  14574. /**
  14575. * @author mikael emtinger / http://gomo.se/
  14576. * @author alteredq / http://alteredqualia.com/
  14577. * @author ikerr / http://verold.com
  14578. */
  14579. function Bone() {
  14580. Object3D.call(this);
  14581. this.type = 'Bone';
  14582. }
  14583. Bone.prototype = Object.assign(Object.create(Object3D.prototype), {
  14584. constructor: Bone,
  14585. isBone: true
  14586. });
  14587. /**
  14588. * @author mikael emtinger / http://gomo.se/
  14589. * @author alteredq / http://alteredqualia.com/
  14590. * @author ikerr / http://verold.com
  14591. */
  14592. function SkinnedMesh(geometry, material) {
  14593. Mesh.call(this, geometry, material);
  14594. this.type = 'SkinnedMesh';
  14595. this.bindMode = 'attached';
  14596. this.bindMatrix = new Matrix4();
  14597. this.bindMatrixInverse = new Matrix4();
  14598. var bones = this.initBones();
  14599. var skeleton = new Skeleton(bones);
  14600. this.bind(skeleton, this.matrixWorld);
  14601. this.normalizeSkinWeights();
  14602. }
  14603. SkinnedMesh.prototype = Object.assign(Object.create(Mesh.prototype), {
  14604. constructor: SkinnedMesh,
  14605. isSkinnedMesh: true,
  14606. initBones: function () {
  14607. var bones = [],
  14608. bone,
  14609. gbone;
  14610. var i, il;
  14611. if (this.geometry && this.geometry.bones !== undefined) {
  14612. // first, create array of 'Bone' objects from geometry data
  14613. for (i = 0, il = this.geometry.bones.length; i < il; i++) {
  14614. gbone = this.geometry.bones[i];
  14615. // create new 'Bone' object
  14616. bone = new Bone();
  14617. bones.push(bone);
  14618. // apply values
  14619. bone.name = gbone.name;
  14620. bone.position.fromArray(gbone.pos);
  14621. bone.quaternion.fromArray(gbone.rotq);
  14622. if (gbone.scl !== undefined) bone.scale.fromArray(gbone.scl);
  14623. }
  14624. // second, create bone hierarchy
  14625. for (i = 0, il = this.geometry.bones.length; i < il; i++) {
  14626. gbone = this.geometry.bones[i];
  14627. if (gbone.parent !== -1 && gbone.parent !== null && bones[gbone.parent] !== undefined) {
  14628. // subsequent bones in the hierarchy
  14629. bones[gbone.parent].add(bones[i]);
  14630. } else {
  14631. // topmost bone, immediate child of the skinned mesh
  14632. this.add(bones[i]);
  14633. }
  14634. }
  14635. }
  14636. // now the bones are part of the scene graph and children of the skinned mesh.
  14637. // let's update the corresponding matrices
  14638. this.updateMatrixWorld(true);
  14639. return bones;
  14640. },
  14641. bind: function (skeleton, bindMatrix) {
  14642. this.skeleton = skeleton;
  14643. if (bindMatrix === undefined) {
  14644. this.updateMatrixWorld(true);
  14645. this.skeleton.calculateInverses();
  14646. bindMatrix = this.matrixWorld;
  14647. }
  14648. this.bindMatrix.copy(bindMatrix);
  14649. this.bindMatrixInverse.getInverse(bindMatrix);
  14650. },
  14651. pose: function () {
  14652. this.skeleton.pose();
  14653. },
  14654. normalizeSkinWeights: function () {
  14655. var scale, i;
  14656. if (this.geometry && this.geometry.isGeometry) {
  14657. for (i = 0; i < this.geometry.skinWeights.length; i++) {
  14658. var sw = this.geometry.skinWeights[i];
  14659. scale = 1.0 / sw.manhattanLength();
  14660. if (scale !== Infinity) {
  14661. sw.multiplyScalar(scale);
  14662. } else {
  14663. sw.set(1, 0, 0, 0); // do something reasonable
  14664. }
  14665. }
  14666. } else if (this.geometry && this.geometry.isBufferGeometry) {
  14667. var vec = new Vector4();
  14668. var skinWeight = this.geometry.attributes.skinWeight;
  14669. for (i = 0; i < skinWeight.count; i++) {
  14670. vec.x = skinWeight.getX(i);
  14671. vec.y = skinWeight.getY(i);
  14672. vec.z = skinWeight.getZ(i);
  14673. vec.w = skinWeight.getW(i);
  14674. scale = 1.0 / vec.manhattanLength();
  14675. if (scale !== Infinity) {
  14676. vec.multiplyScalar(scale);
  14677. } else {
  14678. vec.set(1, 0, 0, 0); // do something reasonable
  14679. }
  14680. skinWeight.setXYZW(i, vec.x, vec.y, vec.z, vec.w);
  14681. }
  14682. }
  14683. },
  14684. updateMatrixWorld: function (force) {
  14685. Mesh.prototype.updateMatrixWorld.call(this, force);
  14686. if (this.bindMode === 'attached') {
  14687. this.bindMatrixInverse.getInverse(this.matrixWorld);
  14688. } else if (this.bindMode === 'detached') {
  14689. this.bindMatrixInverse.getInverse(this.bindMatrix);
  14690. } else {
  14691. console.warn('THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode);
  14692. }
  14693. },
  14694. clone: function () {
  14695. return new this.constructor(this.geometry, this.material).copy(this);
  14696. }
  14697. });
  14698. /**
  14699. * @author mrdoob / http://mrdoob.com/
  14700. * @author alteredq / http://alteredqualia.com/
  14701. *
  14702. * parameters = {
  14703. * color: <hex>,
  14704. * opacity: <float>,
  14705. *
  14706. * linewidth: <float>,
  14707. * linecap: "round",
  14708. * linejoin: "round"
  14709. * }
  14710. */
  14711. function LineBasicMaterial(parameters) {
  14712. Material.call(this);
  14713. this.type = 'LineBasicMaterial';
  14714. this.color = new Color(0xffffff);
  14715. this.linewidth = 1;
  14716. this.linecap = 'round';
  14717. this.linejoin = 'round';
  14718. this.lights = false;
  14719. this.setValues(parameters);
  14720. }
  14721. LineBasicMaterial.prototype = Object.create(Material.prototype);
  14722. LineBasicMaterial.prototype.constructor = LineBasicMaterial;
  14723. LineBasicMaterial.prototype.isLineBasicMaterial = true;
  14724. LineBasicMaterial.prototype.copy = function (source) {
  14725. Material.prototype.copy.call(this, source);
  14726. this.color.copy(source.color);
  14727. this.linewidth = source.linewidth;
  14728. this.linecap = source.linecap;
  14729. this.linejoin = source.linejoin;
  14730. return this;
  14731. };
  14732. /**
  14733. * @author mrdoob / http://mrdoob.com/
  14734. */
  14735. function Line(geometry, material, mode) {
  14736. if (mode === 1) {
  14737. console.warn('THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.');
  14738. return new LineSegments(geometry, material);
  14739. }
  14740. Object3D.call(this);
  14741. this.type = 'Line';
  14742. this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
  14743. this.material = material !== undefined ? material : new LineBasicMaterial({ color: Math.random() * 0xffffff });
  14744. }
  14745. Line.prototype = Object.assign(Object.create(Object3D.prototype), {
  14746. constructor: Line,
  14747. isLine: true,
  14748. computeLineDistances: function () {
  14749. var start = new Vector3();
  14750. var end = new Vector3();
  14751. return function computeLineDistances() {
  14752. var geometry = this.geometry;
  14753. if (geometry.isBufferGeometry) {
  14754. // we assume non-indexed geometry
  14755. if (geometry.index === null) {
  14756. var positionAttribute = geometry.attributes.position;
  14757. var lineDistances = [0];
  14758. for (var i = 1, l = positionAttribute.count; i < l; i++) {
  14759. start.fromBufferAttribute(positionAttribute, i - 1);
  14760. end.fromBufferAttribute(positionAttribute, i);
  14761. lineDistances[i] = lineDistances[i - 1];
  14762. lineDistances[i] += start.distanceTo(end);
  14763. }
  14764. geometry.addAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1));
  14765. } else {
  14766. console.warn('THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.');
  14767. }
  14768. } else if (geometry.isGeometry) {
  14769. var vertices = geometry.vertices;
  14770. var lineDistances = geometry.lineDistances;
  14771. lineDistances[0] = 0;
  14772. for (var i = 1, l = vertices.length; i < l; i++) {
  14773. lineDistances[i] = lineDistances[i - 1];
  14774. lineDistances[i] += vertices[i - 1].distanceTo(vertices[i]);
  14775. }
  14776. }
  14777. return this;
  14778. };
  14779. }(),
  14780. raycast: function () {
  14781. var inverseMatrix = new Matrix4();
  14782. var ray = new Ray();
  14783. var sphere = new Sphere();
  14784. return function raycast(raycaster, intersects) {
  14785. var precision = raycaster.linePrecision;
  14786. var precisionSq = precision * precision;
  14787. var geometry = this.geometry;
  14788. var matrixWorld = this.matrixWorld;
  14789. // Checking boundingSphere distance to ray
  14790. if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
  14791. sphere.copy(geometry.boundingSphere);
  14792. sphere.applyMatrix4(matrixWorld);
  14793. if (raycaster.ray.intersectsSphere(sphere) === false) return;
  14794. //
  14795. inverseMatrix.getInverse(matrixWorld);
  14796. ray.copy(raycaster.ray).applyMatrix4(inverseMatrix);
  14797. var vStart = new Vector3();
  14798. var vEnd = new Vector3();
  14799. var interSegment = new Vector3();
  14800. var interRay = new Vector3();
  14801. var step = this && this.isLineSegments ? 2 : 1;
  14802. if (geometry.isBufferGeometry) {
  14803. var index = geometry.index;
  14804. var attributes = geometry.attributes;
  14805. var positions = attributes.position.array;
  14806. if (index !== null) {
  14807. var indices = index.array;
  14808. for (var i = 0, l = indices.length - 1; i < l; i += step) {
  14809. var a = indices[i];
  14810. var b = indices[i + 1];
  14811. vStart.fromArray(positions, a * 3);
  14812. vEnd.fromArray(positions, b * 3);
  14813. var distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment);
  14814. if (distSq > precisionSq) continue;
  14815. interRay.applyMatrix4(this.matrixWorld); //Move back to world space for distance calculation
  14816. var distance = raycaster.ray.origin.distanceTo(interRay);
  14817. if (distance < raycaster.near || distance > raycaster.far) continue;
  14818. intersects.push({
  14819. distance: distance,
  14820. // What do we want? intersection point on the ray or on the segment??
  14821. // point: raycaster.ray.at( distance ),
  14822. point: interSegment.clone().applyMatrix4(this.matrixWorld),
  14823. index: i,
  14824. face: null,
  14825. faceIndex: null,
  14826. object: this
  14827. });
  14828. }
  14829. } else {
  14830. for (var i = 0, l = positions.length / 3 - 1; i < l; i += step) {
  14831. vStart.fromArray(positions, 3 * i);
  14832. vEnd.fromArray(positions, 3 * i + 3);
  14833. var distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment);
  14834. if (distSq > precisionSq) continue;
  14835. interRay.applyMatrix4(this.matrixWorld); //Move back to world space for distance calculation
  14836. var distance = raycaster.ray.origin.distanceTo(interRay);
  14837. if (distance < raycaster.near || distance > raycaster.far) continue;
  14838. intersects.push({
  14839. distance: distance,
  14840. // What do we want? intersection point on the ray or on the segment??
  14841. // point: raycaster.ray.at( distance ),
  14842. point: interSegment.clone().applyMatrix4(this.matrixWorld),
  14843. index: i,
  14844. face: null,
  14845. faceIndex: null,
  14846. object: this
  14847. });
  14848. }
  14849. }
  14850. } else if (geometry.isGeometry) {
  14851. var vertices = geometry.vertices;
  14852. var nbVertices = vertices.length;
  14853. for (var i = 0; i < nbVertices - 1; i += step) {
  14854. var distSq = ray.distanceSqToSegment(vertices[i], vertices[i + 1], interRay, interSegment);
  14855. if (distSq > precisionSq) continue;
  14856. interRay.applyMatrix4(this.matrixWorld); //Move back to world space for distance calculation
  14857. var distance = raycaster.ray.origin.distanceTo(interRay);
  14858. if (distance < raycaster.near || distance > raycaster.far) continue;
  14859. intersects.push({
  14860. distance: distance,
  14861. // What do we want? intersection point on the ray or on the segment??
  14862. // point: raycaster.ray.at( distance ),
  14863. point: interSegment.clone().applyMatrix4(this.matrixWorld),
  14864. index: i,
  14865. face: null,
  14866. faceIndex: null,
  14867. object: this
  14868. });
  14869. }
  14870. }
  14871. };
  14872. }(),
  14873. clone: function () {
  14874. return new this.constructor(this.geometry, this.material).copy(this);
  14875. }
  14876. });
  14877. /**
  14878. * @author mrdoob / http://mrdoob.com/
  14879. */
  14880. function LineSegments(geometry, material) {
  14881. Line.call(this, geometry, material);
  14882. this.type = 'LineSegments';
  14883. }
  14884. LineSegments.prototype = Object.assign(Object.create(Line.prototype), {
  14885. constructor: LineSegments,
  14886. isLineSegments: true,
  14887. computeLineDistances: function () {
  14888. var start = new Vector3();
  14889. var end = new Vector3();
  14890. return function computeLineDistances() {
  14891. var geometry = this.geometry;
  14892. if (geometry.isBufferGeometry) {
  14893. // we assume non-indexed geometry
  14894. if (geometry.index === null) {
  14895. var positionAttribute = geometry.attributes.position;
  14896. var lineDistances = [];
  14897. for (var i = 0, l = positionAttribute.count; i < l; i += 2) {
  14898. start.fromBufferAttribute(positionAttribute, i);
  14899. end.fromBufferAttribute(positionAttribute, i + 1);
  14900. lineDistances[i] = i === 0 ? 0 : lineDistances[i - 1];
  14901. lineDistances[i + 1] = lineDistances[i] + start.distanceTo(end);
  14902. }
  14903. geometry.addAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1));
  14904. } else {
  14905. console.warn('THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.');
  14906. }
  14907. } else if (geometry.isGeometry) {
  14908. var vertices = geometry.vertices;
  14909. var lineDistances = geometry.lineDistances;
  14910. for (var i = 0, l = vertices.length; i < l; i += 2) {
  14911. start.copy(vertices[i]);
  14912. end.copy(vertices[i + 1]);
  14913. lineDistances[i] = i === 0 ? 0 : lineDistances[i - 1];
  14914. lineDistances[i + 1] = lineDistances[i] + start.distanceTo(end);
  14915. }
  14916. }
  14917. return this;
  14918. };
  14919. }()
  14920. });
  14921. /**
  14922. * @author mgreter / http://github.com/mgreter
  14923. */
  14924. function LineLoop(geometry, material) {
  14925. Line.call(this, geometry, material);
  14926. this.type = 'LineLoop';
  14927. }
  14928. LineLoop.prototype = Object.assign(Object.create(Line.prototype), {
  14929. constructor: LineLoop,
  14930. isLineLoop: true
  14931. });
  14932. /**
  14933. * @author mrdoob / http://mrdoob.com/
  14934. * @author alteredq / http://alteredqualia.com/
  14935. *
  14936. * parameters = {
  14937. * color: <hex>,
  14938. * opacity: <float>,
  14939. * map: new THREE.Texture( <Image> ),
  14940. *
  14941. * size: <float>,
  14942. * sizeAttenuation: <bool>
  14943. *
  14944. * morphTargets: <bool>
  14945. * }
  14946. */
  14947. function PointsMaterial(parameters) {
  14948. Material.call(this);
  14949. this.type = 'PointsMaterial';
  14950. this.color = new Color(0xffffff);
  14951. this.map = null;
  14952. this.size = 1;
  14953. this.sizeAttenuation = true;
  14954. this.morphTargets = false;
  14955. this.lights = false;
  14956. this.setValues(parameters);
  14957. }
  14958. PointsMaterial.prototype = Object.create(Material.prototype);
  14959. PointsMaterial.prototype.constructor = PointsMaterial;
  14960. PointsMaterial.prototype.isPointsMaterial = true;
  14961. PointsMaterial.prototype.copy = function (source) {
  14962. Material.prototype.copy.call(this, source);
  14963. this.color.copy(source.color);
  14964. this.map = source.map;
  14965. this.size = source.size;
  14966. this.sizeAttenuation = source.sizeAttenuation;
  14967. this.morphTargets = source.morphTargets;
  14968. return this;
  14969. };
  14970. /**
  14971. * @author alteredq / http://alteredqualia.com/
  14972. */
  14973. function Points(geometry, material) {
  14974. Object3D.call(this);
  14975. this.type = 'Points';
  14976. this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
  14977. this.material = material !== undefined ? material : new PointsMaterial({ color: Math.random() * 0xffffff });
  14978. }
  14979. Points.prototype = Object.assign(Object.create(Object3D.prototype), {
  14980. constructor: Points,
  14981. isPoints: true,
  14982. raycast: function () {
  14983. var inverseMatrix = new Matrix4();
  14984. var ray = new Ray();
  14985. var sphere = new Sphere();
  14986. return function raycast(raycaster, intersects) {
  14987. var object = this;
  14988. var geometry = this.geometry;
  14989. var matrixWorld = this.matrixWorld;
  14990. var threshold = raycaster.params.Points.threshold;
  14991. // Checking boundingSphere distance to ray
  14992. if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
  14993. sphere.copy(geometry.boundingSphere);
  14994. sphere.applyMatrix4(matrixWorld);
  14995. sphere.radius += threshold;
  14996. if (raycaster.ray.intersectsSphere(sphere) === false) return;
  14997. //
  14998. inverseMatrix.getInverse(matrixWorld);
  14999. ray.copy(raycaster.ray).applyMatrix4(inverseMatrix);
  15000. var localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3);
  15001. var localThresholdSq = localThreshold * localThreshold;
  15002. var position = new Vector3();
  15003. var intersectPoint = new Vector3();
  15004. function testPoint(point, index) {
  15005. var rayPointDistanceSq = ray.distanceSqToPoint(point);
  15006. if (rayPointDistanceSq < localThresholdSq) {
  15007. ray.closestPointToPoint(point, intersectPoint);
  15008. intersectPoint.applyMatrix4(matrixWorld);
  15009. var distance = raycaster.ray.origin.distanceTo(intersectPoint);
  15010. if (distance < raycaster.near || distance > raycaster.far) return;
  15011. intersects.push({
  15012. distance: distance,
  15013. distanceToRay: Math.sqrt(rayPointDistanceSq),
  15014. point: intersectPoint.clone(),
  15015. index: index,
  15016. face: null,
  15017. object: object
  15018. });
  15019. }
  15020. }
  15021. if (geometry.isBufferGeometry) {
  15022. var index = geometry.index;
  15023. var attributes = geometry.attributes;
  15024. var positions = attributes.position.array;
  15025. if (index !== null) {
  15026. var indices = index.array;
  15027. for (var i = 0, il = indices.length; i < il; i++) {
  15028. var a = indices[i];
  15029. position.fromArray(positions, a * 3);
  15030. testPoint(position, a);
  15031. }
  15032. } else {
  15033. for (var i = 0, l = positions.length / 3; i < l; i++) {
  15034. position.fromArray(positions, i * 3);
  15035. testPoint(position, i);
  15036. }
  15037. }
  15038. } else {
  15039. var vertices = geometry.vertices;
  15040. for (var i = 0, l = vertices.length; i < l; i++) {
  15041. testPoint(vertices[i], i);
  15042. }
  15043. }
  15044. };
  15045. }(),
  15046. clone: function () {
  15047. return new this.constructor(this.geometry, this.material).copy(this);
  15048. }
  15049. });
  15050. /**
  15051. * @author mrdoob / http://mrdoob.com/
  15052. */
  15053. function Group() {
  15054. Object3D.call(this);
  15055. this.type = 'Group';
  15056. }
  15057. Group.prototype = Object.assign(Object.create(Object3D.prototype), {
  15058. constructor: Group,
  15059. isGroup: true
  15060. });
  15061. /**
  15062. * @author mrdoob / http://mrdoob.com/
  15063. */
  15064. function VideoTexture(video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) {
  15065. Texture.call(this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy);
  15066. this.generateMipmaps = false;
  15067. }
  15068. VideoTexture.prototype = Object.assign(Object.create(Texture.prototype), {
  15069. constructor: VideoTexture,
  15070. isVideoTexture: true,
  15071. update: function () {
  15072. var video = this.image;
  15073. if (video.readyState >= video.HAVE_CURRENT_DATA) {
  15074. this.needsUpdate = true;
  15075. }
  15076. }
  15077. });
  15078. /**
  15079. * @author alteredq / http://alteredqualia.com/
  15080. */
  15081. function CompressedTexture(mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding) {
  15082. Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding);
  15083. this.image = { width: width, height: height };
  15084. this.mipmaps = mipmaps;
  15085. // no flipping for cube textures
  15086. // (also flipping doesn't work for compressed textures )
  15087. this.flipY = false;
  15088. // can't generate mipmaps for compressed textures
  15089. // mips must be embedded in DDS files
  15090. this.generateMipmaps = false;
  15091. }
  15092. CompressedTexture.prototype = Object.create(Texture.prototype);
  15093. CompressedTexture.prototype.constructor = CompressedTexture;
  15094. CompressedTexture.prototype.isCompressedTexture = true;
  15095. /**
  15096. * @author Matt DesLauriers / @mattdesl
  15097. * @author atix / arthursilber.de
  15098. */
  15099. function DepthTexture(width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format) {
  15100. format = format !== undefined ? format : DepthFormat;
  15101. if (format !== DepthFormat && format !== DepthStencilFormat) {
  15102. throw new Error('DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat');
  15103. }
  15104. if (type === undefined && format === DepthFormat) type = UnsignedShortType;
  15105. if (type === undefined && format === DepthStencilFormat) type = UnsignedInt248Type;
  15106. Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy);
  15107. this.image = { width: width, height: height };
  15108. this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
  15109. this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
  15110. this.flipY = false;
  15111. this.generateMipmaps = false;
  15112. }
  15113. DepthTexture.prototype = Object.create(Texture.prototype);
  15114. DepthTexture.prototype.constructor = DepthTexture;
  15115. DepthTexture.prototype.isDepthTexture = true;
  15116. /**
  15117. * @author mrdoob / http://mrdoob.com/
  15118. * @author Mugen87 / https://github.com/Mugen87
  15119. */
  15120. function WireframeGeometry(geometry) {
  15121. BufferGeometry.call(this);
  15122. this.type = 'WireframeGeometry';
  15123. // buffer
  15124. var vertices = [];
  15125. // helper variables
  15126. var i, j, l, o, ol;
  15127. var edge = [0, 0],
  15128. edges = {},
  15129. e,
  15130. edge1,
  15131. edge2;
  15132. var key,
  15133. keys = ['a', 'b', 'c'];
  15134. var vertex;
  15135. // different logic for Geometry and BufferGeometry
  15136. if (geometry && geometry.isGeometry) {
  15137. // create a data structure that contains all edges without duplicates
  15138. var faces = geometry.faces;
  15139. for (i = 0, l = faces.length; i < l; i++) {
  15140. var face = faces[i];
  15141. for (j = 0; j < 3; j++) {
  15142. edge1 = face[keys[j]];
  15143. edge2 = face[keys[(j + 1) % 3]];
  15144. edge[0] = Math.min(edge1, edge2); // sorting prevents duplicates
  15145. edge[1] = Math.max(edge1, edge2);
  15146. key = edge[0] + ',' + edge[1];
  15147. if (edges[key] === undefined) {
  15148. edges[key] = { index1: edge[0], index2: edge[1] };
  15149. }
  15150. }
  15151. }
  15152. // generate vertices
  15153. for (key in edges) {
  15154. e = edges[key];
  15155. vertex = geometry.vertices[e.index1];
  15156. vertices.push(vertex.x, vertex.y, vertex.z);
  15157. vertex = geometry.vertices[e.index2];
  15158. vertices.push(vertex.x, vertex.y, vertex.z);
  15159. }
  15160. } else if (geometry && geometry.isBufferGeometry) {
  15161. var position, indices, groups;
  15162. var group, start, count;
  15163. var index1, index2;
  15164. vertex = new Vector3();
  15165. if (geometry.index !== null) {
  15166. // indexed BufferGeometry
  15167. position = geometry.attributes.position;
  15168. indices = geometry.index;
  15169. groups = geometry.groups;
  15170. if (groups.length === 0) {
  15171. groups = [{ start: 0, count: indices.count, materialIndex: 0 }];
  15172. }
  15173. // create a data structure that contains all eges without duplicates
  15174. for (o = 0, ol = groups.length; o < ol; ++o) {
  15175. group = groups[o];
  15176. start = group.start;
  15177. count = group.count;
  15178. for (i = start, l = start + count; i < l; i += 3) {
  15179. for (j = 0; j < 3; j++) {
  15180. edge1 = indices.getX(i + j);
  15181. edge2 = indices.getX(i + (j + 1) % 3);
  15182. edge[0] = Math.min(edge1, edge2); // sorting prevents duplicates
  15183. edge[1] = Math.max(edge1, edge2);
  15184. key = edge[0] + ',' + edge[1];
  15185. if (edges[key] === undefined) {
  15186. edges[key] = { index1: edge[0], index2: edge[1] };
  15187. }
  15188. }
  15189. }
  15190. }
  15191. // generate vertices
  15192. for (key in edges) {
  15193. e = edges[key];
  15194. vertex.fromBufferAttribute(position, e.index1);
  15195. vertices.push(vertex.x, vertex.y, vertex.z);
  15196. vertex.fromBufferAttribute(position, e.index2);
  15197. vertices.push(vertex.x, vertex.y, vertex.z);
  15198. }
  15199. } else {
  15200. // non-indexed BufferGeometry
  15201. position = geometry.attributes.position;
  15202. for (i = 0, l = position.count / 3; i < l; i++) {
  15203. for (j = 0; j < 3; j++) {
  15204. // three edges per triangle, an edge is represented as (index1, index2)
  15205. // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
  15206. index1 = 3 * i + j;
  15207. vertex.fromBufferAttribute(position, index1);
  15208. vertices.push(vertex.x, vertex.y, vertex.z);
  15209. index2 = 3 * i + (j + 1) % 3;
  15210. vertex.fromBufferAttribute(position, index2);
  15211. vertices.push(vertex.x, vertex.y, vertex.z);
  15212. }
  15213. }
  15214. }
  15215. }
  15216. // build geometry
  15217. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  15218. }
  15219. WireframeGeometry.prototype = Object.create(BufferGeometry.prototype);
  15220. WireframeGeometry.prototype.constructor = WireframeGeometry;
  15221. /**
  15222. * @author zz85 / https://github.com/zz85
  15223. * @author Mugen87 / https://github.com/Mugen87
  15224. *
  15225. * Parametric Surfaces Geometry
  15226. * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
  15227. */
  15228. // ParametricGeometry
  15229. function ParametricGeometry(func, slices, stacks) {
  15230. Geometry.call(this);
  15231. this.type = 'ParametricGeometry';
  15232. this.parameters = {
  15233. func: func,
  15234. slices: slices,
  15235. stacks: stacks
  15236. };
  15237. this.fromBufferGeometry(new ParametricBufferGeometry(func, slices, stacks));
  15238. this.mergeVertices();
  15239. }
  15240. ParametricGeometry.prototype = Object.create(Geometry.prototype);
  15241. ParametricGeometry.prototype.constructor = ParametricGeometry;
  15242. // ParametricBufferGeometry
  15243. function ParametricBufferGeometry(func, slices, stacks) {
  15244. BufferGeometry.call(this);
  15245. this.type = 'ParametricBufferGeometry';
  15246. this.parameters = {
  15247. func: func,
  15248. slices: slices,
  15249. stacks: stacks
  15250. };
  15251. // buffers
  15252. var indices = [];
  15253. var vertices = [];
  15254. var normals = [];
  15255. var uvs = [];
  15256. var EPS = 0.00001;
  15257. var normal = new Vector3();
  15258. var p0 = new Vector3(),
  15259. p1 = new Vector3();
  15260. var pu = new Vector3(),
  15261. pv = new Vector3();
  15262. var i, j;
  15263. if (func.length < 3) {
  15264. console.error('THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.');
  15265. }
  15266. // generate vertices, normals and uvs
  15267. var sliceCount = slices + 1;
  15268. for (i = 0; i <= stacks; i++) {
  15269. var v = i / stacks;
  15270. for (j = 0; j <= slices; j++) {
  15271. var u = j / slices;
  15272. // vertex
  15273. func(u, v, p0);
  15274. vertices.push(p0.x, p0.y, p0.z);
  15275. // normal
  15276. // approximate tangent vectors via finite differences
  15277. if (u - EPS >= 0) {
  15278. func(u - EPS, v, p1);
  15279. pu.subVectors(p0, p1);
  15280. } else {
  15281. func(u + EPS, v, p1);
  15282. pu.subVectors(p1, p0);
  15283. }
  15284. if (v - EPS >= 0) {
  15285. func(u, v - EPS, p1);
  15286. pv.subVectors(p0, p1);
  15287. } else {
  15288. func(u, v + EPS, p1);
  15289. pv.subVectors(p1, p0);
  15290. }
  15291. // cross product of tangent vectors returns surface normal
  15292. normal.crossVectors(pu, pv).normalize();
  15293. normals.push(normal.x, normal.y, normal.z);
  15294. // uv
  15295. uvs.push(u, v);
  15296. }
  15297. }
  15298. // generate indices
  15299. for (i = 0; i < stacks; i++) {
  15300. for (j = 0; j < slices; j++) {
  15301. var a = i * sliceCount + j;
  15302. var b = i * sliceCount + j + 1;
  15303. var c = (i + 1) * sliceCount + j + 1;
  15304. var d = (i + 1) * sliceCount + j;
  15305. // faces one and two
  15306. indices.push(a, b, d);
  15307. indices.push(b, c, d);
  15308. }
  15309. }
  15310. // build geometry
  15311. this.setIndex(indices);
  15312. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  15313. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  15314. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  15315. }
  15316. ParametricBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  15317. ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
  15318. /**
  15319. * @author clockworkgeek / https://github.com/clockworkgeek
  15320. * @author timothypratley / https://github.com/timothypratley
  15321. * @author WestLangley / http://github.com/WestLangley
  15322. * @author Mugen87 / https://github.com/Mugen87
  15323. */
  15324. // PolyhedronGeometry
  15325. function PolyhedronGeometry(vertices, indices, radius, detail) {
  15326. Geometry.call(this);
  15327. this.type = 'PolyhedronGeometry';
  15328. this.parameters = {
  15329. vertices: vertices,
  15330. indices: indices,
  15331. radius: radius,
  15332. detail: detail
  15333. };
  15334. this.fromBufferGeometry(new PolyhedronBufferGeometry(vertices, indices, radius, detail));
  15335. this.mergeVertices();
  15336. }
  15337. PolyhedronGeometry.prototype = Object.create(Geometry.prototype);
  15338. PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
  15339. // PolyhedronBufferGeometry
  15340. function PolyhedronBufferGeometry(vertices, indices, radius, detail) {
  15341. BufferGeometry.call(this);
  15342. this.type = 'PolyhedronBufferGeometry';
  15343. this.parameters = {
  15344. vertices: vertices,
  15345. indices: indices,
  15346. radius: radius,
  15347. detail: detail
  15348. };
  15349. radius = radius || 1;
  15350. detail = detail || 0;
  15351. // default buffer data
  15352. var vertexBuffer = [];
  15353. var uvBuffer = [];
  15354. // the subdivision creates the vertex buffer data
  15355. subdivide(detail);
  15356. // all vertices should lie on a conceptual sphere with a given radius
  15357. appplyRadius(radius);
  15358. // finally, create the uv data
  15359. generateUVs();
  15360. // build non-indexed geometry
  15361. this.addAttribute('position', new Float32BufferAttribute(vertexBuffer, 3));
  15362. this.addAttribute('normal', new Float32BufferAttribute(vertexBuffer.slice(), 3));
  15363. this.addAttribute('uv', new Float32BufferAttribute(uvBuffer, 2));
  15364. if (detail === 0) {
  15365. this.computeVertexNormals(); // flat normals
  15366. } else {
  15367. this.normalizeNormals(); // smooth normals
  15368. }
  15369. // helper functions
  15370. function subdivide(detail) {
  15371. var a = new Vector3();
  15372. var b = new Vector3();
  15373. var c = new Vector3();
  15374. // iterate over all faces and apply a subdivison with the given detail value
  15375. for (var i = 0; i < indices.length; i += 3) {
  15376. // get the vertices of the face
  15377. getVertexByIndex(indices[i + 0], a);
  15378. getVertexByIndex(indices[i + 1], b);
  15379. getVertexByIndex(indices[i + 2], c);
  15380. // perform subdivision
  15381. subdivideFace(a, b, c, detail);
  15382. }
  15383. }
  15384. function subdivideFace(a, b, c, detail) {
  15385. var cols = Math.pow(2, detail);
  15386. // we use this multidimensional array as a data structure for creating the subdivision
  15387. var v = [];
  15388. var i, j;
  15389. // construct all of the vertices for this subdivision
  15390. for (i = 0; i <= cols; i++) {
  15391. v[i] = [];
  15392. var aj = a.clone().lerp(c, i / cols);
  15393. var bj = b.clone().lerp(c, i / cols);
  15394. var rows = cols - i;
  15395. for (j = 0; j <= rows; j++) {
  15396. if (j === 0 && i === cols) {
  15397. v[i][j] = aj;
  15398. } else {
  15399. v[i][j] = aj.clone().lerp(bj, j / rows);
  15400. }
  15401. }
  15402. }
  15403. // construct all of the faces
  15404. for (i = 0; i < cols; i++) {
  15405. for (j = 0; j < 2 * (cols - i) - 1; j++) {
  15406. var k = Math.floor(j / 2);
  15407. if (j % 2 === 0) {
  15408. pushVertex(v[i][k + 1]);
  15409. pushVertex(v[i + 1][k]);
  15410. pushVertex(v[i][k]);
  15411. } else {
  15412. pushVertex(v[i][k + 1]);
  15413. pushVertex(v[i + 1][k + 1]);
  15414. pushVertex(v[i + 1][k]);
  15415. }
  15416. }
  15417. }
  15418. }
  15419. function appplyRadius(radius) {
  15420. var vertex = new Vector3();
  15421. // iterate over the entire buffer and apply the radius to each vertex
  15422. for (var i = 0; i < vertexBuffer.length; i += 3) {
  15423. vertex.x = vertexBuffer[i + 0];
  15424. vertex.y = vertexBuffer[i + 1];
  15425. vertex.z = vertexBuffer[i + 2];
  15426. vertex.normalize().multiplyScalar(radius);
  15427. vertexBuffer[i + 0] = vertex.x;
  15428. vertexBuffer[i + 1] = vertex.y;
  15429. vertexBuffer[i + 2] = vertex.z;
  15430. }
  15431. }
  15432. function generateUVs() {
  15433. var vertex = new Vector3();
  15434. for (var i = 0; i < vertexBuffer.length; i += 3) {
  15435. vertex.x = vertexBuffer[i + 0];
  15436. vertex.y = vertexBuffer[i + 1];
  15437. vertex.z = vertexBuffer[i + 2];
  15438. var u = azimuth(vertex) / 2 / Math.PI + 0.5;
  15439. var v = inclination(vertex) / Math.PI + 0.5;
  15440. uvBuffer.push(u, 1 - v);
  15441. }
  15442. correctUVs();
  15443. correctSeam();
  15444. }
  15445. function correctSeam() {
  15446. // handle case when face straddles the seam, see #3269
  15447. for (var i = 0; i < uvBuffer.length; i += 6) {
  15448. // uv data of a single face
  15449. var x0 = uvBuffer[i + 0];
  15450. var x1 = uvBuffer[i + 2];
  15451. var x2 = uvBuffer[i + 4];
  15452. var max = Math.max(x0, x1, x2);
  15453. var min = Math.min(x0, x1, x2);
  15454. // 0.9 is somewhat arbitrary
  15455. if (max > 0.9 && min < 0.1) {
  15456. if (x0 < 0.2) uvBuffer[i + 0] += 1;
  15457. if (x1 < 0.2) uvBuffer[i + 2] += 1;
  15458. if (x2 < 0.2) uvBuffer[i + 4] += 1;
  15459. }
  15460. }
  15461. }
  15462. function pushVertex(vertex) {
  15463. vertexBuffer.push(vertex.x, vertex.y, vertex.z);
  15464. }
  15465. function getVertexByIndex(index, vertex) {
  15466. var stride = index * 3;
  15467. vertex.x = vertices[stride + 0];
  15468. vertex.y = vertices[stride + 1];
  15469. vertex.z = vertices[stride + 2];
  15470. }
  15471. function correctUVs() {
  15472. var a = new Vector3();
  15473. var b = new Vector3();
  15474. var c = new Vector3();
  15475. var centroid = new Vector3();
  15476. var uvA = new Vector2();
  15477. var uvB = new Vector2();
  15478. var uvC = new Vector2();
  15479. for (var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6) {
  15480. a.set(vertexBuffer[i + 0], vertexBuffer[i + 1], vertexBuffer[i + 2]);
  15481. b.set(vertexBuffer[i + 3], vertexBuffer[i + 4], vertexBuffer[i + 5]);
  15482. c.set(vertexBuffer[i + 6], vertexBuffer[i + 7], vertexBuffer[i + 8]);
  15483. uvA.set(uvBuffer[j + 0], uvBuffer[j + 1]);
  15484. uvB.set(uvBuffer[j + 2], uvBuffer[j + 3]);
  15485. uvC.set(uvBuffer[j + 4], uvBuffer[j + 5]);
  15486. centroid.copy(a).add(b).add(c).divideScalar(3);
  15487. var azi = azimuth(centroid);
  15488. correctUV(uvA, j + 0, a, azi);
  15489. correctUV(uvB, j + 2, b, azi);
  15490. correctUV(uvC, j + 4, c, azi);
  15491. }
  15492. }
  15493. function correctUV(uv, stride, vector, azimuth) {
  15494. if (azimuth < 0 && uv.x === 1) {
  15495. uvBuffer[stride] = uv.x - 1;
  15496. }
  15497. if (vector.x === 0 && vector.z === 0) {
  15498. uvBuffer[stride] = azimuth / 2 / Math.PI + 0.5;
  15499. }
  15500. }
  15501. // Angle around the Y axis, counter-clockwise when looking from above.
  15502. function azimuth(vector) {
  15503. return Math.atan2(vector.z, -vector.x);
  15504. }
  15505. // Angle above the XZ plane.
  15506. function inclination(vector) {
  15507. return Math.atan2(-vector.y, Math.sqrt(vector.x * vector.x + vector.z * vector.z));
  15508. }
  15509. }
  15510. PolyhedronBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  15511. PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
  15512. /**
  15513. * @author timothypratley / https://github.com/timothypratley
  15514. * @author Mugen87 / https://github.com/Mugen87
  15515. */
  15516. // TetrahedronGeometry
  15517. function TetrahedronGeometry(radius, detail) {
  15518. Geometry.call(this);
  15519. this.type = 'TetrahedronGeometry';
  15520. this.parameters = {
  15521. radius: radius,
  15522. detail: detail
  15523. };
  15524. this.fromBufferGeometry(new TetrahedronBufferGeometry(radius, detail));
  15525. this.mergeVertices();
  15526. }
  15527. TetrahedronGeometry.prototype = Object.create(Geometry.prototype);
  15528. TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
  15529. // TetrahedronBufferGeometry
  15530. function TetrahedronBufferGeometry(radius, detail) {
  15531. var vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
  15532. var indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
  15533. PolyhedronBufferGeometry.call(this, vertices, indices, radius, detail);
  15534. this.type = 'TetrahedronBufferGeometry';
  15535. this.parameters = {
  15536. radius: radius,
  15537. detail: detail
  15538. };
  15539. }
  15540. TetrahedronBufferGeometry.prototype = Object.create(PolyhedronBufferGeometry.prototype);
  15541. TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
  15542. /**
  15543. * @author timothypratley / https://github.com/timothypratley
  15544. * @author Mugen87 / https://github.com/Mugen87
  15545. */
  15546. // OctahedronGeometry
  15547. function OctahedronGeometry(radius, detail) {
  15548. Geometry.call(this);
  15549. this.type = 'OctahedronGeometry';
  15550. this.parameters = {
  15551. radius: radius,
  15552. detail: detail
  15553. };
  15554. this.fromBufferGeometry(new OctahedronBufferGeometry(radius, detail));
  15555. this.mergeVertices();
  15556. }
  15557. OctahedronGeometry.prototype = Object.create(Geometry.prototype);
  15558. OctahedronGeometry.prototype.constructor = OctahedronGeometry;
  15559. // OctahedronBufferGeometry
  15560. function OctahedronBufferGeometry(radius, detail) {
  15561. var vertices = [1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1];
  15562. 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];
  15563. PolyhedronBufferGeometry.call(this, vertices, indices, radius, detail);
  15564. this.type = 'OctahedronBufferGeometry';
  15565. this.parameters = {
  15566. radius: radius,
  15567. detail: detail
  15568. };
  15569. }
  15570. OctahedronBufferGeometry.prototype = Object.create(PolyhedronBufferGeometry.prototype);
  15571. OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
  15572. /**
  15573. * @author timothypratley / https://github.com/timothypratley
  15574. * @author Mugen87 / https://github.com/Mugen87
  15575. */
  15576. // IcosahedronGeometry
  15577. function IcosahedronGeometry(radius, detail) {
  15578. Geometry.call(this);
  15579. this.type = 'IcosahedronGeometry';
  15580. this.parameters = {
  15581. radius: radius,
  15582. detail: detail
  15583. };
  15584. this.fromBufferGeometry(new IcosahedronBufferGeometry(radius, detail));
  15585. this.mergeVertices();
  15586. }
  15587. IcosahedronGeometry.prototype = Object.create(Geometry.prototype);
  15588. IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
  15589. // IcosahedronBufferGeometry
  15590. function IcosahedronBufferGeometry(radius, detail) {
  15591. var t = (1 + Math.sqrt(5)) / 2;
  15592. 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];
  15593. 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];
  15594. PolyhedronBufferGeometry.call(this, vertices, indices, radius, detail);
  15595. this.type = 'IcosahedronBufferGeometry';
  15596. this.parameters = {
  15597. radius: radius,
  15598. detail: detail
  15599. };
  15600. }
  15601. IcosahedronBufferGeometry.prototype = Object.create(PolyhedronBufferGeometry.prototype);
  15602. IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
  15603. /**
  15604. * @author Abe Pazos / https://hamoid.com
  15605. * @author Mugen87 / https://github.com/Mugen87
  15606. */
  15607. // DodecahedronGeometry
  15608. function DodecahedronGeometry(radius, detail) {
  15609. Geometry.call(this);
  15610. this.type = 'DodecahedronGeometry';
  15611. this.parameters = {
  15612. radius: radius,
  15613. detail: detail
  15614. };
  15615. this.fromBufferGeometry(new DodecahedronBufferGeometry(radius, detail));
  15616. this.mergeVertices();
  15617. }
  15618. DodecahedronGeometry.prototype = Object.create(Geometry.prototype);
  15619. DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
  15620. // DodecahedronBufferGeometry
  15621. function DodecahedronBufferGeometry(radius, detail) {
  15622. var t = (1 + Math.sqrt(5)) / 2;
  15623. var r = 1 / t;
  15624. var vertices = [
  15625. // (±1, ±1, ±1)
  15626. -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1,
  15627. // (0, ±1/φ, ±φ)
  15628. 0, -r, -t, 0, -r, t, 0, r, -t, 0, r, t,
  15629. // (±1/φ, ±φ, 0)
  15630. -r, -t, 0, -r, t, 0, r, -t, 0, r, t, 0,
  15631. // (±φ, 0, ±1/φ)
  15632. -t, 0, -r, t, 0, -r, -t, 0, r, t, 0, r];
  15633. 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];
  15634. PolyhedronBufferGeometry.call(this, vertices, indices, radius, detail);
  15635. this.type = 'DodecahedronBufferGeometry';
  15636. this.parameters = {
  15637. radius: radius,
  15638. detail: detail
  15639. };
  15640. }
  15641. DodecahedronBufferGeometry.prototype = Object.create(PolyhedronBufferGeometry.prototype);
  15642. DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
  15643. /**
  15644. * @author oosmoxiecode / https://github.com/oosmoxiecode
  15645. * @author WestLangley / https://github.com/WestLangley
  15646. * @author zz85 / https://github.com/zz85
  15647. * @author miningold / https://github.com/miningold
  15648. * @author jonobr1 / https://github.com/jonobr1
  15649. * @author Mugen87 / https://github.com/Mugen87
  15650. *
  15651. */
  15652. // TubeGeometry
  15653. function TubeGeometry(path, tubularSegments, radius, radialSegments, closed, taper) {
  15654. Geometry.call(this);
  15655. this.type = 'TubeGeometry';
  15656. this.parameters = {
  15657. path: path,
  15658. tubularSegments: tubularSegments,
  15659. radius: radius,
  15660. radialSegments: radialSegments,
  15661. closed: closed
  15662. };
  15663. if (taper !== undefined) console.warn('THREE.TubeGeometry: taper has been removed.');
  15664. var bufferGeometry = new TubeBufferGeometry(path, tubularSegments, radius, radialSegments, closed);
  15665. // expose internals
  15666. this.tangents = bufferGeometry.tangents;
  15667. this.normals = bufferGeometry.normals;
  15668. this.binormals = bufferGeometry.binormals;
  15669. // create geometry
  15670. this.fromBufferGeometry(bufferGeometry);
  15671. this.mergeVertices();
  15672. }
  15673. TubeGeometry.prototype = Object.create(Geometry.prototype);
  15674. TubeGeometry.prototype.constructor = TubeGeometry;
  15675. // TubeBufferGeometry
  15676. function TubeBufferGeometry(path, tubularSegments, radius, radialSegments, closed) {
  15677. BufferGeometry.call(this);
  15678. this.type = 'TubeBufferGeometry';
  15679. this.parameters = {
  15680. path: path,
  15681. tubularSegments: tubularSegments,
  15682. radius: radius,
  15683. radialSegments: radialSegments,
  15684. closed: closed
  15685. };
  15686. tubularSegments = tubularSegments || 64;
  15687. radius = radius || 1;
  15688. radialSegments = radialSegments || 8;
  15689. closed = closed || false;
  15690. var frames = path.computeFrenetFrames(tubularSegments, closed);
  15691. // expose internals
  15692. this.tangents = frames.tangents;
  15693. this.normals = frames.normals;
  15694. this.binormals = frames.binormals;
  15695. // helper variables
  15696. var vertex = new Vector3();
  15697. var normal = new Vector3();
  15698. var uv = new Vector2();
  15699. var P = new Vector3();
  15700. var i, j;
  15701. // buffer
  15702. var vertices = [];
  15703. var normals = [];
  15704. var uvs = [];
  15705. var indices = [];
  15706. // create buffer data
  15707. generateBufferData();
  15708. // build geometry
  15709. this.setIndex(indices);
  15710. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  15711. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  15712. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  15713. // functions
  15714. function generateBufferData() {
  15715. for (i = 0; i < tubularSegments; i++) {
  15716. generateSegment(i);
  15717. }
  15718. // if the geometry is not closed, generate the last row of vertices and normals
  15719. // at the regular position on the given path
  15720. //
  15721. // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
  15722. generateSegment(closed === false ? tubularSegments : 0);
  15723. // uvs are generated in a separate function.
  15724. // this makes it easy compute correct values for closed geometries
  15725. generateUVs();
  15726. // finally create faces
  15727. generateIndices();
  15728. }
  15729. function generateSegment(i) {
  15730. // we use getPointAt to sample evenly distributed points from the given path
  15731. P = path.getPointAt(i / tubularSegments, P);
  15732. // retrieve corresponding normal and binormal
  15733. var N = frames.normals[i];
  15734. var B = frames.binormals[i];
  15735. // generate normals and vertices for the current segment
  15736. for (j = 0; j <= radialSegments; j++) {
  15737. var v = j / radialSegments * Math.PI * 2;
  15738. var sin = Math.sin(v);
  15739. var cos = -Math.cos(v);
  15740. // normal
  15741. normal.x = cos * N.x + sin * B.x;
  15742. normal.y = cos * N.y + sin * B.y;
  15743. normal.z = cos * N.z + sin * B.z;
  15744. normal.normalize();
  15745. normals.push(normal.x, normal.y, normal.z);
  15746. // vertex
  15747. vertex.x = P.x + radius * normal.x;
  15748. vertex.y = P.y + radius * normal.y;
  15749. vertex.z = P.z + radius * normal.z;
  15750. vertices.push(vertex.x, vertex.y, vertex.z);
  15751. }
  15752. }
  15753. function generateIndices() {
  15754. for (j = 1; j <= tubularSegments; j++) {
  15755. for (i = 1; i <= radialSegments; i++) {
  15756. var a = (radialSegments + 1) * (j - 1) + (i - 1);
  15757. var b = (radialSegments + 1) * j + (i - 1);
  15758. var c = (radialSegments + 1) * j + i;
  15759. var d = (radialSegments + 1) * (j - 1) + i;
  15760. // faces
  15761. indices.push(a, b, d);
  15762. indices.push(b, c, d);
  15763. }
  15764. }
  15765. }
  15766. function generateUVs() {
  15767. for (i = 0; i <= tubularSegments; i++) {
  15768. for (j = 0; j <= radialSegments; j++) {
  15769. uv.x = i / tubularSegments;
  15770. uv.y = j / radialSegments;
  15771. uvs.push(uv.x, uv.y);
  15772. }
  15773. }
  15774. }
  15775. }
  15776. TubeBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  15777. TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
  15778. /**
  15779. * @author oosmoxiecode
  15780. * @author Mugen87 / https://github.com/Mugen87
  15781. *
  15782. * based on http://www.blackpawn.com/texts/pqtorus/
  15783. */
  15784. // TorusKnotGeometry
  15785. function TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q, heightScale) {
  15786. Geometry.call(this);
  15787. this.type = 'TorusKnotGeometry';
  15788. this.parameters = {
  15789. radius: radius,
  15790. tube: tube,
  15791. tubularSegments: tubularSegments,
  15792. radialSegments: radialSegments,
  15793. p: p,
  15794. q: q
  15795. };
  15796. if (heightScale !== undefined) console.warn('THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.');
  15797. this.fromBufferGeometry(new TorusKnotBufferGeometry(radius, tube, tubularSegments, radialSegments, p, q));
  15798. this.mergeVertices();
  15799. }
  15800. TorusKnotGeometry.prototype = Object.create(Geometry.prototype);
  15801. TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
  15802. // TorusKnotBufferGeometry
  15803. function TorusKnotBufferGeometry(radius, tube, tubularSegments, radialSegments, p, q) {
  15804. BufferGeometry.call(this);
  15805. this.type = 'TorusKnotBufferGeometry';
  15806. this.parameters = {
  15807. radius: radius,
  15808. tube: tube,
  15809. tubularSegments: tubularSegments,
  15810. radialSegments: radialSegments,
  15811. p: p,
  15812. q: q
  15813. };
  15814. radius = radius || 1;
  15815. tube = tube || 0.4;
  15816. tubularSegments = Math.floor(tubularSegments) || 64;
  15817. radialSegments = Math.floor(radialSegments) || 8;
  15818. p = p || 2;
  15819. q = q || 3;
  15820. // buffers
  15821. var indices = [];
  15822. var vertices = [];
  15823. var normals = [];
  15824. var uvs = [];
  15825. // helper variables
  15826. var i, j;
  15827. var vertex = new Vector3();
  15828. var normal = new Vector3();
  15829. var P1 = new Vector3();
  15830. var P2 = new Vector3();
  15831. var B = new Vector3();
  15832. var T = new Vector3();
  15833. var N = new Vector3();
  15834. // generate vertices, normals and uvs
  15835. for (i = 0; i <= tubularSegments; ++i) {
  15836. // the radian "u" is used to calculate the position on the torus curve of the current tubular segement
  15837. var u = i / tubularSegments * p * Math.PI * 2;
  15838. // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
  15839. // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
  15840. calculatePositionOnCurve(u, p, q, radius, P1);
  15841. calculatePositionOnCurve(u + 0.01, p, q, radius, P2);
  15842. // calculate orthonormal basis
  15843. T.subVectors(P2, P1);
  15844. N.addVectors(P2, P1);
  15845. B.crossVectors(T, N);
  15846. N.crossVectors(B, T);
  15847. // normalize B, N. T can be ignored, we don't use it
  15848. B.normalize();
  15849. N.normalize();
  15850. for (j = 0; j <= radialSegments; ++j) {
  15851. // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
  15852. // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
  15853. var v = j / radialSegments * Math.PI * 2;
  15854. var cx = -tube * Math.cos(v);
  15855. var cy = tube * Math.sin(v);
  15856. // now calculate the final vertex position.
  15857. // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
  15858. vertex.x = P1.x + (cx * N.x + cy * B.x);
  15859. vertex.y = P1.y + (cx * N.y + cy * B.y);
  15860. vertex.z = P1.z + (cx * N.z + cy * B.z);
  15861. vertices.push(vertex.x, vertex.y, vertex.z);
  15862. // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
  15863. normal.subVectors(vertex, P1).normalize();
  15864. normals.push(normal.x, normal.y, normal.z);
  15865. // uv
  15866. uvs.push(i / tubularSegments);
  15867. uvs.push(j / radialSegments);
  15868. }
  15869. }
  15870. // generate indices
  15871. for (j = 1; j <= tubularSegments; j++) {
  15872. for (i = 1; i <= radialSegments; i++) {
  15873. // indices
  15874. var a = (radialSegments + 1) * (j - 1) + (i - 1);
  15875. var b = (radialSegments + 1) * j + (i - 1);
  15876. var c = (radialSegments + 1) * j + i;
  15877. var d = (radialSegments + 1) * (j - 1) + i;
  15878. // faces
  15879. indices.push(a, b, d);
  15880. indices.push(b, c, d);
  15881. }
  15882. }
  15883. // build geometry
  15884. this.setIndex(indices);
  15885. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  15886. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  15887. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  15888. // this function calculates the current position on the torus curve
  15889. function calculatePositionOnCurve(u, p, q, radius, position) {
  15890. var cu = Math.cos(u);
  15891. var su = Math.sin(u);
  15892. var quOverP = q / p * u;
  15893. var cs = Math.cos(quOverP);
  15894. position.x = radius * (2 + cs) * 0.5 * cu;
  15895. position.y = radius * (2 + cs) * su * 0.5;
  15896. position.z = radius * Math.sin(quOverP) * 0.5;
  15897. }
  15898. }
  15899. TorusKnotBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  15900. TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
  15901. /**
  15902. * @author oosmoxiecode
  15903. * @author mrdoob / http://mrdoob.com/
  15904. * @author Mugen87 / https://github.com/Mugen87
  15905. */
  15906. // TorusGeometry
  15907. function TorusGeometry(radius, tube, radialSegments, tubularSegments, arc) {
  15908. Geometry.call(this);
  15909. this.type = 'TorusGeometry';
  15910. this.parameters = {
  15911. radius: radius,
  15912. tube: tube,
  15913. radialSegments: radialSegments,
  15914. tubularSegments: tubularSegments,
  15915. arc: arc
  15916. };
  15917. this.fromBufferGeometry(new TorusBufferGeometry(radius, tube, radialSegments, tubularSegments, arc));
  15918. this.mergeVertices();
  15919. }
  15920. TorusGeometry.prototype = Object.create(Geometry.prototype);
  15921. TorusGeometry.prototype.constructor = TorusGeometry;
  15922. // TorusBufferGeometry
  15923. function TorusBufferGeometry(radius, tube, radialSegments, tubularSegments, arc) {
  15924. BufferGeometry.call(this);
  15925. this.type = 'TorusBufferGeometry';
  15926. this.parameters = {
  15927. radius: radius,
  15928. tube: tube,
  15929. radialSegments: radialSegments,
  15930. tubularSegments: tubularSegments,
  15931. arc: arc
  15932. };
  15933. radius = radius || 1;
  15934. tube = tube || 0.4;
  15935. radialSegments = Math.floor(radialSegments) || 8;
  15936. tubularSegments = Math.floor(tubularSegments) || 6;
  15937. arc = arc || Math.PI * 2;
  15938. // buffers
  15939. var indices = [];
  15940. var vertices = [];
  15941. var normals = [];
  15942. var uvs = [];
  15943. // helper variables
  15944. var center = new Vector3();
  15945. var vertex = new Vector3();
  15946. var normal = new Vector3();
  15947. var j, i;
  15948. // generate vertices, normals and uvs
  15949. for (j = 0; j <= radialSegments; j++) {
  15950. for (i = 0; i <= tubularSegments; i++) {
  15951. var u = i / tubularSegments * arc;
  15952. var v = j / radialSegments * Math.PI * 2;
  15953. // vertex
  15954. vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u);
  15955. vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u);
  15956. vertex.z = tube * Math.sin(v);
  15957. vertices.push(vertex.x, vertex.y, vertex.z);
  15958. // normal
  15959. center.x = radius * Math.cos(u);
  15960. center.y = radius * Math.sin(u);
  15961. normal.subVectors(vertex, center).normalize();
  15962. normals.push(normal.x, normal.y, normal.z);
  15963. // uv
  15964. uvs.push(i / tubularSegments);
  15965. uvs.push(j / radialSegments);
  15966. }
  15967. }
  15968. // generate indices
  15969. for (j = 1; j <= radialSegments; j++) {
  15970. for (i = 1; i <= tubularSegments; i++) {
  15971. // indices
  15972. var a = (tubularSegments + 1) * j + i - 1;
  15973. var b = (tubularSegments + 1) * (j - 1) + i - 1;
  15974. var c = (tubularSegments + 1) * (j - 1) + i;
  15975. var d = (tubularSegments + 1) * j + i;
  15976. // faces
  15977. indices.push(a, b, d);
  15978. indices.push(b, c, d);
  15979. }
  15980. }
  15981. // build geometry
  15982. this.setIndex(indices);
  15983. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  15984. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  15985. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  15986. }
  15987. TorusBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  15988. TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
  15989. /**
  15990. * @author Mugen87 / https://github.com/Mugen87
  15991. * Port from https://github.com/mapbox/earcut (v2.1.2)
  15992. */
  15993. var Earcut = {
  15994. triangulate: function (data, holeIndices, dim) {
  15995. dim = dim || 2;
  15996. var hasHoles = holeIndices && holeIndices.length,
  15997. outerLen = hasHoles ? holeIndices[0] * dim : data.length,
  15998. outerNode = linkedList(data, 0, outerLen, dim, true),
  15999. triangles = [];
  16000. if (!outerNode) return triangles;
  16001. var minX, minY, maxX, maxY, x, y, invSize;
  16002. if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
  16003. // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  16004. if (data.length > 80 * dim) {
  16005. minX = maxX = data[0];
  16006. minY = maxY = data[1];
  16007. for (var i = dim; i < outerLen; i += dim) {
  16008. x = data[i];
  16009. y = data[i + 1];
  16010. if (x < minX) minX = x;
  16011. if (y < minY) minY = y;
  16012. if (x > maxX) maxX = x;
  16013. if (y > maxY) maxY = y;
  16014. }
  16015. // minX, minY and invSize are later used to transform coords into integers for z-order calculation
  16016. invSize = Math.max(maxX - minX, maxY - minY);
  16017. invSize = invSize !== 0 ? 1 / invSize : 0;
  16018. }
  16019. earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
  16020. return triangles;
  16021. }
  16022. };
  16023. // create a circular doubly linked list from polygon points in the specified winding order
  16024. function linkedList(data, start, end, dim, clockwise) {
  16025. var i, last;
  16026. if (clockwise === signedArea(data, start, end, dim) > 0) {
  16027. for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
  16028. } else {
  16029. for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
  16030. }
  16031. if (last && equals(last, last.next)) {
  16032. removeNode(last);
  16033. last = last.next;
  16034. }
  16035. return last;
  16036. }
  16037. // eliminate colinear or duplicate points
  16038. function filterPoints(start, end) {
  16039. if (!start) return start;
  16040. if (!end) end = start;
  16041. var p = start,
  16042. again;
  16043. do {
  16044. again = false;
  16045. if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
  16046. removeNode(p);
  16047. p = end = p.prev;
  16048. if (p === p.next) break;
  16049. again = true;
  16050. } else {
  16051. p = p.next;
  16052. }
  16053. } while (again || p !== end);
  16054. return end;
  16055. }
  16056. // main ear slicing loop which triangulates a polygon (given as a linked list)
  16057. function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
  16058. if (!ear) return;
  16059. // interlink polygon nodes in z-order
  16060. if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
  16061. var stop = ear,
  16062. prev,
  16063. next;
  16064. // iterate through ears, slicing them one by one
  16065. while (ear.prev !== ear.next) {
  16066. prev = ear.prev;
  16067. next = ear.next;
  16068. if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
  16069. // cut off the triangle
  16070. triangles.push(prev.i / dim);
  16071. triangles.push(ear.i / dim);
  16072. triangles.push(next.i / dim);
  16073. removeNode(ear);
  16074. // skipping the next vertice leads to less sliver triangles
  16075. ear = next.next;
  16076. stop = next.next;
  16077. continue;
  16078. }
  16079. ear = next;
  16080. // if we looped through the whole remaining polygon and can't find any more ears
  16081. if (ear === stop) {
  16082. // try filtering points and slicing again
  16083. if (!pass) {
  16084. earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
  16085. // if this didn't work, try curing all small self-intersections locally
  16086. } else if (pass === 1) {
  16087. ear = cureLocalIntersections(ear, triangles, dim);
  16088. earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
  16089. // as a last resort, try splitting the remaining polygon into two
  16090. } else if (pass === 2) {
  16091. splitEarcut(ear, triangles, dim, minX, minY, invSize);
  16092. }
  16093. break;
  16094. }
  16095. }
  16096. }
  16097. // check whether a polygon node forms a valid ear with adjacent nodes
  16098. function isEar(ear) {
  16099. var a = ear.prev,
  16100. b = ear,
  16101. c = ear.next;
  16102. if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  16103. // now make sure we don't have other points inside the potential ear
  16104. var p = ear.next.next;
  16105. while (p !== ear.prev) {
  16106. if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) {
  16107. return false;
  16108. }
  16109. p = p.next;
  16110. }
  16111. return true;
  16112. }
  16113. function isEarHashed(ear, minX, minY, invSize) {
  16114. var a = ear.prev,
  16115. b = ear,
  16116. c = ear.next;
  16117. if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  16118. // triangle bbox; min & max are calculated like this for speed
  16119. var minTX = a.x < b.x ? a.x < c.x ? a.x : c.x : b.x < c.x ? b.x : c.x,
  16120. minTY = a.y < b.y ? a.y < c.y ? a.y : c.y : b.y < c.y ? b.y : c.y,
  16121. maxTX = a.x > b.x ? a.x > c.x ? a.x : c.x : b.x > c.x ? b.x : c.x,
  16122. maxTY = a.y > b.y ? a.y > c.y ? a.y : c.y : b.y > c.y ? b.y : c.y;
  16123. // z-order range for the current triangle bbox;
  16124. var minZ = zOrder(minTX, minTY, minX, minY, invSize),
  16125. maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
  16126. // first look for points inside the triangle in increasing z-order
  16127. var p = ear.nextZ;
  16128. while (p && p.z <= maxZ) {
  16129. if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
  16130. p = p.nextZ;
  16131. }
  16132. // then look for points in decreasing z-order
  16133. p = ear.prevZ;
  16134. while (p && p.z >= minZ) {
  16135. if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
  16136. p = p.prevZ;
  16137. }
  16138. return true;
  16139. }
  16140. // go through all polygon nodes and cure small local self-intersections
  16141. function cureLocalIntersections(start, triangles, dim) {
  16142. var p = start;
  16143. do {
  16144. var a = p.prev,
  16145. b = p.next.next;
  16146. if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  16147. triangles.push(a.i / dim);
  16148. triangles.push(p.i / dim);
  16149. triangles.push(b.i / dim);
  16150. // remove two nodes involved
  16151. removeNode(p);
  16152. removeNode(p.next);
  16153. p = start = b;
  16154. }
  16155. p = p.next;
  16156. } while (p !== start);
  16157. return p;
  16158. }
  16159. // try splitting polygon into two and triangulate them independently
  16160. function splitEarcut(start, triangles, dim, minX, minY, invSize) {
  16161. // look for a valid diagonal that divides the polygon into two
  16162. var a = start;
  16163. do {
  16164. var b = a.next.next;
  16165. while (b !== a.prev) {
  16166. if (a.i !== b.i && isValidDiagonal(a, b)) {
  16167. // split the polygon in two by the diagonal
  16168. var c = splitPolygon(a, b);
  16169. // filter colinear points around the cuts
  16170. a = filterPoints(a, a.next);
  16171. c = filterPoints(c, c.next);
  16172. // run earcut on each half
  16173. earcutLinked(a, triangles, dim, minX, minY, invSize);
  16174. earcutLinked(c, triangles, dim, minX, minY, invSize);
  16175. return;
  16176. }
  16177. b = b.next;
  16178. }
  16179. a = a.next;
  16180. } while (a !== start);
  16181. }
  16182. // link every hole into the outer loop, producing a single-ring polygon without holes
  16183. function eliminateHoles(data, holeIndices, outerNode, dim) {
  16184. var queue = [],
  16185. i,
  16186. len,
  16187. start,
  16188. end,
  16189. list;
  16190. for (i = 0, len = holeIndices.length; i < len; i++) {
  16191. start = holeIndices[i] * dim;
  16192. end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
  16193. list = linkedList(data, start, end, dim, false);
  16194. if (list === list.next) list.steiner = true;
  16195. queue.push(getLeftmost(list));
  16196. }
  16197. queue.sort(compareX);
  16198. // process holes from left to right
  16199. for (i = 0; i < queue.length; i++) {
  16200. eliminateHole(queue[i], outerNode);
  16201. outerNode = filterPoints(outerNode, outerNode.next);
  16202. }
  16203. return outerNode;
  16204. }
  16205. function compareX(a, b) {
  16206. return a.x - b.x;
  16207. }
  16208. // find a bridge between vertices that connects hole with an outer ring and and link it
  16209. function eliminateHole(hole, outerNode) {
  16210. outerNode = findHoleBridge(hole, outerNode);
  16211. if (outerNode) {
  16212. var b = splitPolygon(outerNode, hole);
  16213. filterPoints(b, b.next);
  16214. }
  16215. }
  16216. // David Eberly's algorithm for finding a bridge between hole and outer polygon
  16217. function findHoleBridge(hole, outerNode) {
  16218. var p = outerNode,
  16219. hx = hole.x,
  16220. hy = hole.y,
  16221. qx = -Infinity,
  16222. m;
  16223. // find a segment intersected by a ray from the hole's leftmost point to the left;
  16224. // segment's endpoint with lesser x will be potential connection point
  16225. do {
  16226. if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
  16227. var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
  16228. if (x <= hx && x > qx) {
  16229. qx = x;
  16230. if (x === hx) {
  16231. if (hy === p.y) return p;
  16232. if (hy === p.next.y) return p.next;
  16233. }
  16234. m = p.x < p.next.x ? p : p.next;
  16235. }
  16236. }
  16237. p = p.next;
  16238. } while (p !== outerNode);
  16239. if (!m) return null;
  16240. if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint
  16241. // look for points inside the triangle of hole point, segment intersection and endpoint;
  16242. // if there are no points found, we have a valid connection;
  16243. // otherwise choose the point of the minimum angle with the ray as connection point
  16244. var stop = m,
  16245. mx = m.x,
  16246. my = m.y,
  16247. tanMin = Infinity,
  16248. tan;
  16249. p = m.next;
  16250. while (p !== stop) {
  16251. if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
  16252. tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
  16253. if ((tan < tanMin || tan === tanMin && p.x > m.x) && locallyInside(p, hole)) {
  16254. m = p;
  16255. tanMin = tan;
  16256. }
  16257. }
  16258. p = p.next;
  16259. }
  16260. return m;
  16261. }
  16262. // interlink polygon nodes in z-order
  16263. function indexCurve(start, minX, minY, invSize) {
  16264. var p = start;
  16265. do {
  16266. if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
  16267. p.prevZ = p.prev;
  16268. p.nextZ = p.next;
  16269. p = p.next;
  16270. } while (p !== start);
  16271. p.prevZ.nextZ = null;
  16272. p.prevZ = null;
  16273. sortLinked(p);
  16274. }
  16275. // Simon Tatham's linked list merge sort algorithm
  16276. // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
  16277. function sortLinked(list) {
  16278. var i,
  16279. p,
  16280. q,
  16281. e,
  16282. tail,
  16283. numMerges,
  16284. pSize,
  16285. qSize,
  16286. inSize = 1;
  16287. do {
  16288. p = list;
  16289. list = null;
  16290. tail = null;
  16291. numMerges = 0;
  16292. while (p) {
  16293. numMerges++;
  16294. q = p;
  16295. pSize = 0;
  16296. for (i = 0; i < inSize; i++) {
  16297. pSize++;
  16298. q = q.nextZ;
  16299. if (!q) break;
  16300. }
  16301. qSize = inSize;
  16302. while (pSize > 0 || qSize > 0 && q) {
  16303. if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
  16304. e = p;
  16305. p = p.nextZ;
  16306. pSize--;
  16307. } else {
  16308. e = q;
  16309. q = q.nextZ;
  16310. qSize--;
  16311. }
  16312. if (tail) tail.nextZ = e;else list = e;
  16313. e.prevZ = tail;
  16314. tail = e;
  16315. }
  16316. p = q;
  16317. }
  16318. tail.nextZ = null;
  16319. inSize *= 2;
  16320. } while (numMerges > 1);
  16321. return list;
  16322. }
  16323. // z-order of a point given coords and inverse of the longer side of data bbox
  16324. function zOrder(x, y, minX, minY, invSize) {
  16325. // coords are transformed into non-negative 15-bit integer range
  16326. x = 32767 * (x - minX) * invSize;
  16327. y = 32767 * (y - minY) * invSize;
  16328. x = (x | x << 8) & 0x00FF00FF;
  16329. x = (x | x << 4) & 0x0F0F0F0F;
  16330. x = (x | x << 2) & 0x33333333;
  16331. x = (x | x << 1) & 0x55555555;
  16332. y = (y | y << 8) & 0x00FF00FF;
  16333. y = (y | y << 4) & 0x0F0F0F0F;
  16334. y = (y | y << 2) & 0x33333333;
  16335. y = (y | y << 1) & 0x55555555;
  16336. return x | y << 1;
  16337. }
  16338. // find the leftmost node of a polygon ring
  16339. function getLeftmost(start) {
  16340. var p = start,
  16341. leftmost = start;
  16342. do {
  16343. if (p.x < leftmost.x) leftmost = p;
  16344. p = p.next;
  16345. } while (p !== start);
  16346. return leftmost;
  16347. }
  16348. // check if a point lies within a convex triangle
  16349. function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
  16350. return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
  16351. }
  16352. // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
  16353. function isValidDiagonal(a, b) {
  16354. return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
  16355. }
  16356. // signed area of a triangle
  16357. function area(p, q, r) {
  16358. return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
  16359. }
  16360. // check if two points are equal
  16361. function equals(p1, p2) {
  16362. return p1.x === p2.x && p1.y === p2.y;
  16363. }
  16364. // check if two segments intersect
  16365. function intersects(p1, q1, p2, q2) {
  16366. if (equals(p1, q1) && equals(p2, q2) || equals(p1, q2) && equals(p2, q1)) return true;
  16367. return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 && area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
  16368. }
  16369. // check if a polygon diagonal intersects any polygon segments
  16370. function intersectsPolygon(a, b) {
  16371. var p = a;
  16372. do {
  16373. if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) {
  16374. return true;
  16375. }
  16376. p = p.next;
  16377. } while (p !== a);
  16378. return false;
  16379. }
  16380. // check if a polygon diagonal is locally inside the polygon
  16381. function locallyInside(a, b) {
  16382. return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
  16383. }
  16384. // check if the middle point of a polygon diagonal is inside the polygon
  16385. function middleInside(a, b) {
  16386. var p = a,
  16387. inside = false,
  16388. px = (a.x + b.x) / 2,
  16389. py = (a.y + b.y) / 2;
  16390. do {
  16391. if (p.y > py !== p.next.y > py && p.next.y !== p.y && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) {
  16392. inside = !inside;
  16393. }
  16394. p = p.next;
  16395. } while (p !== a);
  16396. return inside;
  16397. }
  16398. // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
  16399. // if one belongs to the outer ring and another to a hole, it merges it into a single ring
  16400. function splitPolygon(a, b) {
  16401. var a2 = new Node(a.i, a.x, a.y),
  16402. b2 = new Node(b.i, b.x, b.y),
  16403. an = a.next,
  16404. bp = b.prev;
  16405. a.next = b;
  16406. b.prev = a;
  16407. a2.next = an;
  16408. an.prev = a2;
  16409. b2.next = a2;
  16410. a2.prev = b2;
  16411. bp.next = b2;
  16412. b2.prev = bp;
  16413. return b2;
  16414. }
  16415. // create a node and optionally link it with previous one (in a circular doubly linked list)
  16416. function insertNode(i, x, y, last) {
  16417. var p = new Node(i, x, y);
  16418. if (!last) {
  16419. p.prev = p;
  16420. p.next = p;
  16421. } else {
  16422. p.next = last.next;
  16423. p.prev = last;
  16424. last.next.prev = p;
  16425. last.next = p;
  16426. }
  16427. return p;
  16428. }
  16429. function removeNode(p) {
  16430. p.next.prev = p.prev;
  16431. p.prev.next = p.next;
  16432. if (p.prevZ) p.prevZ.nextZ = p.nextZ;
  16433. if (p.nextZ) p.nextZ.prevZ = p.prevZ;
  16434. }
  16435. function Node(i, x, y) {
  16436. // vertice index in coordinates array
  16437. this.i = i;
  16438. // vertex coordinates
  16439. this.x = x;
  16440. this.y = y;
  16441. // previous and next vertice nodes in a polygon ring
  16442. this.prev = null;
  16443. this.next = null;
  16444. // z-order curve value
  16445. this.z = null;
  16446. // previous and next nodes in z-order
  16447. this.prevZ = null;
  16448. this.nextZ = null;
  16449. // indicates whether this is a steiner point
  16450. this.steiner = false;
  16451. }
  16452. function signedArea(data, start, end, dim) {
  16453. var sum = 0;
  16454. for (var i = start, j = end - dim; i < end; i += dim) {
  16455. sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
  16456. j = i;
  16457. }
  16458. return sum;
  16459. }
  16460. /**
  16461. * @author zz85 / http://www.lab4games.net/zz85/blog
  16462. */
  16463. var ShapeUtils = {
  16464. // calculate area of the contour polygon
  16465. area: function (contour) {
  16466. var n = contour.length;
  16467. var a = 0.0;
  16468. for (var p = n - 1, q = 0; q < n; p = q++) {
  16469. a += contour[p].x * contour[q].y - contour[q].x * contour[p].y;
  16470. }
  16471. return a * 0.5;
  16472. },
  16473. isClockWise: function (pts) {
  16474. return ShapeUtils.area(pts) < 0;
  16475. },
  16476. triangulateShape: function (contour, holes) {
  16477. var vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
  16478. var holeIndices = []; // array of hole indices
  16479. var faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
  16480. removeDupEndPts(contour);
  16481. addContour(vertices, contour);
  16482. //
  16483. var holeIndex = contour.length;
  16484. holes.forEach(removeDupEndPts);
  16485. for (var i = 0; i < holes.length; i++) {
  16486. holeIndices.push(holeIndex);
  16487. holeIndex += holes[i].length;
  16488. addContour(vertices, holes[i]);
  16489. }
  16490. //
  16491. var triangles = Earcut.triangulate(vertices, holeIndices);
  16492. //
  16493. for (var i = 0; i < triangles.length; i += 3) {
  16494. faces.push(triangles.slice(i, i + 3));
  16495. }
  16496. return faces;
  16497. }
  16498. };
  16499. function removeDupEndPts(points) {
  16500. var l = points.length;
  16501. if (l > 2 && points[l - 1].equals(points[0])) {
  16502. points.pop();
  16503. }
  16504. }
  16505. function addContour(vertices, contour) {
  16506. for (var i = 0; i < contour.length; i++) {
  16507. vertices.push(contour[i].x);
  16508. vertices.push(contour[i].y);
  16509. }
  16510. }
  16511. /**
  16512. * @author zz85 / http://www.lab4games.net/zz85/blog
  16513. *
  16514. * Creates extruded geometry from a path shape.
  16515. *
  16516. * parameters = {
  16517. *
  16518. * curveSegments: <int>, // number of points on the curves
  16519. * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
  16520. * depth: <float>, // Depth to extrude the shape
  16521. *
  16522. * bevelEnabled: <bool>, // turn on bevel
  16523. * bevelThickness: <float>, // how deep into the original shape bevel goes
  16524. * bevelSize: <float>, // how far from shape outline is bevel
  16525. * bevelSegments: <int>, // number of bevel layers
  16526. *
  16527. * extrudePath: <THREE.Curve> // curve to extrude shape along
  16528. *
  16529. * UVGenerator: <Object> // object that provides UV generator functions
  16530. *
  16531. * }
  16532. */
  16533. // ExtrudeGeometry
  16534. function ExtrudeGeometry(shapes, options) {
  16535. Geometry.call(this);
  16536. this.type = 'ExtrudeGeometry';
  16537. this.parameters = {
  16538. shapes: shapes,
  16539. options: options
  16540. };
  16541. this.fromBufferGeometry(new ExtrudeBufferGeometry(shapes, options));
  16542. this.mergeVertices();
  16543. }
  16544. ExtrudeGeometry.prototype = Object.create(Geometry.prototype);
  16545. ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;
  16546. ExtrudeGeometry.prototype.toJSON = function () {
  16547. var data = Geometry.prototype.toJSON.call(this);
  16548. var shapes = this.parameters.shapes;
  16549. var options = this.parameters.options;
  16550. return toJSON(shapes, options, data);
  16551. };
  16552. // ExtrudeBufferGeometry
  16553. function ExtrudeBufferGeometry(shapes, options) {
  16554. BufferGeometry.call(this);
  16555. this.type = 'ExtrudeBufferGeometry';
  16556. this.parameters = {
  16557. shapes: shapes,
  16558. options: options
  16559. };
  16560. shapes = Array.isArray(shapes) ? shapes : [shapes];
  16561. var scope = this;
  16562. var verticesArray = [];
  16563. var uvArray = [];
  16564. for (var i = 0, l = shapes.length; i < l; i++) {
  16565. var shape = shapes[i];
  16566. addShape(shape);
  16567. }
  16568. // build geometry
  16569. this.addAttribute('position', new Float32BufferAttribute(verticesArray, 3));
  16570. this.addAttribute('uv', new Float32BufferAttribute(uvArray, 2));
  16571. this.computeVertexNormals();
  16572. // functions
  16573. function addShape(shape) {
  16574. var placeholder = [];
  16575. // options
  16576. var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
  16577. var steps = options.steps !== undefined ? options.steps : 1;
  16578. var depth = options.depth !== undefined ? options.depth : 100;
  16579. var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
  16580. var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
  16581. var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
  16582. var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
  16583. var extrudePath = options.extrudePath;
  16584. var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
  16585. // deprecated options
  16586. if (options.amount !== undefined) {
  16587. console.warn('THREE.ExtrudeBufferGeometry: amount has been renamed to depth.');
  16588. depth = options.amount;
  16589. }
  16590. //
  16591. var extrudePts,
  16592. extrudeByPath = false;
  16593. var splineTube, binormal, normal, position2;
  16594. if (extrudePath) {
  16595. extrudePts = extrudePath.getSpacedPoints(steps);
  16596. extrudeByPath = true;
  16597. bevelEnabled = false; // bevels not supported for path extrusion
  16598. // SETUP TNB variables
  16599. // TODO1 - have a .isClosed in spline?
  16600. splineTube = extrudePath.computeFrenetFrames(steps, false);
  16601. // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
  16602. binormal = new Vector3();
  16603. normal = new Vector3();
  16604. position2 = new Vector3();
  16605. }
  16606. // Safeguards if bevels are not enabled
  16607. if (!bevelEnabled) {
  16608. bevelSegments = 0;
  16609. bevelThickness = 0;
  16610. bevelSize = 0;
  16611. }
  16612. // Variables initialization
  16613. var ahole, h, hl; // looping of holes
  16614. var shapePoints = shape.extractPoints(curveSegments);
  16615. var vertices = shapePoints.shape;
  16616. var holes = shapePoints.holes;
  16617. var reverse = !ShapeUtils.isClockWise(vertices);
  16618. if (reverse) {
  16619. vertices = vertices.reverse();
  16620. // Maybe we should also check if holes are in the opposite direction, just to be safe ...
  16621. for (h = 0, hl = holes.length; h < hl; h++) {
  16622. ahole = holes[h];
  16623. if (ShapeUtils.isClockWise(ahole)) {
  16624. holes[h] = ahole.reverse();
  16625. }
  16626. }
  16627. }
  16628. var faces = ShapeUtils.triangulateShape(vertices, holes);
  16629. /* Vertices */
  16630. var contour = vertices; // vertices has all points but contour has only points of circumference
  16631. for (h = 0, hl = holes.length; h < hl; h++) {
  16632. ahole = holes[h];
  16633. vertices = vertices.concat(ahole);
  16634. }
  16635. function scalePt2(pt, vec, size) {
  16636. if (!vec) console.error("THREE.ExtrudeGeometry: vec does not exist");
  16637. return vec.clone().multiplyScalar(size).add(pt);
  16638. }
  16639. var b,
  16640. bs,
  16641. t,
  16642. z,
  16643. vert,
  16644. vlen = vertices.length,
  16645. face,
  16646. flen = faces.length;
  16647. // Find directions for point movement
  16648. function getBevelVec(inPt, inPrev, inNext) {
  16649. // computes for inPt the corresponding point inPt' on a new contour
  16650. // shifted by 1 unit (length of normalized vector) to the left
  16651. // if we walk along contour clockwise, this new contour is outside the old one
  16652. //
  16653. // inPt' is the intersection of the two lines parallel to the two
  16654. // adjacent edges of inPt at a distance of 1 unit on the left side.
  16655. var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
  16656. // good reading for geometry algorithms (here: line-line intersection)
  16657. // http://geomalgorithms.com/a05-_intersect-1.html
  16658. var v_prev_x = inPt.x - inPrev.x,
  16659. v_prev_y = inPt.y - inPrev.y;
  16660. var v_next_x = inNext.x - inPt.x,
  16661. v_next_y = inNext.y - inPt.y;
  16662. var v_prev_lensq = v_prev_x * v_prev_x + v_prev_y * v_prev_y;
  16663. // check for collinear edges
  16664. var collinear0 = v_prev_x * v_next_y - v_prev_y * v_next_x;
  16665. if (Math.abs(collinear0) > Number.EPSILON) {
  16666. // not collinear
  16667. // length of vectors for normalizing
  16668. var v_prev_len = Math.sqrt(v_prev_lensq);
  16669. var v_next_len = Math.sqrt(v_next_x * v_next_x + v_next_y * v_next_y);
  16670. // shift adjacent points by unit vectors to the left
  16671. var ptPrevShift_x = inPrev.x - v_prev_y / v_prev_len;
  16672. var ptPrevShift_y = inPrev.y + v_prev_x / v_prev_len;
  16673. var ptNextShift_x = inNext.x - v_next_y / v_next_len;
  16674. var ptNextShift_y = inNext.y + v_next_x / v_next_len;
  16675. // scaling factor for v_prev to intersection point
  16676. 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);
  16677. // vector from inPt to intersection point
  16678. v_trans_x = ptPrevShift_x + v_prev_x * sf - inPt.x;
  16679. v_trans_y = ptPrevShift_y + v_prev_y * sf - inPt.y;
  16680. // Don't normalize!, otherwise sharp corners become ugly
  16681. // but prevent crazy spikes
  16682. var v_trans_lensq = v_trans_x * v_trans_x + v_trans_y * v_trans_y;
  16683. if (v_trans_lensq <= 2) {
  16684. return new Vector2(v_trans_x, v_trans_y);
  16685. } else {
  16686. shrink_by = Math.sqrt(v_trans_lensq / 2);
  16687. }
  16688. } else {
  16689. // handle special case of collinear edges
  16690. var direction_eq = false; // assumes: opposite
  16691. if (v_prev_x > Number.EPSILON) {
  16692. if (v_next_x > Number.EPSILON) {
  16693. direction_eq = true;
  16694. }
  16695. } else {
  16696. if (v_prev_x < -Number.EPSILON) {
  16697. if (v_next_x < -Number.EPSILON) {
  16698. direction_eq = true;
  16699. }
  16700. } else {
  16701. if (Math.sign(v_prev_y) === Math.sign(v_next_y)) {
  16702. direction_eq = true;
  16703. }
  16704. }
  16705. }
  16706. if (direction_eq) {
  16707. // console.log("Warning: lines are a straight sequence");
  16708. v_trans_x = -v_prev_y;
  16709. v_trans_y = v_prev_x;
  16710. shrink_by = Math.sqrt(v_prev_lensq);
  16711. } else {
  16712. // console.log("Warning: lines are a straight spike");
  16713. v_trans_x = v_prev_x;
  16714. v_trans_y = v_prev_y;
  16715. shrink_by = Math.sqrt(v_prev_lensq / 2);
  16716. }
  16717. }
  16718. return new Vector2(v_trans_x / shrink_by, v_trans_y / shrink_by);
  16719. }
  16720. var contourMovements = [];
  16721. for (var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) {
  16722. if (j === il) j = 0;
  16723. if (k === il) k = 0;
  16724. // (j)---(i)---(k)
  16725. // console.log('i,j,k', i, j , k)
  16726. contourMovements[i] = getBevelVec(contour[i], contour[j], contour[k]);
  16727. }
  16728. var holesMovements = [],
  16729. oneHoleMovements,
  16730. verticesMovements = contourMovements.concat();
  16731. for (h = 0, hl = holes.length; h < hl; h++) {
  16732. ahole = holes[h];
  16733. oneHoleMovements = [];
  16734. for (i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) {
  16735. if (j === il) j = 0;
  16736. if (k === il) k = 0;
  16737. // (j)---(i)---(k)
  16738. oneHoleMovements[i] = getBevelVec(ahole[i], ahole[j], ahole[k]);
  16739. }
  16740. holesMovements.push(oneHoleMovements);
  16741. verticesMovements = verticesMovements.concat(oneHoleMovements);
  16742. }
  16743. // Loop bevelSegments, 1 for the front, 1 for the back
  16744. for (b = 0; b < bevelSegments; b++) {
  16745. //for ( b = bevelSegments; b > 0; b -- ) {
  16746. t = b / bevelSegments;
  16747. z = bevelThickness * Math.cos(t * Math.PI / 2);
  16748. bs = bevelSize * Math.sin(t * Math.PI / 2);
  16749. // contract shape
  16750. for (i = 0, il = contour.length; i < il; i++) {
  16751. vert = scalePt2(contour[i], contourMovements[i], bs);
  16752. v(vert.x, vert.y, -z);
  16753. }
  16754. // expand holes
  16755. for (h = 0, hl = holes.length; h < hl; h++) {
  16756. ahole = holes[h];
  16757. oneHoleMovements = holesMovements[h];
  16758. for (i = 0, il = ahole.length; i < il; i++) {
  16759. vert = scalePt2(ahole[i], oneHoleMovements[i], bs);
  16760. v(vert.x, vert.y, -z);
  16761. }
  16762. }
  16763. }
  16764. bs = bevelSize;
  16765. // Back facing vertices
  16766. for (i = 0; i < vlen; i++) {
  16767. vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
  16768. if (!extrudeByPath) {
  16769. v(vert.x, vert.y, 0);
  16770. } else {
  16771. // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
  16772. normal.copy(splineTube.normals[0]).multiplyScalar(vert.x);
  16773. binormal.copy(splineTube.binormals[0]).multiplyScalar(vert.y);
  16774. position2.copy(extrudePts[0]).add(normal).add(binormal);
  16775. v(position2.x, position2.y, position2.z);
  16776. }
  16777. }
  16778. // Add stepped vertices...
  16779. // Including front facing vertices
  16780. var s;
  16781. for (s = 1; s <= steps; s++) {
  16782. for (i = 0; i < vlen; i++) {
  16783. vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
  16784. if (!extrudeByPath) {
  16785. v(vert.x, vert.y, depth / steps * s);
  16786. } else {
  16787. // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
  16788. normal.copy(splineTube.normals[s]).multiplyScalar(vert.x);
  16789. binormal.copy(splineTube.binormals[s]).multiplyScalar(vert.y);
  16790. position2.copy(extrudePts[s]).add(normal).add(binormal);
  16791. v(position2.x, position2.y, position2.z);
  16792. }
  16793. }
  16794. }
  16795. // Add bevel segments planes
  16796. //for ( b = 1; b <= bevelSegments; b ++ ) {
  16797. for (b = bevelSegments - 1; b >= 0; b--) {
  16798. t = b / bevelSegments;
  16799. z = bevelThickness * Math.cos(t * Math.PI / 2);
  16800. bs = bevelSize * Math.sin(t * Math.PI / 2);
  16801. // contract shape
  16802. for (i = 0, il = contour.length; i < il; i++) {
  16803. vert = scalePt2(contour[i], contourMovements[i], bs);
  16804. v(vert.x, vert.y, depth + z);
  16805. }
  16806. // expand holes
  16807. for (h = 0, hl = holes.length; h < hl; h++) {
  16808. ahole = holes[h];
  16809. oneHoleMovements = holesMovements[h];
  16810. for (i = 0, il = ahole.length; i < il; i++) {
  16811. vert = scalePt2(ahole[i], oneHoleMovements[i], bs);
  16812. if (!extrudeByPath) {
  16813. v(vert.x, vert.y, depth + z);
  16814. } else {
  16815. v(vert.x, vert.y + extrudePts[steps - 1].y, extrudePts[steps - 1].x + z);
  16816. }
  16817. }
  16818. }
  16819. }
  16820. /* Faces */
  16821. // Top and bottom faces
  16822. buildLidFaces();
  16823. // Sides faces
  16824. buildSideFaces();
  16825. ///// Internal functions
  16826. function buildLidFaces() {
  16827. var start = verticesArray.length / 3;
  16828. if (bevelEnabled) {
  16829. var layer = 0; // steps + 1
  16830. var offset = vlen * layer;
  16831. // Bottom faces
  16832. for (i = 0; i < flen; i++) {
  16833. face = faces[i];
  16834. f3(face[2] + offset, face[1] + offset, face[0] + offset);
  16835. }
  16836. layer = steps + bevelSegments * 2;
  16837. offset = vlen * layer;
  16838. // Top faces
  16839. for (i = 0; i < flen; i++) {
  16840. face = faces[i];
  16841. f3(face[0] + offset, face[1] + offset, face[2] + offset);
  16842. }
  16843. } else {
  16844. // Bottom faces
  16845. for (i = 0; i < flen; i++) {
  16846. face = faces[i];
  16847. f3(face[2], face[1], face[0]);
  16848. }
  16849. // Top faces
  16850. for (i = 0; i < flen; i++) {
  16851. face = faces[i];
  16852. f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps);
  16853. }
  16854. }
  16855. scope.addGroup(start, verticesArray.length / 3 - start, 0);
  16856. }
  16857. // Create faces for the z-sides of the shape
  16858. function buildSideFaces() {
  16859. var start = verticesArray.length / 3;
  16860. var layeroffset = 0;
  16861. sidewalls(contour, layeroffset);
  16862. layeroffset += contour.length;
  16863. for (h = 0, hl = holes.length; h < hl; h++) {
  16864. ahole = holes[h];
  16865. sidewalls(ahole, layeroffset);
  16866. //, true
  16867. layeroffset += ahole.length;
  16868. }
  16869. scope.addGroup(start, verticesArray.length / 3 - start, 1);
  16870. }
  16871. function sidewalls(contour, layeroffset) {
  16872. var j, k;
  16873. i = contour.length;
  16874. while (--i >= 0) {
  16875. j = i;
  16876. k = i - 1;
  16877. if (k < 0) k = contour.length - 1;
  16878. //console.log('b', i,j, i-1, k,vertices.length);
  16879. var s = 0,
  16880. sl = steps + bevelSegments * 2;
  16881. for (s = 0; s < sl; s++) {
  16882. var slen1 = vlen * s;
  16883. var slen2 = vlen * (s + 1);
  16884. var a = layeroffset + j + slen1,
  16885. b = layeroffset + k + slen1,
  16886. c = layeroffset + k + slen2,
  16887. d = layeroffset + j + slen2;
  16888. f4(a, b, c, d);
  16889. }
  16890. }
  16891. }
  16892. function v(x, y, z) {
  16893. placeholder.push(x);
  16894. placeholder.push(y);
  16895. placeholder.push(z);
  16896. }
  16897. function f3(a, b, c) {
  16898. addVertex(a);
  16899. addVertex(b);
  16900. addVertex(c);
  16901. var nextIndex = verticesArray.length / 3;
  16902. var uvs = uvgen.generateTopUV(scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1);
  16903. addUV(uvs[0]);
  16904. addUV(uvs[1]);
  16905. addUV(uvs[2]);
  16906. }
  16907. function f4(a, b, c, d) {
  16908. addVertex(a);
  16909. addVertex(b);
  16910. addVertex(d);
  16911. addVertex(b);
  16912. addVertex(c);
  16913. addVertex(d);
  16914. var nextIndex = verticesArray.length / 3;
  16915. var uvs = uvgen.generateSideWallUV(scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1);
  16916. addUV(uvs[0]);
  16917. addUV(uvs[1]);
  16918. addUV(uvs[3]);
  16919. addUV(uvs[1]);
  16920. addUV(uvs[2]);
  16921. addUV(uvs[3]);
  16922. }
  16923. function addVertex(index) {
  16924. verticesArray.push(placeholder[index * 3 + 0]);
  16925. verticesArray.push(placeholder[index * 3 + 1]);
  16926. verticesArray.push(placeholder[index * 3 + 2]);
  16927. }
  16928. function addUV(vector2) {
  16929. uvArray.push(vector2.x);
  16930. uvArray.push(vector2.y);
  16931. }
  16932. }
  16933. }
  16934. ExtrudeBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  16935. ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;
  16936. ExtrudeBufferGeometry.prototype.toJSON = function () {
  16937. var data = BufferGeometry.prototype.toJSON.call(this);
  16938. var shapes = this.parameters.shapes;
  16939. var options = this.parameters.options;
  16940. return toJSON(shapes, options, data);
  16941. };
  16942. //
  16943. var WorldUVGenerator = {
  16944. generateTopUV: function (geometry, vertices, indexA, indexB, indexC) {
  16945. var a_x = vertices[indexA * 3];
  16946. var a_y = vertices[indexA * 3 + 1];
  16947. var b_x = vertices[indexB * 3];
  16948. var b_y = vertices[indexB * 3 + 1];
  16949. var c_x = vertices[indexC * 3];
  16950. var c_y = vertices[indexC * 3 + 1];
  16951. return [new Vector2(a_x, a_y), new Vector2(b_x, b_y), new Vector2(c_x, c_y)];
  16952. },
  16953. generateSideWallUV: function (geometry, vertices, indexA, indexB, indexC, indexD) {
  16954. var a_x = vertices[indexA * 3];
  16955. var a_y = vertices[indexA * 3 + 1];
  16956. var a_z = vertices[indexA * 3 + 2];
  16957. var b_x = vertices[indexB * 3];
  16958. var b_y = vertices[indexB * 3 + 1];
  16959. var b_z = vertices[indexB * 3 + 2];
  16960. var c_x = vertices[indexC * 3];
  16961. var c_y = vertices[indexC * 3 + 1];
  16962. var c_z = vertices[indexC * 3 + 2];
  16963. var d_x = vertices[indexD * 3];
  16964. var d_y = vertices[indexD * 3 + 1];
  16965. var d_z = vertices[indexD * 3 + 2];
  16966. if (Math.abs(a_y - b_y) < 0.01) {
  16967. 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)];
  16968. } else {
  16969. 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)];
  16970. }
  16971. }
  16972. };
  16973. function toJSON(shapes, options, data) {
  16974. //
  16975. data.shapes = [];
  16976. if (Array.isArray(shapes)) {
  16977. for (var i = 0, l = shapes.length; i < l; i++) {
  16978. var shape = shapes[i];
  16979. data.shapes.push(shape.uuid);
  16980. }
  16981. } else {
  16982. data.shapes.push(shapes.uuid);
  16983. }
  16984. //
  16985. if (options.extrudePath !== undefined) data.options.extrudePath = options.extrudePath.toJSON();
  16986. return data;
  16987. }
  16988. /**
  16989. * @author zz85 / http://www.lab4games.net/zz85/blog
  16990. * @author alteredq / http://alteredqualia.com/
  16991. *
  16992. * Text = 3D Text
  16993. *
  16994. * parameters = {
  16995. * font: <THREE.Font>, // font
  16996. *
  16997. * size: <float>, // size of the text
  16998. * height: <float>, // thickness to extrude text
  16999. * curveSegments: <int>, // number of points on the curves
  17000. *
  17001. * bevelEnabled: <bool>, // turn on bevel
  17002. * bevelThickness: <float>, // how deep into text bevel goes
  17003. * bevelSize: <float> // how far from text outline is bevel
  17004. * }
  17005. */
  17006. // TextGeometry
  17007. function TextGeometry(text, parameters) {
  17008. Geometry.call(this);
  17009. this.type = 'TextGeometry';
  17010. this.parameters = {
  17011. text: text,
  17012. parameters: parameters
  17013. };
  17014. this.fromBufferGeometry(new TextBufferGeometry(text, parameters));
  17015. this.mergeVertices();
  17016. }
  17017. TextGeometry.prototype = Object.create(Geometry.prototype);
  17018. TextGeometry.prototype.constructor = TextGeometry;
  17019. // TextBufferGeometry
  17020. function TextBufferGeometry(text, parameters) {
  17021. parameters = parameters || {};
  17022. var font = parameters.font;
  17023. if (!(font && font.isFont)) {
  17024. console.error('THREE.TextGeometry: font parameter is not an instance of THREE.Font.');
  17025. return new Geometry();
  17026. }
  17027. var shapes = font.generateShapes(text, parameters.size, parameters.curveSegments);
  17028. // translate parameters to ExtrudeGeometry API
  17029. parameters.depth = parameters.height !== undefined ? parameters.height : 50;
  17030. // defaults
  17031. if (parameters.bevelThickness === undefined) parameters.bevelThickness = 10;
  17032. if (parameters.bevelSize === undefined) parameters.bevelSize = 8;
  17033. if (parameters.bevelEnabled === undefined) parameters.bevelEnabled = false;
  17034. ExtrudeBufferGeometry.call(this, shapes, parameters);
  17035. this.type = 'TextBufferGeometry';
  17036. }
  17037. TextBufferGeometry.prototype = Object.create(ExtrudeBufferGeometry.prototype);
  17038. TextBufferGeometry.prototype.constructor = TextBufferGeometry;
  17039. /**
  17040. * @author mrdoob / http://mrdoob.com/
  17041. * @author benaadams / https://twitter.com/ben_a_adams
  17042. * @author Mugen87 / https://github.com/Mugen87
  17043. */
  17044. // SphereGeometry
  17045. function SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) {
  17046. Geometry.call(this);
  17047. this.type = 'SphereGeometry';
  17048. this.parameters = {
  17049. radius: radius,
  17050. widthSegments: widthSegments,
  17051. heightSegments: heightSegments,
  17052. phiStart: phiStart,
  17053. phiLength: phiLength,
  17054. thetaStart: thetaStart,
  17055. thetaLength: thetaLength
  17056. };
  17057. this.fromBufferGeometry(new SphereBufferGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength));
  17058. this.mergeVertices();
  17059. }
  17060. SphereGeometry.prototype = Object.create(Geometry.prototype);
  17061. SphereGeometry.prototype.constructor = SphereGeometry;
  17062. // SphereBufferGeometry
  17063. function SphereBufferGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) {
  17064. BufferGeometry.call(this);
  17065. this.type = 'SphereBufferGeometry';
  17066. this.parameters = {
  17067. radius: radius,
  17068. widthSegments: widthSegments,
  17069. heightSegments: heightSegments,
  17070. phiStart: phiStart,
  17071. phiLength: phiLength,
  17072. thetaStart: thetaStart,
  17073. thetaLength: thetaLength
  17074. };
  17075. radius = radius || 1;
  17076. widthSegments = Math.max(3, Math.floor(widthSegments) || 8);
  17077. heightSegments = Math.max(2, Math.floor(heightSegments) || 6);
  17078. phiStart = phiStart !== undefined ? phiStart : 0;
  17079. phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
  17080. thetaStart = thetaStart !== undefined ? thetaStart : 0;
  17081. thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
  17082. var thetaEnd = thetaStart + thetaLength;
  17083. var ix, iy;
  17084. var index = 0;
  17085. var grid = [];
  17086. var vertex = new Vector3();
  17087. var normal = new Vector3();
  17088. // buffers
  17089. var indices = [];
  17090. var vertices = [];
  17091. var normals = [];
  17092. var uvs = [];
  17093. // generate vertices, normals and uvs
  17094. for (iy = 0; iy <= heightSegments; iy++) {
  17095. var verticesRow = [];
  17096. var v = iy / heightSegments;
  17097. for (ix = 0; ix <= widthSegments; ix++) {
  17098. var u = ix / widthSegments;
  17099. // vertex
  17100. vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
  17101. vertex.y = radius * Math.cos(thetaStart + v * thetaLength);
  17102. vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
  17103. vertices.push(vertex.x, vertex.y, vertex.z);
  17104. // normal
  17105. normal.set(vertex.x, vertex.y, vertex.z).normalize();
  17106. normals.push(normal.x, normal.y, normal.z);
  17107. // uv
  17108. uvs.push(u, 1 - v);
  17109. verticesRow.push(index++);
  17110. }
  17111. grid.push(verticesRow);
  17112. }
  17113. // indices
  17114. for (iy = 0; iy < heightSegments; iy++) {
  17115. for (ix = 0; ix < widthSegments; ix++) {
  17116. var a = grid[iy][ix + 1];
  17117. var b = grid[iy][ix];
  17118. var c = grid[iy + 1][ix];
  17119. var d = grid[iy + 1][ix + 1];
  17120. if (iy !== 0 || thetaStart > 0) indices.push(a, b, d);
  17121. if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
  17122. }
  17123. }
  17124. // build geometry
  17125. this.setIndex(indices);
  17126. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17127. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  17128. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17129. }
  17130. SphereBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17131. SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
  17132. /**
  17133. * @author Kaleb Murphy
  17134. * @author Mugen87 / https://github.com/Mugen87
  17135. */
  17136. // RingGeometry
  17137. function RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength) {
  17138. Geometry.call(this);
  17139. this.type = 'RingGeometry';
  17140. this.parameters = {
  17141. innerRadius: innerRadius,
  17142. outerRadius: outerRadius,
  17143. thetaSegments: thetaSegments,
  17144. phiSegments: phiSegments,
  17145. thetaStart: thetaStart,
  17146. thetaLength: thetaLength
  17147. };
  17148. this.fromBufferGeometry(new RingBufferGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength));
  17149. this.mergeVertices();
  17150. }
  17151. RingGeometry.prototype = Object.create(Geometry.prototype);
  17152. RingGeometry.prototype.constructor = RingGeometry;
  17153. // RingBufferGeometry
  17154. function RingBufferGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength) {
  17155. BufferGeometry.call(this);
  17156. this.type = 'RingBufferGeometry';
  17157. this.parameters = {
  17158. innerRadius: innerRadius,
  17159. outerRadius: outerRadius,
  17160. thetaSegments: thetaSegments,
  17161. phiSegments: phiSegments,
  17162. thetaStart: thetaStart,
  17163. thetaLength: thetaLength
  17164. };
  17165. innerRadius = innerRadius || 0.5;
  17166. outerRadius = outerRadius || 1;
  17167. thetaStart = thetaStart !== undefined ? thetaStart : 0;
  17168. thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
  17169. thetaSegments = thetaSegments !== undefined ? Math.max(3, thetaSegments) : 8;
  17170. phiSegments = phiSegments !== undefined ? Math.max(1, phiSegments) : 1;
  17171. // buffers
  17172. var indices = [];
  17173. var vertices = [];
  17174. var normals = [];
  17175. var uvs = [];
  17176. // some helper variables
  17177. var segment;
  17178. var radius = innerRadius;
  17179. var radiusStep = (outerRadius - innerRadius) / phiSegments;
  17180. var vertex = new Vector3();
  17181. var uv = new Vector2();
  17182. var j, i;
  17183. // generate vertices, normals and uvs
  17184. for (j = 0; j <= phiSegments; j++) {
  17185. for (i = 0; i <= thetaSegments; i++) {
  17186. // values are generate from the inside of the ring to the outside
  17187. segment = thetaStart + i / thetaSegments * thetaLength;
  17188. // vertex
  17189. vertex.x = radius * Math.cos(segment);
  17190. vertex.y = radius * Math.sin(segment);
  17191. vertices.push(vertex.x, vertex.y, vertex.z);
  17192. // normal
  17193. normals.push(0, 0, 1);
  17194. // uv
  17195. uv.x = (vertex.x / outerRadius + 1) / 2;
  17196. uv.y = (vertex.y / outerRadius + 1) / 2;
  17197. uvs.push(uv.x, uv.y);
  17198. }
  17199. // increase the radius for next row of vertices
  17200. radius += radiusStep;
  17201. }
  17202. // indices
  17203. for (j = 0; j < phiSegments; j++) {
  17204. var thetaSegmentLevel = j * (thetaSegments + 1);
  17205. for (i = 0; i < thetaSegments; i++) {
  17206. segment = i + thetaSegmentLevel;
  17207. var a = segment;
  17208. var b = segment + thetaSegments + 1;
  17209. var c = segment + thetaSegments + 2;
  17210. var d = segment + 1;
  17211. // faces
  17212. indices.push(a, b, d);
  17213. indices.push(b, c, d);
  17214. }
  17215. }
  17216. // build geometry
  17217. this.setIndex(indices);
  17218. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17219. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  17220. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17221. }
  17222. RingBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17223. RingBufferGeometry.prototype.constructor = RingBufferGeometry;
  17224. /**
  17225. * @author astrodud / http://astrodud.isgreat.org/
  17226. * @author zz85 / https://github.com/zz85
  17227. * @author bhouston / http://clara.io
  17228. * @author Mugen87 / https://github.com/Mugen87
  17229. */
  17230. // LatheGeometry
  17231. function LatheGeometry(points, segments, phiStart, phiLength) {
  17232. Geometry.call(this);
  17233. this.type = 'LatheGeometry';
  17234. this.parameters = {
  17235. points: points,
  17236. segments: segments,
  17237. phiStart: phiStart,
  17238. phiLength: phiLength
  17239. };
  17240. this.fromBufferGeometry(new LatheBufferGeometry(points, segments, phiStart, phiLength));
  17241. this.mergeVertices();
  17242. }
  17243. LatheGeometry.prototype = Object.create(Geometry.prototype);
  17244. LatheGeometry.prototype.constructor = LatheGeometry;
  17245. // LatheBufferGeometry
  17246. function LatheBufferGeometry(points, segments, phiStart, phiLength) {
  17247. BufferGeometry.call(this);
  17248. this.type = 'LatheBufferGeometry';
  17249. this.parameters = {
  17250. points: points,
  17251. segments: segments,
  17252. phiStart: phiStart,
  17253. phiLength: phiLength
  17254. };
  17255. segments = Math.floor(segments) || 12;
  17256. phiStart = phiStart || 0;
  17257. phiLength = phiLength || Math.PI * 2;
  17258. // clamp phiLength so it's in range of [ 0, 2PI ]
  17259. phiLength = _Math.clamp(phiLength, 0, Math.PI * 2);
  17260. // buffers
  17261. var indices = [];
  17262. var vertices = [];
  17263. var uvs = [];
  17264. // helper variables
  17265. var base;
  17266. var inverseSegments = 1.0 / segments;
  17267. var vertex = new Vector3();
  17268. var uv = new Vector2();
  17269. var i, j;
  17270. // generate vertices and uvs
  17271. for (i = 0; i <= segments; i++) {
  17272. var phi = phiStart + i * inverseSegments * phiLength;
  17273. var sin = Math.sin(phi);
  17274. var cos = Math.cos(phi);
  17275. for (j = 0; j <= points.length - 1; j++) {
  17276. // vertex
  17277. vertex.x = points[j].x * sin;
  17278. vertex.y = points[j].y;
  17279. vertex.z = points[j].x * cos;
  17280. vertices.push(vertex.x, vertex.y, vertex.z);
  17281. // uv
  17282. uv.x = i / segments;
  17283. uv.y = j / (points.length - 1);
  17284. uvs.push(uv.x, uv.y);
  17285. }
  17286. }
  17287. // indices
  17288. for (i = 0; i < segments; i++) {
  17289. for (j = 0; j < points.length - 1; j++) {
  17290. base = j + i * points.length;
  17291. var a = base;
  17292. var b = base + points.length;
  17293. var c = base + points.length + 1;
  17294. var d = base + 1;
  17295. // faces
  17296. indices.push(a, b, d);
  17297. indices.push(b, c, d);
  17298. }
  17299. }
  17300. // build geometry
  17301. this.setIndex(indices);
  17302. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17303. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17304. // generate normals
  17305. this.computeVertexNormals();
  17306. // if the geometry is closed, we need to average the normals along the seam.
  17307. // because the corresponding vertices are identical (but still have different UVs).
  17308. if (phiLength === Math.PI * 2) {
  17309. var normals = this.attributes.normal.array;
  17310. var n1 = new Vector3();
  17311. var n2 = new Vector3();
  17312. var n = new Vector3();
  17313. // this is the buffer offset for the last line of vertices
  17314. base = segments * points.length * 3;
  17315. for (i = 0, j = 0; i < points.length; i++, j += 3) {
  17316. // select the normal of the vertex in the first line
  17317. n1.x = normals[j + 0];
  17318. n1.y = normals[j + 1];
  17319. n1.z = normals[j + 2];
  17320. // select the normal of the vertex in the last line
  17321. n2.x = normals[base + j + 0];
  17322. n2.y = normals[base + j + 1];
  17323. n2.z = normals[base + j + 2];
  17324. // average normals
  17325. n.addVectors(n1, n2).normalize();
  17326. // assign the new values to both normals
  17327. normals[j + 0] = normals[base + j + 0] = n.x;
  17328. normals[j + 1] = normals[base + j + 1] = n.y;
  17329. normals[j + 2] = normals[base + j + 2] = n.z;
  17330. }
  17331. }
  17332. }
  17333. LatheBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17334. LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
  17335. /**
  17336. * @author jonobr1 / http://jonobr1.com
  17337. * @author Mugen87 / https://github.com/Mugen87
  17338. */
  17339. // ShapeGeometry
  17340. function ShapeGeometry(shapes, curveSegments) {
  17341. Geometry.call(this);
  17342. this.type = 'ShapeGeometry';
  17343. if (typeof curveSegments === 'object') {
  17344. console.warn('THREE.ShapeGeometry: Options parameter has been removed.');
  17345. curveSegments = curveSegments.curveSegments;
  17346. }
  17347. this.parameters = {
  17348. shapes: shapes,
  17349. curveSegments: curveSegments
  17350. };
  17351. this.fromBufferGeometry(new ShapeBufferGeometry(shapes, curveSegments));
  17352. this.mergeVertices();
  17353. }
  17354. ShapeGeometry.prototype = Object.create(Geometry.prototype);
  17355. ShapeGeometry.prototype.constructor = ShapeGeometry;
  17356. ShapeGeometry.prototype.toJSON = function () {
  17357. var data = Geometry.prototype.toJSON.call(this);
  17358. var shapes = this.parameters.shapes;
  17359. return toJSON$1(shapes, data);
  17360. };
  17361. // ShapeBufferGeometry
  17362. function ShapeBufferGeometry(shapes, curveSegments) {
  17363. BufferGeometry.call(this);
  17364. this.type = 'ShapeBufferGeometry';
  17365. this.parameters = {
  17366. shapes: shapes,
  17367. curveSegments: curveSegments
  17368. };
  17369. curveSegments = curveSegments || 12;
  17370. // buffers
  17371. var indices = [];
  17372. var vertices = [];
  17373. var normals = [];
  17374. var uvs = [];
  17375. // helper variables
  17376. var groupStart = 0;
  17377. var groupCount = 0;
  17378. // allow single and array values for "shapes" parameter
  17379. if (Array.isArray(shapes) === false) {
  17380. addShape(shapes);
  17381. } else {
  17382. for (var i = 0; i < shapes.length; i++) {
  17383. addShape(shapes[i]);
  17384. this.addGroup(groupStart, groupCount, i); // enables MultiMaterial support
  17385. groupStart += groupCount;
  17386. groupCount = 0;
  17387. }
  17388. }
  17389. // build geometry
  17390. this.setIndex(indices);
  17391. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17392. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  17393. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17394. // helper functions
  17395. function addShape(shape) {
  17396. var i, l, shapeHole;
  17397. var indexOffset = vertices.length / 3;
  17398. var points = shape.extractPoints(curveSegments);
  17399. var shapeVertices = points.shape;
  17400. var shapeHoles = points.holes;
  17401. // check direction of vertices
  17402. if (ShapeUtils.isClockWise(shapeVertices) === false) {
  17403. shapeVertices = shapeVertices.reverse();
  17404. // also check if holes are in the opposite direction
  17405. for (i = 0, l = shapeHoles.length; i < l; i++) {
  17406. shapeHole = shapeHoles[i];
  17407. if (ShapeUtils.isClockWise(shapeHole) === true) {
  17408. shapeHoles[i] = shapeHole.reverse();
  17409. }
  17410. }
  17411. }
  17412. var faces = ShapeUtils.triangulateShape(shapeVertices, shapeHoles);
  17413. // join vertices of inner and outer paths to a single array
  17414. for (i = 0, l = shapeHoles.length; i < l; i++) {
  17415. shapeHole = shapeHoles[i];
  17416. shapeVertices = shapeVertices.concat(shapeHole);
  17417. }
  17418. // vertices, normals, uvs
  17419. for (i = 0, l = shapeVertices.length; i < l; i++) {
  17420. var vertex = shapeVertices[i];
  17421. vertices.push(vertex.x, vertex.y, 0);
  17422. normals.push(0, 0, 1);
  17423. uvs.push(vertex.x, vertex.y); // world uvs
  17424. }
  17425. // incides
  17426. for (i = 0, l = faces.length; i < l; i++) {
  17427. var face = faces[i];
  17428. var a = face[0] + indexOffset;
  17429. var b = face[1] + indexOffset;
  17430. var c = face[2] + indexOffset;
  17431. indices.push(a, b, c);
  17432. groupCount += 3;
  17433. }
  17434. }
  17435. }
  17436. ShapeBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17437. ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
  17438. ShapeBufferGeometry.prototype.toJSON = function () {
  17439. var data = BufferGeometry.prototype.toJSON.call(this);
  17440. var shapes = this.parameters.shapes;
  17441. return toJSON$1(shapes, data);
  17442. };
  17443. //
  17444. function toJSON$1(shapes, data) {
  17445. data.shapes = [];
  17446. if (Array.isArray(shapes)) {
  17447. for (var i = 0, l = shapes.length; i < l; i++) {
  17448. var shape = shapes[i];
  17449. data.shapes.push(shape.uuid);
  17450. }
  17451. } else {
  17452. data.shapes.push(shapes.uuid);
  17453. }
  17454. return data;
  17455. }
  17456. /**
  17457. * @author WestLangley / http://github.com/WestLangley
  17458. * @author Mugen87 / https://github.com/Mugen87
  17459. */
  17460. function EdgesGeometry(geometry, thresholdAngle) {
  17461. BufferGeometry.call(this);
  17462. this.type = 'EdgesGeometry';
  17463. this.parameters = {
  17464. thresholdAngle: thresholdAngle
  17465. };
  17466. thresholdAngle = thresholdAngle !== undefined ? thresholdAngle : 1;
  17467. // buffer
  17468. var vertices = [];
  17469. // helper variables
  17470. var thresholdDot = Math.cos(_Math.DEG2RAD * thresholdAngle);
  17471. var edge = [0, 0],
  17472. edges = {},
  17473. edge1,
  17474. edge2;
  17475. var key,
  17476. keys = ['a', 'b', 'c'];
  17477. // prepare source geometry
  17478. var geometry2;
  17479. if (geometry.isBufferGeometry) {
  17480. geometry2 = new Geometry();
  17481. geometry2.fromBufferGeometry(geometry);
  17482. } else {
  17483. geometry2 = geometry.clone();
  17484. }
  17485. geometry2.mergeVertices();
  17486. geometry2.computeFaceNormals();
  17487. var sourceVertices = geometry2.vertices;
  17488. var faces = geometry2.faces;
  17489. // now create a data structure where each entry represents an edge with its adjoining faces
  17490. for (var i = 0, l = faces.length; i < l; i++) {
  17491. var face = faces[i];
  17492. for (var j = 0; j < 3; j++) {
  17493. edge1 = face[keys[j]];
  17494. edge2 = face[keys[(j + 1) % 3]];
  17495. edge[0] = Math.min(edge1, edge2);
  17496. edge[1] = Math.max(edge1, edge2);
  17497. key = edge[0] + ',' + edge[1];
  17498. if (edges[key] === undefined) {
  17499. edges[key] = { index1: edge[0], index2: edge[1], face1: i, face2: undefined };
  17500. } else {
  17501. edges[key].face2 = i;
  17502. }
  17503. }
  17504. }
  17505. // generate vertices
  17506. for (key in edges) {
  17507. var e = edges[key];
  17508. // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
  17509. if (e.face2 === undefined || faces[e.face1].normal.dot(faces[e.face2].normal) <= thresholdDot) {
  17510. var vertex = sourceVertices[e.index1];
  17511. vertices.push(vertex.x, vertex.y, vertex.z);
  17512. vertex = sourceVertices[e.index2];
  17513. vertices.push(vertex.x, vertex.y, vertex.z);
  17514. }
  17515. }
  17516. // build geometry
  17517. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17518. }
  17519. EdgesGeometry.prototype = Object.create(BufferGeometry.prototype);
  17520. EdgesGeometry.prototype.constructor = EdgesGeometry;
  17521. /**
  17522. * @author mrdoob / http://mrdoob.com/
  17523. * @author Mugen87 / https://github.com/Mugen87
  17524. */
  17525. // CylinderGeometry
  17526. function CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
  17527. Geometry.call(this);
  17528. this.type = 'CylinderGeometry';
  17529. this.parameters = {
  17530. radiusTop: radiusTop,
  17531. radiusBottom: radiusBottom,
  17532. height: height,
  17533. radialSegments: radialSegments,
  17534. heightSegments: heightSegments,
  17535. openEnded: openEnded,
  17536. thetaStart: thetaStart,
  17537. thetaLength: thetaLength
  17538. };
  17539. this.fromBufferGeometry(new CylinderBufferGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength));
  17540. this.mergeVertices();
  17541. }
  17542. CylinderGeometry.prototype = Object.create(Geometry.prototype);
  17543. CylinderGeometry.prototype.constructor = CylinderGeometry;
  17544. // CylinderBufferGeometry
  17545. function CylinderBufferGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
  17546. BufferGeometry.call(this);
  17547. this.type = 'CylinderBufferGeometry';
  17548. this.parameters = {
  17549. radiusTop: radiusTop,
  17550. radiusBottom: radiusBottom,
  17551. height: height,
  17552. radialSegments: radialSegments,
  17553. heightSegments: heightSegments,
  17554. openEnded: openEnded,
  17555. thetaStart: thetaStart,
  17556. thetaLength: thetaLength
  17557. };
  17558. var scope = this;
  17559. radiusTop = radiusTop !== undefined ? radiusTop : 1;
  17560. radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
  17561. height = height || 1;
  17562. radialSegments = Math.floor(radialSegments) || 8;
  17563. heightSegments = Math.floor(heightSegments) || 1;
  17564. openEnded = openEnded !== undefined ? openEnded : false;
  17565. thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
  17566. thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
  17567. // buffers
  17568. var indices = [];
  17569. var vertices = [];
  17570. var normals = [];
  17571. var uvs = [];
  17572. // helper variables
  17573. var index = 0;
  17574. var indexArray = [];
  17575. var halfHeight = height / 2;
  17576. var groupStart = 0;
  17577. // generate geometry
  17578. generateTorso();
  17579. if (openEnded === false) {
  17580. if (radiusTop > 0) generateCap(true);
  17581. if (radiusBottom > 0) generateCap(false);
  17582. }
  17583. // build geometry
  17584. this.setIndex(indices);
  17585. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17586. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  17587. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17588. function generateTorso() {
  17589. var x, y;
  17590. var normal = new Vector3();
  17591. var vertex = new Vector3();
  17592. var groupCount = 0;
  17593. // this will be used to calculate the normal
  17594. var slope = (radiusBottom - radiusTop) / height;
  17595. // generate vertices, normals and uvs
  17596. for (y = 0; y <= heightSegments; y++) {
  17597. var indexRow = [];
  17598. var v = y / heightSegments;
  17599. // calculate the radius of the current row
  17600. var radius = v * (radiusBottom - radiusTop) + radiusTop;
  17601. for (x = 0; x <= radialSegments; x++) {
  17602. var u = x / radialSegments;
  17603. var theta = u * thetaLength + thetaStart;
  17604. var sinTheta = Math.sin(theta);
  17605. var cosTheta = Math.cos(theta);
  17606. // vertex
  17607. vertex.x = radius * sinTheta;
  17608. vertex.y = -v * height + halfHeight;
  17609. vertex.z = radius * cosTheta;
  17610. vertices.push(vertex.x, vertex.y, vertex.z);
  17611. // normal
  17612. normal.set(sinTheta, slope, cosTheta).normalize();
  17613. normals.push(normal.x, normal.y, normal.z);
  17614. // uv
  17615. uvs.push(u, 1 - v);
  17616. // save index of vertex in respective row
  17617. indexRow.push(index++);
  17618. }
  17619. // now save vertices of the row in our index array
  17620. indexArray.push(indexRow);
  17621. }
  17622. // generate indices
  17623. for (x = 0; x < radialSegments; x++) {
  17624. for (y = 0; y < heightSegments; y++) {
  17625. // we use the index array to access the correct indices
  17626. var a = indexArray[y][x];
  17627. var b = indexArray[y + 1][x];
  17628. var c = indexArray[y + 1][x + 1];
  17629. var d = indexArray[y][x + 1];
  17630. // faces
  17631. indices.push(a, b, d);
  17632. indices.push(b, c, d);
  17633. // update group counter
  17634. groupCount += 6;
  17635. }
  17636. }
  17637. // add a group to the geometry. this will ensure multi material support
  17638. scope.addGroup(groupStart, groupCount, 0);
  17639. // calculate new start value for groups
  17640. groupStart += groupCount;
  17641. }
  17642. function generateCap(top) {
  17643. var x, centerIndexStart, centerIndexEnd;
  17644. var uv = new Vector2();
  17645. var vertex = new Vector3();
  17646. var groupCount = 0;
  17647. var radius = top === true ? radiusTop : radiusBottom;
  17648. var sign = top === true ? 1 : -1;
  17649. // save the index of the first center vertex
  17650. centerIndexStart = index;
  17651. // first we generate the center vertex data of the cap.
  17652. // because the geometry needs one set of uvs per face,
  17653. // we must generate a center vertex per face/segment
  17654. for (x = 1; x <= radialSegments; x++) {
  17655. // vertex
  17656. vertices.push(0, halfHeight * sign, 0);
  17657. // normal
  17658. normals.push(0, sign, 0);
  17659. // uv
  17660. uvs.push(0.5, 0.5);
  17661. // increase index
  17662. index++;
  17663. }
  17664. // save the index of the last center vertex
  17665. centerIndexEnd = index;
  17666. // now we generate the surrounding vertices, normals and uvs
  17667. for (x = 0; x <= radialSegments; x++) {
  17668. var u = x / radialSegments;
  17669. var theta = u * thetaLength + thetaStart;
  17670. var cosTheta = Math.cos(theta);
  17671. var sinTheta = Math.sin(theta);
  17672. // vertex
  17673. vertex.x = radius * sinTheta;
  17674. vertex.y = halfHeight * sign;
  17675. vertex.z = radius * cosTheta;
  17676. vertices.push(vertex.x, vertex.y, vertex.z);
  17677. // normal
  17678. normals.push(0, sign, 0);
  17679. // uv
  17680. uv.x = cosTheta * 0.5 + 0.5;
  17681. uv.y = sinTheta * 0.5 * sign + 0.5;
  17682. uvs.push(uv.x, uv.y);
  17683. // increase index
  17684. index++;
  17685. }
  17686. // generate indices
  17687. for (x = 0; x < radialSegments; x++) {
  17688. var c = centerIndexStart + x;
  17689. var i = centerIndexEnd + x;
  17690. if (top === true) {
  17691. // face top
  17692. indices.push(i, i + 1, c);
  17693. } else {
  17694. // face bottom
  17695. indices.push(i + 1, i, c);
  17696. }
  17697. groupCount += 3;
  17698. }
  17699. // add a group to the geometry. this will ensure multi material support
  17700. scope.addGroup(groupStart, groupCount, top === true ? 1 : 2);
  17701. // calculate new start value for groups
  17702. groupStart += groupCount;
  17703. }
  17704. }
  17705. CylinderBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17706. CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
  17707. /**
  17708. * @author abelnation / http://github.com/abelnation
  17709. */
  17710. // ConeGeometry
  17711. function ConeGeometry(radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
  17712. CylinderGeometry.call(this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength);
  17713. this.type = 'ConeGeometry';
  17714. this.parameters = {
  17715. radius: radius,
  17716. height: height,
  17717. radialSegments: radialSegments,
  17718. heightSegments: heightSegments,
  17719. openEnded: openEnded,
  17720. thetaStart: thetaStart,
  17721. thetaLength: thetaLength
  17722. };
  17723. }
  17724. ConeGeometry.prototype = Object.create(CylinderGeometry.prototype);
  17725. ConeGeometry.prototype.constructor = ConeGeometry;
  17726. // ConeBufferGeometry
  17727. function ConeBufferGeometry(radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
  17728. CylinderBufferGeometry.call(this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength);
  17729. this.type = 'ConeBufferGeometry';
  17730. this.parameters = {
  17731. radius: radius,
  17732. height: height,
  17733. radialSegments: radialSegments,
  17734. heightSegments: heightSegments,
  17735. openEnded: openEnded,
  17736. thetaStart: thetaStart,
  17737. thetaLength: thetaLength
  17738. };
  17739. }
  17740. ConeBufferGeometry.prototype = Object.create(CylinderBufferGeometry.prototype);
  17741. ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
  17742. /**
  17743. * @author benaadams / https://twitter.com/ben_a_adams
  17744. * @author Mugen87 / https://github.com/Mugen87
  17745. * @author hughes
  17746. */
  17747. // CircleGeometry
  17748. function CircleGeometry(radius, segments, thetaStart, thetaLength) {
  17749. Geometry.call(this);
  17750. this.type = 'CircleGeometry';
  17751. this.parameters = {
  17752. radius: radius,
  17753. segments: segments,
  17754. thetaStart: thetaStart,
  17755. thetaLength: thetaLength
  17756. };
  17757. this.fromBufferGeometry(new CircleBufferGeometry(radius, segments, thetaStart, thetaLength));
  17758. this.mergeVertices();
  17759. }
  17760. CircleGeometry.prototype = Object.create(Geometry.prototype);
  17761. CircleGeometry.prototype.constructor = CircleGeometry;
  17762. // CircleBufferGeometry
  17763. function CircleBufferGeometry(radius, segments, thetaStart, thetaLength) {
  17764. BufferGeometry.call(this);
  17765. this.type = 'CircleBufferGeometry';
  17766. this.parameters = {
  17767. radius: radius,
  17768. segments: segments,
  17769. thetaStart: thetaStart,
  17770. thetaLength: thetaLength
  17771. };
  17772. radius = radius || 1;
  17773. segments = segments !== undefined ? Math.max(3, segments) : 8;
  17774. thetaStart = thetaStart !== undefined ? thetaStart : 0;
  17775. thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
  17776. // buffers
  17777. var indices = [];
  17778. var vertices = [];
  17779. var normals = [];
  17780. var uvs = [];
  17781. // helper variables
  17782. var i, s;
  17783. var vertex = new Vector3();
  17784. var uv = new Vector2();
  17785. // center point
  17786. vertices.push(0, 0, 0);
  17787. normals.push(0, 0, 1);
  17788. uvs.push(0.5, 0.5);
  17789. for (s = 0, i = 3; s <= segments; s++, i += 3) {
  17790. var segment = thetaStart + s / segments * thetaLength;
  17791. // vertex
  17792. vertex.x = radius * Math.cos(segment);
  17793. vertex.y = radius * Math.sin(segment);
  17794. vertices.push(vertex.x, vertex.y, vertex.z);
  17795. // normal
  17796. normals.push(0, 0, 1);
  17797. // uvs
  17798. uv.x = (vertices[i] / radius + 1) / 2;
  17799. uv.y = (vertices[i + 1] / radius + 1) / 2;
  17800. uvs.push(uv.x, uv.y);
  17801. }
  17802. // indices
  17803. for (i = 1; i <= segments; i++) {
  17804. indices.push(i, i + 1, 0);
  17805. }
  17806. // build geometry
  17807. this.setIndex(indices);
  17808. this.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  17809. this.addAttribute('normal', new Float32BufferAttribute(normals, 3));
  17810. this.addAttribute('uv', new Float32BufferAttribute(uvs, 2));
  17811. }
  17812. CircleBufferGeometry.prototype = Object.create(BufferGeometry.prototype);
  17813. CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
  17814. var Geometries = /*#__PURE__*/Object.freeze({
  17815. WireframeGeometry: WireframeGeometry,
  17816. ParametricGeometry: ParametricGeometry,
  17817. ParametricBufferGeometry: ParametricBufferGeometry,
  17818. TetrahedronGeometry: TetrahedronGeometry,
  17819. TetrahedronBufferGeometry: TetrahedronBufferGeometry,
  17820. OctahedronGeometry: OctahedronGeometry,
  17821. OctahedronBufferGeometry: OctahedronBufferGeometry,
  17822. IcosahedronGeometry: IcosahedronGeometry,
  17823. IcosahedronBufferGeometry: IcosahedronBufferGeometry,
  17824. DodecahedronGeometry: DodecahedronGeometry,
  17825. DodecahedronBufferGeometry: DodecahedronBufferGeometry,
  17826. PolyhedronGeometry: PolyhedronGeometry,
  17827. PolyhedronBufferGeometry: PolyhedronBufferGeometry,
  17828. TubeGeometry: TubeGeometry,
  17829. TubeBufferGeometry: TubeBufferGeometry,
  17830. TorusKnotGeometry: TorusKnotGeometry,
  17831. TorusKnotBufferGeometry: TorusKnotBufferGeometry,
  17832. TorusGeometry: TorusGeometry,
  17833. TorusBufferGeometry: TorusBufferGeometry,
  17834. TextGeometry: TextGeometry,
  17835. TextBufferGeometry: TextBufferGeometry,
  17836. SphereGeometry: SphereGeometry,
  17837. SphereBufferGeometry: SphereBufferGeometry,
  17838. RingGeometry: RingGeometry,
  17839. RingBufferGeometry: RingBufferGeometry,
  17840. PlaneGeometry: PlaneGeometry,
  17841. PlaneBufferGeometry: PlaneBufferGeometry,
  17842. LatheGeometry: LatheGeometry,
  17843. LatheBufferGeometry: LatheBufferGeometry,
  17844. ShapeGeometry: ShapeGeometry,
  17845. ShapeBufferGeometry: ShapeBufferGeometry,
  17846. ExtrudeGeometry: ExtrudeGeometry,
  17847. ExtrudeBufferGeometry: ExtrudeBufferGeometry,
  17848. EdgesGeometry: EdgesGeometry,
  17849. ConeGeometry: ConeGeometry,
  17850. ConeBufferGeometry: ConeBufferGeometry,
  17851. CylinderGeometry: CylinderGeometry,
  17852. CylinderBufferGeometry: CylinderBufferGeometry,
  17853. CircleGeometry: CircleGeometry,
  17854. CircleBufferGeometry: CircleBufferGeometry,
  17855. BoxGeometry: BoxGeometry,
  17856. BoxBufferGeometry: BoxBufferGeometry
  17857. });
  17858. /**
  17859. * @author mrdoob / http://mrdoob.com/
  17860. *
  17861. * parameters = {
  17862. * color: <THREE.Color>
  17863. * }
  17864. */
  17865. function ShadowMaterial(parameters) {
  17866. Material.call(this);
  17867. this.type = 'ShadowMaterial';
  17868. this.color = new Color(0x000000);
  17869. this.transparent = true;
  17870. this.setValues(parameters);
  17871. }
  17872. ShadowMaterial.prototype = Object.create(Material.prototype);
  17873. ShadowMaterial.prototype.constructor = ShadowMaterial;
  17874. ShadowMaterial.prototype.isShadowMaterial = true;
  17875. ShadowMaterial.prototype.copy = function (source) {
  17876. Material.prototype.copy.call(this, source);
  17877. this.color.copy(source.color);
  17878. return this;
  17879. };
  17880. /**
  17881. * @author mrdoob / http://mrdoob.com/
  17882. */
  17883. function RawShaderMaterial(parameters) {
  17884. ShaderMaterial.call(this, parameters);
  17885. this.type = 'RawShaderMaterial';
  17886. }
  17887. RawShaderMaterial.prototype = Object.create(ShaderMaterial.prototype);
  17888. RawShaderMaterial.prototype.constructor = RawShaderMaterial;
  17889. RawShaderMaterial.prototype.isRawShaderMaterial = true;
  17890. /**
  17891. * @author WestLangley / http://github.com/WestLangley
  17892. *
  17893. * parameters = {
  17894. * color: <hex>,
  17895. * roughness: <float>,
  17896. * metalness: <float>,
  17897. * opacity: <float>,
  17898. *
  17899. * map: new THREE.Texture( <Image> ),
  17900. *
  17901. * lightMap: new THREE.Texture( <Image> ),
  17902. * lightMapIntensity: <float>
  17903. *
  17904. * aoMap: new THREE.Texture( <Image> ),
  17905. * aoMapIntensity: <float>
  17906. *
  17907. * emissive: <hex>,
  17908. * emissiveIntensity: <float>
  17909. * emissiveMap: new THREE.Texture( <Image> ),
  17910. *
  17911. * bumpMap: new THREE.Texture( <Image> ),
  17912. * bumpScale: <float>,
  17913. *
  17914. * normalMap: new THREE.Texture( <Image> ),
  17915. * normalScale: <Vector2>,
  17916. *
  17917. * displacementMap: new THREE.Texture( <Image> ),
  17918. * displacementScale: <float>,
  17919. * displacementBias: <float>,
  17920. *
  17921. * roughnessMap: new THREE.Texture( <Image> ),
  17922. *
  17923. * metalnessMap: new THREE.Texture( <Image> ),
  17924. *
  17925. * alphaMap: new THREE.Texture( <Image> ),
  17926. *
  17927. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  17928. * envMapIntensity: <float>
  17929. *
  17930. * refractionRatio: <float>,
  17931. *
  17932. * wireframe: <boolean>,
  17933. * wireframeLinewidth: <float>,
  17934. *
  17935. * skinning: <bool>,
  17936. * morphTargets: <bool>,
  17937. * morphNormals: <bool>
  17938. * }
  17939. */
  17940. function MeshStandardMaterial(parameters) {
  17941. Material.call(this);
  17942. this.defines = { 'STANDARD': '' };
  17943. this.type = 'MeshStandardMaterial';
  17944. this.color = new Color(0xffffff); // diffuse
  17945. this.roughness = 0.5;
  17946. this.metalness = 0.5;
  17947. this.map = null;
  17948. this.lightMap = null;
  17949. this.lightMapIntensity = 1.0;
  17950. this.aoMap = null;
  17951. this.aoMapIntensity = 1.0;
  17952. this.emissive = new Color(0x000000);
  17953. this.emissiveIntensity = 1.0;
  17954. this.emissiveMap = null;
  17955. this.bumpMap = null;
  17956. this.bumpScale = 1;
  17957. this.normalMap = null;
  17958. this.normalScale = new Vector2(1, 1);
  17959. this.displacementMap = null;
  17960. this.displacementScale = 1;
  17961. this.displacementBias = 0;
  17962. this.roughnessMap = null;
  17963. this.metalnessMap = null;
  17964. this.alphaMap = null;
  17965. this.envMap = null;
  17966. this.envMapIntensity = 1.0;
  17967. this.refractionRatio = 0.98;
  17968. this.wireframe = false;
  17969. this.wireframeLinewidth = 1;
  17970. this.wireframeLinecap = 'round';
  17971. this.wireframeLinejoin = 'round';
  17972. this.skinning = false;
  17973. this.morphTargets = false;
  17974. this.morphNormals = false;
  17975. this.setValues(parameters);
  17976. }
  17977. MeshStandardMaterial.prototype = Object.create(Material.prototype);
  17978. MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
  17979. MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
  17980. MeshStandardMaterial.prototype.copy = function (source) {
  17981. Material.prototype.copy.call(this, source);
  17982. this.defines = { 'STANDARD': '' };
  17983. this.color.copy(source.color);
  17984. this.roughness = source.roughness;
  17985. this.metalness = source.metalness;
  17986. this.map = source.map;
  17987. this.lightMap = source.lightMap;
  17988. this.lightMapIntensity = source.lightMapIntensity;
  17989. this.aoMap = source.aoMap;
  17990. this.aoMapIntensity = source.aoMapIntensity;
  17991. this.emissive.copy(source.emissive);
  17992. this.emissiveMap = source.emissiveMap;
  17993. this.emissiveIntensity = source.emissiveIntensity;
  17994. this.bumpMap = source.bumpMap;
  17995. this.bumpScale = source.bumpScale;
  17996. this.normalMap = source.normalMap;
  17997. this.normalScale.copy(source.normalScale);
  17998. this.displacementMap = source.displacementMap;
  17999. this.displacementScale = source.displacementScale;
  18000. this.displacementBias = source.displacementBias;
  18001. this.roughnessMap = source.roughnessMap;
  18002. this.metalnessMap = source.metalnessMap;
  18003. this.alphaMap = source.alphaMap;
  18004. this.envMap = source.envMap;
  18005. this.envMapIntensity = source.envMapIntensity;
  18006. this.refractionRatio = source.refractionRatio;
  18007. this.wireframe = source.wireframe;
  18008. this.wireframeLinewidth = source.wireframeLinewidth;
  18009. this.wireframeLinecap = source.wireframeLinecap;
  18010. this.wireframeLinejoin = source.wireframeLinejoin;
  18011. this.skinning = source.skinning;
  18012. this.morphTargets = source.morphTargets;
  18013. this.morphNormals = source.morphNormals;
  18014. return this;
  18015. };
  18016. /**
  18017. * @author WestLangley / http://github.com/WestLangley
  18018. *
  18019. * parameters = {
  18020. * reflectivity: <float>
  18021. * }
  18022. */
  18023. function MeshPhysicalMaterial(parameters) {
  18024. MeshStandardMaterial.call(this);
  18025. this.defines = { 'PHYSICAL': '' };
  18026. this.type = 'MeshPhysicalMaterial';
  18027. this.reflectivity = 0.5; // maps to F0 = 0.04
  18028. this.clearCoat = 0.0;
  18029. this.clearCoatRoughness = 0.0;
  18030. this.setValues(parameters);
  18031. }
  18032. MeshPhysicalMaterial.prototype = Object.create(MeshStandardMaterial.prototype);
  18033. MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
  18034. MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
  18035. MeshPhysicalMaterial.prototype.copy = function (source) {
  18036. MeshStandardMaterial.prototype.copy.call(this, source);
  18037. this.defines = { 'PHYSICAL': '' };
  18038. this.reflectivity = source.reflectivity;
  18039. this.clearCoat = source.clearCoat;
  18040. this.clearCoatRoughness = source.clearCoatRoughness;
  18041. return this;
  18042. };
  18043. /**
  18044. * @author mrdoob / http://mrdoob.com/
  18045. * @author alteredq / http://alteredqualia.com/
  18046. *
  18047. * parameters = {
  18048. * color: <hex>,
  18049. * specular: <hex>,
  18050. * shininess: <float>,
  18051. * opacity: <float>,
  18052. *
  18053. * map: new THREE.Texture( <Image> ),
  18054. *
  18055. * lightMap: new THREE.Texture( <Image> ),
  18056. * lightMapIntensity: <float>
  18057. *
  18058. * aoMap: new THREE.Texture( <Image> ),
  18059. * aoMapIntensity: <float>
  18060. *
  18061. * emissive: <hex>,
  18062. * emissiveIntensity: <float>
  18063. * emissiveMap: new THREE.Texture( <Image> ),
  18064. *
  18065. * bumpMap: new THREE.Texture( <Image> ),
  18066. * bumpScale: <float>,
  18067. *
  18068. * normalMap: new THREE.Texture( <Image> ),
  18069. * normalScale: <Vector2>,
  18070. *
  18071. * displacementMap: new THREE.Texture( <Image> ),
  18072. * displacementScale: <float>,
  18073. * displacementBias: <float>,
  18074. *
  18075. * specularMap: new THREE.Texture( <Image> ),
  18076. *
  18077. * alphaMap: new THREE.Texture( <Image> ),
  18078. *
  18079. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  18080. * combine: THREE.Multiply,
  18081. * reflectivity: <float>,
  18082. * refractionRatio: <float>,
  18083. *
  18084. * wireframe: <boolean>,
  18085. * wireframeLinewidth: <float>,
  18086. *
  18087. * skinning: <bool>,
  18088. * morphTargets: <bool>,
  18089. * morphNormals: <bool>
  18090. * }
  18091. */
  18092. function MeshPhongMaterial(parameters) {
  18093. Material.call(this);
  18094. this.type = 'MeshPhongMaterial';
  18095. this.color = new Color(0xffffff); // diffuse
  18096. this.specular = new Color(0x111111);
  18097. this.shininess = 30;
  18098. this.map = null;
  18099. this.lightMap = null;
  18100. this.lightMapIntensity = 1.0;
  18101. this.aoMap = null;
  18102. this.aoMapIntensity = 1.0;
  18103. this.emissive = new Color(0x000000);
  18104. this.emissiveIntensity = 1.0;
  18105. this.emissiveMap = null;
  18106. this.bumpMap = null;
  18107. this.bumpScale = 1;
  18108. this.normalMap = null;
  18109. this.normalScale = new Vector2(1, 1);
  18110. this.displacementMap = null;
  18111. this.displacementScale = 1;
  18112. this.displacementBias = 0;
  18113. this.specularMap = null;
  18114. this.alphaMap = null;
  18115. this.envMap = null;
  18116. this.combine = MultiplyOperation;
  18117. this.reflectivity = 1;
  18118. this.refractionRatio = 0.98;
  18119. this.wireframe = false;
  18120. this.wireframeLinewidth = 1;
  18121. this.wireframeLinecap = 'round';
  18122. this.wireframeLinejoin = 'round';
  18123. this.skinning = false;
  18124. this.morphTargets = false;
  18125. this.morphNormals = false;
  18126. this.setValues(parameters);
  18127. }
  18128. MeshPhongMaterial.prototype = Object.create(Material.prototype);
  18129. MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
  18130. MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
  18131. MeshPhongMaterial.prototype.copy = function (source) {
  18132. Material.prototype.copy.call(this, source);
  18133. this.color.copy(source.color);
  18134. this.specular.copy(source.specular);
  18135. this.shininess = source.shininess;
  18136. this.map = source.map;
  18137. this.lightMap = source.lightMap;
  18138. this.lightMapIntensity = source.lightMapIntensity;
  18139. this.aoMap = source.aoMap;
  18140. this.aoMapIntensity = source.aoMapIntensity;
  18141. this.emissive.copy(source.emissive);
  18142. this.emissiveMap = source.emissiveMap;
  18143. this.emissiveIntensity = source.emissiveIntensity;
  18144. this.bumpMap = source.bumpMap;
  18145. this.bumpScale = source.bumpScale;
  18146. this.normalMap = source.normalMap;
  18147. this.normalScale.copy(source.normalScale);
  18148. this.displacementMap = source.displacementMap;
  18149. this.displacementScale = source.displacementScale;
  18150. this.displacementBias = source.displacementBias;
  18151. this.specularMap = source.specularMap;
  18152. this.alphaMap = source.alphaMap;
  18153. this.envMap = source.envMap;
  18154. this.combine = source.combine;
  18155. this.reflectivity = source.reflectivity;
  18156. this.refractionRatio = source.refractionRatio;
  18157. this.wireframe = source.wireframe;
  18158. this.wireframeLinewidth = source.wireframeLinewidth;
  18159. this.wireframeLinecap = source.wireframeLinecap;
  18160. this.wireframeLinejoin = source.wireframeLinejoin;
  18161. this.skinning = source.skinning;
  18162. this.morphTargets = source.morphTargets;
  18163. this.morphNormals = source.morphNormals;
  18164. return this;
  18165. };
  18166. /**
  18167. * @author takahirox / http://github.com/takahirox
  18168. *
  18169. * parameters = {
  18170. * gradientMap: new THREE.Texture( <Image> )
  18171. * }
  18172. */
  18173. function MeshToonMaterial(parameters) {
  18174. MeshPhongMaterial.call(this);
  18175. this.defines = { 'TOON': '' };
  18176. this.type = 'MeshToonMaterial';
  18177. this.gradientMap = null;
  18178. this.setValues(parameters);
  18179. }
  18180. MeshToonMaterial.prototype = Object.create(MeshPhongMaterial.prototype);
  18181. MeshToonMaterial.prototype.constructor = MeshToonMaterial;
  18182. MeshToonMaterial.prototype.isMeshToonMaterial = true;
  18183. MeshToonMaterial.prototype.copy = function (source) {
  18184. MeshPhongMaterial.prototype.copy.call(this, source);
  18185. this.gradientMap = source.gradientMap;
  18186. return this;
  18187. };
  18188. /**
  18189. * @author mrdoob / http://mrdoob.com/
  18190. * @author WestLangley / http://github.com/WestLangley
  18191. *
  18192. * parameters = {
  18193. * opacity: <float>,
  18194. *
  18195. * bumpMap: new THREE.Texture( <Image> ),
  18196. * bumpScale: <float>,
  18197. *
  18198. * normalMap: new THREE.Texture( <Image> ),
  18199. * normalScale: <Vector2>,
  18200. *
  18201. * displacementMap: new THREE.Texture( <Image> ),
  18202. * displacementScale: <float>,
  18203. * displacementBias: <float>,
  18204. *
  18205. * wireframe: <boolean>,
  18206. * wireframeLinewidth: <float>
  18207. *
  18208. * skinning: <bool>,
  18209. * morphTargets: <bool>,
  18210. * morphNormals: <bool>
  18211. * }
  18212. */
  18213. function MeshNormalMaterial(parameters) {
  18214. Material.call(this);
  18215. this.type = 'MeshNormalMaterial';
  18216. this.bumpMap = null;
  18217. this.bumpScale = 1;
  18218. this.normalMap = null;
  18219. this.normalScale = new Vector2(1, 1);
  18220. this.displacementMap = null;
  18221. this.displacementScale = 1;
  18222. this.displacementBias = 0;
  18223. this.wireframe = false;
  18224. this.wireframeLinewidth = 1;
  18225. this.fog = false;
  18226. this.lights = false;
  18227. this.skinning = false;
  18228. this.morphTargets = false;
  18229. this.morphNormals = false;
  18230. this.setValues(parameters);
  18231. }
  18232. MeshNormalMaterial.prototype = Object.create(Material.prototype);
  18233. MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
  18234. MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
  18235. MeshNormalMaterial.prototype.copy = function (source) {
  18236. Material.prototype.copy.call(this, source);
  18237. this.bumpMap = source.bumpMap;
  18238. this.bumpScale = source.bumpScale;
  18239. this.normalMap = source.normalMap;
  18240. this.normalScale.copy(source.normalScale);
  18241. this.displacementMap = source.displacementMap;
  18242. this.displacementScale = source.displacementScale;
  18243. this.displacementBias = source.displacementBias;
  18244. this.wireframe = source.wireframe;
  18245. this.wireframeLinewidth = source.wireframeLinewidth;
  18246. this.skinning = source.skinning;
  18247. this.morphTargets = source.morphTargets;
  18248. this.morphNormals = source.morphNormals;
  18249. return this;
  18250. };
  18251. /**
  18252. * @author mrdoob / http://mrdoob.com/
  18253. * @author alteredq / http://alteredqualia.com/
  18254. *
  18255. * parameters = {
  18256. * color: <hex>,
  18257. * opacity: <float>,
  18258. *
  18259. * map: new THREE.Texture( <Image> ),
  18260. *
  18261. * lightMap: new THREE.Texture( <Image> ),
  18262. * lightMapIntensity: <float>
  18263. *
  18264. * aoMap: new THREE.Texture( <Image> ),
  18265. * aoMapIntensity: <float>
  18266. *
  18267. * emissive: <hex>,
  18268. * emissiveIntensity: <float>
  18269. * emissiveMap: new THREE.Texture( <Image> ),
  18270. *
  18271. * specularMap: new THREE.Texture( <Image> ),
  18272. *
  18273. * alphaMap: new THREE.Texture( <Image> ),
  18274. *
  18275. * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
  18276. * combine: THREE.Multiply,
  18277. * reflectivity: <float>,
  18278. * refractionRatio: <float>,
  18279. *
  18280. * wireframe: <boolean>,
  18281. * wireframeLinewidth: <float>,
  18282. *
  18283. * skinning: <bool>,
  18284. * morphTargets: <bool>,
  18285. * morphNormals: <bool>
  18286. * }
  18287. */
  18288. function MeshLambertMaterial(parameters) {
  18289. Material.call(this);
  18290. this.type = 'MeshLambertMaterial';
  18291. this.color = new Color(0xffffff); // diffuse
  18292. this.map = null;
  18293. this.lightMap = null;
  18294. this.lightMapIntensity = 1.0;
  18295. this.aoMap = null;
  18296. this.aoMapIntensity = 1.0;
  18297. this.emissive = new Color(0x000000);
  18298. this.emissiveIntensity = 1.0;
  18299. this.emissiveMap = null;
  18300. this.specularMap = null;
  18301. this.alphaMap = null;
  18302. this.envMap = null;
  18303. this.combine = MultiplyOperation;
  18304. this.reflectivity = 1;
  18305. this.refractionRatio = 0.98;
  18306. this.wireframe = false;
  18307. this.wireframeLinewidth = 1;
  18308. this.wireframeLinecap = 'round';
  18309. this.wireframeLinejoin = 'round';
  18310. this.skinning = false;
  18311. this.morphTargets = false;
  18312. this.morphNormals = false;
  18313. this.setValues(parameters);
  18314. }
  18315. MeshLambertMaterial.prototype = Object.create(Material.prototype);
  18316. MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
  18317. MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
  18318. MeshLambertMaterial.prototype.copy = function (source) {
  18319. Material.prototype.copy.call(this, source);
  18320. this.color.copy(source.color);
  18321. this.map = source.map;
  18322. this.lightMap = source.lightMap;
  18323. this.lightMapIntensity = source.lightMapIntensity;
  18324. this.aoMap = source.aoMap;
  18325. this.aoMapIntensity = source.aoMapIntensity;
  18326. this.emissive.copy(source.emissive);
  18327. this.emissiveMap = source.emissiveMap;
  18328. this.emissiveIntensity = source.emissiveIntensity;
  18329. this.specularMap = source.specularMap;
  18330. this.alphaMap = source.alphaMap;
  18331. this.envMap = source.envMap;
  18332. this.combine = source.combine;
  18333. this.reflectivity = source.reflectivity;
  18334. this.refractionRatio = source.refractionRatio;
  18335. this.wireframe = source.wireframe;
  18336. this.wireframeLinewidth = source.wireframeLinewidth;
  18337. this.wireframeLinecap = source.wireframeLinecap;
  18338. this.wireframeLinejoin = source.wireframeLinejoin;
  18339. this.skinning = source.skinning;
  18340. this.morphTargets = source.morphTargets;
  18341. this.morphNormals = source.morphNormals;
  18342. return this;
  18343. };
  18344. /**
  18345. * @author alteredq / http://alteredqualia.com/
  18346. *
  18347. * parameters = {
  18348. * color: <hex>,
  18349. * opacity: <float>,
  18350. *
  18351. * linewidth: <float>,
  18352. *
  18353. * scale: <float>,
  18354. * dashSize: <float>,
  18355. * gapSize: <float>
  18356. * }
  18357. */
  18358. function LineDashedMaterial(parameters) {
  18359. LineBasicMaterial.call(this);
  18360. this.type = 'LineDashedMaterial';
  18361. this.scale = 1;
  18362. this.dashSize = 3;
  18363. this.gapSize = 1;
  18364. this.setValues(parameters);
  18365. }
  18366. LineDashedMaterial.prototype = Object.create(LineBasicMaterial.prototype);
  18367. LineDashedMaterial.prototype.constructor = LineDashedMaterial;
  18368. LineDashedMaterial.prototype.isLineDashedMaterial = true;
  18369. LineDashedMaterial.prototype.copy = function (source) {
  18370. LineBasicMaterial.prototype.copy.call(this, source);
  18371. this.scale = source.scale;
  18372. this.dashSize = source.dashSize;
  18373. this.gapSize = source.gapSize;
  18374. return this;
  18375. };
  18376. var Materials = /*#__PURE__*/Object.freeze({
  18377. ShadowMaterial: ShadowMaterial,
  18378. SpriteMaterial: SpriteMaterial,
  18379. RawShaderMaterial: RawShaderMaterial,
  18380. ShaderMaterial: ShaderMaterial,
  18381. PointsMaterial: PointsMaterial,
  18382. MeshPhysicalMaterial: MeshPhysicalMaterial,
  18383. MeshStandardMaterial: MeshStandardMaterial,
  18384. MeshPhongMaterial: MeshPhongMaterial,
  18385. MeshToonMaterial: MeshToonMaterial,
  18386. MeshNormalMaterial: MeshNormalMaterial,
  18387. MeshLambertMaterial: MeshLambertMaterial,
  18388. MeshDepthMaterial: MeshDepthMaterial,
  18389. MeshDistanceMaterial: MeshDistanceMaterial,
  18390. MeshBasicMaterial: MeshBasicMaterial,
  18391. LineDashedMaterial: LineDashedMaterial,
  18392. LineBasicMaterial: LineBasicMaterial,
  18393. Material: Material
  18394. });
  18395. /**
  18396. * @author mrdoob / http://mrdoob.com/
  18397. */
  18398. var Cache = {
  18399. enabled: false,
  18400. files: {},
  18401. add: function (key, file) {
  18402. if (this.enabled === false) return;
  18403. // console.log( 'THREE.Cache', 'Adding key:', key );
  18404. this.files[key] = file;
  18405. },
  18406. get: function (key) {
  18407. if (this.enabled === false) return;
  18408. // console.log( 'THREE.Cache', 'Checking key:', key );
  18409. return this.files[key];
  18410. },
  18411. remove: function (key) {
  18412. delete this.files[key];
  18413. },
  18414. clear: function () {
  18415. this.files = {};
  18416. }
  18417. };
  18418. /**
  18419. * @author mrdoob / http://mrdoob.com/
  18420. */
  18421. function LoadingManager(onLoad, onProgress, onError) {
  18422. var scope = this;
  18423. var isLoading = false;
  18424. var itemsLoaded = 0;
  18425. var itemsTotal = 0;
  18426. var urlModifier = undefined;
  18427. this.onStart = undefined;
  18428. this.onLoad = onLoad;
  18429. this.onProgress = onProgress;
  18430. this.onError = onError;
  18431. this.itemStart = function (url) {
  18432. itemsTotal++;
  18433. if (isLoading === false) {
  18434. if (scope.onStart !== undefined) {
  18435. scope.onStart(url, itemsLoaded, itemsTotal);
  18436. }
  18437. }
  18438. isLoading = true;
  18439. };
  18440. this.itemEnd = function (url) {
  18441. itemsLoaded++;
  18442. if (scope.onProgress !== undefined) {
  18443. scope.onProgress(url, itemsLoaded, itemsTotal);
  18444. }
  18445. if (itemsLoaded === itemsTotal) {
  18446. isLoading = false;
  18447. if (scope.onLoad !== undefined) {
  18448. scope.onLoad();
  18449. }
  18450. }
  18451. };
  18452. this.itemError = function (url) {
  18453. if (scope.onError !== undefined) {
  18454. scope.onError(url);
  18455. }
  18456. };
  18457. this.resolveURL = function (url) {
  18458. if (urlModifier) {
  18459. return urlModifier(url);
  18460. }
  18461. return url;
  18462. };
  18463. this.setURLModifier = function (transform) {
  18464. urlModifier = transform;
  18465. return this;
  18466. };
  18467. }
  18468. var DefaultLoadingManager = new LoadingManager();
  18469. /**
  18470. * @author mrdoob / http://mrdoob.com/
  18471. */
  18472. var loading = {};
  18473. function FileLoader(manager) {
  18474. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18475. }
  18476. Object.assign(FileLoader.prototype, {
  18477. load: function (url, onLoad, onProgress, onError) {
  18478. if (url === undefined) url = '';
  18479. if (this.path !== undefined) url = this.path + url;
  18480. url = this.manager.resolveURL(url);
  18481. var scope = this;
  18482. var cached = Cache.get(url);
  18483. if (cached !== undefined) {
  18484. scope.manager.itemStart(url);
  18485. setTimeout(function () {
  18486. if (onLoad) onLoad(cached);
  18487. scope.manager.itemEnd(url);
  18488. }, 0);
  18489. return cached;
  18490. }
  18491. // Check if request is duplicate
  18492. if (loading[url] !== undefined) {
  18493. loading[url].push({
  18494. onLoad: onLoad,
  18495. onProgress: onProgress,
  18496. onError: onError
  18497. });
  18498. return;
  18499. }
  18500. // Check for data: URI
  18501. var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
  18502. var dataUriRegexResult = url.match(dataUriRegex);
  18503. // Safari can not handle Data URIs through XMLHttpRequest so process manually
  18504. if (dataUriRegexResult) {
  18505. var mimeType = dataUriRegexResult[1];
  18506. var isBase64 = !!dataUriRegexResult[2];
  18507. var data = dataUriRegexResult[3];
  18508. data = window.decodeURIComponent(data);
  18509. if (isBase64) data = window.atob(data);
  18510. try {
  18511. var response;
  18512. var responseType = (this.responseType || '').toLowerCase();
  18513. switch (responseType) {
  18514. case 'arraybuffer':
  18515. case 'blob':
  18516. var view = new Uint8Array(data.length);
  18517. for (var i = 0; i < data.length; i++) {
  18518. view[i] = data.charCodeAt(i);
  18519. }
  18520. if (responseType === 'blob') {
  18521. response = new Blob([view.buffer], { type: mimeType });
  18522. } else {
  18523. response = view.buffer;
  18524. }
  18525. break;
  18526. case 'document':
  18527. var parser = new DOMParser();
  18528. response = parser.parseFromString(data, mimeType);
  18529. break;
  18530. case 'json':
  18531. response = JSON.parse(data);
  18532. break;
  18533. default:
  18534. // 'text' or other
  18535. response = data;
  18536. break;
  18537. }
  18538. // Wait for next browser tick like standard XMLHttpRequest event dispatching does
  18539. window.setTimeout(function () {
  18540. if (onLoad) onLoad(response);
  18541. scope.manager.itemEnd(url);
  18542. }, 0);
  18543. } catch (error) {
  18544. // Wait for next browser tick like standard XMLHttpRequest event dispatching does
  18545. window.setTimeout(function () {
  18546. if (onError) onError(error);
  18547. scope.manager.itemEnd(url);
  18548. scope.manager.itemError(url);
  18549. }, 0);
  18550. }
  18551. } else {
  18552. // Initialise array for duplicate requests
  18553. loading[url] = [];
  18554. loading[url].push({
  18555. onLoad: onLoad,
  18556. onProgress: onProgress,
  18557. onError: onError
  18558. });
  18559. var request = new XMLHttpRequest();
  18560. request.open('GET', url, true);
  18561. request.addEventListener('load', function (event) {
  18562. var response = this.response;
  18563. Cache.add(url, response);
  18564. var callbacks = loading[url];
  18565. delete loading[url];
  18566. if (this.status === 200 || this.status === 0) {
  18567. // Some browsers return HTTP Status 0 when using non-http protocol
  18568. // e.g. 'file://' or 'data://'. Handle as success.
  18569. if (this.status === 0) console.warn('THREE.FileLoader: HTTP Status 0 received.');
  18570. for (var i = 0, il = callbacks.length; i < il; i++) {
  18571. var callback = callbacks[i];
  18572. if (callback.onLoad) callback.onLoad(response);
  18573. }
  18574. scope.manager.itemEnd(url);
  18575. } else {
  18576. for (var i = 0, il = callbacks.length; i < il; i++) {
  18577. var callback = callbacks[i];
  18578. if (callback.onError) callback.onError(event);
  18579. }
  18580. scope.manager.itemEnd(url);
  18581. scope.manager.itemError(url);
  18582. }
  18583. }, false);
  18584. request.addEventListener('progress', function (event) {
  18585. var callbacks = loading[url];
  18586. for (var i = 0, il = callbacks.length; i < il; i++) {
  18587. var callback = callbacks[i];
  18588. if (callback.onProgress) callback.onProgress(event);
  18589. }
  18590. }, false);
  18591. request.addEventListener('error', function (event) {
  18592. var callbacks = loading[url];
  18593. delete loading[url];
  18594. for (var i = 0, il = callbacks.length; i < il; i++) {
  18595. var callback = callbacks[i];
  18596. if (callback.onError) callback.onError(event);
  18597. }
  18598. scope.manager.itemEnd(url);
  18599. scope.manager.itemError(url);
  18600. }, false);
  18601. if (this.responseType !== undefined) request.responseType = this.responseType;
  18602. if (this.withCredentials !== undefined) request.withCredentials = this.withCredentials;
  18603. if (request.overrideMimeType) request.overrideMimeType(this.mimeType !== undefined ? this.mimeType : 'text/plain');
  18604. for (var header in this.requestHeader) {
  18605. request.setRequestHeader(header, this.requestHeader[header]);
  18606. }
  18607. request.send(null);
  18608. }
  18609. scope.manager.itemStart(url);
  18610. return request;
  18611. },
  18612. setPath: function (value) {
  18613. this.path = value;
  18614. return this;
  18615. },
  18616. setResponseType: function (value) {
  18617. this.responseType = value;
  18618. return this;
  18619. },
  18620. setWithCredentials: function (value) {
  18621. this.withCredentials = value;
  18622. return this;
  18623. },
  18624. setMimeType: function (value) {
  18625. this.mimeType = value;
  18626. return this;
  18627. },
  18628. setRequestHeader: function (value) {
  18629. this.requestHeader = value;
  18630. return this;
  18631. }
  18632. });
  18633. /**
  18634. * @author mrdoob / http://mrdoob.com/
  18635. *
  18636. * Abstract Base class to block based textures loader (dds, pvr, ...)
  18637. */
  18638. function CompressedTextureLoader(manager) {
  18639. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18640. // override in sub classes
  18641. this._parser = null;
  18642. }
  18643. Object.assign(CompressedTextureLoader.prototype, {
  18644. load: function (url, onLoad, onProgress, onError) {
  18645. var scope = this;
  18646. var images = [];
  18647. var texture = new CompressedTexture();
  18648. texture.image = images;
  18649. var loader = new FileLoader(this.manager);
  18650. loader.setPath(this.path);
  18651. loader.setResponseType('arraybuffer');
  18652. function loadTexture(i) {
  18653. loader.load(url[i], function (buffer) {
  18654. var texDatas = scope._parser(buffer, true);
  18655. images[i] = {
  18656. width: texDatas.width,
  18657. height: texDatas.height,
  18658. format: texDatas.format,
  18659. mipmaps: texDatas.mipmaps
  18660. };
  18661. loaded += 1;
  18662. if (loaded === 6) {
  18663. if (texDatas.mipmapCount === 1) texture.minFilter = LinearFilter;
  18664. texture.format = texDatas.format;
  18665. texture.needsUpdate = true;
  18666. if (onLoad) onLoad(texture);
  18667. }
  18668. }, onProgress, onError);
  18669. }
  18670. if (Array.isArray(url)) {
  18671. var loaded = 0;
  18672. for (var i = 0, il = url.length; i < il; ++i) {
  18673. loadTexture(i);
  18674. }
  18675. } else {
  18676. // compressed cubemap texture stored in a single DDS file
  18677. loader.load(url, function (buffer) {
  18678. var texDatas = scope._parser(buffer, true);
  18679. if (texDatas.isCubemap) {
  18680. var faces = texDatas.mipmaps.length / texDatas.mipmapCount;
  18681. for (var f = 0; f < faces; f++) {
  18682. images[f] = { mipmaps: [] };
  18683. for (var i = 0; i < texDatas.mipmapCount; i++) {
  18684. images[f].mipmaps.push(texDatas.mipmaps[f * texDatas.mipmapCount + i]);
  18685. images[f].format = texDatas.format;
  18686. images[f].width = texDatas.width;
  18687. images[f].height = texDatas.height;
  18688. }
  18689. }
  18690. } else {
  18691. texture.image.width = texDatas.width;
  18692. texture.image.height = texDatas.height;
  18693. texture.mipmaps = texDatas.mipmaps;
  18694. }
  18695. if (texDatas.mipmapCount === 1) {
  18696. texture.minFilter = LinearFilter;
  18697. }
  18698. texture.format = texDatas.format;
  18699. texture.needsUpdate = true;
  18700. if (onLoad) onLoad(texture);
  18701. }, onProgress, onError);
  18702. }
  18703. return texture;
  18704. },
  18705. setPath: function (value) {
  18706. this.path = value;
  18707. return this;
  18708. }
  18709. });
  18710. /**
  18711. * @author Nikos M. / https://github.com/foo123/
  18712. *
  18713. * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
  18714. */
  18715. function DataTextureLoader(manager) {
  18716. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18717. // override in sub classes
  18718. this._parser = null;
  18719. }
  18720. Object.assign(DataTextureLoader.prototype, {
  18721. load: function (url, onLoad, onProgress, onError) {
  18722. var scope = this;
  18723. var texture = new DataTexture();
  18724. var loader = new FileLoader(this.manager);
  18725. loader.setResponseType('arraybuffer');
  18726. loader.load(url, function (buffer) {
  18727. var texData = scope._parser(buffer);
  18728. if (!texData) return;
  18729. if (undefined !== texData.image) {
  18730. texture.image = texData.image;
  18731. } else if (undefined !== texData.data) {
  18732. texture.image.width = texData.width;
  18733. texture.image.height = texData.height;
  18734. texture.image.data = texData.data;
  18735. }
  18736. texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;
  18737. texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;
  18738. texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;
  18739. texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;
  18740. texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;
  18741. if (undefined !== texData.format) {
  18742. texture.format = texData.format;
  18743. }
  18744. if (undefined !== texData.type) {
  18745. texture.type = texData.type;
  18746. }
  18747. if (undefined !== texData.mipmaps) {
  18748. texture.mipmaps = texData.mipmaps;
  18749. }
  18750. if (1 === texData.mipmapCount) {
  18751. texture.minFilter = LinearFilter;
  18752. }
  18753. texture.needsUpdate = true;
  18754. if (onLoad) onLoad(texture, texData);
  18755. }, onProgress, onError);
  18756. return texture;
  18757. }
  18758. });
  18759. /**
  18760. * @author mrdoob / http://mrdoob.com/
  18761. */
  18762. function ImageLoader(manager) {
  18763. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18764. }
  18765. Object.assign(ImageLoader.prototype, {
  18766. crossOrigin: 'Anonymous',
  18767. load: function (url, onLoad, onProgress, onError) {
  18768. if (url === undefined) url = '';
  18769. if (this.path !== undefined) url = this.path + url;
  18770. url = this.manager.resolveURL(url);
  18771. var scope = this;
  18772. var cached = Cache.get(url);
  18773. if (cached !== undefined) {
  18774. scope.manager.itemStart(url);
  18775. setTimeout(function () {
  18776. if (onLoad) onLoad(cached);
  18777. scope.manager.itemEnd(url);
  18778. }, 0);
  18779. return cached;
  18780. }
  18781. var image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
  18782. function onImageLoad() {
  18783. image.removeEventListener('load', onImageLoad, false);
  18784. image.removeEventListener('error', onImageError, false);
  18785. Cache.add(url, this);
  18786. if (onLoad) onLoad(this);
  18787. scope.manager.itemEnd(url);
  18788. }
  18789. function onImageError(event) {
  18790. image.removeEventListener('load', onImageLoad, false);
  18791. image.removeEventListener('error', onImageError, false);
  18792. if (onError) onError(event);
  18793. scope.manager.itemEnd(url);
  18794. scope.manager.itemError(url);
  18795. }
  18796. image.addEventListener('load', onImageLoad, false);
  18797. image.addEventListener('error', onImageError, false);
  18798. if (url.substr(0, 5) !== 'data:') {
  18799. if (this.crossOrigin !== undefined) image.crossOrigin = this.crossOrigin;
  18800. }
  18801. scope.manager.itemStart(url);
  18802. image.src = url;
  18803. return image;
  18804. },
  18805. setCrossOrigin: function (value) {
  18806. this.crossOrigin = value;
  18807. return this;
  18808. },
  18809. setPath: function (value) {
  18810. this.path = value;
  18811. return this;
  18812. }
  18813. });
  18814. /**
  18815. * @author mrdoob / http://mrdoob.com/
  18816. */
  18817. function CubeTextureLoader(manager) {
  18818. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18819. }
  18820. Object.assign(CubeTextureLoader.prototype, {
  18821. crossOrigin: 'Anonymous',
  18822. load: function (urls, onLoad, onProgress, onError) {
  18823. var texture = new CubeTexture();
  18824. var loader = new ImageLoader(this.manager);
  18825. loader.setCrossOrigin(this.crossOrigin);
  18826. loader.setPath(this.path);
  18827. var loaded = 0;
  18828. function loadTexture(i) {
  18829. loader.load(urls[i], function (image) {
  18830. texture.images[i] = image;
  18831. loaded++;
  18832. if (loaded === 6) {
  18833. texture.needsUpdate = true;
  18834. if (onLoad) onLoad(texture);
  18835. }
  18836. }, undefined, onError);
  18837. }
  18838. for (var i = 0; i < urls.length; ++i) {
  18839. loadTexture(i);
  18840. }
  18841. return texture;
  18842. },
  18843. setCrossOrigin: function (value) {
  18844. this.crossOrigin = value;
  18845. return this;
  18846. },
  18847. setPath: function (value) {
  18848. this.path = value;
  18849. return this;
  18850. }
  18851. });
  18852. /**
  18853. * @author mrdoob / http://mrdoob.com/
  18854. */
  18855. function TextureLoader(manager) {
  18856. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  18857. }
  18858. Object.assign(TextureLoader.prototype, {
  18859. crossOrigin: 'Anonymous',
  18860. load: function (url, onLoad, onProgress, onError) {
  18861. var texture = new Texture();
  18862. var loader = new ImageLoader(this.manager);
  18863. loader.setCrossOrigin(this.crossOrigin);
  18864. loader.setPath(this.path);
  18865. loader.load(url, function (image) {
  18866. texture.image = image;
  18867. // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
  18868. var isJPEG = url.search(/\.(jpg|jpeg)$/) > 0 || url.search(/^data\:image\/jpeg/) === 0;
  18869. texture.format = isJPEG ? RGBFormat : RGBAFormat;
  18870. texture.needsUpdate = true;
  18871. if (onLoad !== undefined) {
  18872. onLoad(texture);
  18873. }
  18874. }, onProgress, onError);
  18875. return texture;
  18876. },
  18877. setCrossOrigin: function (value) {
  18878. this.crossOrigin = value;
  18879. return this;
  18880. },
  18881. setPath: function (value) {
  18882. this.path = value;
  18883. return this;
  18884. }
  18885. });
  18886. /**
  18887. * @author zz85 / http://www.lab4games.net/zz85/blog
  18888. * Extensible curve object
  18889. *
  18890. * Some common of curve methods:
  18891. * .getPoint( t, optionalTarget ), .getTangent( t )
  18892. * .getPointAt( u, optionalTarget ), .getTangentAt( u )
  18893. * .getPoints(), .getSpacedPoints()
  18894. * .getLength()
  18895. * .updateArcLengths()
  18896. *
  18897. * This following curves inherit from THREE.Curve:
  18898. *
  18899. * -- 2D curves --
  18900. * THREE.ArcCurve
  18901. * THREE.CubicBezierCurve
  18902. * THREE.EllipseCurve
  18903. * THREE.LineCurve
  18904. * THREE.QuadraticBezierCurve
  18905. * THREE.SplineCurve
  18906. *
  18907. * -- 3D curves --
  18908. * THREE.CatmullRomCurve3
  18909. * THREE.CubicBezierCurve3
  18910. * THREE.LineCurve3
  18911. * THREE.QuadraticBezierCurve3
  18912. *
  18913. * A series of curves can be represented as a THREE.CurvePath.
  18914. *
  18915. **/
  18916. /**************************************************************
  18917. * Abstract Curve base class
  18918. **************************************************************/
  18919. function Curve() {
  18920. this.type = 'Curve';
  18921. this.arcLengthDivisions = 200;
  18922. }
  18923. Object.assign(Curve.prototype, {
  18924. // Virtual base class method to overwrite and implement in subclasses
  18925. // - t [0 .. 1]
  18926. getPoint: function () /* t, optionalTarget */{
  18927. console.warn('THREE.Curve: .getPoint() not implemented.');
  18928. return null;
  18929. },
  18930. // Get point at relative position in curve according to arc length
  18931. // - u [0 .. 1]
  18932. getPointAt: function (u, optionalTarget) {
  18933. var t = this.getUtoTmapping(u);
  18934. return this.getPoint(t, optionalTarget);
  18935. },
  18936. // Get sequence of points using getPoint( t )
  18937. getPoints: function (divisions) {
  18938. if (divisions === undefined) divisions = 5;
  18939. var points = [];
  18940. for (var d = 0; d <= divisions; d++) {
  18941. points.push(this.getPoint(d / divisions));
  18942. }
  18943. return points;
  18944. },
  18945. // Get sequence of points using getPointAt( u )
  18946. getSpacedPoints: function (divisions) {
  18947. if (divisions === undefined) divisions = 5;
  18948. var points = [];
  18949. for (var d = 0; d <= divisions; d++) {
  18950. points.push(this.getPointAt(d / divisions));
  18951. }
  18952. return points;
  18953. },
  18954. // Get total curve arc length
  18955. getLength: function () {
  18956. var lengths = this.getLengths();
  18957. return lengths[lengths.length - 1];
  18958. },
  18959. // Get list of cumulative segment lengths
  18960. getLengths: function (divisions) {
  18961. if (divisions === undefined) divisions = this.arcLengthDivisions;
  18962. if (this.cacheArcLengths && this.cacheArcLengths.length === divisions + 1 && !this.needsUpdate) {
  18963. return this.cacheArcLengths;
  18964. }
  18965. this.needsUpdate = false;
  18966. var cache = [];
  18967. var current,
  18968. last = this.getPoint(0);
  18969. var p,
  18970. sum = 0;
  18971. cache.push(0);
  18972. for (p = 1; p <= divisions; p++) {
  18973. current = this.getPoint(p / divisions);
  18974. sum += current.distanceTo(last);
  18975. cache.push(sum);
  18976. last = current;
  18977. }
  18978. this.cacheArcLengths = cache;
  18979. return cache; // { sums: cache, sum: sum }; Sum is in the last element.
  18980. },
  18981. updateArcLengths: function () {
  18982. this.needsUpdate = true;
  18983. this.getLengths();
  18984. },
  18985. // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
  18986. getUtoTmapping: function (u, distance) {
  18987. var arcLengths = this.getLengths();
  18988. var i = 0,
  18989. il = arcLengths.length;
  18990. var targetArcLength; // The targeted u distance value to get
  18991. if (distance) {
  18992. targetArcLength = distance;
  18993. } else {
  18994. targetArcLength = u * arcLengths[il - 1];
  18995. }
  18996. // binary search for the index with largest value smaller than target u distance
  18997. var low = 0,
  18998. high = il - 1,
  18999. comparison;
  19000. while (low <= high) {
  19001. 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
  19002. comparison = arcLengths[i] - targetArcLength;
  19003. if (comparison < 0) {
  19004. low = i + 1;
  19005. } else if (comparison > 0) {
  19006. high = i - 1;
  19007. } else {
  19008. high = i;
  19009. break;
  19010. // DONE
  19011. }
  19012. }
  19013. i = high;
  19014. if (arcLengths[i] === targetArcLength) {
  19015. return i / (il - 1);
  19016. }
  19017. // we could get finer grain at lengths, or use simple interpolation between two points
  19018. var lengthBefore = arcLengths[i];
  19019. var lengthAfter = arcLengths[i + 1];
  19020. var segmentLength = lengthAfter - lengthBefore;
  19021. // determine where we are between the 'before' and 'after' points
  19022. var segmentFraction = (targetArcLength - lengthBefore) / segmentLength;
  19023. // add that fractional amount to t
  19024. var t = (i + segmentFraction) / (il - 1);
  19025. return t;
  19026. },
  19027. // Returns a unit vector tangent at t
  19028. // In case any sub curve does not implement its tangent derivation,
  19029. // 2 points a small delta apart will be used to find its gradient
  19030. // which seems to give a reasonable approximation
  19031. getTangent: function (t) {
  19032. var delta = 0.0001;
  19033. var t1 = t - delta;
  19034. var t2 = t + delta;
  19035. // Capping in case of danger
  19036. if (t1 < 0) t1 = 0;
  19037. if (t2 > 1) t2 = 1;
  19038. var pt1 = this.getPoint(t1);
  19039. var pt2 = this.getPoint(t2);
  19040. var vec = pt2.clone().sub(pt1);
  19041. return vec.normalize();
  19042. },
  19043. getTangentAt: function (u) {
  19044. var t = this.getUtoTmapping(u);
  19045. return this.getTangent(t);
  19046. },
  19047. computeFrenetFrames: function (segments, closed) {
  19048. // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
  19049. var normal = new Vector3();
  19050. var tangents = [];
  19051. var normals = [];
  19052. var binormals = [];
  19053. var vec = new Vector3();
  19054. var mat = new Matrix4();
  19055. var i, u, theta;
  19056. // compute the tangent vectors for each segment on the curve
  19057. for (i = 0; i <= segments; i++) {
  19058. u = i / segments;
  19059. tangents[i] = this.getTangentAt(u);
  19060. tangents[i].normalize();
  19061. }
  19062. // select an initial normal vector perpendicular to the first tangent vector,
  19063. // and in the direction of the minimum tangent xyz component
  19064. normals[0] = new Vector3();
  19065. binormals[0] = new Vector3();
  19066. var min = Number.MAX_VALUE;
  19067. var tx = Math.abs(tangents[0].x);
  19068. var ty = Math.abs(tangents[0].y);
  19069. var tz = Math.abs(tangents[0].z);
  19070. if (tx <= min) {
  19071. min = tx;
  19072. normal.set(1, 0, 0);
  19073. }
  19074. if (ty <= min) {
  19075. min = ty;
  19076. normal.set(0, 1, 0);
  19077. }
  19078. if (tz <= min) {
  19079. normal.set(0, 0, 1);
  19080. }
  19081. vec.crossVectors(tangents[0], normal).normalize();
  19082. normals[0].crossVectors(tangents[0], vec);
  19083. binormals[0].crossVectors(tangents[0], normals[0]);
  19084. // compute the slowly-varying normal and binormal vectors for each segment on the curve
  19085. for (i = 1; i <= segments; i++) {
  19086. normals[i] = normals[i - 1].clone();
  19087. binormals[i] = binormals[i - 1].clone();
  19088. vec.crossVectors(tangents[i - 1], tangents[i]);
  19089. if (vec.length() > Number.EPSILON) {
  19090. vec.normalize();
  19091. theta = Math.acos(_Math.clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors
  19092. normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
  19093. }
  19094. binormals[i].crossVectors(tangents[i], normals[i]);
  19095. }
  19096. // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
  19097. if (closed === true) {
  19098. theta = Math.acos(_Math.clamp(normals[0].dot(normals[segments]), -1, 1));
  19099. theta /= segments;
  19100. if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
  19101. theta = -theta;
  19102. }
  19103. for (i = 1; i <= segments; i++) {
  19104. // twist a little...
  19105. normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
  19106. binormals[i].crossVectors(tangents[i], normals[i]);
  19107. }
  19108. }
  19109. return {
  19110. tangents: tangents,
  19111. normals: normals,
  19112. binormals: binormals
  19113. };
  19114. },
  19115. clone: function () {
  19116. return new this.constructor().copy(this);
  19117. },
  19118. copy: function (source) {
  19119. this.arcLengthDivisions = source.arcLengthDivisions;
  19120. return this;
  19121. },
  19122. toJSON: function () {
  19123. var data = {
  19124. metadata: {
  19125. version: 4.5,
  19126. type: 'Curve',
  19127. generator: 'Curve.toJSON'
  19128. }
  19129. };
  19130. data.arcLengthDivisions = this.arcLengthDivisions;
  19131. data.type = this.type;
  19132. return data;
  19133. },
  19134. fromJSON: function (json) {
  19135. this.arcLengthDivisions = json.arcLengthDivisions;
  19136. return this;
  19137. }
  19138. });
  19139. function EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) {
  19140. Curve.call(this);
  19141. this.type = 'EllipseCurve';
  19142. this.aX = aX || 0;
  19143. this.aY = aY || 0;
  19144. this.xRadius = xRadius || 1;
  19145. this.yRadius = yRadius || 1;
  19146. this.aStartAngle = aStartAngle || 0;
  19147. this.aEndAngle = aEndAngle || 2 * Math.PI;
  19148. this.aClockwise = aClockwise || false;
  19149. this.aRotation = aRotation || 0;
  19150. }
  19151. EllipseCurve.prototype = Object.create(Curve.prototype);
  19152. EllipseCurve.prototype.constructor = EllipseCurve;
  19153. EllipseCurve.prototype.isEllipseCurve = true;
  19154. EllipseCurve.prototype.getPoint = function (t, optionalTarget) {
  19155. var point = optionalTarget || new Vector2();
  19156. var twoPi = Math.PI * 2;
  19157. var deltaAngle = this.aEndAngle - this.aStartAngle;
  19158. var samePoints = Math.abs(deltaAngle) < Number.EPSILON;
  19159. // ensures that deltaAngle is 0 .. 2 PI
  19160. while (deltaAngle < 0) deltaAngle += twoPi;
  19161. while (deltaAngle > twoPi) deltaAngle -= twoPi;
  19162. if (deltaAngle < Number.EPSILON) {
  19163. if (samePoints) {
  19164. deltaAngle = 0;
  19165. } else {
  19166. deltaAngle = twoPi;
  19167. }
  19168. }
  19169. if (this.aClockwise === true && !samePoints) {
  19170. if (deltaAngle === twoPi) {
  19171. deltaAngle = -twoPi;
  19172. } else {
  19173. deltaAngle = deltaAngle - twoPi;
  19174. }
  19175. }
  19176. var angle = this.aStartAngle + t * deltaAngle;
  19177. var x = this.aX + this.xRadius * Math.cos(angle);
  19178. var y = this.aY + this.yRadius * Math.sin(angle);
  19179. if (this.aRotation !== 0) {
  19180. var cos = Math.cos(this.aRotation);
  19181. var sin = Math.sin(this.aRotation);
  19182. var tx = x - this.aX;
  19183. var ty = y - this.aY;
  19184. // Rotate the point about the center of the ellipse.
  19185. x = tx * cos - ty * sin + this.aX;
  19186. y = tx * sin + ty * cos + this.aY;
  19187. }
  19188. return point.set(x, y);
  19189. };
  19190. EllipseCurve.prototype.copy = function (source) {
  19191. Curve.prototype.copy.call(this, source);
  19192. this.aX = source.aX;
  19193. this.aY = source.aY;
  19194. this.xRadius = source.xRadius;
  19195. this.yRadius = source.yRadius;
  19196. this.aStartAngle = source.aStartAngle;
  19197. this.aEndAngle = source.aEndAngle;
  19198. this.aClockwise = source.aClockwise;
  19199. this.aRotation = source.aRotation;
  19200. return this;
  19201. };
  19202. EllipseCurve.prototype.toJSON = function () {
  19203. var data = Curve.prototype.toJSON.call(this);
  19204. data.aX = this.aX;
  19205. data.aY = this.aY;
  19206. data.xRadius = this.xRadius;
  19207. data.yRadius = this.yRadius;
  19208. data.aStartAngle = this.aStartAngle;
  19209. data.aEndAngle = this.aEndAngle;
  19210. data.aClockwise = this.aClockwise;
  19211. data.aRotation = this.aRotation;
  19212. return data;
  19213. };
  19214. EllipseCurve.prototype.fromJSON = function (json) {
  19215. Curve.prototype.fromJSON.call(this, json);
  19216. this.aX = json.aX;
  19217. this.aY = json.aY;
  19218. this.xRadius = json.xRadius;
  19219. this.yRadius = json.yRadius;
  19220. this.aStartAngle = json.aStartAngle;
  19221. this.aEndAngle = json.aEndAngle;
  19222. this.aClockwise = json.aClockwise;
  19223. this.aRotation = json.aRotation;
  19224. return this;
  19225. };
  19226. function ArcCurve(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) {
  19227. EllipseCurve.call(this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
  19228. this.type = 'ArcCurve';
  19229. }
  19230. ArcCurve.prototype = Object.create(EllipseCurve.prototype);
  19231. ArcCurve.prototype.constructor = ArcCurve;
  19232. ArcCurve.prototype.isArcCurve = true;
  19233. /**
  19234. * @author zz85 https://github.com/zz85
  19235. *
  19236. * Centripetal CatmullRom Curve - which is useful for avoiding
  19237. * cusps and self-intersections in non-uniform catmull rom curves.
  19238. * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
  19239. *
  19240. * curve.type accepts centripetal(default), chordal and catmullrom
  19241. * curve.tension is used for catmullrom which defaults to 0.5
  19242. */
  19243. /*
  19244. Based on an optimized c++ solution in
  19245. - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
  19246. - http://ideone.com/NoEbVM
  19247. This CubicPoly class could be used for reusing some variables and calculations,
  19248. but for three.js curve use, it could be possible inlined and flatten into a single function call
  19249. which can be placed in CurveUtils.
  19250. */
  19251. function CubicPoly() {
  19252. var c0 = 0,
  19253. c1 = 0,
  19254. c2 = 0,
  19255. c3 = 0;
  19256. /*
  19257. * Compute coefficients for a cubic polynomial
  19258. * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
  19259. * such that
  19260. * p(0) = x0, p(1) = x1
  19261. * and
  19262. * p'(0) = t0, p'(1) = t1.
  19263. */
  19264. function init(x0, x1, t0, t1) {
  19265. c0 = x0;
  19266. c1 = t0;
  19267. c2 = -3 * x0 + 3 * x1 - 2 * t0 - t1;
  19268. c3 = 2 * x0 - 2 * x1 + t0 + t1;
  19269. }
  19270. return {
  19271. initCatmullRom: function (x0, x1, x2, x3, tension) {
  19272. init(x1, x2, tension * (x2 - x0), tension * (x3 - x1));
  19273. },
  19274. initNonuniformCatmullRom: function (x0, x1, x2, x3, dt0, dt1, dt2) {
  19275. // compute tangents when parameterized in [t1,t2]
  19276. var t1 = (x1 - x0) / dt0 - (x2 - x0) / (dt0 + dt1) + (x2 - x1) / dt1;
  19277. var t2 = (x2 - x1) / dt1 - (x3 - x1) / (dt1 + dt2) + (x3 - x2) / dt2;
  19278. // rescale tangents for parametrization in [0,1]
  19279. t1 *= dt1;
  19280. t2 *= dt1;
  19281. init(x1, x2, t1, t2);
  19282. },
  19283. calc: function (t) {
  19284. var t2 = t * t;
  19285. var t3 = t2 * t;
  19286. return c0 + c1 * t + c2 * t2 + c3 * t3;
  19287. }
  19288. };
  19289. }
  19290. //
  19291. var tmp = new Vector3();
  19292. var px = new CubicPoly(),
  19293. py = new CubicPoly(),
  19294. pz = new CubicPoly();
  19295. function CatmullRomCurve3(points, closed, curveType, tension) {
  19296. Curve.call(this);
  19297. this.type = 'CatmullRomCurve3';
  19298. this.points = points || [];
  19299. this.closed = closed || false;
  19300. this.curveType = curveType || 'centripetal';
  19301. this.tension = tension || 0.5;
  19302. }
  19303. CatmullRomCurve3.prototype = Object.create(Curve.prototype);
  19304. CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
  19305. CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
  19306. CatmullRomCurve3.prototype.getPoint = function (t, optionalTarget) {
  19307. var point = optionalTarget || new Vector3();
  19308. var points = this.points;
  19309. var l = points.length;
  19310. var p = (l - (this.closed ? 0 : 1)) * t;
  19311. var intPoint = Math.floor(p);
  19312. var weight = p - intPoint;
  19313. if (this.closed) {
  19314. intPoint += intPoint > 0 ? 0 : (Math.floor(Math.abs(intPoint) / l) + 1) * l;
  19315. } else if (weight === 0 && intPoint === l - 1) {
  19316. intPoint = l - 2;
  19317. weight = 1;
  19318. }
  19319. var p0, p1, p2, p3; // 4 points
  19320. if (this.closed || intPoint > 0) {
  19321. p0 = points[(intPoint - 1) % l];
  19322. } else {
  19323. // extrapolate first point
  19324. tmp.subVectors(points[0], points[1]).add(points[0]);
  19325. p0 = tmp;
  19326. }
  19327. p1 = points[intPoint % l];
  19328. p2 = points[(intPoint + 1) % l];
  19329. if (this.closed || intPoint + 2 < l) {
  19330. p3 = points[(intPoint + 2) % l];
  19331. } else {
  19332. // extrapolate last point
  19333. tmp.subVectors(points[l - 1], points[l - 2]).add(points[l - 1]);
  19334. p3 = tmp;
  19335. }
  19336. if (this.curveType === 'centripetal' || this.curveType === 'chordal') {
  19337. // init Centripetal / Chordal Catmull-Rom
  19338. var pow = this.curveType === 'chordal' ? 0.5 : 0.25;
  19339. var dt0 = Math.pow(p0.distanceToSquared(p1), pow);
  19340. var dt1 = Math.pow(p1.distanceToSquared(p2), pow);
  19341. var dt2 = Math.pow(p2.distanceToSquared(p3), pow);
  19342. // safety check for repeated points
  19343. if (dt1 < 1e-4) dt1 = 1.0;
  19344. if (dt0 < 1e-4) dt0 = dt1;
  19345. if (dt2 < 1e-4) dt2 = dt1;
  19346. px.initNonuniformCatmullRom(p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2);
  19347. py.initNonuniformCatmullRom(p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2);
  19348. pz.initNonuniformCatmullRom(p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2);
  19349. } else if (this.curveType === 'catmullrom') {
  19350. px.initCatmullRom(p0.x, p1.x, p2.x, p3.x, this.tension);
  19351. py.initCatmullRom(p0.y, p1.y, p2.y, p3.y, this.tension);
  19352. pz.initCatmullRom(p0.z, p1.z, p2.z, p3.z, this.tension);
  19353. }
  19354. point.set(px.calc(weight), py.calc(weight), pz.calc(weight));
  19355. return point;
  19356. };
  19357. CatmullRomCurve3.prototype.copy = function (source) {
  19358. Curve.prototype.copy.call(this, source);
  19359. this.points = [];
  19360. for (var i = 0, l = source.points.length; i < l; i++) {
  19361. var point = source.points[i];
  19362. this.points.push(point.clone());
  19363. }
  19364. this.closed = source.closed;
  19365. this.curveType = source.curveType;
  19366. this.tension = source.tension;
  19367. return this;
  19368. };
  19369. CatmullRomCurve3.prototype.toJSON = function () {
  19370. var data = Curve.prototype.toJSON.call(this);
  19371. data.points = [];
  19372. for (var i = 0, l = this.points.length; i < l; i++) {
  19373. var point = this.points[i];
  19374. data.points.push(point.toArray());
  19375. }
  19376. data.closed = this.closed;
  19377. data.curveType = this.curveType;
  19378. data.tension = this.tension;
  19379. return data;
  19380. };
  19381. CatmullRomCurve3.prototype.fromJSON = function (json) {
  19382. Curve.prototype.fromJSON.call(this, json);
  19383. this.points = [];
  19384. for (var i = 0, l = json.points.length; i < l; i++) {
  19385. var point = json.points[i];
  19386. this.points.push(new Vector3().fromArray(point));
  19387. }
  19388. this.closed = json.closed;
  19389. this.curveType = json.curveType;
  19390. this.tension = json.tension;
  19391. return this;
  19392. };
  19393. /**
  19394. * @author zz85 / http://www.lab4games.net/zz85/blog
  19395. *
  19396. * Bezier Curves formulas obtained from
  19397. * http://en.wikipedia.org/wiki/Bézier_curve
  19398. */
  19399. function CatmullRom(t, p0, p1, p2, p3) {
  19400. var v0 = (p2 - p0) * 0.5;
  19401. var v1 = (p3 - p1) * 0.5;
  19402. var t2 = t * t;
  19403. var t3 = t * t2;
  19404. return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
  19405. }
  19406. //
  19407. function QuadraticBezierP0(t, p) {
  19408. var k = 1 - t;
  19409. return k * k * p;
  19410. }
  19411. function QuadraticBezierP1(t, p) {
  19412. return 2 * (1 - t) * t * p;
  19413. }
  19414. function QuadraticBezierP2(t, p) {
  19415. return t * t * p;
  19416. }
  19417. function QuadraticBezier(t, p0, p1, p2) {
  19418. return QuadraticBezierP0(t, p0) + QuadraticBezierP1(t, p1) + QuadraticBezierP2(t, p2);
  19419. }
  19420. //
  19421. function CubicBezierP0(t, p) {
  19422. var k = 1 - t;
  19423. return k * k * k * p;
  19424. }
  19425. function CubicBezierP1(t, p) {
  19426. var k = 1 - t;
  19427. return 3 * k * k * t * p;
  19428. }
  19429. function CubicBezierP2(t, p) {
  19430. return 3 * (1 - t) * t * t * p;
  19431. }
  19432. function CubicBezierP3(t, p) {
  19433. return t * t * t * p;
  19434. }
  19435. function CubicBezier(t, p0, p1, p2, p3) {
  19436. return CubicBezierP0(t, p0) + CubicBezierP1(t, p1) + CubicBezierP2(t, p2) + CubicBezierP3(t, p3);
  19437. }
  19438. function CubicBezierCurve(v0, v1, v2, v3) {
  19439. Curve.call(this);
  19440. this.type = 'CubicBezierCurve';
  19441. this.v0 = v0 || new Vector2();
  19442. this.v1 = v1 || new Vector2();
  19443. this.v2 = v2 || new Vector2();
  19444. this.v3 = v3 || new Vector2();
  19445. }
  19446. CubicBezierCurve.prototype = Object.create(Curve.prototype);
  19447. CubicBezierCurve.prototype.constructor = CubicBezierCurve;
  19448. CubicBezierCurve.prototype.isCubicBezierCurve = true;
  19449. CubicBezierCurve.prototype.getPoint = function (t, optionalTarget) {
  19450. var point = optionalTarget || new Vector2();
  19451. var v0 = this.v0,
  19452. v1 = this.v1,
  19453. v2 = this.v2,
  19454. v3 = this.v3;
  19455. point.set(CubicBezier(t, v0.x, v1.x, v2.x, v3.x), CubicBezier(t, v0.y, v1.y, v2.y, v3.y));
  19456. return point;
  19457. };
  19458. CubicBezierCurve.prototype.copy = function (source) {
  19459. Curve.prototype.copy.call(this, source);
  19460. this.v0.copy(source.v0);
  19461. this.v1.copy(source.v1);
  19462. this.v2.copy(source.v2);
  19463. this.v3.copy(source.v3);
  19464. return this;
  19465. };
  19466. CubicBezierCurve.prototype.toJSON = function () {
  19467. var data = Curve.prototype.toJSON.call(this);
  19468. data.v0 = this.v0.toArray();
  19469. data.v1 = this.v1.toArray();
  19470. data.v2 = this.v2.toArray();
  19471. data.v3 = this.v3.toArray();
  19472. return data;
  19473. };
  19474. CubicBezierCurve.prototype.fromJSON = function (json) {
  19475. Curve.prototype.fromJSON.call(this, json);
  19476. this.v0.fromArray(json.v0);
  19477. this.v1.fromArray(json.v1);
  19478. this.v2.fromArray(json.v2);
  19479. this.v3.fromArray(json.v3);
  19480. return this;
  19481. };
  19482. function CubicBezierCurve3(v0, v1, v2, v3) {
  19483. Curve.call(this);
  19484. this.type = 'CubicBezierCurve3';
  19485. this.v0 = v0 || new Vector3();
  19486. this.v1 = v1 || new Vector3();
  19487. this.v2 = v2 || new Vector3();
  19488. this.v3 = v3 || new Vector3();
  19489. }
  19490. CubicBezierCurve3.prototype = Object.create(Curve.prototype);
  19491. CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
  19492. CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
  19493. CubicBezierCurve3.prototype.getPoint = function (t, optionalTarget) {
  19494. var point = optionalTarget || new Vector3();
  19495. var v0 = this.v0,
  19496. v1 = this.v1,
  19497. v2 = this.v2,
  19498. v3 = this.v3;
  19499. point.set(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));
  19500. return point;
  19501. };
  19502. CubicBezierCurve3.prototype.copy = function (source) {
  19503. Curve.prototype.copy.call(this, source);
  19504. this.v0.copy(source.v0);
  19505. this.v1.copy(source.v1);
  19506. this.v2.copy(source.v2);
  19507. this.v3.copy(source.v3);
  19508. return this;
  19509. };
  19510. CubicBezierCurve3.prototype.toJSON = function () {
  19511. var data = Curve.prototype.toJSON.call(this);
  19512. data.v0 = this.v0.toArray();
  19513. data.v1 = this.v1.toArray();
  19514. data.v2 = this.v2.toArray();
  19515. data.v3 = this.v3.toArray();
  19516. return data;
  19517. };
  19518. CubicBezierCurve3.prototype.fromJSON = function (json) {
  19519. Curve.prototype.fromJSON.call(this, json);
  19520. this.v0.fromArray(json.v0);
  19521. this.v1.fromArray(json.v1);
  19522. this.v2.fromArray(json.v2);
  19523. this.v3.fromArray(json.v3);
  19524. return this;
  19525. };
  19526. function LineCurve(v1, v2) {
  19527. Curve.call(this);
  19528. this.type = 'LineCurve';
  19529. this.v1 = v1 || new Vector2();
  19530. this.v2 = v2 || new Vector2();
  19531. }
  19532. LineCurve.prototype = Object.create(Curve.prototype);
  19533. LineCurve.prototype.constructor = LineCurve;
  19534. LineCurve.prototype.isLineCurve = true;
  19535. LineCurve.prototype.getPoint = function (t, optionalTarget) {
  19536. var point = optionalTarget || new Vector2();
  19537. if (t === 1) {
  19538. point.copy(this.v2);
  19539. } else {
  19540. point.copy(this.v2).sub(this.v1);
  19541. point.multiplyScalar(t).add(this.v1);
  19542. }
  19543. return point;
  19544. };
  19545. // Line curve is linear, so we can overwrite default getPointAt
  19546. LineCurve.prototype.getPointAt = function (u, optionalTarget) {
  19547. return this.getPoint(u, optionalTarget);
  19548. };
  19549. LineCurve.prototype.getTangent = function () /* t */{
  19550. var tangent = this.v2.clone().sub(this.v1);
  19551. return tangent.normalize();
  19552. };
  19553. LineCurve.prototype.copy = function (source) {
  19554. Curve.prototype.copy.call(this, source);
  19555. this.v1.copy(source.v1);
  19556. this.v2.copy(source.v2);
  19557. return this;
  19558. };
  19559. LineCurve.prototype.toJSON = function () {
  19560. var data = Curve.prototype.toJSON.call(this);
  19561. data.v1 = this.v1.toArray();
  19562. data.v2 = this.v2.toArray();
  19563. return data;
  19564. };
  19565. LineCurve.prototype.fromJSON = function (json) {
  19566. Curve.prototype.fromJSON.call(this, json);
  19567. this.v1.fromArray(json.v1);
  19568. this.v2.fromArray(json.v2);
  19569. return this;
  19570. };
  19571. function LineCurve3(v1, v2) {
  19572. Curve.call(this);
  19573. this.type = 'LineCurve3';
  19574. this.v1 = v1 || new Vector3();
  19575. this.v2 = v2 || new Vector3();
  19576. }
  19577. LineCurve3.prototype = Object.create(Curve.prototype);
  19578. LineCurve3.prototype.constructor = LineCurve3;
  19579. LineCurve3.prototype.isLineCurve3 = true;
  19580. LineCurve3.prototype.getPoint = function (t, optionalTarget) {
  19581. var point = optionalTarget || new Vector3();
  19582. if (t === 1) {
  19583. point.copy(this.v2);
  19584. } else {
  19585. point.copy(this.v2).sub(this.v1);
  19586. point.multiplyScalar(t).add(this.v1);
  19587. }
  19588. return point;
  19589. };
  19590. // Line curve is linear, so we can overwrite default getPointAt
  19591. LineCurve3.prototype.getPointAt = function (u, optionalTarget) {
  19592. return this.getPoint(u, optionalTarget);
  19593. };
  19594. LineCurve3.prototype.copy = function (source) {
  19595. Curve.prototype.copy.call(this, source);
  19596. this.v1.copy(source.v1);
  19597. this.v2.copy(source.v2);
  19598. return this;
  19599. };
  19600. LineCurve3.prototype.toJSON = function () {
  19601. var data = Curve.prototype.toJSON.call(this);
  19602. data.v1 = this.v1.toArray();
  19603. data.v2 = this.v2.toArray();
  19604. return data;
  19605. };
  19606. LineCurve3.prototype.fromJSON = function (json) {
  19607. Curve.prototype.fromJSON.call(this, json);
  19608. this.v1.fromArray(json.v1);
  19609. this.v2.fromArray(json.v2);
  19610. return this;
  19611. };
  19612. function QuadraticBezierCurve(v0, v1, v2) {
  19613. Curve.call(this);
  19614. this.type = 'QuadraticBezierCurve';
  19615. this.v0 = v0 || new Vector2();
  19616. this.v1 = v1 || new Vector2();
  19617. this.v2 = v2 || new Vector2();
  19618. }
  19619. QuadraticBezierCurve.prototype = Object.create(Curve.prototype);
  19620. QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
  19621. QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
  19622. QuadraticBezierCurve.prototype.getPoint = function (t, optionalTarget) {
  19623. var point = optionalTarget || new Vector2();
  19624. var v0 = this.v0,
  19625. v1 = this.v1,
  19626. v2 = this.v2;
  19627. point.set(QuadraticBezier(t, v0.x, v1.x, v2.x), QuadraticBezier(t, v0.y, v1.y, v2.y));
  19628. return point;
  19629. };
  19630. QuadraticBezierCurve.prototype.copy = function (source) {
  19631. Curve.prototype.copy.call(this, source);
  19632. this.v0.copy(source.v0);
  19633. this.v1.copy(source.v1);
  19634. this.v2.copy(source.v2);
  19635. return this;
  19636. };
  19637. QuadraticBezierCurve.prototype.toJSON = function () {
  19638. var data = Curve.prototype.toJSON.call(this);
  19639. data.v0 = this.v0.toArray();
  19640. data.v1 = this.v1.toArray();
  19641. data.v2 = this.v2.toArray();
  19642. return data;
  19643. };
  19644. QuadraticBezierCurve.prototype.fromJSON = function (json) {
  19645. Curve.prototype.fromJSON.call(this, json);
  19646. this.v0.fromArray(json.v0);
  19647. this.v1.fromArray(json.v1);
  19648. this.v2.fromArray(json.v2);
  19649. return this;
  19650. };
  19651. function QuadraticBezierCurve3(v0, v1, v2) {
  19652. Curve.call(this);
  19653. this.type = 'QuadraticBezierCurve3';
  19654. this.v0 = v0 || new Vector3();
  19655. this.v1 = v1 || new Vector3();
  19656. this.v2 = v2 || new Vector3();
  19657. }
  19658. QuadraticBezierCurve3.prototype = Object.create(Curve.prototype);
  19659. QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
  19660. QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
  19661. QuadraticBezierCurve3.prototype.getPoint = function (t, optionalTarget) {
  19662. var point = optionalTarget || new Vector3();
  19663. var v0 = this.v0,
  19664. v1 = this.v1,
  19665. v2 = this.v2;
  19666. point.set(QuadraticBezier(t, v0.x, v1.x, v2.x), QuadraticBezier(t, v0.y, v1.y, v2.y), QuadraticBezier(t, v0.z, v1.z, v2.z));
  19667. return point;
  19668. };
  19669. QuadraticBezierCurve3.prototype.copy = function (source) {
  19670. Curve.prototype.copy.call(this, source);
  19671. this.v0.copy(source.v0);
  19672. this.v1.copy(source.v1);
  19673. this.v2.copy(source.v2);
  19674. return this;
  19675. };
  19676. QuadraticBezierCurve3.prototype.toJSON = function () {
  19677. var data = Curve.prototype.toJSON.call(this);
  19678. data.v0 = this.v0.toArray();
  19679. data.v1 = this.v1.toArray();
  19680. data.v2 = this.v2.toArray();
  19681. return data;
  19682. };
  19683. QuadraticBezierCurve3.prototype.fromJSON = function (json) {
  19684. Curve.prototype.fromJSON.call(this, json);
  19685. this.v0.fromArray(json.v0);
  19686. this.v1.fromArray(json.v1);
  19687. this.v2.fromArray(json.v2);
  19688. return this;
  19689. };
  19690. function SplineCurve(points /* array of Vector2 */) {
  19691. Curve.call(this);
  19692. this.type = 'SplineCurve';
  19693. this.points = points || [];
  19694. }
  19695. SplineCurve.prototype = Object.create(Curve.prototype);
  19696. SplineCurve.prototype.constructor = SplineCurve;
  19697. SplineCurve.prototype.isSplineCurve = true;
  19698. SplineCurve.prototype.getPoint = function (t, optionalTarget) {
  19699. var point = optionalTarget || new Vector2();
  19700. var points = this.points;
  19701. var p = (points.length - 1) * t;
  19702. var intPoint = Math.floor(p);
  19703. var weight = p - intPoint;
  19704. var p0 = points[intPoint === 0 ? intPoint : intPoint - 1];
  19705. var p1 = points[intPoint];
  19706. var p2 = points[intPoint > points.length - 2 ? points.length - 1 : intPoint + 1];
  19707. var p3 = points[intPoint > points.length - 3 ? points.length - 1 : intPoint + 2];
  19708. point.set(CatmullRom(weight, p0.x, p1.x, p2.x, p3.x), CatmullRom(weight, p0.y, p1.y, p2.y, p3.y));
  19709. return point;
  19710. };
  19711. SplineCurve.prototype.copy = function (source) {
  19712. Curve.prototype.copy.call(this, source);
  19713. this.points = [];
  19714. for (var i = 0, l = source.points.length; i < l; i++) {
  19715. var point = source.points[i];
  19716. this.points.push(point.clone());
  19717. }
  19718. return this;
  19719. };
  19720. SplineCurve.prototype.toJSON = function () {
  19721. var data = Curve.prototype.toJSON.call(this);
  19722. data.points = [];
  19723. for (var i = 0, l = this.points.length; i < l; i++) {
  19724. var point = this.points[i];
  19725. data.points.push(point.toArray());
  19726. }
  19727. return data;
  19728. };
  19729. SplineCurve.prototype.fromJSON = function (json) {
  19730. Curve.prototype.fromJSON.call(this, json);
  19731. this.points = [];
  19732. for (var i = 0, l = json.points.length; i < l; i++) {
  19733. var point = json.points[i];
  19734. this.points.push(new Vector2().fromArray(point));
  19735. }
  19736. return this;
  19737. };
  19738. var Curves = /*#__PURE__*/Object.freeze({
  19739. ArcCurve: ArcCurve,
  19740. CatmullRomCurve3: CatmullRomCurve3,
  19741. CubicBezierCurve: CubicBezierCurve,
  19742. CubicBezierCurve3: CubicBezierCurve3,
  19743. EllipseCurve: EllipseCurve,
  19744. LineCurve: LineCurve,
  19745. LineCurve3: LineCurve3,
  19746. QuadraticBezierCurve: QuadraticBezierCurve,
  19747. QuadraticBezierCurve3: QuadraticBezierCurve3,
  19748. SplineCurve: SplineCurve
  19749. });
  19750. /**
  19751. * @author zz85 / http://www.lab4games.net/zz85/blog
  19752. *
  19753. **/
  19754. /**************************************************************
  19755. * Curved Path - a curve path is simply a array of connected
  19756. * curves, but retains the api of a curve
  19757. **************************************************************/
  19758. function CurvePath() {
  19759. Curve.call(this);
  19760. this.type = 'CurvePath';
  19761. this.curves = [];
  19762. this.autoClose = false; // Automatically closes the path
  19763. }
  19764. CurvePath.prototype = Object.assign(Object.create(Curve.prototype), {
  19765. constructor: CurvePath,
  19766. add: function (curve) {
  19767. this.curves.push(curve);
  19768. },
  19769. closePath: function () {
  19770. // Add a line curve if start and end of lines are not connected
  19771. var startPoint = this.curves[0].getPoint(0);
  19772. var endPoint = this.curves[this.curves.length - 1].getPoint(1);
  19773. if (!startPoint.equals(endPoint)) {
  19774. this.curves.push(new LineCurve(endPoint, startPoint));
  19775. }
  19776. },
  19777. // To get accurate point with reference to
  19778. // entire path distance at time t,
  19779. // following has to be done:
  19780. // 1. Length of each sub path have to be known
  19781. // 2. Locate and identify type of curve
  19782. // 3. Get t for the curve
  19783. // 4. Return curve.getPointAt(t')
  19784. getPoint: function (t) {
  19785. var d = t * this.getLength();
  19786. var curveLengths = this.getCurveLengths();
  19787. var i = 0;
  19788. // To think about boundaries points.
  19789. while (i < curveLengths.length) {
  19790. if (curveLengths[i] >= d) {
  19791. var diff = curveLengths[i] - d;
  19792. var curve = this.curves[i];
  19793. var segmentLength = curve.getLength();
  19794. var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
  19795. return curve.getPointAt(u);
  19796. }
  19797. i++;
  19798. }
  19799. return null;
  19800. // loop where sum != 0, sum > d , sum+1 <d
  19801. },
  19802. // We cannot use the default THREE.Curve getPoint() with getLength() because in
  19803. // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
  19804. // getPoint() depends on getLength
  19805. getLength: function () {
  19806. var lens = this.getCurveLengths();
  19807. return lens[lens.length - 1];
  19808. },
  19809. // cacheLengths must be recalculated.
  19810. updateArcLengths: function () {
  19811. this.needsUpdate = true;
  19812. this.cacheLengths = null;
  19813. this.getCurveLengths();
  19814. },
  19815. // Compute lengths and cache them
  19816. // We cannot overwrite getLengths() because UtoT mapping uses it.
  19817. getCurveLengths: function () {
  19818. // We use cache values if curves and cache array are same length
  19819. if (this.cacheLengths && this.cacheLengths.length === this.curves.length) {
  19820. return this.cacheLengths;
  19821. }
  19822. // Get length of sub-curve
  19823. // Push sums into cached array
  19824. var lengths = [],
  19825. sums = 0;
  19826. for (var i = 0, l = this.curves.length; i < l; i++) {
  19827. sums += this.curves[i].getLength();
  19828. lengths.push(sums);
  19829. }
  19830. this.cacheLengths = lengths;
  19831. return lengths;
  19832. },
  19833. getSpacedPoints: function (divisions) {
  19834. if (divisions === undefined) divisions = 40;
  19835. var points = [];
  19836. for (var i = 0; i <= divisions; i++) {
  19837. points.push(this.getPoint(i / divisions));
  19838. }
  19839. if (this.autoClose) {
  19840. points.push(points[0]);
  19841. }
  19842. return points;
  19843. },
  19844. getPoints: function (divisions) {
  19845. divisions = divisions || 12;
  19846. var points = [],
  19847. last;
  19848. for (var i = 0, curves = this.curves; i < curves.length; i++) {
  19849. var curve = curves[i];
  19850. var resolution = curve && curve.isEllipseCurve ? divisions * 2 : curve && curve.isLineCurve ? 1 : curve && curve.isSplineCurve ? divisions * curve.points.length : divisions;
  19851. var pts = curve.getPoints(resolution);
  19852. for (var j = 0; j < pts.length; j++) {
  19853. var point = pts[j];
  19854. if (last && last.equals(point)) continue; // ensures no consecutive points are duplicates
  19855. points.push(point);
  19856. last = point;
  19857. }
  19858. }
  19859. if (this.autoClose && points.length > 1 && !points[points.length - 1].equals(points[0])) {
  19860. points.push(points[0]);
  19861. }
  19862. return points;
  19863. },
  19864. copy: function (source) {
  19865. Curve.prototype.copy.call(this, source);
  19866. this.curves = [];
  19867. for (var i = 0, l = source.curves.length; i < l; i++) {
  19868. var curve = source.curves[i];
  19869. this.curves.push(curve.clone());
  19870. }
  19871. this.autoClose = source.autoClose;
  19872. return this;
  19873. },
  19874. toJSON: function () {
  19875. var data = Curve.prototype.toJSON.call(this);
  19876. data.autoClose = this.autoClose;
  19877. data.curves = [];
  19878. for (var i = 0, l = this.curves.length; i < l; i++) {
  19879. var curve = this.curves[i];
  19880. data.curves.push(curve.toJSON());
  19881. }
  19882. return data;
  19883. },
  19884. fromJSON: function (json) {
  19885. Curve.prototype.fromJSON.call(this, json);
  19886. this.autoClose = json.autoClose;
  19887. this.curves = [];
  19888. for (var i = 0, l = json.curves.length; i < l; i++) {
  19889. var curve = json.curves[i];
  19890. this.curves.push(new Curves[curve.type]().fromJSON(curve));
  19891. }
  19892. return this;
  19893. }
  19894. });
  19895. /**
  19896. * @author zz85 / http://www.lab4games.net/zz85/blog
  19897. * Creates free form 2d path using series of points, lines or curves.
  19898. **/
  19899. function Path(points) {
  19900. CurvePath.call(this);
  19901. this.type = 'Path';
  19902. this.currentPoint = new Vector2();
  19903. if (points) {
  19904. this.setFromPoints(points);
  19905. }
  19906. }
  19907. Path.prototype = Object.assign(Object.create(CurvePath.prototype), {
  19908. constructor: Path,
  19909. setFromPoints: function (points) {
  19910. this.moveTo(points[0].x, points[0].y);
  19911. for (var i = 1, l = points.length; i < l; i++) {
  19912. this.lineTo(points[i].x, points[i].y);
  19913. }
  19914. },
  19915. moveTo: function (x, y) {
  19916. this.currentPoint.set(x, y); // TODO consider referencing vectors instead of copying?
  19917. },
  19918. lineTo: function (x, y) {
  19919. var curve = new LineCurve(this.currentPoint.clone(), new Vector2(x, y));
  19920. this.curves.push(curve);
  19921. this.currentPoint.set(x, y);
  19922. },
  19923. quadraticCurveTo: function (aCPx, aCPy, aX, aY) {
  19924. var curve = new QuadraticBezierCurve(this.currentPoint.clone(), new Vector2(aCPx, aCPy), new Vector2(aX, aY));
  19925. this.curves.push(curve);
  19926. this.currentPoint.set(aX, aY);
  19927. },
  19928. bezierCurveTo: function (aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) {
  19929. var curve = new CubicBezierCurve(this.currentPoint.clone(), new Vector2(aCP1x, aCP1y), new Vector2(aCP2x, aCP2y), new Vector2(aX, aY));
  19930. this.curves.push(curve);
  19931. this.currentPoint.set(aX, aY);
  19932. },
  19933. splineThru: function (pts /*Array of Vector*/) {
  19934. var npts = [this.currentPoint.clone()].concat(pts);
  19935. var curve = new SplineCurve(npts);
  19936. this.curves.push(curve);
  19937. this.currentPoint.copy(pts[pts.length - 1]);
  19938. },
  19939. arc: function (aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) {
  19940. var x0 = this.currentPoint.x;
  19941. var y0 = this.currentPoint.y;
  19942. this.absarc(aX + x0, aY + y0, aRadius, aStartAngle, aEndAngle, aClockwise);
  19943. },
  19944. absarc: function (aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) {
  19945. this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
  19946. },
  19947. ellipse: function (aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) {
  19948. var x0 = this.currentPoint.x;
  19949. var y0 = this.currentPoint.y;
  19950. this.absellipse(aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);
  19951. },
  19952. absellipse: function (aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) {
  19953. var curve = new EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);
  19954. if (this.curves.length > 0) {
  19955. // if a previous curve is present, attempt to join
  19956. var firstPoint = curve.getPoint(0);
  19957. if (!firstPoint.equals(this.currentPoint)) {
  19958. this.lineTo(firstPoint.x, firstPoint.y);
  19959. }
  19960. }
  19961. this.curves.push(curve);
  19962. var lastPoint = curve.getPoint(1);
  19963. this.currentPoint.copy(lastPoint);
  19964. },
  19965. copy: function (source) {
  19966. CurvePath.prototype.copy.call(this, source);
  19967. this.currentPoint.copy(source.currentPoint);
  19968. return this;
  19969. },
  19970. toJSON: function () {
  19971. var data = CurvePath.prototype.toJSON.call(this);
  19972. data.currentPoint = this.currentPoint.toArray();
  19973. return data;
  19974. },
  19975. fromJSON: function (json) {
  19976. CurvePath.prototype.fromJSON.call(this, json);
  19977. this.currentPoint.fromArray(json.currentPoint);
  19978. return this;
  19979. }
  19980. });
  19981. /**
  19982. * @author zz85 / http://www.lab4games.net/zz85/blog
  19983. * Defines a 2d shape plane using paths.
  19984. **/
  19985. // STEP 1 Create a path.
  19986. // STEP 2 Turn path into shape.
  19987. // STEP 3 ExtrudeGeometry takes in Shape/Shapes
  19988. // STEP 3a - Extract points from each shape, turn to vertices
  19989. // STEP 3b - Triangulate each shape, add faces.
  19990. function Shape(points) {
  19991. Path.call(this, points);
  19992. this.uuid = _Math.generateUUID();
  19993. this.type = 'Shape';
  19994. this.holes = [];
  19995. }
  19996. Shape.prototype = Object.assign(Object.create(Path.prototype), {
  19997. constructor: Shape,
  19998. getPointsHoles: function (divisions) {
  19999. var holesPts = [];
  20000. for (var i = 0, l = this.holes.length; i < l; i++) {
  20001. holesPts[i] = this.holes[i].getPoints(divisions);
  20002. }
  20003. return holesPts;
  20004. },
  20005. // get points of shape and holes (keypoints based on segments parameter)
  20006. extractPoints: function (divisions) {
  20007. return {
  20008. shape: this.getPoints(divisions),
  20009. holes: this.getPointsHoles(divisions)
  20010. };
  20011. },
  20012. copy: function (source) {
  20013. Path.prototype.copy.call(this, source);
  20014. this.holes = [];
  20015. for (var i = 0, l = source.holes.length; i < l; i++) {
  20016. var hole = source.holes[i];
  20017. this.holes.push(hole.clone());
  20018. }
  20019. return this;
  20020. },
  20021. toJSON: function () {
  20022. var data = Path.prototype.toJSON.call(this);
  20023. data.uuid = this.uuid;
  20024. data.holes = [];
  20025. for (var i = 0, l = this.holes.length; i < l; i++) {
  20026. var hole = this.holes[i];
  20027. data.holes.push(hole.toJSON());
  20028. }
  20029. return data;
  20030. },
  20031. fromJSON: function (json) {
  20032. Path.prototype.fromJSON.call(this, json);
  20033. this.uuid = json.uuid;
  20034. this.holes = [];
  20035. for (var i = 0, l = json.holes.length; i < l; i++) {
  20036. var hole = json.holes[i];
  20037. this.holes.push(new Path().fromJSON(hole));
  20038. }
  20039. return this;
  20040. }
  20041. });
  20042. /**
  20043. * @author mrdoob / http://mrdoob.com/
  20044. * @author alteredq / http://alteredqualia.com/
  20045. */
  20046. function Light(color, intensity) {
  20047. Object3D.call(this);
  20048. this.type = 'Light';
  20049. this.color = new Color(color);
  20050. this.intensity = intensity !== undefined ? intensity : 1;
  20051. this.receiveShadow = undefined;
  20052. }
  20053. Light.prototype = Object.assign(Object.create(Object3D.prototype), {
  20054. constructor: Light,
  20055. isLight: true,
  20056. copy: function (source) {
  20057. Object3D.prototype.copy.call(this, source);
  20058. this.color.copy(source.color);
  20059. this.intensity = source.intensity;
  20060. return this;
  20061. },
  20062. toJSON: function (meta) {
  20063. var data = Object3D.prototype.toJSON.call(this, meta);
  20064. data.object.color = this.color.getHex();
  20065. data.object.intensity = this.intensity;
  20066. if (this.groundColor !== undefined) data.object.groundColor = this.groundColor.getHex();
  20067. if (this.distance !== undefined) data.object.distance = this.distance;
  20068. if (this.angle !== undefined) data.object.angle = this.angle;
  20069. if (this.decay !== undefined) data.object.decay = this.decay;
  20070. if (this.penumbra !== undefined) data.object.penumbra = this.penumbra;
  20071. if (this.shadow !== undefined) data.object.shadow = this.shadow.toJSON();
  20072. return data;
  20073. }
  20074. });
  20075. /**
  20076. * @author alteredq / http://alteredqualia.com/
  20077. */
  20078. function HemisphereLight(skyColor, groundColor, intensity) {
  20079. Light.call(this, skyColor, intensity);
  20080. this.type = 'HemisphereLight';
  20081. this.castShadow = undefined;
  20082. this.position.copy(Object3D.DefaultUp);
  20083. this.updateMatrix();
  20084. this.groundColor = new Color(groundColor);
  20085. }
  20086. HemisphereLight.prototype = Object.assign(Object.create(Light.prototype), {
  20087. constructor: HemisphereLight,
  20088. isHemisphereLight: true,
  20089. copy: function (source) {
  20090. Light.prototype.copy.call(this, source);
  20091. this.groundColor.copy(source.groundColor);
  20092. return this;
  20093. }
  20094. });
  20095. /**
  20096. * @author mrdoob / http://mrdoob.com/
  20097. */
  20098. function LightShadow(camera) {
  20099. this.camera = camera;
  20100. this.bias = 0;
  20101. this.radius = 1;
  20102. this.mapSize = new Vector2(512, 512);
  20103. this.map = null;
  20104. this.matrix = new Matrix4();
  20105. }
  20106. Object.assign(LightShadow.prototype, {
  20107. copy: function (source) {
  20108. this.camera = source.camera.clone();
  20109. this.bias = source.bias;
  20110. this.radius = source.radius;
  20111. this.mapSize.copy(source.mapSize);
  20112. return this;
  20113. },
  20114. clone: function () {
  20115. return new this.constructor().copy(this);
  20116. },
  20117. toJSON: function () {
  20118. var object = {};
  20119. if (this.bias !== 0) object.bias = this.bias;
  20120. if (this.radius !== 1) object.radius = this.radius;
  20121. if (this.mapSize.x !== 512 || this.mapSize.y !== 512) object.mapSize = this.mapSize.toArray();
  20122. object.camera = this.camera.toJSON(false).object;
  20123. delete object.camera.matrix;
  20124. return object;
  20125. }
  20126. });
  20127. /**
  20128. * @author mrdoob / http://mrdoob.com/
  20129. */
  20130. function SpotLightShadow() {
  20131. LightShadow.call(this, new PerspectiveCamera(50, 1, 0.5, 500));
  20132. }
  20133. SpotLightShadow.prototype = Object.assign(Object.create(LightShadow.prototype), {
  20134. constructor: SpotLightShadow,
  20135. isSpotLightShadow: true,
  20136. update: function (light) {
  20137. var camera = this.camera;
  20138. var fov = _Math.RAD2DEG * 2 * light.angle;
  20139. var aspect = this.mapSize.width / this.mapSize.height;
  20140. var far = light.distance || camera.far;
  20141. if (fov !== camera.fov || aspect !== camera.aspect || far !== camera.far) {
  20142. camera.fov = fov;
  20143. camera.aspect = aspect;
  20144. camera.far = far;
  20145. camera.updateProjectionMatrix();
  20146. }
  20147. }
  20148. });
  20149. /**
  20150. * @author alteredq / http://alteredqualia.com/
  20151. */
  20152. function SpotLight(color, intensity, distance, angle, penumbra, decay) {
  20153. Light.call(this, color, intensity);
  20154. this.type = 'SpotLight';
  20155. this.position.copy(Object3D.DefaultUp);
  20156. this.updateMatrix();
  20157. this.target = new Object3D();
  20158. Object.defineProperty(this, 'power', {
  20159. get: function () {
  20160. // intensity = power per solid angle.
  20161. // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  20162. return this.intensity * Math.PI;
  20163. },
  20164. set: function (power) {
  20165. // intensity = power per solid angle.
  20166. // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  20167. this.intensity = power / Math.PI;
  20168. }
  20169. });
  20170. this.distance = distance !== undefined ? distance : 0;
  20171. this.angle = angle !== undefined ? angle : Math.PI / 3;
  20172. this.penumbra = penumbra !== undefined ? penumbra : 0;
  20173. this.decay = decay !== undefined ? decay : 1; // for physically correct lights, should be 2.
  20174. this.shadow = new SpotLightShadow();
  20175. }
  20176. SpotLight.prototype = Object.assign(Object.create(Light.prototype), {
  20177. constructor: SpotLight,
  20178. isSpotLight: true,
  20179. copy: function (source) {
  20180. Light.prototype.copy.call(this, source);
  20181. this.distance = source.distance;
  20182. this.angle = source.angle;
  20183. this.penumbra = source.penumbra;
  20184. this.decay = source.decay;
  20185. this.target = source.target.clone();
  20186. this.shadow = source.shadow.clone();
  20187. return this;
  20188. }
  20189. });
  20190. /**
  20191. * @author mrdoob / http://mrdoob.com/
  20192. */
  20193. function PointLight(color, intensity, distance, decay) {
  20194. Light.call(this, color, intensity);
  20195. this.type = 'PointLight';
  20196. Object.defineProperty(this, 'power', {
  20197. get: function () {
  20198. // intensity = power per solid angle.
  20199. // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  20200. return this.intensity * 4 * Math.PI;
  20201. },
  20202. set: function (power) {
  20203. // intensity = power per solid angle.
  20204. // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
  20205. this.intensity = power / (4 * Math.PI);
  20206. }
  20207. });
  20208. this.distance = distance !== undefined ? distance : 0;
  20209. this.decay = decay !== undefined ? decay : 1; // for physically correct lights, should be 2.
  20210. this.shadow = new LightShadow(new PerspectiveCamera(90, 1, 0.5, 500));
  20211. }
  20212. PointLight.prototype = Object.assign(Object.create(Light.prototype), {
  20213. constructor: PointLight,
  20214. isPointLight: true,
  20215. copy: function (source) {
  20216. Light.prototype.copy.call(this, source);
  20217. this.distance = source.distance;
  20218. this.decay = source.decay;
  20219. this.shadow = source.shadow.clone();
  20220. return this;
  20221. }
  20222. });
  20223. /**
  20224. * @author mrdoob / http://mrdoob.com/
  20225. */
  20226. function DirectionalLightShadow() {
  20227. LightShadow.call(this, new OrthographicCamera(-5, 5, 5, -5, 0.5, 500));
  20228. }
  20229. DirectionalLightShadow.prototype = Object.assign(Object.create(LightShadow.prototype), {
  20230. constructor: DirectionalLightShadow
  20231. });
  20232. /**
  20233. * @author mrdoob / http://mrdoob.com/
  20234. * @author alteredq / http://alteredqualia.com/
  20235. */
  20236. function DirectionalLight(color, intensity) {
  20237. Light.call(this, color, intensity);
  20238. this.type = 'DirectionalLight';
  20239. this.position.copy(Object3D.DefaultUp);
  20240. this.updateMatrix();
  20241. this.target = new Object3D();
  20242. this.shadow = new DirectionalLightShadow();
  20243. }
  20244. DirectionalLight.prototype = Object.assign(Object.create(Light.prototype), {
  20245. constructor: DirectionalLight,
  20246. isDirectionalLight: true,
  20247. copy: function (source) {
  20248. Light.prototype.copy.call(this, source);
  20249. this.target = source.target.clone();
  20250. this.shadow = source.shadow.clone();
  20251. return this;
  20252. }
  20253. });
  20254. /**
  20255. * @author mrdoob / http://mrdoob.com/
  20256. */
  20257. function AmbientLight(color, intensity) {
  20258. Light.call(this, color, intensity);
  20259. this.type = 'AmbientLight';
  20260. this.castShadow = undefined;
  20261. }
  20262. AmbientLight.prototype = Object.assign(Object.create(Light.prototype), {
  20263. constructor: AmbientLight,
  20264. isAmbientLight: true
  20265. });
  20266. /**
  20267. * @author abelnation / http://github.com/abelnation
  20268. */
  20269. function RectAreaLight(color, intensity, width, height) {
  20270. Light.call(this, color, intensity);
  20271. this.type = 'RectAreaLight';
  20272. this.width = width !== undefined ? width : 10;
  20273. this.height = height !== undefined ? height : 10;
  20274. }
  20275. RectAreaLight.prototype = Object.assign(Object.create(Light.prototype), {
  20276. constructor: RectAreaLight,
  20277. isRectAreaLight: true,
  20278. copy: function (source) {
  20279. Light.prototype.copy.call(this, source);
  20280. this.width = source.width;
  20281. this.height = source.height;
  20282. return this;
  20283. },
  20284. toJSON: function (meta) {
  20285. var data = Light.prototype.toJSON.call(this, meta);
  20286. data.object.width = this.width;
  20287. data.object.height = this.height;
  20288. return data;
  20289. }
  20290. });
  20291. /**
  20292. *
  20293. * A Track that interpolates Strings
  20294. *
  20295. *
  20296. * @author Ben Houston / http://clara.io/
  20297. * @author David Sarno / http://lighthaus.us/
  20298. * @author tschw
  20299. */
  20300. function StringKeyframeTrack(name, times, values, interpolation) {
  20301. KeyframeTrack.call(this, name, times, values, interpolation);
  20302. }
  20303. StringKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  20304. constructor: StringKeyframeTrack,
  20305. ValueTypeName: 'string',
  20306. ValueBufferType: Array,
  20307. DefaultInterpolation: InterpolateDiscrete,
  20308. InterpolantFactoryMethodLinear: undefined,
  20309. InterpolantFactoryMethodSmooth: undefined
  20310. });
  20311. /**
  20312. *
  20313. * A Track of Boolean keyframe values.
  20314. *
  20315. *
  20316. * @author Ben Houston / http://clara.io/
  20317. * @author David Sarno / http://lighthaus.us/
  20318. * @author tschw
  20319. */
  20320. function BooleanKeyframeTrack(name, times, values) {
  20321. KeyframeTrack.call(this, name, times, values);
  20322. }
  20323. BooleanKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  20324. constructor: BooleanKeyframeTrack,
  20325. ValueTypeName: 'bool',
  20326. ValueBufferType: Array,
  20327. DefaultInterpolation: InterpolateDiscrete,
  20328. InterpolantFactoryMethodLinear: undefined,
  20329. InterpolantFactoryMethodSmooth: undefined
  20330. // Note: Actually this track could have a optimized / compressed
  20331. // representation of a single value and a custom interpolant that
  20332. // computes "firstValue ^ isOdd( index )".
  20333. });
  20334. /**
  20335. * Abstract base class of interpolants over parametric samples.
  20336. *
  20337. * The parameter domain is one dimensional, typically the time or a path
  20338. * along a curve defined by the data.
  20339. *
  20340. * The sample values can have any dimensionality and derived classes may
  20341. * apply special interpretations to the data.
  20342. *
  20343. * This class provides the interval seek in a Template Method, deferring
  20344. * the actual interpolation to derived classes.
  20345. *
  20346. * Time complexity is O(1) for linear access crossing at most two points
  20347. * and O(log N) for random access, where N is the number of positions.
  20348. *
  20349. * References:
  20350. *
  20351. * http://www.oodesign.com/template-method-pattern.html
  20352. *
  20353. * @author tschw
  20354. */
  20355. function Interpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
  20356. this.parameterPositions = parameterPositions;
  20357. this._cachedIndex = 0;
  20358. this.resultBuffer = resultBuffer !== undefined ? resultBuffer : new sampleValues.constructor(sampleSize);
  20359. this.sampleValues = sampleValues;
  20360. this.valueSize = sampleSize;
  20361. }
  20362. Object.assign(Interpolant.prototype, {
  20363. evaluate: function (t) {
  20364. var pp = this.parameterPositions,
  20365. i1 = this._cachedIndex,
  20366. t1 = pp[i1],
  20367. t0 = pp[i1 - 1];
  20368. validate_interval: {
  20369. seek: {
  20370. var right;
  20371. linear_scan: {
  20372. //- See http://jsperf.com/comparison-to-undefined/3
  20373. //- slower code:
  20374. //-
  20375. //- if ( t >= t1 || t1 === undefined ) {
  20376. forward_scan: if (!(t < t1)) {
  20377. for (var giveUpAt = i1 + 2;;) {
  20378. if (t1 === undefined) {
  20379. if (t < t0) break forward_scan;
  20380. // after end
  20381. i1 = pp.length;
  20382. this._cachedIndex = i1;
  20383. return this.afterEnd_(i1 - 1, t, t0);
  20384. }
  20385. if (i1 === giveUpAt) break; // this loop
  20386. t0 = t1;
  20387. t1 = pp[++i1];
  20388. if (t < t1) {
  20389. // we have arrived at the sought interval
  20390. break seek;
  20391. }
  20392. }
  20393. // prepare binary search on the right side of the index
  20394. right = pp.length;
  20395. break linear_scan;
  20396. }
  20397. //- slower code:
  20398. //- if ( t < t0 || t0 === undefined ) {
  20399. if (!(t >= t0)) {
  20400. // looping?
  20401. var t1global = pp[1];
  20402. if (t < t1global) {
  20403. i1 = 2; // + 1, using the scan for the details
  20404. t0 = t1global;
  20405. }
  20406. // linear reverse scan
  20407. for (var giveUpAt = i1 - 2;;) {
  20408. if (t0 === undefined) {
  20409. // before start
  20410. this._cachedIndex = 0;
  20411. return this.beforeStart_(0, t, t1);
  20412. }
  20413. if (i1 === giveUpAt) break; // this loop
  20414. t1 = t0;
  20415. t0 = pp[--i1 - 1];
  20416. if (t >= t0) {
  20417. // we have arrived at the sought interval
  20418. break seek;
  20419. }
  20420. }
  20421. // prepare binary search on the left side of the index
  20422. right = i1;
  20423. i1 = 0;
  20424. break linear_scan;
  20425. }
  20426. // the interval is valid
  20427. break validate_interval;
  20428. } // linear scan
  20429. // binary search
  20430. while (i1 < right) {
  20431. var mid = i1 + right >>> 1;
  20432. if (t < pp[mid]) {
  20433. right = mid;
  20434. } else {
  20435. i1 = mid + 1;
  20436. }
  20437. }
  20438. t1 = pp[i1];
  20439. t0 = pp[i1 - 1];
  20440. // check boundary cases, again
  20441. if (t0 === undefined) {
  20442. this._cachedIndex = 0;
  20443. return this.beforeStart_(0, t, t1);
  20444. }
  20445. if (t1 === undefined) {
  20446. i1 = pp.length;
  20447. this._cachedIndex = i1;
  20448. return this.afterEnd_(i1 - 1, t0, t);
  20449. }
  20450. } // seek
  20451. this._cachedIndex = i1;
  20452. this.intervalChanged_(i1, t0, t1);
  20453. } // validate_interval
  20454. return this.interpolate_(i1, t0, t, t1);
  20455. },
  20456. settings: null, // optional, subclass-specific settings structure
  20457. // Note: The indirection allows central control of many interpolants.
  20458. // --- Protected interface
  20459. DefaultSettings_: {},
  20460. getSettings_: function () {
  20461. return this.settings || this.DefaultSettings_;
  20462. },
  20463. copySampleValue_: function (index) {
  20464. // copies a sample value to the result buffer
  20465. var result = this.resultBuffer,
  20466. values = this.sampleValues,
  20467. stride = this.valueSize,
  20468. offset = index * stride;
  20469. for (var i = 0; i !== stride; ++i) {
  20470. result[i] = values[offset + i];
  20471. }
  20472. return result;
  20473. },
  20474. // Template methods for derived classes:
  20475. interpolate_: function () /* i1, t0, t, t1 */{
  20476. throw new Error('call to abstract method');
  20477. // implementations shall return this.resultBuffer
  20478. },
  20479. intervalChanged_: function () /* i1, t0, t1 */{
  20480. // empty
  20481. }
  20482. });
  20483. //!\ DECLARE ALIAS AFTER assign prototype !
  20484. Object.assign(Interpolant.prototype, {
  20485. //( 0, t, t0 ), returns this.resultBuffer
  20486. beforeStart_: Interpolant.prototype.copySampleValue_,
  20487. //( N-1, tN-1, t ), returns this.resultBuffer
  20488. afterEnd_: Interpolant.prototype.copySampleValue_
  20489. });
  20490. /**
  20491. * Spherical linear unit quaternion interpolant.
  20492. *
  20493. * @author tschw
  20494. */
  20495. function QuaternionLinearInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
  20496. Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
  20497. }
  20498. QuaternionLinearInterpolant.prototype = Object.assign(Object.create(Interpolant.prototype), {
  20499. constructor: QuaternionLinearInterpolant,
  20500. interpolate_: function (i1, t0, t, t1) {
  20501. var result = this.resultBuffer,
  20502. values = this.sampleValues,
  20503. stride = this.valueSize,
  20504. offset = i1 * stride,
  20505. alpha = (t - t0) / (t1 - t0);
  20506. for (var end = offset + stride; offset !== end; offset += 4) {
  20507. Quaternion.slerpFlat(result, 0, values, offset - stride, values, offset, alpha);
  20508. }
  20509. return result;
  20510. }
  20511. });
  20512. /**
  20513. *
  20514. * A Track of quaternion keyframe values.
  20515. *
  20516. * @author Ben Houston / http://clara.io/
  20517. * @author David Sarno / http://lighthaus.us/
  20518. * @author tschw
  20519. */
  20520. function QuaternionKeyframeTrack(name, times, values, interpolation) {
  20521. KeyframeTrack.call(this, name, times, values, interpolation);
  20522. }
  20523. QuaternionKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  20524. constructor: QuaternionKeyframeTrack,
  20525. ValueTypeName: 'quaternion',
  20526. // ValueBufferType is inherited
  20527. DefaultInterpolation: InterpolateLinear,
  20528. InterpolantFactoryMethodLinear: function (result) {
  20529. return new QuaternionLinearInterpolant(this.times, this.values, this.getValueSize(), result);
  20530. },
  20531. InterpolantFactoryMethodSmooth: undefined // not yet implemented
  20532. });
  20533. /**
  20534. *
  20535. * A Track of keyframe values that represent color.
  20536. *
  20537. *
  20538. * @author Ben Houston / http://clara.io/
  20539. * @author David Sarno / http://lighthaus.us/
  20540. * @author tschw
  20541. */
  20542. function ColorKeyframeTrack(name, times, values, interpolation) {
  20543. KeyframeTrack.call(this, name, times, values, interpolation);
  20544. }
  20545. ColorKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  20546. constructor: ColorKeyframeTrack,
  20547. ValueTypeName: 'color'
  20548. // ValueBufferType is inherited
  20549. // DefaultInterpolation is inherited
  20550. // Note: Very basic implementation and nothing special yet.
  20551. // However, this is the place for color space parameterization.
  20552. });
  20553. /**
  20554. *
  20555. * A Track of numeric keyframe values.
  20556. *
  20557. * @author Ben Houston / http://clara.io/
  20558. * @author David Sarno / http://lighthaus.us/
  20559. * @author tschw
  20560. */
  20561. function NumberKeyframeTrack(name, times, values, interpolation) {
  20562. KeyframeTrack.call(this, name, times, values, interpolation);
  20563. }
  20564. NumberKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  20565. constructor: NumberKeyframeTrack,
  20566. ValueTypeName: 'number'
  20567. // ValueBufferType is inherited
  20568. // DefaultInterpolation is inherited
  20569. });
  20570. /**
  20571. * Fast and simple cubic spline interpolant.
  20572. *
  20573. * It was derived from a Hermitian construction setting the first derivative
  20574. * at each sample position to the linear slope between neighboring positions
  20575. * over their parameter interval.
  20576. *
  20577. * @author tschw
  20578. */
  20579. function CubicInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
  20580. Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
  20581. this._weightPrev = -0;
  20582. this._offsetPrev = -0;
  20583. this._weightNext = -0;
  20584. this._offsetNext = -0;
  20585. }
  20586. CubicInterpolant.prototype = Object.assign(Object.create(Interpolant.prototype), {
  20587. constructor: CubicInterpolant,
  20588. DefaultSettings_: {
  20589. endingStart: ZeroCurvatureEnding,
  20590. endingEnd: ZeroCurvatureEnding
  20591. },
  20592. intervalChanged_: function (i1, t0, t1) {
  20593. var pp = this.parameterPositions,
  20594. iPrev = i1 - 2,
  20595. iNext = i1 + 1,
  20596. tPrev = pp[iPrev],
  20597. tNext = pp[iNext];
  20598. if (tPrev === undefined) {
  20599. switch (this.getSettings_().endingStart) {
  20600. case ZeroSlopeEnding:
  20601. // f'(t0) = 0
  20602. iPrev = i1;
  20603. tPrev = 2 * t0 - t1;
  20604. break;
  20605. case WrapAroundEnding:
  20606. // use the other end of the curve
  20607. iPrev = pp.length - 2;
  20608. tPrev = t0 + pp[iPrev] - pp[iPrev + 1];
  20609. break;
  20610. default:
  20611. // ZeroCurvatureEnding
  20612. // f''(t0) = 0 a.k.a. Natural Spline
  20613. iPrev = i1;
  20614. tPrev = t1;
  20615. }
  20616. }
  20617. if (tNext === undefined) {
  20618. switch (this.getSettings_().endingEnd) {
  20619. case ZeroSlopeEnding:
  20620. // f'(tN) = 0
  20621. iNext = i1;
  20622. tNext = 2 * t1 - t0;
  20623. break;
  20624. case WrapAroundEnding:
  20625. // use the other end of the curve
  20626. iNext = 1;
  20627. tNext = t1 + pp[1] - pp[0];
  20628. break;
  20629. default:
  20630. // ZeroCurvatureEnding
  20631. // f''(tN) = 0, a.k.a. Natural Spline
  20632. iNext = i1 - 1;
  20633. tNext = t0;
  20634. }
  20635. }
  20636. var halfDt = (t1 - t0) * 0.5,
  20637. stride = this.valueSize;
  20638. this._weightPrev = halfDt / (t0 - tPrev);
  20639. this._weightNext = halfDt / (tNext - t1);
  20640. this._offsetPrev = iPrev * stride;
  20641. this._offsetNext = iNext * stride;
  20642. },
  20643. interpolate_: function (i1, t0, t, t1) {
  20644. var result = this.resultBuffer,
  20645. values = this.sampleValues,
  20646. stride = this.valueSize,
  20647. o1 = i1 * stride,
  20648. o0 = o1 - stride,
  20649. oP = this._offsetPrev,
  20650. oN = this._offsetNext,
  20651. wP = this._weightPrev,
  20652. wN = this._weightNext,
  20653. p = (t - t0) / (t1 - t0),
  20654. pp = p * p,
  20655. ppp = pp * p;
  20656. // evaluate polynomials
  20657. var sP = -wP * ppp + 2 * wP * pp - wP * p;
  20658. var s0 = (1 + wP) * ppp + (-1.5 - 2 * wP) * pp + (-0.5 + wP) * p + 1;
  20659. var s1 = (-1 - wN) * ppp + (1.5 + wN) * pp + 0.5 * p;
  20660. var sN = wN * ppp - wN * pp;
  20661. // combine data linearly
  20662. for (var i = 0; i !== stride; ++i) {
  20663. result[i] = sP * values[oP + i] + s0 * values[o0 + i] + s1 * values[o1 + i] + sN * values[oN + i];
  20664. }
  20665. return result;
  20666. }
  20667. });
  20668. /**
  20669. * @author tschw
  20670. */
  20671. function LinearInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
  20672. Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
  20673. }
  20674. LinearInterpolant.prototype = Object.assign(Object.create(Interpolant.prototype), {
  20675. constructor: LinearInterpolant,
  20676. interpolate_: function (i1, t0, t, t1) {
  20677. var result = this.resultBuffer,
  20678. values = this.sampleValues,
  20679. stride = this.valueSize,
  20680. offset1 = i1 * stride,
  20681. offset0 = offset1 - stride,
  20682. weight1 = (t - t0) / (t1 - t0),
  20683. weight0 = 1 - weight1;
  20684. for (var i = 0; i !== stride; ++i) {
  20685. result[i] = values[offset0 + i] * weight0 + values[offset1 + i] * weight1;
  20686. }
  20687. return result;
  20688. }
  20689. });
  20690. /**
  20691. *
  20692. * Interpolant that evaluates to the sample value at the position preceeding
  20693. * the parameter.
  20694. *
  20695. * @author tschw
  20696. */
  20697. function DiscreteInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {
  20698. Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
  20699. }
  20700. DiscreteInterpolant.prototype = Object.assign(Object.create(Interpolant.prototype), {
  20701. constructor: DiscreteInterpolant,
  20702. interpolate_: function (i1 /*, t0, t, t1 */) {
  20703. return this.copySampleValue_(i1 - 1);
  20704. }
  20705. });
  20706. /**
  20707. * @author tschw
  20708. * @author Ben Houston / http://clara.io/
  20709. * @author David Sarno / http://lighthaus.us/
  20710. */
  20711. var AnimationUtils = {
  20712. // same as Array.prototype.slice, but also works on typed arrays
  20713. arraySlice: function (array, from, to) {
  20714. if (AnimationUtils.isTypedArray(array)) {
  20715. // in ios9 array.subarray(from, undefined) will return empty array
  20716. // but array.subarray(from) or array.subarray(from, len) is correct
  20717. return new array.constructor(array.subarray(from, to !== undefined ? to : array.length));
  20718. }
  20719. return array.slice(from, to);
  20720. },
  20721. // converts an array to a specific type
  20722. convertArray: function (array, type, forceClone) {
  20723. if (!array || // let 'undefined' and 'null' pass
  20724. !forceClone && array.constructor === type) return array;
  20725. if (typeof type.BYTES_PER_ELEMENT === 'number') {
  20726. return new type(array); // create typed array
  20727. }
  20728. return Array.prototype.slice.call(array); // create Array
  20729. },
  20730. isTypedArray: function (object) {
  20731. return ArrayBuffer.isView(object) && !(object instanceof DataView);
  20732. },
  20733. // returns an array by which times and values can be sorted
  20734. getKeyframeOrder: function (times) {
  20735. function compareTime(i, j) {
  20736. return times[i] - times[j];
  20737. }
  20738. var n = times.length;
  20739. var result = new Array(n);
  20740. for (var i = 0; i !== n; ++i) result[i] = i;
  20741. result.sort(compareTime);
  20742. return result;
  20743. },
  20744. // uses the array previously returned by 'getKeyframeOrder' to sort data
  20745. sortedArray: function (values, stride, order) {
  20746. var nValues = values.length;
  20747. var result = new values.constructor(nValues);
  20748. for (var i = 0, dstOffset = 0; dstOffset !== nValues; ++i) {
  20749. var srcOffset = order[i] * stride;
  20750. for (var j = 0; j !== stride; ++j) {
  20751. result[dstOffset++] = values[srcOffset + j];
  20752. }
  20753. }
  20754. return result;
  20755. },
  20756. // function for parsing AOS keyframe formats
  20757. flattenJSON: function (jsonKeys, times, values, valuePropertyName) {
  20758. var i = 1,
  20759. key = jsonKeys[0];
  20760. while (key !== undefined && key[valuePropertyName] === undefined) {
  20761. key = jsonKeys[i++];
  20762. }
  20763. if (key === undefined) return; // no data
  20764. var value = key[valuePropertyName];
  20765. if (value === undefined) return; // no data
  20766. if (Array.isArray(value)) {
  20767. do {
  20768. value = key[valuePropertyName];
  20769. if (value !== undefined) {
  20770. times.push(key.time);
  20771. values.push.apply(values, value); // push all elements
  20772. }
  20773. key = jsonKeys[i++];
  20774. } while (key !== undefined);
  20775. } else if (value.toArray !== undefined) {
  20776. // ...assume THREE.Math-ish
  20777. do {
  20778. value = key[valuePropertyName];
  20779. if (value !== undefined) {
  20780. times.push(key.time);
  20781. value.toArray(values, values.length);
  20782. }
  20783. key = jsonKeys[i++];
  20784. } while (key !== undefined);
  20785. } else {
  20786. // otherwise push as-is
  20787. do {
  20788. value = key[valuePropertyName];
  20789. if (value !== undefined) {
  20790. times.push(key.time);
  20791. values.push(value);
  20792. }
  20793. key = jsonKeys[i++];
  20794. } while (key !== undefined);
  20795. }
  20796. }
  20797. };
  20798. /**
  20799. *
  20800. * A timed sequence of keyframes for a specific property.
  20801. *
  20802. *
  20803. * @author Ben Houston / http://clara.io/
  20804. * @author David Sarno / http://lighthaus.us/
  20805. * @author tschw
  20806. */
  20807. function KeyframeTrack(name, times, values, interpolation) {
  20808. if (name === undefined) throw new Error('THREE.KeyframeTrack: track name is undefined');
  20809. if (times === undefined || times.length === 0) throw new Error('THREE.KeyframeTrack: no keyframes in track named ' + name);
  20810. this.name = name;
  20811. this.times = AnimationUtils.convertArray(times, this.TimeBufferType);
  20812. this.values = AnimationUtils.convertArray(values, this.ValueBufferType);
  20813. this.setInterpolation(interpolation || this.DefaultInterpolation);
  20814. this.validate();
  20815. this.optimize();
  20816. }
  20817. // Static methods:
  20818. Object.assign(KeyframeTrack, {
  20819. // Serialization (in static context, because of constructor invocation
  20820. // and automatic invocation of .toJSON):
  20821. parse: function (json) {
  20822. if (json.type === undefined) {
  20823. throw new Error('THREE.KeyframeTrack: track type undefined, can not parse');
  20824. }
  20825. var trackType = KeyframeTrack._getTrackTypeForValueTypeName(json.type);
  20826. if (json.times === undefined) {
  20827. var times = [],
  20828. values = [];
  20829. AnimationUtils.flattenJSON(json.keys, times, values, 'value');
  20830. json.times = times;
  20831. json.values = values;
  20832. }
  20833. // derived classes can define a static parse method
  20834. if (trackType.parse !== undefined) {
  20835. return trackType.parse(json);
  20836. } else {
  20837. // by default, we assume a constructor compatible with the base
  20838. return new trackType(json.name, json.times, json.values, json.interpolation);
  20839. }
  20840. },
  20841. toJSON: function (track) {
  20842. var trackType = track.constructor;
  20843. var json;
  20844. // derived classes can define a static toJSON method
  20845. if (trackType.toJSON !== undefined) {
  20846. json = trackType.toJSON(track);
  20847. } else {
  20848. // by default, we assume the data can be serialized as-is
  20849. json = {
  20850. 'name': track.name,
  20851. 'times': AnimationUtils.convertArray(track.times, Array),
  20852. 'values': AnimationUtils.convertArray(track.values, Array)
  20853. };
  20854. var interpolation = track.getInterpolation();
  20855. if (interpolation !== track.DefaultInterpolation) {
  20856. json.interpolation = interpolation;
  20857. }
  20858. }
  20859. json.type = track.ValueTypeName; // mandatory
  20860. return json;
  20861. },
  20862. _getTrackTypeForValueTypeName: function (typeName) {
  20863. switch (typeName.toLowerCase()) {
  20864. case 'scalar':
  20865. case 'double':
  20866. case 'float':
  20867. case 'number':
  20868. case 'integer':
  20869. return NumberKeyframeTrack;
  20870. case 'vector':
  20871. case 'vector2':
  20872. case 'vector3':
  20873. case 'vector4':
  20874. return VectorKeyframeTrack;
  20875. case 'color':
  20876. return ColorKeyframeTrack;
  20877. case 'quaternion':
  20878. return QuaternionKeyframeTrack;
  20879. case 'bool':
  20880. case 'boolean':
  20881. return BooleanKeyframeTrack;
  20882. case 'string':
  20883. return StringKeyframeTrack;
  20884. }
  20885. throw new Error('THREE.KeyframeTrack: Unsupported typeName: ' + typeName);
  20886. }
  20887. });
  20888. Object.assign(KeyframeTrack.prototype, {
  20889. constructor: KeyframeTrack,
  20890. TimeBufferType: Float32Array,
  20891. ValueBufferType: Float32Array,
  20892. DefaultInterpolation: InterpolateLinear,
  20893. InterpolantFactoryMethodDiscrete: function (result) {
  20894. return new DiscreteInterpolant(this.times, this.values, this.getValueSize(), result);
  20895. },
  20896. InterpolantFactoryMethodLinear: function (result) {
  20897. return new LinearInterpolant(this.times, this.values, this.getValueSize(), result);
  20898. },
  20899. InterpolantFactoryMethodSmooth: function (result) {
  20900. return new CubicInterpolant(this.times, this.values, this.getValueSize(), result);
  20901. },
  20902. setInterpolation: function (interpolation) {
  20903. var factoryMethod;
  20904. switch (interpolation) {
  20905. case InterpolateDiscrete:
  20906. factoryMethod = this.InterpolantFactoryMethodDiscrete;
  20907. break;
  20908. case InterpolateLinear:
  20909. factoryMethod = this.InterpolantFactoryMethodLinear;
  20910. break;
  20911. case InterpolateSmooth:
  20912. factoryMethod = this.InterpolantFactoryMethodSmooth;
  20913. break;
  20914. }
  20915. if (factoryMethod === undefined) {
  20916. var message = "unsupported interpolation for " + this.ValueTypeName + " keyframe track named " + this.name;
  20917. if (this.createInterpolant === undefined) {
  20918. // fall back to default, unless the default itself is messed up
  20919. if (interpolation !== this.DefaultInterpolation) {
  20920. this.setInterpolation(this.DefaultInterpolation);
  20921. } else {
  20922. throw new Error(message); // fatal, in this case
  20923. }
  20924. }
  20925. console.warn('THREE.KeyframeTrack:', message);
  20926. return;
  20927. }
  20928. this.createInterpolant = factoryMethod;
  20929. },
  20930. getInterpolation: function () {
  20931. switch (this.createInterpolant) {
  20932. case this.InterpolantFactoryMethodDiscrete:
  20933. return InterpolateDiscrete;
  20934. case this.InterpolantFactoryMethodLinear:
  20935. return InterpolateLinear;
  20936. case this.InterpolantFactoryMethodSmooth:
  20937. return InterpolateSmooth;
  20938. }
  20939. },
  20940. getValueSize: function () {
  20941. return this.values.length / this.times.length;
  20942. },
  20943. // move all keyframes either forwards or backwards in time
  20944. shift: function (timeOffset) {
  20945. if (timeOffset !== 0.0) {
  20946. var times = this.times;
  20947. for (var i = 0, n = times.length; i !== n; ++i) {
  20948. times[i] += timeOffset;
  20949. }
  20950. }
  20951. return this;
  20952. },
  20953. // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
  20954. scale: function (timeScale) {
  20955. if (timeScale !== 1.0) {
  20956. var times = this.times;
  20957. for (var i = 0, n = times.length; i !== n; ++i) {
  20958. times[i] *= timeScale;
  20959. }
  20960. }
  20961. return this;
  20962. },
  20963. // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
  20964. // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
  20965. trim: function (startTime, endTime) {
  20966. var times = this.times,
  20967. nKeys = times.length,
  20968. from = 0,
  20969. to = nKeys - 1;
  20970. while (from !== nKeys && times[from] < startTime) {
  20971. ++from;
  20972. }
  20973. while (to !== -1 && times[to] > endTime) {
  20974. --to;
  20975. }
  20976. ++to; // inclusive -> exclusive bound
  20977. if (from !== 0 || to !== nKeys) {
  20978. // empty tracks are forbidden, so keep at least one keyframe
  20979. if (from >= to) to = Math.max(to, 1), from = to - 1;
  20980. var stride = this.getValueSize();
  20981. this.times = AnimationUtils.arraySlice(times, from, to);
  20982. this.values = AnimationUtils.arraySlice(this.values, from * stride, to * stride);
  20983. }
  20984. return this;
  20985. },
  20986. // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
  20987. validate: function () {
  20988. var valid = true;
  20989. var valueSize = this.getValueSize();
  20990. if (valueSize - Math.floor(valueSize) !== 0) {
  20991. console.error('THREE.KeyframeTrack: Invalid value size in track.', this);
  20992. valid = false;
  20993. }
  20994. var times = this.times,
  20995. values = this.values,
  20996. nKeys = times.length;
  20997. if (nKeys === 0) {
  20998. console.error('THREE.KeyframeTrack: Track is empty.', this);
  20999. valid = false;
  21000. }
  21001. var prevTime = null;
  21002. for (var i = 0; i !== nKeys; i++) {
  21003. var currTime = times[i];
  21004. if (typeof currTime === 'number' && isNaN(currTime)) {
  21005. console.error('THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime);
  21006. valid = false;
  21007. break;
  21008. }
  21009. if (prevTime !== null && prevTime > currTime) {
  21010. console.error('THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime);
  21011. valid = false;
  21012. break;
  21013. }
  21014. prevTime = currTime;
  21015. }
  21016. if (values !== undefined) {
  21017. if (AnimationUtils.isTypedArray(values)) {
  21018. for (var i = 0, n = values.length; i !== n; ++i) {
  21019. var value = values[i];
  21020. if (isNaN(value)) {
  21021. console.error('THREE.KeyframeTrack: Value is not a valid number.', this, i, value);
  21022. valid = false;
  21023. break;
  21024. }
  21025. }
  21026. }
  21027. }
  21028. return valid;
  21029. },
  21030. // removes equivalent sequential keys as common in morph target sequences
  21031. // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
  21032. optimize: function () {
  21033. var times = this.times,
  21034. values = this.values,
  21035. stride = this.getValueSize(),
  21036. smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
  21037. writeIndex = 1,
  21038. lastIndex = times.length - 1;
  21039. for (var i = 1; i < lastIndex; ++i) {
  21040. var keep = false;
  21041. var time = times[i];
  21042. var timeNext = times[i + 1];
  21043. // remove adjacent keyframes scheduled at the same time
  21044. if (time !== timeNext && (i !== 1 || time !== time[0])) {
  21045. if (!smoothInterpolation) {
  21046. // remove unnecessary keyframes same as their neighbors
  21047. var offset = i * stride,
  21048. offsetP = offset - stride,
  21049. offsetN = offset + stride;
  21050. for (var j = 0; j !== stride; ++j) {
  21051. var value = values[offset + j];
  21052. if (value !== values[offsetP + j] || value !== values[offsetN + j]) {
  21053. keep = true;
  21054. break;
  21055. }
  21056. }
  21057. } else {
  21058. keep = true;
  21059. }
  21060. }
  21061. // in-place compaction
  21062. if (keep) {
  21063. if (i !== writeIndex) {
  21064. times[writeIndex] = times[i];
  21065. var readOffset = i * stride,
  21066. writeOffset = writeIndex * stride;
  21067. for (var j = 0; j !== stride; ++j) {
  21068. values[writeOffset + j] = values[readOffset + j];
  21069. }
  21070. }
  21071. ++writeIndex;
  21072. }
  21073. }
  21074. // flush last keyframe (compaction looks ahead)
  21075. if (lastIndex > 0) {
  21076. times[writeIndex] = times[lastIndex];
  21077. for (var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++j) {
  21078. values[writeOffset + j] = values[readOffset + j];
  21079. }
  21080. ++writeIndex;
  21081. }
  21082. if (writeIndex !== times.length) {
  21083. this.times = AnimationUtils.arraySlice(times, 0, writeIndex);
  21084. this.values = AnimationUtils.arraySlice(values, 0, writeIndex * stride);
  21085. }
  21086. return this;
  21087. }
  21088. });
  21089. /**
  21090. *
  21091. * A Track of vectored keyframe values.
  21092. *
  21093. *
  21094. * @author Ben Houston / http://clara.io/
  21095. * @author David Sarno / http://lighthaus.us/
  21096. * @author tschw
  21097. */
  21098. function VectorKeyframeTrack(name, times, values, interpolation) {
  21099. KeyframeTrack.call(this, name, times, values, interpolation);
  21100. }
  21101. VectorKeyframeTrack.prototype = Object.assign(Object.create(KeyframeTrack.prototype), {
  21102. constructor: VectorKeyframeTrack,
  21103. ValueTypeName: 'vector'
  21104. // ValueBufferType is inherited
  21105. // DefaultInterpolation is inherited
  21106. });
  21107. /**
  21108. *
  21109. * Reusable set of Tracks that represent an animation.
  21110. *
  21111. * @author Ben Houston / http://clara.io/
  21112. * @author David Sarno / http://lighthaus.us/
  21113. */
  21114. function AnimationClip(name, duration, tracks) {
  21115. this.name = name;
  21116. this.tracks = tracks;
  21117. this.duration = duration !== undefined ? duration : -1;
  21118. this.uuid = _Math.generateUUID();
  21119. // this means it should figure out its duration by scanning the tracks
  21120. if (this.duration < 0) {
  21121. this.resetDuration();
  21122. }
  21123. this.optimize();
  21124. }
  21125. Object.assign(AnimationClip, {
  21126. parse: function (json) {
  21127. var tracks = [],
  21128. jsonTracks = json.tracks,
  21129. frameTime = 1.0 / (json.fps || 1.0);
  21130. for (var i = 0, n = jsonTracks.length; i !== n; ++i) {
  21131. tracks.push(KeyframeTrack.parse(jsonTracks[i]).scale(frameTime));
  21132. }
  21133. return new AnimationClip(json.name, json.duration, tracks);
  21134. },
  21135. toJSON: function (clip) {
  21136. var tracks = [],
  21137. clipTracks = clip.tracks;
  21138. var json = {
  21139. 'name': clip.name,
  21140. 'duration': clip.duration,
  21141. 'tracks': tracks,
  21142. 'uuid': clip.uuid
  21143. };
  21144. for (var i = 0, n = clipTracks.length; i !== n; ++i) {
  21145. tracks.push(KeyframeTrack.toJSON(clipTracks[i]));
  21146. }
  21147. return json;
  21148. },
  21149. CreateFromMorphTargetSequence: function (name, morphTargetSequence, fps, noLoop) {
  21150. var numMorphTargets = morphTargetSequence.length;
  21151. var tracks = [];
  21152. for (var i = 0; i < numMorphTargets; i++) {
  21153. var times = [];
  21154. var values = [];
  21155. times.push((i + numMorphTargets - 1) % numMorphTargets, i, (i + 1) % numMorphTargets);
  21156. values.push(0, 1, 0);
  21157. var order = AnimationUtils.getKeyframeOrder(times);
  21158. times = AnimationUtils.sortedArray(times, 1, order);
  21159. values = AnimationUtils.sortedArray(values, 1, order);
  21160. // if there is a key at the first frame, duplicate it as the
  21161. // last frame as well for perfect loop.
  21162. if (!noLoop && times[0] === 0) {
  21163. times.push(numMorphTargets);
  21164. values.push(values[0]);
  21165. }
  21166. tracks.push(new NumberKeyframeTrack('.morphTargetInfluences[' + morphTargetSequence[i].name + ']', times, values).scale(1.0 / fps));
  21167. }
  21168. return new AnimationClip(name, -1, tracks);
  21169. },
  21170. findByName: function (objectOrClipArray, name) {
  21171. var clipArray = objectOrClipArray;
  21172. if (!Array.isArray(objectOrClipArray)) {
  21173. var o = objectOrClipArray;
  21174. clipArray = o.geometry && o.geometry.animations || o.animations;
  21175. }
  21176. for (var i = 0; i < clipArray.length; i++) {
  21177. if (clipArray[i].name === name) {
  21178. return clipArray[i];
  21179. }
  21180. }
  21181. return null;
  21182. },
  21183. CreateClipsFromMorphTargetSequences: function (morphTargets, fps, noLoop) {
  21184. var animationToMorphTargets = {};
  21185. // tested with https://regex101.com/ on trick sequences
  21186. // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
  21187. var pattern = /^([\w-]*?)([\d]+)$/;
  21188. // sort morph target names into animation groups based
  21189. // patterns like Walk_001, Walk_002, Run_001, Run_002
  21190. for (var i = 0, il = morphTargets.length; i < il; i++) {
  21191. var morphTarget = morphTargets[i];
  21192. var parts = morphTarget.name.match(pattern);
  21193. if (parts && parts.length > 1) {
  21194. var name = parts[1];
  21195. var animationMorphTargets = animationToMorphTargets[name];
  21196. if (!animationMorphTargets) {
  21197. animationToMorphTargets[name] = animationMorphTargets = [];
  21198. }
  21199. animationMorphTargets.push(morphTarget);
  21200. }
  21201. }
  21202. var clips = [];
  21203. for (var name in animationToMorphTargets) {
  21204. clips.push(AnimationClip.CreateFromMorphTargetSequence(name, animationToMorphTargets[name], fps, noLoop));
  21205. }
  21206. return clips;
  21207. },
  21208. // parse the animation.hierarchy format
  21209. parseAnimation: function (animation, bones) {
  21210. if (!animation) {
  21211. console.error('THREE.AnimationClip: No animation in JSONLoader data.');
  21212. return null;
  21213. }
  21214. var addNonemptyTrack = function (trackType, trackName, animationKeys, propertyName, destTracks) {
  21215. // only return track if there are actually keys.
  21216. if (animationKeys.length !== 0) {
  21217. var times = [];
  21218. var values = [];
  21219. AnimationUtils.flattenJSON(animationKeys, times, values, propertyName);
  21220. // empty keys are filtered out, so check again
  21221. if (times.length !== 0) {
  21222. destTracks.push(new trackType(trackName, times, values));
  21223. }
  21224. }
  21225. };
  21226. var tracks = [];
  21227. var clipName = animation.name || 'default';
  21228. // automatic length determination in AnimationClip.
  21229. var duration = animation.length || -1;
  21230. var fps = animation.fps || 30;
  21231. var hierarchyTracks = animation.hierarchy || [];
  21232. for (var h = 0; h < hierarchyTracks.length; h++) {
  21233. var animationKeys = hierarchyTracks[h].keys;
  21234. // skip empty tracks
  21235. if (!animationKeys || animationKeys.length === 0) continue;
  21236. // process morph targets
  21237. if (animationKeys[0].morphTargets) {
  21238. // figure out all morph targets used in this track
  21239. var morphTargetNames = {};
  21240. for (var k = 0; k < animationKeys.length; k++) {
  21241. if (animationKeys[k].morphTargets) {
  21242. for (var m = 0; m < animationKeys[k].morphTargets.length; m++) {
  21243. morphTargetNames[animationKeys[k].morphTargets[m]] = -1;
  21244. }
  21245. }
  21246. }
  21247. // create a track for each morph target with all zero
  21248. // morphTargetInfluences except for the keys in which
  21249. // the morphTarget is named.
  21250. for (var morphTargetName in morphTargetNames) {
  21251. var times = [];
  21252. var values = [];
  21253. for (var m = 0; m !== animationKeys[k].morphTargets.length; ++m) {
  21254. var animationKey = animationKeys[k];
  21255. times.push(animationKey.time);
  21256. values.push(animationKey.morphTarget === morphTargetName ? 1 : 0);
  21257. }
  21258. tracks.push(new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values));
  21259. }
  21260. duration = morphTargetNames.length * (fps || 1.0);
  21261. } else {
  21262. // ...assume skeletal animation
  21263. var boneName = '.bones[' + bones[h].name + ']';
  21264. addNonemptyTrack(VectorKeyframeTrack, boneName + '.position', animationKeys, 'pos', tracks);
  21265. addNonemptyTrack(QuaternionKeyframeTrack, boneName + '.quaternion', animationKeys, 'rot', tracks);
  21266. addNonemptyTrack(VectorKeyframeTrack, boneName + '.scale', animationKeys, 'scl', tracks);
  21267. }
  21268. }
  21269. if (tracks.length === 0) {
  21270. return null;
  21271. }
  21272. var clip = new AnimationClip(clipName, duration, tracks);
  21273. return clip;
  21274. }
  21275. });
  21276. Object.assign(AnimationClip.prototype, {
  21277. resetDuration: function () {
  21278. var tracks = this.tracks,
  21279. duration = 0;
  21280. for (var i = 0, n = tracks.length; i !== n; ++i) {
  21281. var track = this.tracks[i];
  21282. duration = Math.max(duration, track.times[track.times.length - 1]);
  21283. }
  21284. this.duration = duration;
  21285. },
  21286. trim: function () {
  21287. for (var i = 0; i < this.tracks.length; i++) {
  21288. this.tracks[i].trim(0, this.duration);
  21289. }
  21290. return this;
  21291. },
  21292. optimize: function () {
  21293. for (var i = 0; i < this.tracks.length; i++) {
  21294. this.tracks[i].optimize();
  21295. }
  21296. return this;
  21297. }
  21298. });
  21299. /**
  21300. * @author mrdoob / http://mrdoob.com/
  21301. */
  21302. function MaterialLoader(manager) {
  21303. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  21304. this.textures = {};
  21305. }
  21306. Object.assign(MaterialLoader.prototype, {
  21307. load: function (url, onLoad, onProgress, onError) {
  21308. var scope = this;
  21309. var loader = new FileLoader(scope.manager);
  21310. loader.load(url, function (text) {
  21311. onLoad(scope.parse(JSON.parse(text)));
  21312. }, onProgress, onError);
  21313. },
  21314. setTextures: function (value) {
  21315. this.textures = value;
  21316. },
  21317. parse: function (json) {
  21318. var textures = this.textures;
  21319. function getTexture(name) {
  21320. if (textures[name] === undefined) {
  21321. console.warn('THREE.MaterialLoader: Undefined texture', name);
  21322. }
  21323. return textures[name];
  21324. }
  21325. var material = new Materials[json.type]();
  21326. if (json.uuid !== undefined) material.uuid = json.uuid;
  21327. if (json.name !== undefined) material.name = json.name;
  21328. if (json.color !== undefined) material.color.setHex(json.color);
  21329. if (json.roughness !== undefined) material.roughness = json.roughness;
  21330. if (json.metalness !== undefined) material.metalness = json.metalness;
  21331. if (json.emissive !== undefined) material.emissive.setHex(json.emissive);
  21332. if (json.specular !== undefined) material.specular.setHex(json.specular);
  21333. if (json.shininess !== undefined) material.shininess = json.shininess;
  21334. if (json.clearCoat !== undefined) material.clearCoat = json.clearCoat;
  21335. if (json.clearCoatRoughness !== undefined) material.clearCoatRoughness = json.clearCoatRoughness;
  21336. if (json.uniforms !== undefined) material.uniforms = json.uniforms;
  21337. if (json.vertexShader !== undefined) material.vertexShader = json.vertexShader;
  21338. if (json.fragmentShader !== undefined) material.fragmentShader = json.fragmentShader;
  21339. if (json.vertexColors !== undefined) material.vertexColors = json.vertexColors;
  21340. if (json.fog !== undefined) material.fog = json.fog;
  21341. if (json.flatShading !== undefined) material.flatShading = json.flatShading;
  21342. if (json.blending !== undefined) material.blending = json.blending;
  21343. if (json.side !== undefined) material.side = json.side;
  21344. if (json.opacity !== undefined) material.opacity = json.opacity;
  21345. if (json.transparent !== undefined) material.transparent = json.transparent;
  21346. if (json.alphaTest !== undefined) material.alphaTest = json.alphaTest;
  21347. if (json.depthTest !== undefined) material.depthTest = json.depthTest;
  21348. if (json.depthWrite !== undefined) material.depthWrite = json.depthWrite;
  21349. if (json.colorWrite !== undefined) material.colorWrite = json.colorWrite;
  21350. if (json.wireframe !== undefined) material.wireframe = json.wireframe;
  21351. if (json.wireframeLinewidth !== undefined) material.wireframeLinewidth = json.wireframeLinewidth;
  21352. if (json.wireframeLinecap !== undefined) material.wireframeLinecap = json.wireframeLinecap;
  21353. if (json.wireframeLinejoin !== undefined) material.wireframeLinejoin = json.wireframeLinejoin;
  21354. if (json.rotation !== undefined) material.rotation = json.rotation;
  21355. if (json.linewidth !== 1) material.linewidth = json.linewidth;
  21356. if (json.dashSize !== undefined) material.dashSize = json.dashSize;
  21357. if (json.gapSize !== undefined) material.gapSize = json.gapSize;
  21358. if (json.scale !== undefined) material.scale = json.scale;
  21359. if (json.polygonOffset !== undefined) material.polygonOffset = json.polygonOffset;
  21360. if (json.polygonOffsetFactor !== undefined) material.polygonOffsetFactor = json.polygonOffsetFactor;
  21361. if (json.polygonOffsetUnits !== undefined) material.polygonOffsetUnits = json.polygonOffsetUnits;
  21362. if (json.skinning !== undefined) material.skinning = json.skinning;
  21363. if (json.morphTargets !== undefined) material.morphTargets = json.morphTargets;
  21364. if (json.dithering !== undefined) material.dithering = json.dithering;
  21365. if (json.visible !== undefined) material.visible = json.visible;
  21366. if (json.userData !== undefined) material.userData = json.userData;
  21367. // Deprecated
  21368. if (json.shading !== undefined) material.flatShading = json.shading === 1; // THREE.FlatShading
  21369. // for PointsMaterial
  21370. if (json.size !== undefined) material.size = json.size;
  21371. if (json.sizeAttenuation !== undefined) material.sizeAttenuation = json.sizeAttenuation;
  21372. // maps
  21373. if (json.map !== undefined) material.map = getTexture(json.map);
  21374. if (json.alphaMap !== undefined) {
  21375. material.alphaMap = getTexture(json.alphaMap);
  21376. material.transparent = true;
  21377. }
  21378. if (json.bumpMap !== undefined) material.bumpMap = getTexture(json.bumpMap);
  21379. if (json.bumpScale !== undefined) material.bumpScale = json.bumpScale;
  21380. if (json.normalMap !== undefined) material.normalMap = getTexture(json.normalMap);
  21381. if (json.normalScale !== undefined) {
  21382. var normalScale = json.normalScale;
  21383. if (Array.isArray(normalScale) === false) {
  21384. // Blender exporter used to export a scalar. See #7459
  21385. normalScale = [normalScale, normalScale];
  21386. }
  21387. material.normalScale = new Vector2().fromArray(normalScale);
  21388. }
  21389. if (json.displacementMap !== undefined) material.displacementMap = getTexture(json.displacementMap);
  21390. if (json.displacementScale !== undefined) material.displacementScale = json.displacementScale;
  21391. if (json.displacementBias !== undefined) material.displacementBias = json.displacementBias;
  21392. if (json.roughnessMap !== undefined) material.roughnessMap = getTexture(json.roughnessMap);
  21393. if (json.metalnessMap !== undefined) material.metalnessMap = getTexture(json.metalnessMap);
  21394. if (json.emissiveMap !== undefined) material.emissiveMap = getTexture(json.emissiveMap);
  21395. if (json.emissiveIntensity !== undefined) material.emissiveIntensity = json.emissiveIntensity;
  21396. if (json.specularMap !== undefined) material.specularMap = getTexture(json.specularMap);
  21397. if (json.envMap !== undefined) material.envMap = getTexture(json.envMap);
  21398. if (json.reflectivity !== undefined) material.reflectivity = json.reflectivity;
  21399. if (json.lightMap !== undefined) material.lightMap = getTexture(json.lightMap);
  21400. if (json.lightMapIntensity !== undefined) material.lightMapIntensity = json.lightMapIntensity;
  21401. if (json.aoMap !== undefined) material.aoMap = getTexture(json.aoMap);
  21402. if (json.aoMapIntensity !== undefined) material.aoMapIntensity = json.aoMapIntensity;
  21403. if (json.gradientMap !== undefined) material.gradientMap = getTexture(json.gradientMap);
  21404. return material;
  21405. }
  21406. });
  21407. /**
  21408. * @author mrdoob / http://mrdoob.com/
  21409. */
  21410. function BufferGeometryLoader(manager) {
  21411. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  21412. }
  21413. Object.assign(BufferGeometryLoader.prototype, {
  21414. load: function (url, onLoad, onProgress, onError) {
  21415. var scope = this;
  21416. var loader = new FileLoader(scope.manager);
  21417. loader.load(url, function (text) {
  21418. onLoad(scope.parse(JSON.parse(text)));
  21419. }, onProgress, onError);
  21420. },
  21421. parse: function (json) {
  21422. var geometry = new BufferGeometry();
  21423. var index = json.data.index;
  21424. if (index !== undefined) {
  21425. var typedArray = new TYPED_ARRAYS[index.type](index.array);
  21426. geometry.setIndex(new BufferAttribute(typedArray, 1));
  21427. }
  21428. var attributes = json.data.attributes;
  21429. for (var key in attributes) {
  21430. var attribute = attributes[key];
  21431. var typedArray = new TYPED_ARRAYS[attribute.type](attribute.array);
  21432. geometry.addAttribute(key, new BufferAttribute(typedArray, attribute.itemSize, attribute.normalized));
  21433. }
  21434. var groups = json.data.groups || json.data.drawcalls || json.data.offsets;
  21435. if (groups !== undefined) {
  21436. for (var i = 0, n = groups.length; i !== n; ++i) {
  21437. var group = groups[i];
  21438. geometry.addGroup(group.start, group.count, group.materialIndex);
  21439. }
  21440. }
  21441. var boundingSphere = json.data.boundingSphere;
  21442. if (boundingSphere !== undefined) {
  21443. var center = new Vector3();
  21444. if (boundingSphere.center !== undefined) {
  21445. center.fromArray(boundingSphere.center);
  21446. }
  21447. geometry.boundingSphere = new Sphere(center, boundingSphere.radius);
  21448. }
  21449. return geometry;
  21450. }
  21451. });
  21452. var TYPED_ARRAYS = {
  21453. Int8Array: Int8Array,
  21454. Uint8Array: Uint8Array,
  21455. // Workaround for IE11 pre KB2929437. See #11440
  21456. Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
  21457. Int16Array: Int16Array,
  21458. Uint16Array: Uint16Array,
  21459. Int32Array: Int32Array,
  21460. Uint32Array: Uint32Array,
  21461. Float32Array: Float32Array,
  21462. Float64Array: Float64Array
  21463. };
  21464. /**
  21465. * @author alteredq / http://alteredqualia.com/
  21466. */
  21467. function Loader() {}
  21468. Loader.Handlers = {
  21469. handlers: [],
  21470. add: function (regex, loader) {
  21471. this.handlers.push(regex, loader);
  21472. },
  21473. get: function (file) {
  21474. var handlers = this.handlers;
  21475. for (var i = 0, l = handlers.length; i < l; i += 2) {
  21476. var regex = handlers[i];
  21477. var loader = handlers[i + 1];
  21478. if (regex.test(file)) {
  21479. return loader;
  21480. }
  21481. }
  21482. return null;
  21483. }
  21484. };
  21485. Object.assign(Loader.prototype, {
  21486. crossOrigin: undefined,
  21487. onLoadStart: function () {},
  21488. onLoadProgress: function () {},
  21489. onLoadComplete: function () {},
  21490. initMaterials: function (materials, texturePath, crossOrigin) {
  21491. var array = [];
  21492. for (var i = 0; i < materials.length; ++i) {
  21493. array[i] = this.createMaterial(materials[i], texturePath, crossOrigin);
  21494. }
  21495. return array;
  21496. },
  21497. createMaterial: function () {
  21498. var BlendingMode = {
  21499. NoBlending: NoBlending,
  21500. NormalBlending: NormalBlending,
  21501. AdditiveBlending: AdditiveBlending,
  21502. SubtractiveBlending: SubtractiveBlending,
  21503. MultiplyBlending: MultiplyBlending,
  21504. CustomBlending: CustomBlending
  21505. };
  21506. var color = new Color();
  21507. var textureLoader = new TextureLoader();
  21508. var materialLoader = new MaterialLoader();
  21509. return function createMaterial(m, texturePath, crossOrigin) {
  21510. // convert from old material format
  21511. var textures = {};
  21512. function loadTexture(path, repeat, offset, wrap, anisotropy) {
  21513. var fullPath = texturePath + path;
  21514. var loader = Loader.Handlers.get(fullPath);
  21515. var texture;
  21516. if (loader !== null) {
  21517. texture = loader.load(fullPath);
  21518. } else {
  21519. textureLoader.setCrossOrigin(crossOrigin);
  21520. texture = textureLoader.load(fullPath);
  21521. }
  21522. if (repeat !== undefined) {
  21523. texture.repeat.fromArray(repeat);
  21524. if (repeat[0] !== 1) texture.wrapS = RepeatWrapping;
  21525. if (repeat[1] !== 1) texture.wrapT = RepeatWrapping;
  21526. }
  21527. if (offset !== undefined) {
  21528. texture.offset.fromArray(offset);
  21529. }
  21530. if (wrap !== undefined) {
  21531. if (wrap[0] === 'repeat') texture.wrapS = RepeatWrapping;
  21532. if (wrap[0] === 'mirror') texture.wrapS = MirroredRepeatWrapping;
  21533. if (wrap[1] === 'repeat') texture.wrapT = RepeatWrapping;
  21534. if (wrap[1] === 'mirror') texture.wrapT = MirroredRepeatWrapping;
  21535. }
  21536. if (anisotropy !== undefined) {
  21537. texture.anisotropy = anisotropy;
  21538. }
  21539. var uuid = _Math.generateUUID();
  21540. textures[uuid] = texture;
  21541. return uuid;
  21542. }
  21543. //
  21544. var json = {
  21545. uuid: _Math.generateUUID(),
  21546. type: 'MeshLambertMaterial'
  21547. };
  21548. for (var name in m) {
  21549. var value = m[name];
  21550. switch (name) {
  21551. case 'DbgColor':
  21552. case 'DbgIndex':
  21553. case 'opticalDensity':
  21554. case 'illumination':
  21555. break;
  21556. case 'DbgName':
  21557. json.name = value;
  21558. break;
  21559. case 'blending':
  21560. json.blending = BlendingMode[value];
  21561. break;
  21562. case 'colorAmbient':
  21563. case 'mapAmbient':
  21564. console.warn('THREE.Loader.createMaterial:', name, 'is no longer supported.');
  21565. break;
  21566. case 'colorDiffuse':
  21567. json.color = color.fromArray(value).getHex();
  21568. break;
  21569. case 'colorSpecular':
  21570. json.specular = color.fromArray(value).getHex();
  21571. break;
  21572. case 'colorEmissive':
  21573. json.emissive = color.fromArray(value).getHex();
  21574. break;
  21575. case 'specularCoef':
  21576. json.shininess = value;
  21577. break;
  21578. case 'shading':
  21579. if (value.toLowerCase() === 'basic') json.type = 'MeshBasicMaterial';
  21580. if (value.toLowerCase() === 'phong') json.type = 'MeshPhongMaterial';
  21581. if (value.toLowerCase() === 'standard') json.type = 'MeshStandardMaterial';
  21582. break;
  21583. case 'mapDiffuse':
  21584. json.map = loadTexture(value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy);
  21585. break;
  21586. case 'mapDiffuseRepeat':
  21587. case 'mapDiffuseOffset':
  21588. case 'mapDiffuseWrap':
  21589. case 'mapDiffuseAnisotropy':
  21590. break;
  21591. case 'mapEmissive':
  21592. json.emissiveMap = loadTexture(value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy);
  21593. break;
  21594. case 'mapEmissiveRepeat':
  21595. case 'mapEmissiveOffset':
  21596. case 'mapEmissiveWrap':
  21597. case 'mapEmissiveAnisotropy':
  21598. break;
  21599. case 'mapLight':
  21600. json.lightMap = loadTexture(value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy);
  21601. break;
  21602. case 'mapLightRepeat':
  21603. case 'mapLightOffset':
  21604. case 'mapLightWrap':
  21605. case 'mapLightAnisotropy':
  21606. break;
  21607. case 'mapAO':
  21608. json.aoMap = loadTexture(value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy);
  21609. break;
  21610. case 'mapAORepeat':
  21611. case 'mapAOOffset':
  21612. case 'mapAOWrap':
  21613. case 'mapAOAnisotropy':
  21614. break;
  21615. case 'mapBump':
  21616. json.bumpMap = loadTexture(value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy);
  21617. break;
  21618. case 'mapBumpScale':
  21619. json.bumpScale = value;
  21620. break;
  21621. case 'mapBumpRepeat':
  21622. case 'mapBumpOffset':
  21623. case 'mapBumpWrap':
  21624. case 'mapBumpAnisotropy':
  21625. break;
  21626. case 'mapNormal':
  21627. json.normalMap = loadTexture(value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy);
  21628. break;
  21629. case 'mapNormalFactor':
  21630. json.normalScale = value;
  21631. break;
  21632. case 'mapNormalRepeat':
  21633. case 'mapNormalOffset':
  21634. case 'mapNormalWrap':
  21635. case 'mapNormalAnisotropy':
  21636. break;
  21637. case 'mapSpecular':
  21638. json.specularMap = loadTexture(value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy);
  21639. break;
  21640. case 'mapSpecularRepeat':
  21641. case 'mapSpecularOffset':
  21642. case 'mapSpecularWrap':
  21643. case 'mapSpecularAnisotropy':
  21644. break;
  21645. case 'mapMetalness':
  21646. json.metalnessMap = loadTexture(value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy);
  21647. break;
  21648. case 'mapMetalnessRepeat':
  21649. case 'mapMetalnessOffset':
  21650. case 'mapMetalnessWrap':
  21651. case 'mapMetalnessAnisotropy':
  21652. break;
  21653. case 'mapRoughness':
  21654. json.roughnessMap = loadTexture(value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy);
  21655. break;
  21656. case 'mapRoughnessRepeat':
  21657. case 'mapRoughnessOffset':
  21658. case 'mapRoughnessWrap':
  21659. case 'mapRoughnessAnisotropy':
  21660. break;
  21661. case 'mapAlpha':
  21662. json.alphaMap = loadTexture(value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy);
  21663. break;
  21664. case 'mapAlphaRepeat':
  21665. case 'mapAlphaOffset':
  21666. case 'mapAlphaWrap':
  21667. case 'mapAlphaAnisotropy':
  21668. break;
  21669. case 'flipSided':
  21670. json.side = BackSide;
  21671. break;
  21672. case 'doubleSided':
  21673. json.side = DoubleSide;
  21674. break;
  21675. case 'transparency':
  21676. console.warn('THREE.Loader.createMaterial: transparency has been renamed to opacity');
  21677. json.opacity = value;
  21678. break;
  21679. case 'depthTest':
  21680. case 'depthWrite':
  21681. case 'colorWrite':
  21682. case 'opacity':
  21683. case 'reflectivity':
  21684. case 'transparent':
  21685. case 'visible':
  21686. case 'wireframe':
  21687. json[name] = value;
  21688. break;
  21689. case 'vertexColors':
  21690. if (value === true) json.vertexColors = VertexColors;
  21691. if (value === 'face') json.vertexColors = FaceColors;
  21692. break;
  21693. default:
  21694. console.error('THREE.Loader.createMaterial: Unsupported', name, value);
  21695. break;
  21696. }
  21697. }
  21698. if (json.type === 'MeshBasicMaterial') delete json.emissive;
  21699. if (json.type !== 'MeshPhongMaterial') delete json.specular;
  21700. if (json.opacity < 1) json.transparent = true;
  21701. materialLoader.setTextures(textures);
  21702. return materialLoader.parse(json);
  21703. };
  21704. }()
  21705. });
  21706. /**
  21707. * @author Don McCurdy / https://www.donmccurdy.com
  21708. */
  21709. var LoaderUtils = {
  21710. decodeText: function (array) {
  21711. if (typeof TextDecoder !== 'undefined') {
  21712. return new TextDecoder().decode(array);
  21713. }
  21714. // Avoid the String.fromCharCode.apply(null, array) shortcut, which
  21715. // throws a "maximum call stack size exceeded" error for large arrays.
  21716. var s = '';
  21717. for (var i = 0, il = array.length; i < il; i++) {
  21718. // Implicitly assumes little-endian.
  21719. s += String.fromCharCode(array[i]);
  21720. }
  21721. // Merges multi-byte utf-8 characters.
  21722. return decodeURIComponent(escape(s));
  21723. },
  21724. extractUrlBase: function (url) {
  21725. var index = url.lastIndexOf('/');
  21726. if (index === -1) return './';
  21727. return url.substr(0, index + 1);
  21728. }
  21729. };
  21730. /**
  21731. * @author mrdoob / http://mrdoob.com/
  21732. * @author alteredq / http://alteredqualia.com/
  21733. */
  21734. function JSONLoader(manager) {
  21735. if (typeof manager === 'boolean') {
  21736. console.warn('THREE.JSONLoader: showStatus parameter has been removed from constructor.');
  21737. manager = undefined;
  21738. }
  21739. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  21740. this.withCredentials = false;
  21741. }
  21742. Object.assign(JSONLoader.prototype, {
  21743. load: function (url, onLoad, onProgress, onError) {
  21744. var scope = this;
  21745. var texturePath = this.texturePath && typeof this.texturePath === 'string' ? this.texturePath : LoaderUtils.extractUrlBase(url);
  21746. var loader = new FileLoader(this.manager);
  21747. loader.setWithCredentials(this.withCredentials);
  21748. loader.load(url, function (text) {
  21749. var json = JSON.parse(text);
  21750. var metadata = json.metadata;
  21751. if (metadata !== undefined) {
  21752. var type = metadata.type;
  21753. if (type !== undefined) {
  21754. if (type.toLowerCase() === 'object') {
  21755. console.error('THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.');
  21756. return;
  21757. }
  21758. }
  21759. }
  21760. var object = scope.parse(json, texturePath);
  21761. onLoad(object.geometry, object.materials);
  21762. }, onProgress, onError);
  21763. },
  21764. setTexturePath: function (value) {
  21765. this.texturePath = value;
  21766. },
  21767. parse: function () {
  21768. function parseModel(json, geometry) {
  21769. function isBitSet(value, position) {
  21770. return value & 1 << position;
  21771. }
  21772. var i,
  21773. j,
  21774. fi,
  21775. offset,
  21776. zLength,
  21777. colorIndex,
  21778. normalIndex,
  21779. uvIndex,
  21780. materialIndex,
  21781. type,
  21782. isQuad,
  21783. hasMaterial,
  21784. hasFaceVertexUv,
  21785. hasFaceNormal,
  21786. hasFaceVertexNormal,
  21787. hasFaceColor,
  21788. hasFaceVertexColor,
  21789. vertex,
  21790. face,
  21791. faceA,
  21792. faceB,
  21793. hex,
  21794. normal,
  21795. uvLayer,
  21796. uv,
  21797. u,
  21798. v,
  21799. faces = json.faces,
  21800. vertices = json.vertices,
  21801. normals = json.normals,
  21802. colors = json.colors,
  21803. scale = json.scale,
  21804. nUvLayers = 0;
  21805. if (json.uvs !== undefined) {
  21806. // disregard empty arrays
  21807. for (i = 0; i < json.uvs.length; i++) {
  21808. if (json.uvs[i].length) nUvLayers++;
  21809. }
  21810. for (i = 0; i < nUvLayers; i++) {
  21811. geometry.faceVertexUvs[i] = [];
  21812. }
  21813. }
  21814. offset = 0;
  21815. zLength = vertices.length;
  21816. while (offset < zLength) {
  21817. vertex = new Vector3();
  21818. vertex.x = vertices[offset++] * scale;
  21819. vertex.y = vertices[offset++] * scale;
  21820. vertex.z = vertices[offset++] * scale;
  21821. geometry.vertices.push(vertex);
  21822. }
  21823. offset = 0;
  21824. zLength = faces.length;
  21825. while (offset < zLength) {
  21826. type = faces[offset++];
  21827. isQuad = isBitSet(type, 0);
  21828. hasMaterial = isBitSet(type, 1);
  21829. hasFaceVertexUv = isBitSet(type, 3);
  21830. hasFaceNormal = isBitSet(type, 4);
  21831. hasFaceVertexNormal = isBitSet(type, 5);
  21832. hasFaceColor = isBitSet(type, 6);
  21833. hasFaceVertexColor = isBitSet(type, 7);
  21834. // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
  21835. if (isQuad) {
  21836. faceA = new Face3();
  21837. faceA.a = faces[offset];
  21838. faceA.b = faces[offset + 1];
  21839. faceA.c = faces[offset + 3];
  21840. faceB = new Face3();
  21841. faceB.a = faces[offset + 1];
  21842. faceB.b = faces[offset + 2];
  21843. faceB.c = faces[offset + 3];
  21844. offset += 4;
  21845. if (hasMaterial) {
  21846. materialIndex = faces[offset++];
  21847. faceA.materialIndex = materialIndex;
  21848. faceB.materialIndex = materialIndex;
  21849. }
  21850. // to get face <=> uv index correspondence
  21851. fi = geometry.faces.length;
  21852. if (hasFaceVertexUv) {
  21853. for (i = 0; i < nUvLayers; i++) {
  21854. uvLayer = json.uvs[i];
  21855. geometry.faceVertexUvs[i][fi] = [];
  21856. geometry.faceVertexUvs[i][fi + 1] = [];
  21857. for (j = 0; j < 4; j++) {
  21858. uvIndex = faces[offset++];
  21859. u = uvLayer[uvIndex * 2];
  21860. v = uvLayer[uvIndex * 2 + 1];
  21861. uv = new Vector2(u, v);
  21862. if (j !== 2) geometry.faceVertexUvs[i][fi].push(uv);
  21863. if (j !== 0) geometry.faceVertexUvs[i][fi + 1].push(uv);
  21864. }
  21865. }
  21866. }
  21867. if (hasFaceNormal) {
  21868. normalIndex = faces[offset++] * 3;
  21869. faceA.normal.set(normals[normalIndex++], normals[normalIndex++], normals[normalIndex]);
  21870. faceB.normal.copy(faceA.normal);
  21871. }
  21872. if (hasFaceVertexNormal) {
  21873. for (i = 0; i < 4; i++) {
  21874. normalIndex = faces[offset++] * 3;
  21875. normal = new Vector3(normals[normalIndex++], normals[normalIndex++], normals[normalIndex]);
  21876. if (i !== 2) faceA.vertexNormals.push(normal);
  21877. if (i !== 0) faceB.vertexNormals.push(normal);
  21878. }
  21879. }
  21880. if (hasFaceColor) {
  21881. colorIndex = faces[offset++];
  21882. hex = colors[colorIndex];
  21883. faceA.color.setHex(hex);
  21884. faceB.color.setHex(hex);
  21885. }
  21886. if (hasFaceVertexColor) {
  21887. for (i = 0; i < 4; i++) {
  21888. colorIndex = faces[offset++];
  21889. hex = colors[colorIndex];
  21890. if (i !== 2) faceA.vertexColors.push(new Color(hex));
  21891. if (i !== 0) faceB.vertexColors.push(new Color(hex));
  21892. }
  21893. }
  21894. geometry.faces.push(faceA);
  21895. geometry.faces.push(faceB);
  21896. } else {
  21897. face = new Face3();
  21898. face.a = faces[offset++];
  21899. face.b = faces[offset++];
  21900. face.c = faces[offset++];
  21901. if (hasMaterial) {
  21902. materialIndex = faces[offset++];
  21903. face.materialIndex = materialIndex;
  21904. }
  21905. // to get face <=> uv index correspondence
  21906. fi = geometry.faces.length;
  21907. if (hasFaceVertexUv) {
  21908. for (i = 0; i < nUvLayers; i++) {
  21909. uvLayer = json.uvs[i];
  21910. geometry.faceVertexUvs[i][fi] = [];
  21911. for (j = 0; j < 3; j++) {
  21912. uvIndex = faces[offset++];
  21913. u = uvLayer[uvIndex * 2];
  21914. v = uvLayer[uvIndex * 2 + 1];
  21915. uv = new Vector2(u, v);
  21916. geometry.faceVertexUvs[i][fi].push(uv);
  21917. }
  21918. }
  21919. }
  21920. if (hasFaceNormal) {
  21921. normalIndex = faces[offset++] * 3;
  21922. face.normal.set(normals[normalIndex++], normals[normalIndex++], normals[normalIndex]);
  21923. }
  21924. if (hasFaceVertexNormal) {
  21925. for (i = 0; i < 3; i++) {
  21926. normalIndex = faces[offset++] * 3;
  21927. normal = new Vector3(normals[normalIndex++], normals[normalIndex++], normals[normalIndex]);
  21928. face.vertexNormals.push(normal);
  21929. }
  21930. }
  21931. if (hasFaceColor) {
  21932. colorIndex = faces[offset++];
  21933. face.color.setHex(colors[colorIndex]);
  21934. }
  21935. if (hasFaceVertexColor) {
  21936. for (i = 0; i < 3; i++) {
  21937. colorIndex = faces[offset++];
  21938. face.vertexColors.push(new Color(colors[colorIndex]));
  21939. }
  21940. }
  21941. geometry.faces.push(face);
  21942. }
  21943. }
  21944. }
  21945. function parseSkin(json, geometry) {
  21946. var influencesPerVertex = json.influencesPerVertex !== undefined ? json.influencesPerVertex : 2;
  21947. if (json.skinWeights) {
  21948. for (var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex) {
  21949. var x = json.skinWeights[i];
  21950. var y = influencesPerVertex > 1 ? json.skinWeights[i + 1] : 0;
  21951. var z = influencesPerVertex > 2 ? json.skinWeights[i + 2] : 0;
  21952. var w = influencesPerVertex > 3 ? json.skinWeights[i + 3] : 0;
  21953. geometry.skinWeights.push(new Vector4(x, y, z, w));
  21954. }
  21955. }
  21956. if (json.skinIndices) {
  21957. for (var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex) {
  21958. var a = json.skinIndices[i];
  21959. var b = influencesPerVertex > 1 ? json.skinIndices[i + 1] : 0;
  21960. var c = influencesPerVertex > 2 ? json.skinIndices[i + 2] : 0;
  21961. var d = influencesPerVertex > 3 ? json.skinIndices[i + 3] : 0;
  21962. geometry.skinIndices.push(new Vector4(a, b, c, d));
  21963. }
  21964. }
  21965. geometry.bones = json.bones;
  21966. if (geometry.bones && geometry.bones.length > 0 && (geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length)) {
  21967. console.warn('When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.');
  21968. }
  21969. }
  21970. function parseMorphing(json, geometry) {
  21971. var scale = json.scale;
  21972. if (json.morphTargets !== undefined) {
  21973. for (var i = 0, l = json.morphTargets.length; i < l; i++) {
  21974. geometry.morphTargets[i] = {};
  21975. geometry.morphTargets[i].name = json.morphTargets[i].name;
  21976. geometry.morphTargets[i].vertices = [];
  21977. var dstVertices = geometry.morphTargets[i].vertices;
  21978. var srcVertices = json.morphTargets[i].vertices;
  21979. for (var v = 0, vl = srcVertices.length; v < vl; v += 3) {
  21980. var vertex = new Vector3();
  21981. vertex.x = srcVertices[v] * scale;
  21982. vertex.y = srcVertices[v + 1] * scale;
  21983. vertex.z = srcVertices[v + 2] * scale;
  21984. dstVertices.push(vertex);
  21985. }
  21986. }
  21987. }
  21988. if (json.morphColors !== undefined && json.morphColors.length > 0) {
  21989. console.warn('THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.');
  21990. var faces = geometry.faces;
  21991. var morphColors = json.morphColors[0].colors;
  21992. for (var i = 0, l = faces.length; i < l; i++) {
  21993. faces[i].color.fromArray(morphColors, i * 3);
  21994. }
  21995. }
  21996. }
  21997. function parseAnimations(json, geometry) {
  21998. var outputAnimations = [];
  21999. // parse old style Bone/Hierarchy animations
  22000. var animations = [];
  22001. if (json.animation !== undefined) {
  22002. animations.push(json.animation);
  22003. }
  22004. if (json.animations !== undefined) {
  22005. if (json.animations.length) {
  22006. animations = animations.concat(json.animations);
  22007. } else {
  22008. animations.push(json.animations);
  22009. }
  22010. }
  22011. for (var i = 0; i < animations.length; i++) {
  22012. var clip = AnimationClip.parseAnimation(animations[i], geometry.bones);
  22013. if (clip) outputAnimations.push(clip);
  22014. }
  22015. // parse implicit morph animations
  22016. if (geometry.morphTargets) {
  22017. // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
  22018. var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences(geometry.morphTargets, 10);
  22019. outputAnimations = outputAnimations.concat(morphAnimationClips);
  22020. }
  22021. if (outputAnimations.length > 0) geometry.animations = outputAnimations;
  22022. }
  22023. return function parse(json, texturePath) {
  22024. if (json.data !== undefined) {
  22025. // Geometry 4.0 spec
  22026. json = json.data;
  22027. }
  22028. if (json.scale !== undefined) {
  22029. json.scale = 1.0 / json.scale;
  22030. } else {
  22031. json.scale = 1.0;
  22032. }
  22033. var geometry = new Geometry();
  22034. parseModel(json, geometry);
  22035. parseSkin(json, geometry);
  22036. parseMorphing(json, geometry);
  22037. parseAnimations(json, geometry);
  22038. geometry.computeFaceNormals();
  22039. geometry.computeBoundingSphere();
  22040. if (json.materials === undefined || json.materials.length === 0) {
  22041. return { geometry: geometry };
  22042. } else {
  22043. var materials = Loader.prototype.initMaterials(json.materials, texturePath, this.crossOrigin);
  22044. return { geometry: geometry, materials: materials };
  22045. }
  22046. };
  22047. }()
  22048. });
  22049. /**
  22050. * @author mrdoob / http://mrdoob.com/
  22051. */
  22052. function ObjectLoader(manager) {
  22053. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  22054. this.texturePath = '';
  22055. }
  22056. Object.assign(ObjectLoader.prototype, {
  22057. load: function (url, onLoad, onProgress, onError) {
  22058. if (this.texturePath === '') {
  22059. this.texturePath = url.substring(0, url.lastIndexOf('/') + 1);
  22060. }
  22061. var scope = this;
  22062. var loader = new FileLoader(scope.manager);
  22063. loader.load(url, function (text) {
  22064. var json = null;
  22065. try {
  22066. json = JSON.parse(text);
  22067. } catch (error) {
  22068. if (onError !== undefined) onError(error);
  22069. console.error('THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message);
  22070. return;
  22071. }
  22072. var metadata = json.metadata;
  22073. if (metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry') {
  22074. console.error('THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.');
  22075. return;
  22076. }
  22077. scope.parse(json, onLoad);
  22078. }, onProgress, onError);
  22079. },
  22080. setTexturePath: function (value) {
  22081. this.texturePath = value;
  22082. return this;
  22083. },
  22084. setCrossOrigin: function (value) {
  22085. this.crossOrigin = value;
  22086. return this;
  22087. },
  22088. parse: function (json, onLoad) {
  22089. var shapes = this.parseShape(json.shapes);
  22090. var geometries = this.parseGeometries(json.geometries, shapes);
  22091. var images = this.parseImages(json.images, function () {
  22092. if (onLoad !== undefined) onLoad(object);
  22093. });
  22094. var textures = this.parseTextures(json.textures, images);
  22095. var materials = this.parseMaterials(json.materials, textures);
  22096. var object = this.parseObject(json.object, geometries, materials);
  22097. if (json.animations) {
  22098. object.animations = this.parseAnimations(json.animations);
  22099. }
  22100. if (json.images === undefined || json.images.length === 0) {
  22101. if (onLoad !== undefined) onLoad(object);
  22102. }
  22103. return object;
  22104. },
  22105. parseShape: function (json) {
  22106. var shapes = {};
  22107. if (json !== undefined) {
  22108. for (var i = 0, l = json.length; i < l; i++) {
  22109. var shape = new Shape().fromJSON(json[i]);
  22110. shapes[shape.uuid] = shape;
  22111. }
  22112. }
  22113. return shapes;
  22114. },
  22115. parseGeometries: function (json, shapes) {
  22116. var geometries = {};
  22117. if (json !== undefined) {
  22118. var geometryLoader = new JSONLoader();
  22119. var bufferGeometryLoader = new BufferGeometryLoader();
  22120. for (var i = 0, l = json.length; i < l; i++) {
  22121. var geometry;
  22122. var data = json[i];
  22123. switch (data.type) {
  22124. case 'PlaneGeometry':
  22125. case 'PlaneBufferGeometry':
  22126. geometry = new Geometries[data.type](data.width, data.height, data.widthSegments, data.heightSegments);
  22127. break;
  22128. case 'BoxGeometry':
  22129. case 'BoxBufferGeometry':
  22130. case 'CubeGeometry':
  22131. // backwards compatible
  22132. geometry = new Geometries[data.type](data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments);
  22133. break;
  22134. case 'CircleGeometry':
  22135. case 'CircleBufferGeometry':
  22136. geometry = new Geometries[data.type](data.radius, data.segments, data.thetaStart, data.thetaLength);
  22137. break;
  22138. case 'CylinderGeometry':
  22139. case 'CylinderBufferGeometry':
  22140. geometry = new Geometries[data.type](data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength);
  22141. break;
  22142. case 'ConeGeometry':
  22143. case 'ConeBufferGeometry':
  22144. geometry = new Geometries[data.type](data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength);
  22145. break;
  22146. case 'SphereGeometry':
  22147. case 'SphereBufferGeometry':
  22148. geometry = new Geometries[data.type](data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength);
  22149. break;
  22150. case 'DodecahedronGeometry':
  22151. case 'DodecahedronBufferGeometry':
  22152. case 'IcosahedronGeometry':
  22153. case 'IcosahedronBufferGeometry':
  22154. case 'OctahedronGeometry':
  22155. case 'OctahedronBufferGeometry':
  22156. case 'TetrahedronGeometry':
  22157. case 'TetrahedronBufferGeometry':
  22158. geometry = new Geometries[data.type](data.radius, data.detail);
  22159. break;
  22160. case 'RingGeometry':
  22161. case 'RingBufferGeometry':
  22162. geometry = new Geometries[data.type](data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength);
  22163. break;
  22164. case 'TorusGeometry':
  22165. case 'TorusBufferGeometry':
  22166. geometry = new Geometries[data.type](data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc);
  22167. break;
  22168. case 'TorusKnotGeometry':
  22169. case 'TorusKnotBufferGeometry':
  22170. geometry = new Geometries[data.type](data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q);
  22171. break;
  22172. case 'LatheGeometry':
  22173. case 'LatheBufferGeometry':
  22174. geometry = new Geometries[data.type](data.points, data.segments, data.phiStart, data.phiLength);
  22175. break;
  22176. case 'PolyhedronGeometry':
  22177. case 'PolyhedronBufferGeometry':
  22178. geometry = new Geometries[data.type](data.vertices, data.indices, data.radius, data.details);
  22179. break;
  22180. case 'ShapeGeometry':
  22181. case 'ShapeBufferGeometry':
  22182. var geometryShapes = [];
  22183. for (var j = 0, jl = data.shapes.length; j < jl; j++) {
  22184. var shape = shapes[data.shapes[j]];
  22185. geometryShapes.push(shape);
  22186. }
  22187. geometry = new Geometries[data.type](geometryShapes, data.curveSegments);
  22188. break;
  22189. case 'ExtrudeGeometry':
  22190. case 'ExtrudeBufferGeometry':
  22191. var geometryShapes = [];
  22192. for (var j = 0, jl = data.shapes.length; j < jl; j++) {
  22193. var shape = shapes[data.shapes[j]];
  22194. geometryShapes.push(shape);
  22195. }
  22196. var extrudePath = data.options.extrudePath;
  22197. if (extrudePath !== undefined) {
  22198. data.options.extrudePath = new Curves[extrudePath.type]().fromJSON(extrudePath);
  22199. }
  22200. geometry = new Geometries[data.type](geometryShapes, data.options);
  22201. break;
  22202. case 'BufferGeometry':
  22203. geometry = bufferGeometryLoader.parse(data);
  22204. break;
  22205. case 'Geometry':
  22206. geometry = geometryLoader.parse(data, this.texturePath).geometry;
  22207. break;
  22208. default:
  22209. console.warn('THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"');
  22210. continue;
  22211. }
  22212. geometry.uuid = data.uuid;
  22213. if (data.name !== undefined) geometry.name = data.name;
  22214. if (geometry.isBufferGeometry === true && data.userData !== undefined) geometry.userData = data.userData;
  22215. geometries[data.uuid] = geometry;
  22216. }
  22217. }
  22218. return geometries;
  22219. },
  22220. parseMaterials: function (json, textures) {
  22221. var materials = {};
  22222. if (json !== undefined) {
  22223. var loader = new MaterialLoader();
  22224. loader.setTextures(textures);
  22225. for (var i = 0, l = json.length; i < l; i++) {
  22226. var data = json[i];
  22227. if (data.type === 'MultiMaterial') {
  22228. // Deprecated
  22229. var array = [];
  22230. for (var j = 0; j < data.materials.length; j++) {
  22231. array.push(loader.parse(data.materials[j]));
  22232. }
  22233. materials[data.uuid] = array;
  22234. } else {
  22235. materials[data.uuid] = loader.parse(data);
  22236. }
  22237. }
  22238. }
  22239. return materials;
  22240. },
  22241. parseAnimations: function (json) {
  22242. var animations = [];
  22243. for (var i = 0; i < json.length; i++) {
  22244. var data = json[i];
  22245. var clip = AnimationClip.parse(data);
  22246. if (data.uuid !== undefined) clip.uuid = data.uuid;
  22247. animations.push(clip);
  22248. }
  22249. return animations;
  22250. },
  22251. parseImages: function (json, onLoad) {
  22252. var scope = this;
  22253. var images = {};
  22254. function loadImage(url) {
  22255. scope.manager.itemStart(url);
  22256. return loader.load(url, function () {
  22257. scope.manager.itemEnd(url);
  22258. }, undefined, function () {
  22259. scope.manager.itemEnd(url);
  22260. scope.manager.itemError(url);
  22261. });
  22262. }
  22263. if (json !== undefined && json.length > 0) {
  22264. var manager = new LoadingManager(onLoad);
  22265. var loader = new ImageLoader(manager);
  22266. loader.setCrossOrigin(this.crossOrigin);
  22267. for (var i = 0, l = json.length; i < l; i++) {
  22268. var image = json[i];
  22269. var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(image.url) ? image.url : scope.texturePath + image.url;
  22270. images[image.uuid] = loadImage(path);
  22271. }
  22272. }
  22273. return images;
  22274. },
  22275. parseTextures: function (json, images) {
  22276. function parseConstant(value, type) {
  22277. if (typeof value === 'number') return value;
  22278. console.warn('THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value);
  22279. return type[value];
  22280. }
  22281. var textures = {};
  22282. if (json !== undefined) {
  22283. for (var i = 0, l = json.length; i < l; i++) {
  22284. var data = json[i];
  22285. if (data.image === undefined) {
  22286. console.warn('THREE.ObjectLoader: No "image" specified for', data.uuid);
  22287. }
  22288. if (images[data.image] === undefined) {
  22289. console.warn('THREE.ObjectLoader: Undefined image', data.image);
  22290. }
  22291. var texture = new Texture(images[data.image]);
  22292. texture.needsUpdate = true;
  22293. texture.uuid = data.uuid;
  22294. if (data.name !== undefined) texture.name = data.name;
  22295. if (data.mapping !== undefined) texture.mapping = parseConstant(data.mapping, TEXTURE_MAPPING);
  22296. if (data.offset !== undefined) texture.offset.fromArray(data.offset);
  22297. if (data.repeat !== undefined) texture.repeat.fromArray(data.repeat);
  22298. if (data.center !== undefined) texture.center.fromArray(data.center);
  22299. if (data.rotation !== undefined) texture.rotation = data.rotation;
  22300. if (data.wrap !== undefined) {
  22301. texture.wrapS = parseConstant(data.wrap[0], TEXTURE_WRAPPING);
  22302. texture.wrapT = parseConstant(data.wrap[1], TEXTURE_WRAPPING);
  22303. }
  22304. if (data.format !== undefined) texture.format = data.format;
  22305. if (data.minFilter !== undefined) texture.minFilter = parseConstant(data.minFilter, TEXTURE_FILTER);
  22306. if (data.magFilter !== undefined) texture.magFilter = parseConstant(data.magFilter, TEXTURE_FILTER);
  22307. if (data.anisotropy !== undefined) texture.anisotropy = data.anisotropy;
  22308. if (data.flipY !== undefined) texture.flipY = data.flipY;
  22309. textures[data.uuid] = texture;
  22310. }
  22311. }
  22312. return textures;
  22313. },
  22314. parseObject: function (data, geometries, materials) {
  22315. var object;
  22316. function getGeometry(name) {
  22317. if (geometries[name] === undefined) {
  22318. console.warn('THREE.ObjectLoader: Undefined geometry', name);
  22319. }
  22320. return geometries[name];
  22321. }
  22322. function getMaterial(name) {
  22323. if (name === undefined) return undefined;
  22324. if (Array.isArray(name)) {
  22325. var array = [];
  22326. for (var i = 0, l = name.length; i < l; i++) {
  22327. var uuid = name[i];
  22328. if (materials[uuid] === undefined) {
  22329. console.warn('THREE.ObjectLoader: Undefined material', uuid);
  22330. }
  22331. array.push(materials[uuid]);
  22332. }
  22333. return array;
  22334. }
  22335. if (materials[name] === undefined) {
  22336. console.warn('THREE.ObjectLoader: Undefined material', name);
  22337. }
  22338. return materials[name];
  22339. }
  22340. switch (data.type) {
  22341. case 'Scene':
  22342. object = new Scene();
  22343. if (data.background !== undefined) {
  22344. if (Number.isInteger(data.background)) {
  22345. object.background = new Color(data.background);
  22346. }
  22347. }
  22348. if (data.fog !== undefined) {
  22349. if (data.fog.type === 'Fog') {
  22350. object.fog = new Fog(data.fog.color, data.fog.near, data.fog.far);
  22351. } else if (data.fog.type === 'FogExp2') {
  22352. object.fog = new FogExp2(data.fog.color, data.fog.density);
  22353. }
  22354. }
  22355. break;
  22356. case 'PerspectiveCamera':
  22357. object = new PerspectiveCamera(data.fov, data.aspect, data.near, data.far);
  22358. if (data.focus !== undefined) object.focus = data.focus;
  22359. if (data.zoom !== undefined) object.zoom = data.zoom;
  22360. if (data.filmGauge !== undefined) object.filmGauge = data.filmGauge;
  22361. if (data.filmOffset !== undefined) object.filmOffset = data.filmOffset;
  22362. if (data.view !== undefined) object.view = Object.assign({}, data.view);
  22363. break;
  22364. case 'OrthographicCamera':
  22365. object = new OrthographicCamera(data.left, data.right, data.top, data.bottom, data.near, data.far);
  22366. if (data.zoom !== undefined) object.zoom = data.zoom;
  22367. if (data.view !== undefined) object.view = Object.assign({}, data.view);
  22368. break;
  22369. case 'AmbientLight':
  22370. object = new AmbientLight(data.color, data.intensity);
  22371. break;
  22372. case 'DirectionalLight':
  22373. object = new DirectionalLight(data.color, data.intensity);
  22374. break;
  22375. case 'PointLight':
  22376. object = new PointLight(data.color, data.intensity, data.distance, data.decay);
  22377. break;
  22378. case 'RectAreaLight':
  22379. object = new RectAreaLight(data.color, data.intensity, data.width, data.height);
  22380. break;
  22381. case 'SpotLight':
  22382. object = new SpotLight(data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay);
  22383. break;
  22384. case 'HemisphereLight':
  22385. object = new HemisphereLight(data.color, data.groundColor, data.intensity);
  22386. break;
  22387. case 'SkinnedMesh':
  22388. console.warn('THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.');
  22389. case 'Mesh':
  22390. var geometry = getGeometry(data.geometry);
  22391. var material = getMaterial(data.material);
  22392. if (geometry.bones && geometry.bones.length > 0) {
  22393. object = new SkinnedMesh(geometry, material);
  22394. } else {
  22395. object = new Mesh(geometry, material);
  22396. }
  22397. break;
  22398. case 'LOD':
  22399. object = new LOD();
  22400. break;
  22401. case 'Line':
  22402. object = new Line(getGeometry(data.geometry), getMaterial(data.material), data.mode);
  22403. break;
  22404. case 'LineLoop':
  22405. object = new LineLoop(getGeometry(data.geometry), getMaterial(data.material));
  22406. break;
  22407. case 'LineSegments':
  22408. object = new LineSegments(getGeometry(data.geometry), getMaterial(data.material));
  22409. break;
  22410. case 'PointCloud':
  22411. case 'Points':
  22412. object = new Points(getGeometry(data.geometry), getMaterial(data.material));
  22413. break;
  22414. case 'Sprite':
  22415. object = new Sprite(getMaterial(data.material));
  22416. break;
  22417. case 'Group':
  22418. object = new Group();
  22419. break;
  22420. default:
  22421. object = new Object3D();
  22422. }
  22423. object.uuid = data.uuid;
  22424. if (data.name !== undefined) object.name = data.name;
  22425. if (data.matrix !== undefined) {
  22426. object.matrix.fromArray(data.matrix);
  22427. if (data.matrixAutoUpdate !== undefined) object.matrixAutoUpdate = data.matrixAutoUpdate;
  22428. if (object.matrixAutoUpdate) object.matrix.decompose(object.position, object.quaternion, object.scale);
  22429. } else {
  22430. if (data.position !== undefined) object.position.fromArray(data.position);
  22431. if (data.rotation !== undefined) object.rotation.fromArray(data.rotation);
  22432. if (data.quaternion !== undefined) object.quaternion.fromArray(data.quaternion);
  22433. if (data.scale !== undefined) object.scale.fromArray(data.scale);
  22434. }
  22435. if (data.castShadow !== undefined) object.castShadow = data.castShadow;
  22436. if (data.receiveShadow !== undefined) object.receiveShadow = data.receiveShadow;
  22437. if (data.shadow) {
  22438. if (data.shadow.bias !== undefined) object.shadow.bias = data.shadow.bias;
  22439. if (data.shadow.radius !== undefined) object.shadow.radius = data.shadow.radius;
  22440. if (data.shadow.mapSize !== undefined) object.shadow.mapSize.fromArray(data.shadow.mapSize);
  22441. if (data.shadow.camera !== undefined) object.shadow.camera = this.parseObject(data.shadow.camera);
  22442. }
  22443. if (data.visible !== undefined) object.visible = data.visible;
  22444. if (data.frustumCulled !== undefined) object.frustumCulled = data.frustumCulled;
  22445. if (data.renderOrder !== undefined) object.renderOrder = data.renderOrder;
  22446. if (data.userData !== undefined) object.userData = data.userData;
  22447. if (data.children !== undefined) {
  22448. var children = data.children;
  22449. for (var i = 0; i < children.length; i++) {
  22450. object.add(this.parseObject(children[i], geometries, materials));
  22451. }
  22452. }
  22453. if (data.type === 'LOD') {
  22454. var levels = data.levels;
  22455. for (var l = 0; l < levels.length; l++) {
  22456. var level = levels[l];
  22457. var child = object.getObjectByProperty('uuid', level.object);
  22458. if (child !== undefined) {
  22459. object.addLevel(child, level.distance);
  22460. }
  22461. }
  22462. }
  22463. return object;
  22464. }
  22465. });
  22466. var TEXTURE_MAPPING = {
  22467. UVMapping: UVMapping,
  22468. CubeReflectionMapping: CubeReflectionMapping,
  22469. CubeRefractionMapping: CubeRefractionMapping,
  22470. EquirectangularReflectionMapping: EquirectangularReflectionMapping,
  22471. EquirectangularRefractionMapping: EquirectangularRefractionMapping,
  22472. SphericalReflectionMapping: SphericalReflectionMapping,
  22473. CubeUVReflectionMapping: CubeUVReflectionMapping,
  22474. CubeUVRefractionMapping: CubeUVRefractionMapping
  22475. };
  22476. var TEXTURE_WRAPPING = {
  22477. RepeatWrapping: RepeatWrapping,
  22478. ClampToEdgeWrapping: ClampToEdgeWrapping,
  22479. MirroredRepeatWrapping: MirroredRepeatWrapping
  22480. };
  22481. var TEXTURE_FILTER = {
  22482. NearestFilter: NearestFilter,
  22483. NearestMipMapNearestFilter: NearestMipMapNearestFilter,
  22484. NearestMipMapLinearFilter: NearestMipMapLinearFilter,
  22485. LinearFilter: LinearFilter,
  22486. LinearMipMapNearestFilter: LinearMipMapNearestFilter,
  22487. LinearMipMapLinearFilter: LinearMipMapLinearFilter
  22488. };
  22489. /**
  22490. * @author thespite / http://clicktorelease.com/
  22491. */
  22492. function ImageBitmapLoader(manager) {
  22493. if (typeof createImageBitmap === 'undefined') {
  22494. console.warn('THREE.ImageBitmapLoader: createImageBitmap() not supported.');
  22495. }
  22496. if (typeof fetch === 'undefined') {
  22497. console.warn('THREE.ImageBitmapLoader: fetch() not supported.');
  22498. }
  22499. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  22500. this.options = undefined;
  22501. }
  22502. ImageBitmapLoader.prototype = {
  22503. constructor: ImageBitmapLoader,
  22504. setOptions: function setOptions(options) {
  22505. this.options = options;
  22506. return this;
  22507. },
  22508. load: function (url, onLoad, onProgress, onError) {
  22509. if (url === undefined) url = '';
  22510. if (this.path !== undefined) url = this.path + url;
  22511. url = this.manager.resolveURL(url);
  22512. var scope = this;
  22513. var cached = Cache.get(url);
  22514. if (cached !== undefined) {
  22515. scope.manager.itemStart(url);
  22516. setTimeout(function () {
  22517. if (onLoad) onLoad(cached);
  22518. scope.manager.itemEnd(url);
  22519. }, 0);
  22520. return cached;
  22521. }
  22522. fetch(url).then(function (res) {
  22523. return res.blob();
  22524. }).then(function (blob) {
  22525. return createImageBitmap(blob, scope.options);
  22526. }).then(function (imageBitmap) {
  22527. Cache.add(url, imageBitmap);
  22528. if (onLoad) onLoad(imageBitmap);
  22529. scope.manager.itemEnd(url);
  22530. }).catch(function (e) {
  22531. if (onError) onError(e);
  22532. scope.manager.itemEnd(url);
  22533. scope.manager.itemError(url);
  22534. });
  22535. },
  22536. setCrossOrigin: function () /* value */{
  22537. return this;
  22538. },
  22539. setPath: function (value) {
  22540. this.path = value;
  22541. return this;
  22542. }
  22543. };
  22544. /**
  22545. * @author zz85 / http://www.lab4games.net/zz85/blog
  22546. * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
  22547. **/
  22548. function ShapePath() {
  22549. this.type = 'ShapePath';
  22550. this.color = new Color();
  22551. this.subPaths = [];
  22552. this.currentPath = null;
  22553. }
  22554. Object.assign(ShapePath.prototype, {
  22555. moveTo: function (x, y) {
  22556. this.currentPath = new Path();
  22557. this.subPaths.push(this.currentPath);
  22558. this.currentPath.moveTo(x, y);
  22559. },
  22560. lineTo: function (x, y) {
  22561. this.currentPath.lineTo(x, y);
  22562. },
  22563. quadraticCurveTo: function (aCPx, aCPy, aX, aY) {
  22564. this.currentPath.quadraticCurveTo(aCPx, aCPy, aX, aY);
  22565. },
  22566. bezierCurveTo: function (aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) {
  22567. this.currentPath.bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY);
  22568. },
  22569. splineThru: function (pts) {
  22570. this.currentPath.splineThru(pts);
  22571. },
  22572. toShapes: function (isCCW, noHoles) {
  22573. function toShapesNoHoles(inSubpaths) {
  22574. var shapes = [];
  22575. for (var i = 0, l = inSubpaths.length; i < l; i++) {
  22576. var tmpPath = inSubpaths[i];
  22577. var tmpShape = new Shape();
  22578. tmpShape.curves = tmpPath.curves;
  22579. shapes.push(tmpShape);
  22580. }
  22581. return shapes;
  22582. }
  22583. function isPointInsidePolygon(inPt, inPolygon) {
  22584. var polyLen = inPolygon.length;
  22585. // inPt on polygon contour => immediate success or
  22586. // toggling of inside/outside at every single! intersection point of an edge
  22587. // with the horizontal line through inPt, left of inPt
  22588. // not counting lowerY endpoints of edges and whole edges on that line
  22589. var inside = false;
  22590. for (var p = polyLen - 1, q = 0; q < polyLen; p = q++) {
  22591. var edgeLowPt = inPolygon[p];
  22592. var edgeHighPt = inPolygon[q];
  22593. var edgeDx = edgeHighPt.x - edgeLowPt.x;
  22594. var edgeDy = edgeHighPt.y - edgeLowPt.y;
  22595. if (Math.abs(edgeDy) > Number.EPSILON) {
  22596. // not parallel
  22597. if (edgeDy < 0) {
  22598. edgeLowPt = inPolygon[q];edgeDx = -edgeDx;
  22599. edgeHighPt = inPolygon[p];edgeDy = -edgeDy;
  22600. }
  22601. if (inPt.y < edgeLowPt.y || inPt.y > edgeHighPt.y) continue;
  22602. if (inPt.y === edgeLowPt.y) {
  22603. if (inPt.x === edgeLowPt.x) return true; // inPt is on contour ?
  22604. // continue; // no intersection or edgeLowPt => doesn't count !!!
  22605. } else {
  22606. var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
  22607. if (perpEdge === 0) return true; // inPt is on contour ?
  22608. if (perpEdge < 0) continue;
  22609. inside = !inside; // true intersection left of inPt
  22610. }
  22611. } else {
  22612. // parallel or collinear
  22613. if (inPt.y !== edgeLowPt.y) continue; // parallel
  22614. // edge lies on the same horizontal line as inPt
  22615. if (edgeHighPt.x <= inPt.x && inPt.x <= edgeLowPt.x || edgeLowPt.x <= inPt.x && inPt.x <= edgeHighPt.x) return true; // inPt: Point on contour !
  22616. // continue;
  22617. }
  22618. }
  22619. return inside;
  22620. }
  22621. var isClockWise = ShapeUtils.isClockWise;
  22622. var subPaths = this.subPaths;
  22623. if (subPaths.length === 0) return [];
  22624. if (noHoles === true) return toShapesNoHoles(subPaths);
  22625. var solid,
  22626. tmpPath,
  22627. tmpShape,
  22628. shapes = [];
  22629. if (subPaths.length === 1) {
  22630. tmpPath = subPaths[0];
  22631. tmpShape = new Shape();
  22632. tmpShape.curves = tmpPath.curves;
  22633. shapes.push(tmpShape);
  22634. return shapes;
  22635. }
  22636. var holesFirst = !isClockWise(subPaths[0].getPoints());
  22637. holesFirst = isCCW ? !holesFirst : holesFirst;
  22638. // console.log("Holes first", holesFirst);
  22639. var betterShapeHoles = [];
  22640. var newShapes = [];
  22641. var newShapeHoles = [];
  22642. var mainIdx = 0;
  22643. var tmpPoints;
  22644. newShapes[mainIdx] = undefined;
  22645. newShapeHoles[mainIdx] = [];
  22646. for (var i = 0, l = subPaths.length; i < l; i++) {
  22647. tmpPath = subPaths[i];
  22648. tmpPoints = tmpPath.getPoints();
  22649. solid = isClockWise(tmpPoints);
  22650. solid = isCCW ? !solid : solid;
  22651. if (solid) {
  22652. if (!holesFirst && newShapes[mainIdx]) mainIdx++;
  22653. newShapes[mainIdx] = { s: new Shape(), p: tmpPoints };
  22654. newShapes[mainIdx].s.curves = tmpPath.curves;
  22655. if (holesFirst) mainIdx++;
  22656. newShapeHoles[mainIdx] = [];
  22657. //console.log('cw', i);
  22658. } else {
  22659. newShapeHoles[mainIdx].push({ h: tmpPath, p: tmpPoints[0] });
  22660. //console.log('ccw', i);
  22661. }
  22662. }
  22663. // only Holes? -> probably all Shapes with wrong orientation
  22664. if (!newShapes[0]) return toShapesNoHoles(subPaths);
  22665. if (newShapes.length > 1) {
  22666. var ambiguous = false;
  22667. var toChange = [];
  22668. for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++) {
  22669. betterShapeHoles[sIdx] = [];
  22670. }
  22671. for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++) {
  22672. var sho = newShapeHoles[sIdx];
  22673. for (var hIdx = 0; hIdx < sho.length; hIdx++) {
  22674. var ho = sho[hIdx];
  22675. var hole_unassigned = true;
  22676. for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx++) {
  22677. if (isPointInsidePolygon(ho.p, newShapes[s2Idx].p)) {
  22678. if (sIdx !== s2Idx) toChange.push({ froms: sIdx, tos: s2Idx, hole: hIdx });
  22679. if (hole_unassigned) {
  22680. hole_unassigned = false;
  22681. betterShapeHoles[s2Idx].push(ho);
  22682. } else {
  22683. ambiguous = true;
  22684. }
  22685. }
  22686. }
  22687. if (hole_unassigned) {
  22688. betterShapeHoles[sIdx].push(ho);
  22689. }
  22690. }
  22691. }
  22692. // console.log("ambiguous: ", ambiguous);
  22693. if (toChange.length > 0) {
  22694. // console.log("to change: ", toChange);
  22695. if (!ambiguous) newShapeHoles = betterShapeHoles;
  22696. }
  22697. }
  22698. var tmpHoles;
  22699. for (var i = 0, il = newShapes.length; i < il; i++) {
  22700. tmpShape = newShapes[i].s;
  22701. shapes.push(tmpShape);
  22702. tmpHoles = newShapeHoles[i];
  22703. for (var j = 0, jl = tmpHoles.length; j < jl; j++) {
  22704. tmpShape.holes.push(tmpHoles[j].h);
  22705. }
  22706. }
  22707. //console.log("shape", shapes);
  22708. return shapes;
  22709. }
  22710. });
  22711. /**
  22712. * @author zz85 / http://www.lab4games.net/zz85/blog
  22713. * @author mrdoob / http://mrdoob.com/
  22714. */
  22715. function Font(data) {
  22716. this.type = 'Font';
  22717. this.data = data;
  22718. }
  22719. Object.assign(Font.prototype, {
  22720. isFont: true,
  22721. generateShapes: function (text, size, divisions) {
  22722. if (size === undefined) size = 100;
  22723. if (divisions === undefined) divisions = 4;
  22724. var shapes = [];
  22725. var paths = createPaths(text, size, divisions, this.data);
  22726. for (var p = 0, pl = paths.length; p < pl; p++) {
  22727. Array.prototype.push.apply(shapes, paths[p].toShapes());
  22728. }
  22729. return shapes;
  22730. }
  22731. });
  22732. function createPaths(text, size, divisions, data) {
  22733. var chars = Array.from ? Array.from(text) : String(text).split(''); // see #13988
  22734. var scale = size / data.resolution;
  22735. var line_height = (data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness) * scale;
  22736. var paths = [];
  22737. var offsetX = 0,
  22738. offsetY = 0;
  22739. for (var i = 0; i < chars.length; i++) {
  22740. var char = chars[i];
  22741. if (char === '\n') {
  22742. offsetX = 0;
  22743. offsetY -= line_height;
  22744. } else {
  22745. var ret = createPath(char, divisions, scale, offsetX, offsetY, data);
  22746. offsetX += ret.offsetX;
  22747. paths.push(ret.path);
  22748. }
  22749. }
  22750. return paths;
  22751. }
  22752. function createPath(char, divisions, scale, offsetX, offsetY, data) {
  22753. var glyph = data.glyphs[char] || data.glyphs['?'];
  22754. if (!glyph) return;
  22755. var path = new ShapePath();
  22756. var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
  22757. if (glyph.o) {
  22758. var outline = glyph._cachedOutline || (glyph._cachedOutline = glyph.o.split(' '));
  22759. for (var i = 0, l = outline.length; i < l;) {
  22760. var action = outline[i++];
  22761. switch (action) {
  22762. case 'm':
  22763. // moveTo
  22764. x = outline[i++] * scale + offsetX;
  22765. y = outline[i++] * scale + offsetY;
  22766. path.moveTo(x, y);
  22767. break;
  22768. case 'l':
  22769. // lineTo
  22770. x = outline[i++] * scale + offsetX;
  22771. y = outline[i++] * scale + offsetY;
  22772. path.lineTo(x, y);
  22773. break;
  22774. case 'q':
  22775. // quadraticCurveTo
  22776. cpx = outline[i++] * scale + offsetX;
  22777. cpy = outline[i++] * scale + offsetY;
  22778. cpx1 = outline[i++] * scale + offsetX;
  22779. cpy1 = outline[i++] * scale + offsetY;
  22780. path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
  22781. break;
  22782. case 'b':
  22783. // bezierCurveTo
  22784. cpx = outline[i++] * scale + offsetX;
  22785. cpy = outline[i++] * scale + offsetY;
  22786. cpx1 = outline[i++] * scale + offsetX;
  22787. cpy1 = outline[i++] * scale + offsetY;
  22788. cpx2 = outline[i++] * scale + offsetX;
  22789. cpy2 = outline[i++] * scale + offsetY;
  22790. path.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, cpx, cpy);
  22791. break;
  22792. }
  22793. }
  22794. }
  22795. return { offsetX: glyph.ha * scale, path: path };
  22796. }
  22797. /**
  22798. * @author mrdoob / http://mrdoob.com/
  22799. */
  22800. function FontLoader(manager) {
  22801. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  22802. }
  22803. Object.assign(FontLoader.prototype, {
  22804. load: function (url, onLoad, onProgress, onError) {
  22805. var scope = this;
  22806. var loader = new FileLoader(this.manager);
  22807. loader.setPath(this.path);
  22808. loader.load(url, function (text) {
  22809. var json;
  22810. try {
  22811. json = JSON.parse(text);
  22812. } catch (e) {
  22813. console.warn('THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.');
  22814. json = JSON.parse(text.substring(65, text.length - 2));
  22815. }
  22816. var font = scope.parse(json);
  22817. if (onLoad) onLoad(font);
  22818. }, onProgress, onError);
  22819. },
  22820. parse: function (json) {
  22821. return new Font(json);
  22822. },
  22823. setPath: function (value) {
  22824. this.path = value;
  22825. return this;
  22826. }
  22827. });
  22828. /**
  22829. * @author mrdoob / http://mrdoob.com/
  22830. */
  22831. var context;
  22832. var AudioContext = {
  22833. getContext: function () {
  22834. if (context === undefined) {
  22835. context = new (window.AudioContext || window.webkitAudioContext)();
  22836. }
  22837. return context;
  22838. },
  22839. setContext: function (value) {
  22840. context = value;
  22841. }
  22842. };
  22843. /**
  22844. * @author Reece Aaron Lecrivain / http://reecenotes.com/
  22845. */
  22846. function AudioLoader(manager) {
  22847. this.manager = manager !== undefined ? manager : DefaultLoadingManager;
  22848. }
  22849. Object.assign(AudioLoader.prototype, {
  22850. load: function (url, onLoad, onProgress, onError) {
  22851. var loader = new FileLoader(this.manager);
  22852. loader.setResponseType('arraybuffer');
  22853. loader.load(url, function (buffer) {
  22854. var context = AudioContext.getContext();
  22855. context.decodeAudioData(buffer, function (audioBuffer) {
  22856. onLoad(audioBuffer);
  22857. });
  22858. }, onProgress, onError);
  22859. }
  22860. });
  22861. /**
  22862. * @author mrdoob / http://mrdoob.com/
  22863. */
  22864. function StereoCamera() {
  22865. this.type = 'StereoCamera';
  22866. this.aspect = 1;
  22867. this.eyeSep = 0.064;
  22868. this.cameraL = new PerspectiveCamera();
  22869. this.cameraL.layers.enable(1);
  22870. this.cameraL.matrixAutoUpdate = false;
  22871. this.cameraR = new PerspectiveCamera();
  22872. this.cameraR.layers.enable(2);
  22873. this.cameraR.matrixAutoUpdate = false;
  22874. }
  22875. Object.assign(StereoCamera.prototype, {
  22876. update: function () {
  22877. var instance, focus, fov, aspect, near, far, zoom, eyeSep;
  22878. var eyeRight = new Matrix4();
  22879. var eyeLeft = new Matrix4();
  22880. return function update(camera) {
  22881. 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;
  22882. if (needsUpdate) {
  22883. instance = this;
  22884. focus = camera.focus;
  22885. fov = camera.fov;
  22886. aspect = camera.aspect * this.aspect;
  22887. near = camera.near;
  22888. far = camera.far;
  22889. zoom = camera.zoom;
  22890. // Off-axis stereoscopic effect based on
  22891. // http://paulbourke.net/stereographics/stereorender/
  22892. var projectionMatrix = camera.projectionMatrix.clone();
  22893. eyeSep = this.eyeSep / 2;
  22894. var eyeSepOnProjection = eyeSep * near / focus;
  22895. var ymax = near * Math.tan(_Math.DEG2RAD * fov * 0.5) / zoom;
  22896. var xmin, xmax;
  22897. // translate xOffset
  22898. eyeLeft.elements[12] = -eyeSep;
  22899. eyeRight.elements[12] = eyeSep;
  22900. // for left eye
  22901. xmin = -ymax * aspect + eyeSepOnProjection;
  22902. xmax = ymax * aspect + eyeSepOnProjection;
  22903. projectionMatrix.elements[0] = 2 * near / (xmax - xmin);
  22904. projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin);
  22905. this.cameraL.projectionMatrix.copy(projectionMatrix);
  22906. // for right eye
  22907. xmin = -ymax * aspect - eyeSepOnProjection;
  22908. xmax = ymax * aspect - eyeSepOnProjection;
  22909. projectionMatrix.elements[0] = 2 * near / (xmax - xmin);
  22910. projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin);
  22911. this.cameraR.projectionMatrix.copy(projectionMatrix);
  22912. }
  22913. this.cameraL.matrixWorld.copy(camera.matrixWorld).multiply(eyeLeft);
  22914. this.cameraR.matrixWorld.copy(camera.matrixWorld).multiply(eyeRight);
  22915. };
  22916. }()
  22917. });
  22918. /**
  22919. * Camera for rendering cube maps
  22920. * - renders scene into axis-aligned cube
  22921. *
  22922. * @author alteredq / http://alteredqualia.com/
  22923. */
  22924. function CubeCamera(near, far, cubeResolution) {
  22925. Object3D.call(this);
  22926. this.type = 'CubeCamera';
  22927. var fov = 90,
  22928. aspect = 1;
  22929. var cameraPX = new PerspectiveCamera(fov, aspect, near, far);
  22930. cameraPX.up.set(0, -1, 0);
  22931. cameraPX.lookAt(new Vector3(1, 0, 0));
  22932. this.add(cameraPX);
  22933. var cameraNX = new PerspectiveCamera(fov, aspect, near, far);
  22934. cameraNX.up.set(0, -1, 0);
  22935. cameraNX.lookAt(new Vector3(-1, 0, 0));
  22936. this.add(cameraNX);
  22937. var cameraPY = new PerspectiveCamera(fov, aspect, near, far);
  22938. cameraPY.up.set(0, 0, 1);
  22939. cameraPY.lookAt(new Vector3(0, 1, 0));
  22940. this.add(cameraPY);
  22941. var cameraNY = new PerspectiveCamera(fov, aspect, near, far);
  22942. cameraNY.up.set(0, 0, -1);
  22943. cameraNY.lookAt(new Vector3(0, -1, 0));
  22944. this.add(cameraNY);
  22945. var cameraPZ = new PerspectiveCamera(fov, aspect, near, far);
  22946. cameraPZ.up.set(0, -1, 0);
  22947. cameraPZ.lookAt(new Vector3(0, 0, 1));
  22948. this.add(cameraPZ);
  22949. var cameraNZ = new PerspectiveCamera(fov, aspect, near, far);
  22950. cameraNZ.up.set(0, -1, 0);
  22951. cameraNZ.lookAt(new Vector3(0, 0, -1));
  22952. this.add(cameraNZ);
  22953. var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };
  22954. this.renderTarget = new WebGLRenderTargetCube(cubeResolution, cubeResolution, options);
  22955. this.renderTarget.texture.name = "CubeCamera";
  22956. this.update = function (renderer, scene) {
  22957. if (this.parent === null) this.updateMatrixWorld();
  22958. var renderTarget = this.renderTarget;
  22959. var generateMipmaps = renderTarget.texture.generateMipmaps;
  22960. renderTarget.texture.generateMipmaps = false;
  22961. renderTarget.activeCubeFace = 0;
  22962. renderer.render(scene, cameraPX, renderTarget);
  22963. renderTarget.activeCubeFace = 1;
  22964. renderer.render(scene, cameraNX, renderTarget);
  22965. renderTarget.activeCubeFace = 2;
  22966. renderer.render(scene, cameraPY, renderTarget);
  22967. renderTarget.activeCubeFace = 3;
  22968. renderer.render(scene, cameraNY, renderTarget);
  22969. renderTarget.activeCubeFace = 4;
  22970. renderer.render(scene, cameraPZ, renderTarget);
  22971. renderTarget.texture.generateMipmaps = generateMipmaps;
  22972. renderTarget.activeCubeFace = 5;
  22973. renderer.render(scene, cameraNZ, renderTarget);
  22974. renderer.setRenderTarget(null);
  22975. };
  22976. this.clear = function (renderer, color, depth, stencil) {
  22977. var renderTarget = this.renderTarget;
  22978. for (var i = 0; i < 6; i++) {
  22979. renderTarget.activeCubeFace = i;
  22980. renderer.setRenderTarget(renderTarget);
  22981. renderer.clear(color, depth, stencil);
  22982. }
  22983. renderer.setRenderTarget(null);
  22984. };
  22985. }
  22986. CubeCamera.prototype = Object.create(Object3D.prototype);
  22987. CubeCamera.prototype.constructor = CubeCamera;
  22988. /**
  22989. * @author mrdoob / http://mrdoob.com/
  22990. */
  22991. function AudioListener() {
  22992. Object3D.call(this);
  22993. this.type = 'AudioListener';
  22994. this.context = AudioContext.getContext();
  22995. this.gain = this.context.createGain();
  22996. this.gain.connect(this.context.destination);
  22997. this.filter = null;
  22998. }
  22999. AudioListener.prototype = Object.assign(Object.create(Object3D.prototype), {
  23000. constructor: AudioListener,
  23001. getInput: function () {
  23002. return this.gain;
  23003. },
  23004. removeFilter: function () {
  23005. if (this.filter !== null) {
  23006. this.gain.disconnect(this.filter);
  23007. this.filter.disconnect(this.context.destination);
  23008. this.gain.connect(this.context.destination);
  23009. this.filter = null;
  23010. }
  23011. },
  23012. getFilter: function () {
  23013. return this.filter;
  23014. },
  23015. setFilter: function (value) {
  23016. if (this.filter !== null) {
  23017. this.gain.disconnect(this.filter);
  23018. this.filter.disconnect(this.context.destination);
  23019. } else {
  23020. this.gain.disconnect(this.context.destination);
  23021. }
  23022. this.filter = value;
  23023. this.gain.connect(this.filter);
  23024. this.filter.connect(this.context.destination);
  23025. },
  23026. getMasterVolume: function () {
  23027. return this.gain.gain.value;
  23028. },
  23029. setMasterVolume: function (value) {
  23030. this.gain.gain.setTargetAtTime(value, this.context.currentTime, 0.01);
  23031. },
  23032. updateMatrixWorld: function () {
  23033. var position = new Vector3();
  23034. var quaternion = new Quaternion();
  23035. var scale = new Vector3();
  23036. var orientation = new Vector3();
  23037. return function updateMatrixWorld(force) {
  23038. Object3D.prototype.updateMatrixWorld.call(this, force);
  23039. var listener = this.context.listener;
  23040. var up = this.up;
  23041. this.matrixWorld.decompose(position, quaternion, scale);
  23042. orientation.set(0, 0, -1).applyQuaternion(quaternion);
  23043. if (listener.positionX) {
  23044. listener.positionX.setValueAtTime(position.x, this.context.currentTime);
  23045. listener.positionY.setValueAtTime(position.y, this.context.currentTime);
  23046. listener.positionZ.setValueAtTime(position.z, this.context.currentTime);
  23047. listener.forwardX.setValueAtTime(orientation.x, this.context.currentTime);
  23048. listener.forwardY.setValueAtTime(orientation.y, this.context.currentTime);
  23049. listener.forwardZ.setValueAtTime(orientation.z, this.context.currentTime);
  23050. listener.upX.setValueAtTime(up.x, this.context.currentTime);
  23051. listener.upY.setValueAtTime(up.y, this.context.currentTime);
  23052. listener.upZ.setValueAtTime(up.z, this.context.currentTime);
  23053. } else {
  23054. listener.setPosition(position.x, position.y, position.z);
  23055. listener.setOrientation(orientation.x, orientation.y, orientation.z, up.x, up.y, up.z);
  23056. }
  23057. };
  23058. }()
  23059. });
  23060. /**
  23061. * @author mrdoob / http://mrdoob.com/
  23062. * @author Reece Aaron Lecrivain / http://reecenotes.com/
  23063. */
  23064. function Audio(listener) {
  23065. Object3D.call(this);
  23066. this.type = 'Audio';
  23067. this.context = listener.context;
  23068. this.gain = this.context.createGain();
  23069. this.gain.connect(listener.getInput());
  23070. this.autoplay = false;
  23071. this.buffer = null;
  23072. this.loop = false;
  23073. this.startTime = 0;
  23074. this.offset = 0;
  23075. this.playbackRate = 1;
  23076. this.isPlaying = false;
  23077. this.hasPlaybackControl = true;
  23078. this.sourceType = 'empty';
  23079. this.filters = [];
  23080. }
  23081. Audio.prototype = Object.assign(Object.create(Object3D.prototype), {
  23082. constructor: Audio,
  23083. getOutput: function () {
  23084. return this.gain;
  23085. },
  23086. setNodeSource: function (audioNode) {
  23087. this.hasPlaybackControl = false;
  23088. this.sourceType = 'audioNode';
  23089. this.source = audioNode;
  23090. this.connect();
  23091. return this;
  23092. },
  23093. setMediaElementSource: function (mediaElement) {
  23094. this.hasPlaybackControl = false;
  23095. this.sourceType = 'mediaNode';
  23096. this.source = this.context.createMediaElementSource(mediaElement);
  23097. this.connect();
  23098. return this;
  23099. },
  23100. setBuffer: function (audioBuffer) {
  23101. this.buffer = audioBuffer;
  23102. this.sourceType = 'buffer';
  23103. if (this.autoplay) this.play();
  23104. return this;
  23105. },
  23106. play: function () {
  23107. if (this.isPlaying === true) {
  23108. console.warn('THREE.Audio: Audio is already playing.');
  23109. return;
  23110. }
  23111. if (this.hasPlaybackControl === false) {
  23112. console.warn('THREE.Audio: this Audio has no playback control.');
  23113. return;
  23114. }
  23115. var source = this.context.createBufferSource();
  23116. source.buffer = this.buffer;
  23117. source.loop = this.loop;
  23118. source.onended = this.onEnded.bind(this);
  23119. source.playbackRate.setValueAtTime(this.playbackRate, this.startTime);
  23120. this.startTime = this.context.currentTime;
  23121. source.start(this.startTime, this.offset);
  23122. this.isPlaying = true;
  23123. this.source = source;
  23124. return this.connect();
  23125. },
  23126. pause: function () {
  23127. if (this.hasPlaybackControl === false) {
  23128. console.warn('THREE.Audio: this Audio has no playback control.');
  23129. return;
  23130. }
  23131. if (this.isPlaying === true) {
  23132. this.source.stop();
  23133. this.offset += (this.context.currentTime - this.startTime) * this.playbackRate;
  23134. this.isPlaying = false;
  23135. }
  23136. return this;
  23137. },
  23138. stop: function () {
  23139. if (this.hasPlaybackControl === false) {
  23140. console.warn('THREE.Audio: this Audio has no playback control.');
  23141. return;
  23142. }
  23143. this.source.stop();
  23144. this.offset = 0;
  23145. this.isPlaying = false;
  23146. return this;
  23147. },
  23148. connect: function () {
  23149. if (this.filters.length > 0) {
  23150. this.source.connect(this.filters[0]);
  23151. for (var i = 1, l = this.filters.length; i < l; i++) {
  23152. this.filters[i - 1].connect(this.filters[i]);
  23153. }
  23154. this.filters[this.filters.length - 1].connect(this.getOutput());
  23155. } else {
  23156. this.source.connect(this.getOutput());
  23157. }
  23158. return this;
  23159. },
  23160. disconnect: function () {
  23161. if (this.filters.length > 0) {
  23162. this.source.disconnect(this.filters[0]);
  23163. for (var i = 1, l = this.filters.length; i < l; i++) {
  23164. this.filters[i - 1].disconnect(this.filters[i]);
  23165. }
  23166. this.filters[this.filters.length - 1].disconnect(this.getOutput());
  23167. } else {
  23168. this.source.disconnect(this.getOutput());
  23169. }
  23170. return this;
  23171. },
  23172. getFilters: function () {
  23173. return this.filters;
  23174. },
  23175. setFilters: function (value) {
  23176. if (!value) value = [];
  23177. if (this.isPlaying === true) {
  23178. this.disconnect();
  23179. this.filters = value;
  23180. this.connect();
  23181. } else {
  23182. this.filters = value;
  23183. }
  23184. return this;
  23185. },
  23186. getFilter: function () {
  23187. return this.getFilters()[0];
  23188. },
  23189. setFilter: function (filter) {
  23190. return this.setFilters(filter ? [filter] : []);
  23191. },
  23192. setPlaybackRate: function (value) {
  23193. if (this.hasPlaybackControl === false) {
  23194. console.warn('THREE.Audio: this Audio has no playback control.');
  23195. return;
  23196. }
  23197. this.playbackRate = value;
  23198. if (this.isPlaying === true) {
  23199. this.source.playbackRate.setValueAtTime(this.playbackRate, this.context.currentTime);
  23200. }
  23201. return this;
  23202. },
  23203. getPlaybackRate: function () {
  23204. return this.playbackRate;
  23205. },
  23206. onEnded: function () {
  23207. this.isPlaying = false;
  23208. },
  23209. getLoop: function () {
  23210. if (this.hasPlaybackControl === false) {
  23211. console.warn('THREE.Audio: this Audio has no playback control.');
  23212. return false;
  23213. }
  23214. return this.loop;
  23215. },
  23216. setLoop: function (value) {
  23217. if (this.hasPlaybackControl === false) {
  23218. console.warn('THREE.Audio: this Audio has no playback control.');
  23219. return;
  23220. }
  23221. this.loop = value;
  23222. if (this.isPlaying === true) {
  23223. this.source.loop = this.loop;
  23224. }
  23225. return this;
  23226. },
  23227. getVolume: function () {
  23228. return this.gain.gain.value;
  23229. },
  23230. setVolume: function (value) {
  23231. this.gain.gain.setTargetAtTime(value, this.context.currentTime, 0.01);
  23232. return this;
  23233. }
  23234. });
  23235. /**
  23236. * @author mrdoob / http://mrdoob.com/
  23237. */
  23238. function PositionalAudio(listener) {
  23239. Audio.call(this, listener);
  23240. this.panner = this.context.createPanner();
  23241. this.panner.connect(this.gain);
  23242. }
  23243. PositionalAudio.prototype = Object.assign(Object.create(Audio.prototype), {
  23244. constructor: PositionalAudio,
  23245. getOutput: function () {
  23246. return this.panner;
  23247. },
  23248. getRefDistance: function () {
  23249. return this.panner.refDistance;
  23250. },
  23251. setRefDistance: function (value) {
  23252. this.panner.refDistance = value;
  23253. },
  23254. getRolloffFactor: function () {
  23255. return this.panner.rolloffFactor;
  23256. },
  23257. setRolloffFactor: function (value) {
  23258. this.panner.rolloffFactor = value;
  23259. },
  23260. getDistanceModel: function () {
  23261. return this.panner.distanceModel;
  23262. },
  23263. setDistanceModel: function (value) {
  23264. this.panner.distanceModel = value;
  23265. },
  23266. getMaxDistance: function () {
  23267. return this.panner.maxDistance;
  23268. },
  23269. setMaxDistance: function (value) {
  23270. this.panner.maxDistance = value;
  23271. },
  23272. updateMatrixWorld: function () {
  23273. var position = new Vector3();
  23274. return function updateMatrixWorld(force) {
  23275. Object3D.prototype.updateMatrixWorld.call(this, force);
  23276. position.setFromMatrixPosition(this.matrixWorld);
  23277. this.panner.setPosition(position.x, position.y, position.z);
  23278. };
  23279. }()
  23280. });
  23281. /**
  23282. * @author mrdoob / http://mrdoob.com/
  23283. */
  23284. function AudioAnalyser(audio, fftSize) {
  23285. this.analyser = audio.context.createAnalyser();
  23286. this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
  23287. this.data = new Uint8Array(this.analyser.frequencyBinCount);
  23288. audio.getOutput().connect(this.analyser);
  23289. }
  23290. Object.assign(AudioAnalyser.prototype, {
  23291. getFrequencyData: function () {
  23292. this.analyser.getByteFrequencyData(this.data);
  23293. return this.data;
  23294. },
  23295. getAverageFrequency: function () {
  23296. var value = 0,
  23297. data = this.getFrequencyData();
  23298. for (var i = 0; i < data.length; i++) {
  23299. value += data[i];
  23300. }
  23301. return value / data.length;
  23302. }
  23303. });
  23304. /**
  23305. *
  23306. * Buffered scene graph property that allows weighted accumulation.
  23307. *
  23308. *
  23309. * @author Ben Houston / http://clara.io/
  23310. * @author David Sarno / http://lighthaus.us/
  23311. * @author tschw
  23312. */
  23313. function PropertyMixer(binding, typeName, valueSize) {
  23314. this.binding = binding;
  23315. this.valueSize = valueSize;
  23316. var bufferType = Float64Array,
  23317. mixFunction;
  23318. switch (typeName) {
  23319. case 'quaternion':
  23320. mixFunction = this._slerp;
  23321. break;
  23322. case 'string':
  23323. case 'bool':
  23324. bufferType = Array;
  23325. mixFunction = this._select;
  23326. break;
  23327. default:
  23328. mixFunction = this._lerp;
  23329. }
  23330. this.buffer = new bufferType(valueSize * 4);
  23331. // layout: [ incoming | accu0 | accu1 | orig ]
  23332. //
  23333. // interpolators can use .buffer as their .result
  23334. // the data then goes to 'incoming'
  23335. //
  23336. // 'accu0' and 'accu1' are used frame-interleaved for
  23337. // the cumulative result and are compared to detect
  23338. // changes
  23339. //
  23340. // 'orig' stores the original state of the property
  23341. this._mixBufferRegion = mixFunction;
  23342. this.cumulativeWeight = 0;
  23343. this.useCount = 0;
  23344. this.referenceCount = 0;
  23345. }
  23346. Object.assign(PropertyMixer.prototype, {
  23347. // accumulate data in the 'incoming' region into 'accu<i>'
  23348. accumulate: function (accuIndex, weight) {
  23349. // note: happily accumulating nothing when weight = 0, the caller knows
  23350. // the weight and shouldn't have made the call in the first place
  23351. var buffer = this.buffer,
  23352. stride = this.valueSize,
  23353. offset = accuIndex * stride + stride,
  23354. currentWeight = this.cumulativeWeight;
  23355. if (currentWeight === 0) {
  23356. // accuN := incoming * weight
  23357. for (var i = 0; i !== stride; ++i) {
  23358. buffer[offset + i] = buffer[i];
  23359. }
  23360. currentWeight = weight;
  23361. } else {
  23362. // accuN := accuN + incoming * weight
  23363. currentWeight += weight;
  23364. var mix = weight / currentWeight;
  23365. this._mixBufferRegion(buffer, offset, 0, mix, stride);
  23366. }
  23367. this.cumulativeWeight = currentWeight;
  23368. },
  23369. // apply the state of 'accu<i>' to the binding when accus differ
  23370. apply: function (accuIndex) {
  23371. var stride = this.valueSize,
  23372. buffer = this.buffer,
  23373. offset = accuIndex * stride + stride,
  23374. weight = this.cumulativeWeight,
  23375. binding = this.binding;
  23376. this.cumulativeWeight = 0;
  23377. if (weight < 1) {
  23378. // accuN := accuN + original * ( 1 - cumulativeWeight )
  23379. var originalValueOffset = stride * 3;
  23380. this._mixBufferRegion(buffer, offset, originalValueOffset, 1 - weight, stride);
  23381. }
  23382. for (var i = stride, e = stride + stride; i !== e; ++i) {
  23383. if (buffer[i] !== buffer[i + stride]) {
  23384. // value has changed -> update scene graph
  23385. binding.setValue(buffer, offset);
  23386. break;
  23387. }
  23388. }
  23389. },
  23390. // remember the state of the bound property and copy it to both accus
  23391. saveOriginalState: function () {
  23392. var binding = this.binding;
  23393. var buffer = this.buffer,
  23394. stride = this.valueSize,
  23395. originalValueOffset = stride * 3;
  23396. binding.getValue(buffer, originalValueOffset);
  23397. // accu[0..1] := orig -- initially detect changes against the original
  23398. for (var i = stride, e = originalValueOffset; i !== e; ++i) {
  23399. buffer[i] = buffer[originalValueOffset + i % stride];
  23400. }
  23401. this.cumulativeWeight = 0;
  23402. },
  23403. // apply the state previously taken via 'saveOriginalState' to the binding
  23404. restoreOriginalState: function () {
  23405. var originalValueOffset = this.valueSize * 3;
  23406. this.binding.setValue(this.buffer, originalValueOffset);
  23407. },
  23408. // mix functions
  23409. _select: function (buffer, dstOffset, srcOffset, t, stride) {
  23410. if (t >= 0.5) {
  23411. for (var i = 0; i !== stride; ++i) {
  23412. buffer[dstOffset + i] = buffer[srcOffset + i];
  23413. }
  23414. }
  23415. },
  23416. _slerp: function (buffer, dstOffset, srcOffset, t) {
  23417. Quaternion.slerpFlat(buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t);
  23418. },
  23419. _lerp: function (buffer, dstOffset, srcOffset, t, stride) {
  23420. var s = 1 - t;
  23421. for (var i = 0; i !== stride; ++i) {
  23422. var j = dstOffset + i;
  23423. buffer[j] = buffer[j] * s + buffer[srcOffset + i] * t;
  23424. }
  23425. }
  23426. });
  23427. /**
  23428. *
  23429. * A reference to a real property in the scene graph.
  23430. *
  23431. *
  23432. * @author Ben Houston / http://clara.io/
  23433. * @author David Sarno / http://lighthaus.us/
  23434. * @author tschw
  23435. */
  23436. // Characters [].:/ are reserved for track binding syntax.
  23437. var RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
  23438. function Composite(targetGroup, path, optionalParsedPath) {
  23439. var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName(path);
  23440. this._targetGroup = targetGroup;
  23441. this._bindings = targetGroup.subscribe_(path, parsedPath);
  23442. }
  23443. Object.assign(Composite.prototype, {
  23444. getValue: function (array, offset) {
  23445. this.bind(); // bind all binding
  23446. var firstValidIndex = this._targetGroup.nCachedObjects_,
  23447. binding = this._bindings[firstValidIndex];
  23448. // and only call .getValue on the first
  23449. if (binding !== undefined) binding.getValue(array, offset);
  23450. },
  23451. setValue: function (array, offset) {
  23452. var bindings = this._bindings;
  23453. for (var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) {
  23454. bindings[i].setValue(array, offset);
  23455. }
  23456. },
  23457. bind: function () {
  23458. var bindings = this._bindings;
  23459. for (var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) {
  23460. bindings[i].bind();
  23461. }
  23462. },
  23463. unbind: function () {
  23464. var bindings = this._bindings;
  23465. for (var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) {
  23466. bindings[i].unbind();
  23467. }
  23468. }
  23469. });
  23470. function PropertyBinding(rootNode, path, parsedPath) {
  23471. this.path = path;
  23472. this.parsedPath = parsedPath || PropertyBinding.parseTrackName(path);
  23473. this.node = PropertyBinding.findNode(rootNode, this.parsedPath.nodeName) || rootNode;
  23474. this.rootNode = rootNode;
  23475. }
  23476. Object.assign(PropertyBinding, {
  23477. Composite: Composite,
  23478. create: function (root, path, parsedPath) {
  23479. if (!(root && root.isAnimationObjectGroup)) {
  23480. return new PropertyBinding(root, path, parsedPath);
  23481. } else {
  23482. return new PropertyBinding.Composite(root, path, parsedPath);
  23483. }
  23484. },
  23485. /**
  23486. * Replaces spaces with underscores and removes unsupported characters from
  23487. * node names, to ensure compatibility with parseTrackName().
  23488. *
  23489. * @param {string} name Node name to be sanitized.
  23490. * @return {string}
  23491. */
  23492. sanitizeNodeName: function () {
  23493. var reservedRe = new RegExp('[' + RESERVED_CHARS_RE + ']', 'g');
  23494. return function sanitizeNodeName(name) {
  23495. return name.replace(/\s/g, '_').replace(reservedRe, '');
  23496. };
  23497. }(),
  23498. parseTrackName: function () {
  23499. // Attempts to allow node names from any language. ES5's `\w` regexp matches
  23500. // only latin characters, and the unicode \p{L} is not yet supported. So
  23501. // instead, we exclude reserved characters and match everything else.
  23502. var wordChar = '[^' + RESERVED_CHARS_RE + ']';
  23503. var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace('\\.', '') + ']';
  23504. // Parent directories, delimited by '/' or ':'. Currently unused, but must
  23505. // be matched to parse the rest of the track name.
  23506. var directoryRe = /((?:WC+[\/:])*)/.source.replace('WC', wordChar);
  23507. // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
  23508. var nodeRe = /(WCOD+)?/.source.replace('WCOD', wordCharOrDot);
  23509. // Object on target node, and accessor. May not contain reserved
  23510. // characters. Accessor may contain any character except closing bracket.
  23511. var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace('WC', wordChar);
  23512. // Property and accessor. May not contain reserved characters. Accessor may
  23513. // contain any non-bracket characters.
  23514. var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace('WC', wordChar);
  23515. var trackRe = new RegExp('' + '^' + directoryRe + nodeRe + objectRe + propertyRe + '$');
  23516. var supportedObjectNames = ['material', 'materials', 'bones'];
  23517. return function parseTrackName(trackName) {
  23518. var matches = trackRe.exec(trackName);
  23519. if (!matches) {
  23520. throw new Error('PropertyBinding: Cannot parse trackName: ' + trackName);
  23521. }
  23522. var results = {
  23523. // directoryName: matches[ 1 ], // (tschw) currently unused
  23524. nodeName: matches[2],
  23525. objectName: matches[3],
  23526. objectIndex: matches[4],
  23527. propertyName: matches[5], // required
  23528. propertyIndex: matches[6]
  23529. };
  23530. var lastDot = results.nodeName && results.nodeName.lastIndexOf('.');
  23531. if (lastDot !== undefined && lastDot !== -1) {
  23532. var objectName = results.nodeName.substring(lastDot + 1);
  23533. // Object names must be checked against a whitelist. Otherwise, there
  23534. // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
  23535. // 'bar' could be the objectName, or part of a nodeName (which can
  23536. // include '.' characters).
  23537. if (supportedObjectNames.indexOf(objectName) !== -1) {
  23538. results.nodeName = results.nodeName.substring(0, lastDot);
  23539. results.objectName = objectName;
  23540. }
  23541. }
  23542. if (results.propertyName === null || results.propertyName.length === 0) {
  23543. throw new Error('PropertyBinding: can not parse propertyName from trackName: ' + trackName);
  23544. }
  23545. return results;
  23546. };
  23547. }(),
  23548. findNode: function (root, nodeName) {
  23549. if (!nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid) {
  23550. return root;
  23551. }
  23552. // search into skeleton bones.
  23553. if (root.skeleton) {
  23554. var bone = root.skeleton.getBoneByName(nodeName);
  23555. if (bone !== undefined) {
  23556. return bone;
  23557. }
  23558. }
  23559. // search into node subtree.
  23560. if (root.children) {
  23561. var searchNodeSubtree = function (children) {
  23562. for (var i = 0; i < children.length; i++) {
  23563. var childNode = children[i];
  23564. if (childNode.name === nodeName || childNode.uuid === nodeName) {
  23565. return childNode;
  23566. }
  23567. var result = searchNodeSubtree(childNode.children);
  23568. if (result) return result;
  23569. }
  23570. return null;
  23571. };
  23572. var subTreeNode = searchNodeSubtree(root.children);
  23573. if (subTreeNode) {
  23574. return subTreeNode;
  23575. }
  23576. }
  23577. return null;
  23578. }
  23579. });
  23580. Object.assign(PropertyBinding.prototype, { // prototype, continued
  23581. // these are used to "bind" a nonexistent property
  23582. _getValue_unavailable: function () {},
  23583. _setValue_unavailable: function () {},
  23584. BindingType: {
  23585. Direct: 0,
  23586. EntireArray: 1,
  23587. ArrayElement: 2,
  23588. HasFromToArray: 3
  23589. },
  23590. Versioning: {
  23591. None: 0,
  23592. NeedsUpdate: 1,
  23593. MatrixWorldNeedsUpdate: 2
  23594. },
  23595. GetterByBindingType: [function getValue_direct(buffer, offset) {
  23596. buffer[offset] = this.node[this.propertyName];
  23597. }, function getValue_array(buffer, offset) {
  23598. var source = this.resolvedProperty;
  23599. for (var i = 0, n = source.length; i !== n; ++i) {
  23600. buffer[offset++] = source[i];
  23601. }
  23602. }, function getValue_arrayElement(buffer, offset) {
  23603. buffer[offset] = this.resolvedProperty[this.propertyIndex];
  23604. }, function getValue_toArray(buffer, offset) {
  23605. this.resolvedProperty.toArray(buffer, offset);
  23606. }],
  23607. SetterByBindingTypeAndVersioning: [[
  23608. // Direct
  23609. function setValue_direct(buffer, offset) {
  23610. this.targetObject[this.propertyName] = buffer[offset];
  23611. }, function setValue_direct_setNeedsUpdate(buffer, offset) {
  23612. this.targetObject[this.propertyName] = buffer[offset];
  23613. this.targetObject.needsUpdate = true;
  23614. }, function setValue_direct_setMatrixWorldNeedsUpdate(buffer, offset) {
  23615. this.targetObject[this.propertyName] = buffer[offset];
  23616. this.targetObject.matrixWorldNeedsUpdate = true;
  23617. }], [
  23618. // EntireArray
  23619. function setValue_array(buffer, offset) {
  23620. var dest = this.resolvedProperty;
  23621. for (var i = 0, n = dest.length; i !== n; ++i) {
  23622. dest[i] = buffer[offset++];
  23623. }
  23624. }, function setValue_array_setNeedsUpdate(buffer, offset) {
  23625. var dest = this.resolvedProperty;
  23626. for (var i = 0, n = dest.length; i !== n; ++i) {
  23627. dest[i] = buffer[offset++];
  23628. }
  23629. this.targetObject.needsUpdate = true;
  23630. }, function setValue_array_setMatrixWorldNeedsUpdate(buffer, offset) {
  23631. var dest = this.resolvedProperty;
  23632. for (var i = 0, n = dest.length; i !== n; ++i) {
  23633. dest[i] = buffer[offset++];
  23634. }
  23635. this.targetObject.matrixWorldNeedsUpdate = true;
  23636. }], [
  23637. // ArrayElement
  23638. function setValue_arrayElement(buffer, offset) {
  23639. this.resolvedProperty[this.propertyIndex] = buffer[offset];
  23640. }, function setValue_arrayElement_setNeedsUpdate(buffer, offset) {
  23641. this.resolvedProperty[this.propertyIndex] = buffer[offset];
  23642. this.targetObject.needsUpdate = true;
  23643. }, function setValue_arrayElement_setMatrixWorldNeedsUpdate(buffer, offset) {
  23644. this.resolvedProperty[this.propertyIndex] = buffer[offset];
  23645. this.targetObject.matrixWorldNeedsUpdate = true;
  23646. }], [
  23647. // HasToFromArray
  23648. function setValue_fromArray(buffer, offset) {
  23649. this.resolvedProperty.fromArray(buffer, offset);
  23650. }, function setValue_fromArray_setNeedsUpdate(buffer, offset) {
  23651. this.resolvedProperty.fromArray(buffer, offset);
  23652. this.targetObject.needsUpdate = true;
  23653. }, function setValue_fromArray_setMatrixWorldNeedsUpdate(buffer, offset) {
  23654. this.resolvedProperty.fromArray(buffer, offset);
  23655. this.targetObject.matrixWorldNeedsUpdate = true;
  23656. }]],
  23657. getValue: function getValue_unbound(targetArray, offset) {
  23658. this.bind();
  23659. this.getValue(targetArray, offset);
  23660. // Note: This class uses a State pattern on a per-method basis:
  23661. // 'bind' sets 'this.getValue' / 'setValue' and shadows the
  23662. // prototype version of these methods with one that represents
  23663. // the bound state. When the property is not found, the methods
  23664. // become no-ops.
  23665. },
  23666. setValue: function getValue_unbound(sourceArray, offset) {
  23667. this.bind();
  23668. this.setValue(sourceArray, offset);
  23669. },
  23670. // create getter / setter pair for a property in the scene graph
  23671. bind: function () {
  23672. var targetObject = this.node,
  23673. parsedPath = this.parsedPath,
  23674. objectName = parsedPath.objectName,
  23675. propertyName = parsedPath.propertyName,
  23676. propertyIndex = parsedPath.propertyIndex;
  23677. if (!targetObject) {
  23678. targetObject = PropertyBinding.findNode(this.rootNode, parsedPath.nodeName) || this.rootNode;
  23679. this.node = targetObject;
  23680. }
  23681. // set fail state so we can just 'return' on error
  23682. this.getValue = this._getValue_unavailable;
  23683. this.setValue = this._setValue_unavailable;
  23684. // ensure there is a value node
  23685. if (!targetObject) {
  23686. console.error('THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.');
  23687. return;
  23688. }
  23689. if (objectName) {
  23690. var objectIndex = parsedPath.objectIndex;
  23691. // special cases were we need to reach deeper into the hierarchy to get the face materials....
  23692. switch (objectName) {
  23693. case 'materials':
  23694. if (!targetObject.material) {
  23695. console.error('THREE.PropertyBinding: Can not bind to material as node does not have a material.', this);
  23696. return;
  23697. }
  23698. if (!targetObject.material.materials) {
  23699. console.error('THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this);
  23700. return;
  23701. }
  23702. targetObject = targetObject.material.materials;
  23703. break;
  23704. case 'bones':
  23705. if (!targetObject.skeleton) {
  23706. console.error('THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this);
  23707. return;
  23708. }
  23709. // potential future optimization: skip this if propertyIndex is already an integer
  23710. // and convert the integer string to a true integer.
  23711. targetObject = targetObject.skeleton.bones;
  23712. // support resolving morphTarget names into indices.
  23713. for (var i = 0; i < targetObject.length; i++) {
  23714. if (targetObject[i].name === objectIndex) {
  23715. objectIndex = i;
  23716. break;
  23717. }
  23718. }
  23719. break;
  23720. default:
  23721. if (targetObject[objectName] === undefined) {
  23722. console.error('THREE.PropertyBinding: Can not bind to objectName of node undefined.', this);
  23723. return;
  23724. }
  23725. targetObject = targetObject[objectName];
  23726. }
  23727. if (objectIndex !== undefined) {
  23728. if (targetObject[objectIndex] === undefined) {
  23729. console.error('THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject);
  23730. return;
  23731. }
  23732. targetObject = targetObject[objectIndex];
  23733. }
  23734. }
  23735. // resolve property
  23736. var nodeProperty = targetObject[propertyName];
  23737. if (nodeProperty === undefined) {
  23738. var nodeName = parsedPath.nodeName;
  23739. console.error('THREE.PropertyBinding: Trying to update property for track: ' + nodeName + '.' + propertyName + ' but it wasn\'t found.', targetObject);
  23740. return;
  23741. }
  23742. // determine versioning scheme
  23743. var versioning = this.Versioning.None;
  23744. if (targetObject.needsUpdate !== undefined) {
  23745. // material
  23746. versioning = this.Versioning.NeedsUpdate;
  23747. this.targetObject = targetObject;
  23748. } else if (targetObject.matrixWorldNeedsUpdate !== undefined) {
  23749. // node transform
  23750. versioning = this.Versioning.MatrixWorldNeedsUpdate;
  23751. this.targetObject = targetObject;
  23752. }
  23753. // determine how the property gets bound
  23754. var bindingType = this.BindingType.Direct;
  23755. if (propertyIndex !== undefined) {
  23756. // access a sub element of the property array (only primitives are supported right now)
  23757. if (propertyName === "morphTargetInfluences") {
  23758. // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
  23759. // support resolving morphTarget names into indices.
  23760. if (!targetObject.geometry) {
  23761. console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this);
  23762. return;
  23763. }
  23764. if (targetObject.geometry.isBufferGeometry) {
  23765. if (!targetObject.geometry.morphAttributes) {
  23766. console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this);
  23767. return;
  23768. }
  23769. for (var i = 0; i < this.node.geometry.morphAttributes.position.length; i++) {
  23770. if (targetObject.geometry.morphAttributes.position[i].name === propertyIndex) {
  23771. propertyIndex = i;
  23772. break;
  23773. }
  23774. }
  23775. } else {
  23776. if (!targetObject.geometry.morphTargets) {
  23777. console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this);
  23778. return;
  23779. }
  23780. for (var i = 0; i < this.node.geometry.morphTargets.length; i++) {
  23781. if (targetObject.geometry.morphTargets[i].name === propertyIndex) {
  23782. propertyIndex = i;
  23783. break;
  23784. }
  23785. }
  23786. }
  23787. }
  23788. bindingType = this.BindingType.ArrayElement;
  23789. this.resolvedProperty = nodeProperty;
  23790. this.propertyIndex = propertyIndex;
  23791. } else if (nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined) {
  23792. // must use copy for Object3D.Euler/Quaternion
  23793. bindingType = this.BindingType.HasFromToArray;
  23794. this.resolvedProperty = nodeProperty;
  23795. } else if (Array.isArray(nodeProperty)) {
  23796. bindingType = this.BindingType.EntireArray;
  23797. this.resolvedProperty = nodeProperty;
  23798. } else {
  23799. this.propertyName = propertyName;
  23800. }
  23801. // select getter / setter
  23802. this.getValue = this.GetterByBindingType[bindingType];
  23803. this.setValue = this.SetterByBindingTypeAndVersioning[bindingType][versioning];
  23804. },
  23805. unbind: function () {
  23806. this.node = null;
  23807. // back to the prototype version of getValue / setValue
  23808. // note: avoiding to mutate the shape of 'this' via 'delete'
  23809. this.getValue = this._getValue_unbound;
  23810. this.setValue = this._setValue_unbound;
  23811. }
  23812. });
  23813. //!\ DECLARE ALIAS AFTER assign prototype !
  23814. Object.assign(PropertyBinding.prototype, {
  23815. // initial state of these methods that calls 'bind'
  23816. _getValue_unbound: PropertyBinding.prototype.getValue,
  23817. _setValue_unbound: PropertyBinding.prototype.setValue
  23818. });
  23819. /**
  23820. *
  23821. * A group of objects that receives a shared animation state.
  23822. *
  23823. * Usage:
  23824. *
  23825. * - Add objects you would otherwise pass as 'root' to the
  23826. * constructor or the .clipAction method of AnimationMixer.
  23827. *
  23828. * - Instead pass this object as 'root'.
  23829. *
  23830. * - You can also add and remove objects later when the mixer
  23831. * is running.
  23832. *
  23833. * Note:
  23834. *
  23835. * Objects of this class appear as one object to the mixer,
  23836. * so cache control of the individual objects must be done
  23837. * on the group.
  23838. *
  23839. * Limitation:
  23840. *
  23841. * - The animated properties must be compatible among the
  23842. * all objects in the group.
  23843. *
  23844. * - A single property can either be controlled through a
  23845. * target group or directly, but not both.
  23846. *
  23847. * @author tschw
  23848. */
  23849. function AnimationObjectGroup() {
  23850. this.uuid = _Math.generateUUID();
  23851. // cached objects followed by the active ones
  23852. this._objects = Array.prototype.slice.call(arguments);
  23853. this.nCachedObjects_ = 0; // threshold
  23854. // note: read by PropertyBinding.Composite
  23855. var indices = {};
  23856. this._indicesByUUID = indices; // for bookkeeping
  23857. for (var i = 0, n = arguments.length; i !== n; ++i) {
  23858. indices[arguments[i].uuid] = i;
  23859. }
  23860. this._paths = []; // inside: string
  23861. this._parsedPaths = []; // inside: { we don't care, here }
  23862. this._bindings = []; // inside: Array< PropertyBinding >
  23863. this._bindingsIndicesByPath = {}; // inside: indices in these arrays
  23864. var scope = this;
  23865. this.stats = {
  23866. objects: {
  23867. get total() {
  23868. return scope._objects.length;
  23869. },
  23870. get inUse() {
  23871. return this.total - scope.nCachedObjects_;
  23872. }
  23873. },
  23874. get bindingsPerObject() {
  23875. return scope._bindings.length;
  23876. }
  23877. };
  23878. }
  23879. Object.assign(AnimationObjectGroup.prototype, {
  23880. isAnimationObjectGroup: true,
  23881. add: function () {
  23882. var objects = this._objects,
  23883. nObjects = objects.length,
  23884. nCachedObjects = this.nCachedObjects_,
  23885. indicesByUUID = this._indicesByUUID,
  23886. paths = this._paths,
  23887. parsedPaths = this._parsedPaths,
  23888. bindings = this._bindings,
  23889. nBindings = bindings.length,
  23890. knownObject = undefined;
  23891. for (var i = 0, n = arguments.length; i !== n; ++i) {
  23892. var object = arguments[i],
  23893. uuid = object.uuid,
  23894. index = indicesByUUID[uuid];
  23895. if (index === undefined) {
  23896. // unknown object -> add it to the ACTIVE region
  23897. index = nObjects++;
  23898. indicesByUUID[uuid] = index;
  23899. objects.push(object);
  23900. // accounting is done, now do the same for all bindings
  23901. for (var j = 0, m = nBindings; j !== m; ++j) {
  23902. bindings[j].push(new PropertyBinding(object, paths[j], parsedPaths[j]));
  23903. }
  23904. } else if (index < nCachedObjects) {
  23905. knownObject = objects[index];
  23906. // move existing object to the ACTIVE region
  23907. var firstActiveIndex = --nCachedObjects,
  23908. lastCachedObject = objects[firstActiveIndex];
  23909. indicesByUUID[lastCachedObject.uuid] = index;
  23910. objects[index] = lastCachedObject;
  23911. indicesByUUID[uuid] = firstActiveIndex;
  23912. objects[firstActiveIndex] = object;
  23913. // accounting is done, now do the same for all bindings
  23914. for (var j = 0, m = nBindings; j !== m; ++j) {
  23915. var bindingsForPath = bindings[j],
  23916. lastCached = bindingsForPath[firstActiveIndex],
  23917. binding = bindingsForPath[index];
  23918. bindingsForPath[index] = lastCached;
  23919. if (binding === undefined) {
  23920. // since we do not bother to create new bindings
  23921. // for objects that are cached, the binding may
  23922. // or may not exist
  23923. binding = new PropertyBinding(object, paths[j], parsedPaths[j]);
  23924. }
  23925. bindingsForPath[firstActiveIndex] = binding;
  23926. }
  23927. } else if (objects[index] !== knownObject) {
  23928. console.error('THREE.AnimationObjectGroup: Different objects with the same UUID ' + 'detected. Clean the caches or recreate your infrastructure when reloading scenes.');
  23929. } // else the object is already where we want it to be
  23930. } // for arguments
  23931. this.nCachedObjects_ = nCachedObjects;
  23932. },
  23933. remove: function () {
  23934. var objects = this._objects,
  23935. nCachedObjects = this.nCachedObjects_,
  23936. indicesByUUID = this._indicesByUUID,
  23937. bindings = this._bindings,
  23938. nBindings = bindings.length;
  23939. for (var i = 0, n = arguments.length; i !== n; ++i) {
  23940. var object = arguments[i],
  23941. uuid = object.uuid,
  23942. index = indicesByUUID[uuid];
  23943. if (index !== undefined && index >= nCachedObjects) {
  23944. // move existing object into the CACHED region
  23945. var lastCachedIndex = nCachedObjects++,
  23946. firstActiveObject = objects[lastCachedIndex];
  23947. indicesByUUID[firstActiveObject.uuid] = index;
  23948. objects[index] = firstActiveObject;
  23949. indicesByUUID[uuid] = lastCachedIndex;
  23950. objects[lastCachedIndex] = object;
  23951. // accounting is done, now do the same for all bindings
  23952. for (var j = 0, m = nBindings; j !== m; ++j) {
  23953. var bindingsForPath = bindings[j],
  23954. firstActive = bindingsForPath[lastCachedIndex],
  23955. binding = bindingsForPath[index];
  23956. bindingsForPath[index] = firstActive;
  23957. bindingsForPath[lastCachedIndex] = binding;
  23958. }
  23959. }
  23960. } // for arguments
  23961. this.nCachedObjects_ = nCachedObjects;
  23962. },
  23963. // remove & forget
  23964. uncache: function () {
  23965. var objects = this._objects,
  23966. nObjects = objects.length,
  23967. nCachedObjects = this.nCachedObjects_,
  23968. indicesByUUID = this._indicesByUUID,
  23969. bindings = this._bindings,
  23970. nBindings = bindings.length;
  23971. for (var i = 0, n = arguments.length; i !== n; ++i) {
  23972. var object = arguments[i],
  23973. uuid = object.uuid,
  23974. index = indicesByUUID[uuid];
  23975. if (index !== undefined) {
  23976. delete indicesByUUID[uuid];
  23977. if (index < nCachedObjects) {
  23978. // object is cached, shrink the CACHED region
  23979. var firstActiveIndex = --nCachedObjects,
  23980. lastCachedObject = objects[firstActiveIndex],
  23981. lastIndex = --nObjects,
  23982. lastObject = objects[lastIndex];
  23983. // last cached object takes this object's place
  23984. indicesByUUID[lastCachedObject.uuid] = index;
  23985. objects[index] = lastCachedObject;
  23986. // last object goes to the activated slot and pop
  23987. indicesByUUID[lastObject.uuid] = firstActiveIndex;
  23988. objects[firstActiveIndex] = lastObject;
  23989. objects.pop();
  23990. // accounting is done, now do the same for all bindings
  23991. for (var j = 0, m = nBindings; j !== m; ++j) {
  23992. var bindingsForPath = bindings[j],
  23993. lastCached = bindingsForPath[firstActiveIndex],
  23994. last = bindingsForPath[lastIndex];
  23995. bindingsForPath[index] = lastCached;
  23996. bindingsForPath[firstActiveIndex] = last;
  23997. bindingsForPath.pop();
  23998. }
  23999. } else {
  24000. // object is active, just swap with the last and pop
  24001. var lastIndex = --nObjects,
  24002. lastObject = objects[lastIndex];
  24003. indicesByUUID[lastObject.uuid] = index;
  24004. objects[index] = lastObject;
  24005. objects.pop();
  24006. // accounting is done, now do the same for all bindings
  24007. for (var j = 0, m = nBindings; j !== m; ++j) {
  24008. var bindingsForPath = bindings[j];
  24009. bindingsForPath[index] = bindingsForPath[lastIndex];
  24010. bindingsForPath.pop();
  24011. }
  24012. } // cached or active
  24013. } // if object is known
  24014. } // for arguments
  24015. this.nCachedObjects_ = nCachedObjects;
  24016. },
  24017. // Internal interface used by befriended PropertyBinding.Composite:
  24018. subscribe_: function (path, parsedPath) {
  24019. // returns an array of bindings for the given path that is changed
  24020. // according to the contained objects in the group
  24021. var indicesByPath = this._bindingsIndicesByPath,
  24022. index = indicesByPath[path],
  24023. bindings = this._bindings;
  24024. if (index !== undefined) return bindings[index];
  24025. var paths = this._paths,
  24026. parsedPaths = this._parsedPaths,
  24027. objects = this._objects,
  24028. nObjects = objects.length,
  24029. nCachedObjects = this.nCachedObjects_,
  24030. bindingsForPath = new Array(nObjects);
  24031. index = bindings.length;
  24032. indicesByPath[path] = index;
  24033. paths.push(path);
  24034. parsedPaths.push(parsedPath);
  24035. bindings.push(bindingsForPath);
  24036. for (var i = nCachedObjects, n = objects.length; i !== n; ++i) {
  24037. var object = objects[i];
  24038. bindingsForPath[i] = new PropertyBinding(object, path, parsedPath);
  24039. }
  24040. return bindingsForPath;
  24041. },
  24042. unsubscribe_: function (path) {
  24043. // tells the group to forget about a property path and no longer
  24044. // update the array previously obtained with 'subscribe_'
  24045. var indicesByPath = this._bindingsIndicesByPath,
  24046. index = indicesByPath[path];
  24047. if (index !== undefined) {
  24048. var paths = this._paths,
  24049. parsedPaths = this._parsedPaths,
  24050. bindings = this._bindings,
  24051. lastBindingsIndex = bindings.length - 1,
  24052. lastBindings = bindings[lastBindingsIndex],
  24053. lastBindingsPath = path[lastBindingsIndex];
  24054. indicesByPath[lastBindingsPath] = index;
  24055. bindings[index] = lastBindings;
  24056. bindings.pop();
  24057. parsedPaths[index] = parsedPaths[lastBindingsIndex];
  24058. parsedPaths.pop();
  24059. paths[index] = paths[lastBindingsIndex];
  24060. paths.pop();
  24061. }
  24062. }
  24063. });
  24064. /**
  24065. *
  24066. * Action provided by AnimationMixer for scheduling clip playback on specific
  24067. * objects.
  24068. *
  24069. * @author Ben Houston / http://clara.io/
  24070. * @author David Sarno / http://lighthaus.us/
  24071. * @author tschw
  24072. *
  24073. */
  24074. function AnimationAction(mixer, clip, localRoot) {
  24075. this._mixer = mixer;
  24076. this._clip = clip;
  24077. this._localRoot = localRoot || null;
  24078. var tracks = clip.tracks,
  24079. nTracks = tracks.length,
  24080. interpolants = new Array(nTracks);
  24081. var interpolantSettings = {
  24082. endingStart: ZeroCurvatureEnding,
  24083. endingEnd: ZeroCurvatureEnding
  24084. };
  24085. for (var i = 0; i !== nTracks; ++i) {
  24086. var interpolant = tracks[i].createInterpolant(null);
  24087. interpolants[i] = interpolant;
  24088. interpolant.settings = interpolantSettings;
  24089. }
  24090. this._interpolantSettings = interpolantSettings;
  24091. this._interpolants = interpolants; // bound by the mixer
  24092. // inside: PropertyMixer (managed by the mixer)
  24093. this._propertyBindings = new Array(nTracks);
  24094. this._cacheIndex = null; // for the memory manager
  24095. this._byClipCacheIndex = null; // for the memory manager
  24096. this._timeScaleInterpolant = null;
  24097. this._weightInterpolant = null;
  24098. this.loop = LoopRepeat;
  24099. this._loopCount = -1;
  24100. // global mixer time when the action is to be started
  24101. // it's set back to 'null' upon start of the action
  24102. this._startTime = null;
  24103. // scaled local time of the action
  24104. // gets clamped or wrapped to 0..clip.duration according to loop
  24105. this.time = 0;
  24106. this.timeScale = 1;
  24107. this._effectiveTimeScale = 1;
  24108. this.weight = 1;
  24109. this._effectiveWeight = 1;
  24110. this.repetitions = Infinity; // no. of repetitions when looping
  24111. this.paused = false; // true -> zero effective time scale
  24112. this.enabled = true; // false -> zero effective weight
  24113. this.clampWhenFinished = false; // keep feeding the last frame?
  24114. this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate
  24115. this.zeroSlopeAtEnd = true; // clips for start, loop and end
  24116. }
  24117. Object.assign(AnimationAction.prototype, {
  24118. // State & Scheduling
  24119. play: function () {
  24120. this._mixer._activateAction(this);
  24121. return this;
  24122. },
  24123. stop: function () {
  24124. this._mixer._deactivateAction(this);
  24125. return this.reset();
  24126. },
  24127. reset: function () {
  24128. this.paused = false;
  24129. this.enabled = true;
  24130. this.time = 0; // restart clip
  24131. this._loopCount = -1; // forget previous loops
  24132. this._startTime = null; // forget scheduling
  24133. return this.stopFading().stopWarping();
  24134. },
  24135. isRunning: function () {
  24136. return this.enabled && !this.paused && this.timeScale !== 0 && this._startTime === null && this._mixer._isActiveAction(this);
  24137. },
  24138. // return true when play has been called
  24139. isScheduled: function () {
  24140. return this._mixer._isActiveAction(this);
  24141. },
  24142. startAt: function (time) {
  24143. this._startTime = time;
  24144. return this;
  24145. },
  24146. setLoop: function (mode, repetitions) {
  24147. this.loop = mode;
  24148. this.repetitions = repetitions;
  24149. return this;
  24150. },
  24151. // Weight
  24152. // set the weight stopping any scheduled fading
  24153. // although .enabled = false yields an effective weight of zero, this
  24154. // method does *not* change .enabled, because it would be confusing
  24155. setEffectiveWeight: function (weight) {
  24156. this.weight = weight;
  24157. // note: same logic as when updated at runtime
  24158. this._effectiveWeight = this.enabled ? weight : 0;
  24159. return this.stopFading();
  24160. },
  24161. // return the weight considering fading and .enabled
  24162. getEffectiveWeight: function () {
  24163. return this._effectiveWeight;
  24164. },
  24165. fadeIn: function (duration) {
  24166. return this._scheduleFading(duration, 0, 1);
  24167. },
  24168. fadeOut: function (duration) {
  24169. return this._scheduleFading(duration, 1, 0);
  24170. },
  24171. crossFadeFrom: function (fadeOutAction, duration, warp) {
  24172. fadeOutAction.fadeOut(duration);
  24173. this.fadeIn(duration);
  24174. if (warp) {
  24175. var fadeInDuration = this._clip.duration,
  24176. fadeOutDuration = fadeOutAction._clip.duration,
  24177. startEndRatio = fadeOutDuration / fadeInDuration,
  24178. endStartRatio = fadeInDuration / fadeOutDuration;
  24179. fadeOutAction.warp(1.0, startEndRatio, duration);
  24180. this.warp(endStartRatio, 1.0, duration);
  24181. }
  24182. return this;
  24183. },
  24184. crossFadeTo: function (fadeInAction, duration, warp) {
  24185. return fadeInAction.crossFadeFrom(this, duration, warp);
  24186. },
  24187. stopFading: function () {
  24188. var weightInterpolant = this._weightInterpolant;
  24189. if (weightInterpolant !== null) {
  24190. this._weightInterpolant = null;
  24191. this._mixer._takeBackControlInterpolant(weightInterpolant);
  24192. }
  24193. return this;
  24194. },
  24195. // Time Scale Control
  24196. // set the time scale stopping any scheduled warping
  24197. // although .paused = true yields an effective time scale of zero, this
  24198. // method does *not* change .paused, because it would be confusing
  24199. setEffectiveTimeScale: function (timeScale) {
  24200. this.timeScale = timeScale;
  24201. this._effectiveTimeScale = this.paused ? 0 : timeScale;
  24202. return this.stopWarping();
  24203. },
  24204. // return the time scale considering warping and .paused
  24205. getEffectiveTimeScale: function () {
  24206. return this._effectiveTimeScale;
  24207. },
  24208. setDuration: function (duration) {
  24209. this.timeScale = this._clip.duration / duration;
  24210. return this.stopWarping();
  24211. },
  24212. syncWith: function (action) {
  24213. this.time = action.time;
  24214. this.timeScale = action.timeScale;
  24215. return this.stopWarping();
  24216. },
  24217. halt: function (duration) {
  24218. return this.warp(this._effectiveTimeScale, 0, duration);
  24219. },
  24220. warp: function (startTimeScale, endTimeScale, duration) {
  24221. var mixer = this._mixer,
  24222. now = mixer.time,
  24223. interpolant = this._timeScaleInterpolant,
  24224. timeScale = this.timeScale;
  24225. if (interpolant === null) {
  24226. interpolant = mixer._lendControlInterpolant();
  24227. this._timeScaleInterpolant = interpolant;
  24228. }
  24229. var times = interpolant.parameterPositions,
  24230. values = interpolant.sampleValues;
  24231. times[0] = now;
  24232. times[1] = now + duration;
  24233. values[0] = startTimeScale / timeScale;
  24234. values[1] = endTimeScale / timeScale;
  24235. return this;
  24236. },
  24237. stopWarping: function () {
  24238. var timeScaleInterpolant = this._timeScaleInterpolant;
  24239. if (timeScaleInterpolant !== null) {
  24240. this._timeScaleInterpolant = null;
  24241. this._mixer._takeBackControlInterpolant(timeScaleInterpolant);
  24242. }
  24243. return this;
  24244. },
  24245. // Object Accessors
  24246. getMixer: function () {
  24247. return this._mixer;
  24248. },
  24249. getClip: function () {
  24250. return this._clip;
  24251. },
  24252. getRoot: function () {
  24253. return this._localRoot || this._mixer._root;
  24254. },
  24255. // Interna
  24256. _update: function (time, deltaTime, timeDirection, accuIndex) {
  24257. // called by the mixer
  24258. if (!this.enabled) {
  24259. // call ._updateWeight() to update ._effectiveWeight
  24260. this._updateWeight(time);
  24261. return;
  24262. }
  24263. var startTime = this._startTime;
  24264. if (startTime !== null) {
  24265. // check for scheduled start of action
  24266. var timeRunning = (time - startTime) * timeDirection;
  24267. if (timeRunning < 0 || timeDirection === 0) {
  24268. return; // yet to come / don't decide when delta = 0
  24269. }
  24270. // start
  24271. this._startTime = null; // unschedule
  24272. deltaTime = timeDirection * timeRunning;
  24273. }
  24274. // apply time scale and advance time
  24275. deltaTime *= this._updateTimeScale(time);
  24276. var clipTime = this._updateTime(deltaTime);
  24277. // note: _updateTime may disable the action resulting in
  24278. // an effective weight of 0
  24279. var weight = this._updateWeight(time);
  24280. if (weight > 0) {
  24281. var interpolants = this._interpolants;
  24282. var propertyMixers = this._propertyBindings;
  24283. for (var j = 0, m = interpolants.length; j !== m; ++j) {
  24284. interpolants[j].evaluate(clipTime);
  24285. propertyMixers[j].accumulate(accuIndex, weight);
  24286. }
  24287. }
  24288. },
  24289. _updateWeight: function (time) {
  24290. var weight = 0;
  24291. if (this.enabled) {
  24292. weight = this.weight;
  24293. var interpolant = this._weightInterpolant;
  24294. if (interpolant !== null) {
  24295. var interpolantValue = interpolant.evaluate(time)[0];
  24296. weight *= interpolantValue;
  24297. if (time > interpolant.parameterPositions[1]) {
  24298. this.stopFading();
  24299. if (interpolantValue === 0) {
  24300. // faded out, disable
  24301. this.enabled = false;
  24302. }
  24303. }
  24304. }
  24305. }
  24306. this._effectiveWeight = weight;
  24307. return weight;
  24308. },
  24309. _updateTimeScale: function (time) {
  24310. var timeScale = 0;
  24311. if (!this.paused) {
  24312. timeScale = this.timeScale;
  24313. var interpolant = this._timeScaleInterpolant;
  24314. if (interpolant !== null) {
  24315. var interpolantValue = interpolant.evaluate(time)[0];
  24316. timeScale *= interpolantValue;
  24317. if (time > interpolant.parameterPositions[1]) {
  24318. this.stopWarping();
  24319. if (timeScale === 0) {
  24320. // motion has halted, pause
  24321. this.paused = true;
  24322. } else {
  24323. // warp done - apply final time scale
  24324. this.timeScale = timeScale;
  24325. }
  24326. }
  24327. }
  24328. }
  24329. this._effectiveTimeScale = timeScale;
  24330. return timeScale;
  24331. },
  24332. _updateTime: function (deltaTime) {
  24333. var time = this.time + deltaTime;
  24334. if (deltaTime === 0) return time;
  24335. var duration = this._clip.duration,
  24336. loop = this.loop,
  24337. loopCount = this._loopCount;
  24338. if (loop === LoopOnce) {
  24339. if (loopCount === -1) {
  24340. // just started
  24341. this._loopCount = 0;
  24342. this._setEndings(true, true, false);
  24343. }
  24344. handle_stop: {
  24345. if (time >= duration) {
  24346. time = duration;
  24347. } else if (time < 0) {
  24348. time = 0;
  24349. } else break handle_stop;
  24350. if (this.clampWhenFinished) this.paused = true;else this.enabled = false;
  24351. this._mixer.dispatchEvent({
  24352. type: 'finished', action: this,
  24353. direction: deltaTime < 0 ? -1 : 1
  24354. });
  24355. }
  24356. } else {
  24357. // repetitive Repeat or PingPong
  24358. var pingPong = loop === LoopPingPong;
  24359. if (loopCount === -1) {
  24360. // just started
  24361. if (deltaTime >= 0) {
  24362. loopCount = 0;
  24363. this._setEndings(true, this.repetitions === 0, pingPong);
  24364. } else {
  24365. // when looping in reverse direction, the initial
  24366. // transition through zero counts as a repetition,
  24367. // so leave loopCount at -1
  24368. this._setEndings(this.repetitions === 0, true, pingPong);
  24369. }
  24370. }
  24371. if (time >= duration || time < 0) {
  24372. // wrap around
  24373. var loopDelta = Math.floor(time / duration); // signed
  24374. time -= duration * loopDelta;
  24375. loopCount += Math.abs(loopDelta);
  24376. var pending = this.repetitions - loopCount;
  24377. if (pending <= 0) {
  24378. // have to stop (switch state, clamp time, fire event)
  24379. if (this.clampWhenFinished) this.paused = true;else this.enabled = false;
  24380. time = deltaTime > 0 ? duration : 0;
  24381. this._mixer.dispatchEvent({
  24382. type: 'finished', action: this,
  24383. direction: deltaTime > 0 ? 1 : -1
  24384. });
  24385. } else {
  24386. // keep running
  24387. if (pending === 1) {
  24388. // entering the last round
  24389. var atStart = deltaTime < 0;
  24390. this._setEndings(atStart, !atStart, pingPong);
  24391. } else {
  24392. this._setEndings(false, false, pingPong);
  24393. }
  24394. this._loopCount = loopCount;
  24395. this._mixer.dispatchEvent({
  24396. type: 'loop', action: this, loopDelta: loopDelta
  24397. });
  24398. }
  24399. }
  24400. if (pingPong && (loopCount & 1) === 1) {
  24401. // invert time for the "pong round"
  24402. this.time = time;
  24403. return duration - time;
  24404. }
  24405. }
  24406. this.time = time;
  24407. return time;
  24408. },
  24409. _setEndings: function (atStart, atEnd, pingPong) {
  24410. var settings = this._interpolantSettings;
  24411. if (pingPong) {
  24412. settings.endingStart = ZeroSlopeEnding;
  24413. settings.endingEnd = ZeroSlopeEnding;
  24414. } else {
  24415. // assuming for LoopOnce atStart == atEnd == true
  24416. if (atStart) {
  24417. settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
  24418. } else {
  24419. settings.endingStart = WrapAroundEnding;
  24420. }
  24421. if (atEnd) {
  24422. settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
  24423. } else {
  24424. settings.endingEnd = WrapAroundEnding;
  24425. }
  24426. }
  24427. },
  24428. _scheduleFading: function (duration, weightNow, weightThen) {
  24429. var mixer = this._mixer,
  24430. now = mixer.time,
  24431. interpolant = this._weightInterpolant;
  24432. if (interpolant === null) {
  24433. interpolant = mixer._lendControlInterpolant();
  24434. this._weightInterpolant = interpolant;
  24435. }
  24436. var times = interpolant.parameterPositions,
  24437. values = interpolant.sampleValues;
  24438. times[0] = now;values[0] = weightNow;
  24439. times[1] = now + duration;values[1] = weightThen;
  24440. return this;
  24441. }
  24442. });
  24443. /**
  24444. *
  24445. * Player for AnimationClips.
  24446. *
  24447. *
  24448. * @author Ben Houston / http://clara.io/
  24449. * @author David Sarno / http://lighthaus.us/
  24450. * @author tschw
  24451. */
  24452. function AnimationMixer(root) {
  24453. this._root = root;
  24454. this._initMemoryManager();
  24455. this._accuIndex = 0;
  24456. this.time = 0;
  24457. this.timeScale = 1.0;
  24458. }
  24459. AnimationMixer.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  24460. constructor: AnimationMixer,
  24461. _bindAction: function (action, prototypeAction) {
  24462. var root = action._localRoot || this._root,
  24463. tracks = action._clip.tracks,
  24464. nTracks = tracks.length,
  24465. bindings = action._propertyBindings,
  24466. interpolants = action._interpolants,
  24467. rootUuid = root.uuid,
  24468. bindingsByRoot = this._bindingsByRootAndName,
  24469. bindingsByName = bindingsByRoot[rootUuid];
  24470. if (bindingsByName === undefined) {
  24471. bindingsByName = {};
  24472. bindingsByRoot[rootUuid] = bindingsByName;
  24473. }
  24474. for (var i = 0; i !== nTracks; ++i) {
  24475. var track = tracks[i],
  24476. trackName = track.name,
  24477. binding = bindingsByName[trackName];
  24478. if (binding !== undefined) {
  24479. bindings[i] = binding;
  24480. } else {
  24481. binding = bindings[i];
  24482. if (binding !== undefined) {
  24483. // existing binding, make sure the cache knows
  24484. if (binding._cacheIndex === null) {
  24485. ++binding.referenceCount;
  24486. this._addInactiveBinding(binding, rootUuid, trackName);
  24487. }
  24488. continue;
  24489. }
  24490. var path = prototypeAction && prototypeAction._propertyBindings[i].binding.parsedPath;
  24491. binding = new PropertyMixer(PropertyBinding.create(root, trackName, path), track.ValueTypeName, track.getValueSize());
  24492. ++binding.referenceCount;
  24493. this._addInactiveBinding(binding, rootUuid, trackName);
  24494. bindings[i] = binding;
  24495. }
  24496. interpolants[i].resultBuffer = binding.buffer;
  24497. }
  24498. },
  24499. _activateAction: function (action) {
  24500. if (!this._isActiveAction(action)) {
  24501. if (action._cacheIndex === null) {
  24502. // this action has been forgotten by the cache, but the user
  24503. // appears to be still using it -> rebind
  24504. var rootUuid = (action._localRoot || this._root).uuid,
  24505. clipUuid = action._clip.uuid,
  24506. actionsForClip = this._actionsByClip[clipUuid];
  24507. this._bindAction(action, actionsForClip && actionsForClip.knownActions[0]);
  24508. this._addInactiveAction(action, clipUuid, rootUuid);
  24509. }
  24510. var bindings = action._propertyBindings;
  24511. // increment reference counts / sort out state
  24512. for (var i = 0, n = bindings.length; i !== n; ++i) {
  24513. var binding = bindings[i];
  24514. if (binding.useCount++ === 0) {
  24515. this._lendBinding(binding);
  24516. binding.saveOriginalState();
  24517. }
  24518. }
  24519. this._lendAction(action);
  24520. }
  24521. },
  24522. _deactivateAction: function (action) {
  24523. if (this._isActiveAction(action)) {
  24524. var bindings = action._propertyBindings;
  24525. // decrement reference counts / sort out state
  24526. for (var i = 0, n = bindings.length; i !== n; ++i) {
  24527. var binding = bindings[i];
  24528. if (--binding.useCount === 0) {
  24529. binding.restoreOriginalState();
  24530. this._takeBackBinding(binding);
  24531. }
  24532. }
  24533. this._takeBackAction(action);
  24534. }
  24535. },
  24536. // Memory manager
  24537. _initMemoryManager: function () {
  24538. this._actions = []; // 'nActiveActions' followed by inactive ones
  24539. this._nActiveActions = 0;
  24540. this._actionsByClip = {};
  24541. // inside:
  24542. // {
  24543. // knownActions: Array< AnimationAction > - used as prototypes
  24544. // actionByRoot: AnimationAction - lookup
  24545. // }
  24546. this._bindings = []; // 'nActiveBindings' followed by inactive ones
  24547. this._nActiveBindings = 0;
  24548. this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
  24549. this._controlInterpolants = []; // same game as above
  24550. this._nActiveControlInterpolants = 0;
  24551. var scope = this;
  24552. this.stats = {
  24553. actions: {
  24554. get total() {
  24555. return scope._actions.length;
  24556. },
  24557. get inUse() {
  24558. return scope._nActiveActions;
  24559. }
  24560. },
  24561. bindings: {
  24562. get total() {
  24563. return scope._bindings.length;
  24564. },
  24565. get inUse() {
  24566. return scope._nActiveBindings;
  24567. }
  24568. },
  24569. controlInterpolants: {
  24570. get total() {
  24571. return scope._controlInterpolants.length;
  24572. },
  24573. get inUse() {
  24574. return scope._nActiveControlInterpolants;
  24575. }
  24576. }
  24577. };
  24578. },
  24579. // Memory management for AnimationAction objects
  24580. _isActiveAction: function (action) {
  24581. var index = action._cacheIndex;
  24582. return index !== null && index < this._nActiveActions;
  24583. },
  24584. _addInactiveAction: function (action, clipUuid, rootUuid) {
  24585. var actions = this._actions,
  24586. actionsByClip = this._actionsByClip,
  24587. actionsForClip = actionsByClip[clipUuid];
  24588. if (actionsForClip === undefined) {
  24589. actionsForClip = {
  24590. knownActions: [action],
  24591. actionByRoot: {}
  24592. };
  24593. action._byClipCacheIndex = 0;
  24594. actionsByClip[clipUuid] = actionsForClip;
  24595. } else {
  24596. var knownActions = actionsForClip.knownActions;
  24597. action._byClipCacheIndex = knownActions.length;
  24598. knownActions.push(action);
  24599. }
  24600. action._cacheIndex = actions.length;
  24601. actions.push(action);
  24602. actionsForClip.actionByRoot[rootUuid] = action;
  24603. },
  24604. _removeInactiveAction: function (action) {
  24605. var actions = this._actions,
  24606. lastInactiveAction = actions[actions.length - 1],
  24607. cacheIndex = action._cacheIndex;
  24608. lastInactiveAction._cacheIndex = cacheIndex;
  24609. actions[cacheIndex] = lastInactiveAction;
  24610. actions.pop();
  24611. action._cacheIndex = null;
  24612. var clipUuid = action._clip.uuid,
  24613. actionsByClip = this._actionsByClip,
  24614. actionsForClip = actionsByClip[clipUuid],
  24615. knownActionsForClip = actionsForClip.knownActions,
  24616. lastKnownAction = knownActionsForClip[knownActionsForClip.length - 1],
  24617. byClipCacheIndex = action._byClipCacheIndex;
  24618. lastKnownAction._byClipCacheIndex = byClipCacheIndex;
  24619. knownActionsForClip[byClipCacheIndex] = lastKnownAction;
  24620. knownActionsForClip.pop();
  24621. action._byClipCacheIndex = null;
  24622. var actionByRoot = actionsForClip.actionByRoot,
  24623. rootUuid = (action._localRoot || this._root).uuid;
  24624. delete actionByRoot[rootUuid];
  24625. if (knownActionsForClip.length === 0) {
  24626. delete actionsByClip[clipUuid];
  24627. }
  24628. this._removeInactiveBindingsForAction(action);
  24629. },
  24630. _removeInactiveBindingsForAction: function (action) {
  24631. var bindings = action._propertyBindings;
  24632. for (var i = 0, n = bindings.length; i !== n; ++i) {
  24633. var binding = bindings[i];
  24634. if (--binding.referenceCount === 0) {
  24635. this._removeInactiveBinding(binding);
  24636. }
  24637. }
  24638. },
  24639. _lendAction: function (action) {
  24640. // [ active actions | inactive actions ]
  24641. // [ active actions >| inactive actions ]
  24642. // s a
  24643. // <-swap->
  24644. // a s
  24645. var actions = this._actions,
  24646. prevIndex = action._cacheIndex,
  24647. lastActiveIndex = this._nActiveActions++,
  24648. firstInactiveAction = actions[lastActiveIndex];
  24649. action._cacheIndex = lastActiveIndex;
  24650. actions[lastActiveIndex] = action;
  24651. firstInactiveAction._cacheIndex = prevIndex;
  24652. actions[prevIndex] = firstInactiveAction;
  24653. },
  24654. _takeBackAction: function (action) {
  24655. // [ active actions | inactive actions ]
  24656. // [ active actions |< inactive actions ]
  24657. // a s
  24658. // <-swap->
  24659. // s a
  24660. var actions = this._actions,
  24661. prevIndex = action._cacheIndex,
  24662. firstInactiveIndex = --this._nActiveActions,
  24663. lastActiveAction = actions[firstInactiveIndex];
  24664. action._cacheIndex = firstInactiveIndex;
  24665. actions[firstInactiveIndex] = action;
  24666. lastActiveAction._cacheIndex = prevIndex;
  24667. actions[prevIndex] = lastActiveAction;
  24668. },
  24669. // Memory management for PropertyMixer objects
  24670. _addInactiveBinding: function (binding, rootUuid, trackName) {
  24671. var bindingsByRoot = this._bindingsByRootAndName,
  24672. bindingByName = bindingsByRoot[rootUuid],
  24673. bindings = this._bindings;
  24674. if (bindingByName === undefined) {
  24675. bindingByName = {};
  24676. bindingsByRoot[rootUuid] = bindingByName;
  24677. }
  24678. bindingByName[trackName] = binding;
  24679. binding._cacheIndex = bindings.length;
  24680. bindings.push(binding);
  24681. },
  24682. _removeInactiveBinding: function (binding) {
  24683. var bindings = this._bindings,
  24684. propBinding = binding.binding,
  24685. rootUuid = propBinding.rootNode.uuid,
  24686. trackName = propBinding.path,
  24687. bindingsByRoot = this._bindingsByRootAndName,
  24688. bindingByName = bindingsByRoot[rootUuid],
  24689. lastInactiveBinding = bindings[bindings.length - 1],
  24690. cacheIndex = binding._cacheIndex;
  24691. lastInactiveBinding._cacheIndex = cacheIndex;
  24692. bindings[cacheIndex] = lastInactiveBinding;
  24693. bindings.pop();
  24694. delete bindingByName[trackName];
  24695. remove_empty_map: {
  24696. for (var _ in bindingByName) break remove_empty_map; // eslint-disable-line no-unused-vars
  24697. delete bindingsByRoot[rootUuid];
  24698. }
  24699. },
  24700. _lendBinding: function (binding) {
  24701. var bindings = this._bindings,
  24702. prevIndex = binding._cacheIndex,
  24703. lastActiveIndex = this._nActiveBindings++,
  24704. firstInactiveBinding = bindings[lastActiveIndex];
  24705. binding._cacheIndex = lastActiveIndex;
  24706. bindings[lastActiveIndex] = binding;
  24707. firstInactiveBinding._cacheIndex = prevIndex;
  24708. bindings[prevIndex] = firstInactiveBinding;
  24709. },
  24710. _takeBackBinding: function (binding) {
  24711. var bindings = this._bindings,
  24712. prevIndex = binding._cacheIndex,
  24713. firstInactiveIndex = --this._nActiveBindings,
  24714. lastActiveBinding = bindings[firstInactiveIndex];
  24715. binding._cacheIndex = firstInactiveIndex;
  24716. bindings[firstInactiveIndex] = binding;
  24717. lastActiveBinding._cacheIndex = prevIndex;
  24718. bindings[prevIndex] = lastActiveBinding;
  24719. },
  24720. // Memory management of Interpolants for weight and time scale
  24721. _lendControlInterpolant: function () {
  24722. var interpolants = this._controlInterpolants,
  24723. lastActiveIndex = this._nActiveControlInterpolants++,
  24724. interpolant = interpolants[lastActiveIndex];
  24725. if (interpolant === undefined) {
  24726. interpolant = new LinearInterpolant(new Float32Array(2), new Float32Array(2), 1, this._controlInterpolantsResultBuffer);
  24727. interpolant.__cacheIndex = lastActiveIndex;
  24728. interpolants[lastActiveIndex] = interpolant;
  24729. }
  24730. return interpolant;
  24731. },
  24732. _takeBackControlInterpolant: function (interpolant) {
  24733. var interpolants = this._controlInterpolants,
  24734. prevIndex = interpolant.__cacheIndex,
  24735. firstInactiveIndex = --this._nActiveControlInterpolants,
  24736. lastActiveInterpolant = interpolants[firstInactiveIndex];
  24737. interpolant.__cacheIndex = firstInactiveIndex;
  24738. interpolants[firstInactiveIndex] = interpolant;
  24739. lastActiveInterpolant.__cacheIndex = prevIndex;
  24740. interpolants[prevIndex] = lastActiveInterpolant;
  24741. },
  24742. _controlInterpolantsResultBuffer: new Float32Array(1),
  24743. // return an action for a clip optionally using a custom root target
  24744. // object (this method allocates a lot of dynamic memory in case a
  24745. // previously unknown clip/root combination is specified)
  24746. clipAction: function (clip, optionalRoot) {
  24747. var root = optionalRoot || this._root,
  24748. rootUuid = root.uuid,
  24749. clipObject = typeof clip === 'string' ? AnimationClip.findByName(root, clip) : clip,
  24750. clipUuid = clipObject !== null ? clipObject.uuid : clip,
  24751. actionsForClip = this._actionsByClip[clipUuid],
  24752. prototypeAction = null;
  24753. if (actionsForClip !== undefined) {
  24754. var existingAction = actionsForClip.actionByRoot[rootUuid];
  24755. if (existingAction !== undefined) {
  24756. return existingAction;
  24757. }
  24758. // we know the clip, so we don't have to parse all
  24759. // the bindings again but can just copy
  24760. prototypeAction = actionsForClip.knownActions[0];
  24761. // also, take the clip from the prototype action
  24762. if (clipObject === null) clipObject = prototypeAction._clip;
  24763. }
  24764. // clip must be known when specified via string
  24765. if (clipObject === null) return null;
  24766. // allocate all resources required to run it
  24767. var newAction = new AnimationAction(this, clipObject, optionalRoot);
  24768. this._bindAction(newAction, prototypeAction);
  24769. // and make the action known to the memory manager
  24770. this._addInactiveAction(newAction, clipUuid, rootUuid);
  24771. return newAction;
  24772. },
  24773. // get an existing action
  24774. existingAction: function (clip, optionalRoot) {
  24775. var root = optionalRoot || this._root,
  24776. rootUuid = root.uuid,
  24777. clipObject = typeof clip === 'string' ? AnimationClip.findByName(root, clip) : clip,
  24778. clipUuid = clipObject ? clipObject.uuid : clip,
  24779. actionsForClip = this._actionsByClip[clipUuid];
  24780. if (actionsForClip !== undefined) {
  24781. return actionsForClip.actionByRoot[rootUuid] || null;
  24782. }
  24783. return null;
  24784. },
  24785. // deactivates all previously scheduled actions
  24786. stopAllAction: function () {
  24787. var actions = this._actions,
  24788. nActions = this._nActiveActions,
  24789. bindings = this._bindings,
  24790. nBindings = this._nActiveBindings;
  24791. this._nActiveActions = 0;
  24792. this._nActiveBindings = 0;
  24793. for (var i = 0; i !== nActions; ++i) {
  24794. actions[i].reset();
  24795. }
  24796. for (var i = 0; i !== nBindings; ++i) {
  24797. bindings[i].useCount = 0;
  24798. }
  24799. return this;
  24800. },
  24801. // advance the time and update apply the animation
  24802. update: function (deltaTime) {
  24803. deltaTime *= this.timeScale;
  24804. var actions = this._actions,
  24805. nActions = this._nActiveActions,
  24806. time = this.time += deltaTime,
  24807. timeDirection = Math.sign(deltaTime),
  24808. accuIndex = this._accuIndex ^= 1;
  24809. // run active actions
  24810. for (var i = 0; i !== nActions; ++i) {
  24811. var action = actions[i];
  24812. action._update(time, deltaTime, timeDirection, accuIndex);
  24813. }
  24814. // update scene graph
  24815. var bindings = this._bindings,
  24816. nBindings = this._nActiveBindings;
  24817. for (var i = 0; i !== nBindings; ++i) {
  24818. bindings[i].apply(accuIndex);
  24819. }
  24820. return this;
  24821. },
  24822. // return this mixer's root target object
  24823. getRoot: function () {
  24824. return this._root;
  24825. },
  24826. // free all resources specific to a particular clip
  24827. uncacheClip: function (clip) {
  24828. var actions = this._actions,
  24829. clipUuid = clip.uuid,
  24830. actionsByClip = this._actionsByClip,
  24831. actionsForClip = actionsByClip[clipUuid];
  24832. if (actionsForClip !== undefined) {
  24833. // note: just calling _removeInactiveAction would mess up the
  24834. // iteration state and also require updating the state we can
  24835. // just throw away
  24836. var actionsToRemove = actionsForClip.knownActions;
  24837. for (var i = 0, n = actionsToRemove.length; i !== n; ++i) {
  24838. var action = actionsToRemove[i];
  24839. this._deactivateAction(action);
  24840. var cacheIndex = action._cacheIndex,
  24841. lastInactiveAction = actions[actions.length - 1];
  24842. action._cacheIndex = null;
  24843. action._byClipCacheIndex = null;
  24844. lastInactiveAction._cacheIndex = cacheIndex;
  24845. actions[cacheIndex] = lastInactiveAction;
  24846. actions.pop();
  24847. this._removeInactiveBindingsForAction(action);
  24848. }
  24849. delete actionsByClip[clipUuid];
  24850. }
  24851. },
  24852. // free all resources specific to a particular root target object
  24853. uncacheRoot: function (root) {
  24854. var rootUuid = root.uuid,
  24855. actionsByClip = this._actionsByClip;
  24856. for (var clipUuid in actionsByClip) {
  24857. var actionByRoot = actionsByClip[clipUuid].actionByRoot,
  24858. action = actionByRoot[rootUuid];
  24859. if (action !== undefined) {
  24860. this._deactivateAction(action);
  24861. this._removeInactiveAction(action);
  24862. }
  24863. }
  24864. var bindingsByRoot = this._bindingsByRootAndName,
  24865. bindingByName = bindingsByRoot[rootUuid];
  24866. if (bindingByName !== undefined) {
  24867. for (var trackName in bindingByName) {
  24868. var binding = bindingByName[trackName];
  24869. binding.restoreOriginalState();
  24870. this._removeInactiveBinding(binding);
  24871. }
  24872. }
  24873. },
  24874. // remove a targeted clip from the cache
  24875. uncacheAction: function (clip, optionalRoot) {
  24876. var action = this.existingAction(clip, optionalRoot);
  24877. if (action !== null) {
  24878. this._deactivateAction(action);
  24879. this._removeInactiveAction(action);
  24880. }
  24881. }
  24882. });
  24883. /**
  24884. * @author mrdoob / http://mrdoob.com/
  24885. */
  24886. function Uniform(value) {
  24887. if (typeof value === 'string') {
  24888. console.warn('THREE.Uniform: Type parameter is no longer needed.');
  24889. value = arguments[1];
  24890. }
  24891. this.value = value;
  24892. }
  24893. Uniform.prototype.clone = function () {
  24894. return new Uniform(this.value.clone === undefined ? this.value : this.value.clone());
  24895. };
  24896. /**
  24897. * @author benaadams / https://twitter.com/ben_a_adams
  24898. */
  24899. function InstancedBufferGeometry() {
  24900. BufferGeometry.call(this);
  24901. this.type = 'InstancedBufferGeometry';
  24902. this.maxInstancedCount = undefined;
  24903. }
  24904. InstancedBufferGeometry.prototype = Object.assign(Object.create(BufferGeometry.prototype), {
  24905. constructor: InstancedBufferGeometry,
  24906. isInstancedBufferGeometry: true,
  24907. copy: function (source) {
  24908. BufferGeometry.prototype.copy.call(this, source);
  24909. this.maxInstancedCount = source.maxInstancedCount;
  24910. return this;
  24911. },
  24912. clone: function () {
  24913. return new this.constructor().copy(this);
  24914. }
  24915. });
  24916. /**
  24917. * @author benaadams / https://twitter.com/ben_a_adams
  24918. */
  24919. function InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, normalized) {
  24920. this.data = interleavedBuffer;
  24921. this.itemSize = itemSize;
  24922. this.offset = offset;
  24923. this.normalized = normalized === true;
  24924. }
  24925. Object.defineProperties(InterleavedBufferAttribute.prototype, {
  24926. count: {
  24927. get: function () {
  24928. return this.data.count;
  24929. }
  24930. },
  24931. array: {
  24932. get: function () {
  24933. return this.data.array;
  24934. }
  24935. }
  24936. });
  24937. Object.assign(InterleavedBufferAttribute.prototype, {
  24938. isInterleavedBufferAttribute: true,
  24939. setX: function (index, x) {
  24940. this.data.array[index * this.data.stride + this.offset] = x;
  24941. return this;
  24942. },
  24943. setY: function (index, y) {
  24944. this.data.array[index * this.data.stride + this.offset + 1] = y;
  24945. return this;
  24946. },
  24947. setZ: function (index, z) {
  24948. this.data.array[index * this.data.stride + this.offset + 2] = z;
  24949. return this;
  24950. },
  24951. setW: function (index, w) {
  24952. this.data.array[index * this.data.stride + this.offset + 3] = w;
  24953. return this;
  24954. },
  24955. getX: function (index) {
  24956. return this.data.array[index * this.data.stride + this.offset];
  24957. },
  24958. getY: function (index) {
  24959. return this.data.array[index * this.data.stride + this.offset + 1];
  24960. },
  24961. getZ: function (index) {
  24962. return this.data.array[index * this.data.stride + this.offset + 2];
  24963. },
  24964. getW: function (index) {
  24965. return this.data.array[index * this.data.stride + this.offset + 3];
  24966. },
  24967. setXY: function (index, x, y) {
  24968. index = index * this.data.stride + this.offset;
  24969. this.data.array[index + 0] = x;
  24970. this.data.array[index + 1] = y;
  24971. return this;
  24972. },
  24973. setXYZ: function (index, x, y, z) {
  24974. index = index * this.data.stride + this.offset;
  24975. this.data.array[index + 0] = x;
  24976. this.data.array[index + 1] = y;
  24977. this.data.array[index + 2] = z;
  24978. return this;
  24979. },
  24980. setXYZW: function (index, x, y, z, w) {
  24981. index = index * this.data.stride + this.offset;
  24982. this.data.array[index + 0] = x;
  24983. this.data.array[index + 1] = y;
  24984. this.data.array[index + 2] = z;
  24985. this.data.array[index + 3] = w;
  24986. return this;
  24987. }
  24988. });
  24989. /**
  24990. * @author benaadams / https://twitter.com/ben_a_adams
  24991. */
  24992. function InterleavedBuffer(array, stride) {
  24993. this.array = array;
  24994. this.stride = stride;
  24995. this.count = array !== undefined ? array.length / stride : 0;
  24996. this.dynamic = false;
  24997. this.updateRange = { offset: 0, count: -1 };
  24998. this.version = 0;
  24999. }
  25000. Object.defineProperty(InterleavedBuffer.prototype, 'needsUpdate', {
  25001. set: function (value) {
  25002. if (value === true) this.version++;
  25003. }
  25004. });
  25005. Object.assign(InterleavedBuffer.prototype, {
  25006. isInterleavedBuffer: true,
  25007. onUploadCallback: function () {},
  25008. setArray: function (array) {
  25009. if (Array.isArray(array)) {
  25010. throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.');
  25011. }
  25012. this.count = array !== undefined ? array.length / this.stride : 0;
  25013. this.array = array;
  25014. return this;
  25015. },
  25016. setDynamic: function (value) {
  25017. this.dynamic = value;
  25018. return this;
  25019. },
  25020. copy: function (source) {
  25021. this.array = new source.array.constructor(source.array);
  25022. this.count = source.count;
  25023. this.stride = source.stride;
  25024. this.dynamic = source.dynamic;
  25025. return this;
  25026. },
  25027. copyAt: function (index1, attribute, index2) {
  25028. index1 *= this.stride;
  25029. index2 *= attribute.stride;
  25030. for (var i = 0, l = this.stride; i < l; i++) {
  25031. this.array[index1 + i] = attribute.array[index2 + i];
  25032. }
  25033. return this;
  25034. },
  25035. set: function (value, offset) {
  25036. if (offset === undefined) offset = 0;
  25037. this.array.set(value, offset);
  25038. return this;
  25039. },
  25040. clone: function () {
  25041. return new this.constructor().copy(this);
  25042. },
  25043. onUpload: function (callback) {
  25044. this.onUploadCallback = callback;
  25045. return this;
  25046. }
  25047. });
  25048. /**
  25049. * @author benaadams / https://twitter.com/ben_a_adams
  25050. */
  25051. function InstancedInterleavedBuffer(array, stride, meshPerAttribute) {
  25052. InterleavedBuffer.call(this, array, stride);
  25053. this.meshPerAttribute = meshPerAttribute || 1;
  25054. }
  25055. InstancedInterleavedBuffer.prototype = Object.assign(Object.create(InterleavedBuffer.prototype), {
  25056. constructor: InstancedInterleavedBuffer,
  25057. isInstancedInterleavedBuffer: true,
  25058. copy: function (source) {
  25059. InterleavedBuffer.prototype.copy.call(this, source);
  25060. this.meshPerAttribute = source.meshPerAttribute;
  25061. return this;
  25062. }
  25063. });
  25064. /**
  25065. * @author benaadams / https://twitter.com/ben_a_adams
  25066. */
  25067. function InstancedBufferAttribute(array, itemSize, meshPerAttribute) {
  25068. BufferAttribute.call(this, array, itemSize);
  25069. this.meshPerAttribute = meshPerAttribute || 1;
  25070. }
  25071. InstancedBufferAttribute.prototype = Object.assign(Object.create(BufferAttribute.prototype), {
  25072. constructor: InstancedBufferAttribute,
  25073. isInstancedBufferAttribute: true,
  25074. copy: function (source) {
  25075. BufferAttribute.prototype.copy.call(this, source);
  25076. this.meshPerAttribute = source.meshPerAttribute;
  25077. return this;
  25078. }
  25079. });
  25080. /**
  25081. * @author mrdoob / http://mrdoob.com/
  25082. * @author bhouston / http://clara.io/
  25083. * @author stephomi / http://stephaneginier.com/
  25084. */
  25085. function Raycaster(origin, direction, near, far) {
  25086. this.ray = new Ray(origin, direction);
  25087. // direction is assumed to be normalized (for accurate distance calculations)
  25088. this.near = near || 0;
  25089. this.far = far || Infinity;
  25090. this.params = {
  25091. Mesh: {},
  25092. Line: {},
  25093. LOD: {},
  25094. Points: { threshold: 1 },
  25095. Sprite: {}
  25096. };
  25097. Object.defineProperties(this.params, {
  25098. PointCloud: {
  25099. get: function () {
  25100. console.warn('THREE.Raycaster: params.PointCloud has been renamed to params.Points.');
  25101. return this.Points;
  25102. }
  25103. }
  25104. });
  25105. }
  25106. function ascSort(a, b) {
  25107. return a.distance - b.distance;
  25108. }
  25109. function intersectObject(object, raycaster, intersects, recursive) {
  25110. if (object.visible === false) return;
  25111. object.raycast(raycaster, intersects);
  25112. if (recursive === true) {
  25113. var children = object.children;
  25114. for (var i = 0, l = children.length; i < l; i++) {
  25115. intersectObject(children[i], raycaster, intersects, true);
  25116. }
  25117. }
  25118. }
  25119. Object.assign(Raycaster.prototype, {
  25120. linePrecision: 1,
  25121. set: function (origin, direction) {
  25122. // direction is assumed to be normalized (for accurate distance calculations)
  25123. this.ray.set(origin, direction);
  25124. },
  25125. setFromCamera: function (coords, camera) {
  25126. if (camera && camera.isPerspectiveCamera) {
  25127. this.ray.origin.setFromMatrixPosition(camera.matrixWorld);
  25128. this.ray.direction.set(coords.x, coords.y, 0.5).unproject(camera).sub(this.ray.origin).normalize();
  25129. } else if (camera && camera.isOrthographicCamera) {
  25130. this.ray.origin.set(coords.x, coords.y, (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera); // set origin in plane of camera
  25131. this.ray.direction.set(0, 0, -1).transformDirection(camera.matrixWorld);
  25132. } else {
  25133. console.error('THREE.Raycaster: Unsupported camera type.');
  25134. }
  25135. },
  25136. intersectObject: function (object, recursive, optionalTarget) {
  25137. var intersects = optionalTarget || [];
  25138. intersectObject(object, this, intersects, recursive);
  25139. intersects.sort(ascSort);
  25140. return intersects;
  25141. },
  25142. intersectObjects: function (objects, recursive, optionalTarget) {
  25143. var intersects = optionalTarget || [];
  25144. if (Array.isArray(objects) === false) {
  25145. console.warn('THREE.Raycaster.intersectObjects: objects is not an Array.');
  25146. return intersects;
  25147. }
  25148. for (var i = 0, l = objects.length; i < l; i++) {
  25149. intersectObject(objects[i], this, intersects, recursive);
  25150. }
  25151. intersects.sort(ascSort);
  25152. return intersects;
  25153. }
  25154. });
  25155. /**
  25156. * @author alteredq / http://alteredqualia.com/
  25157. */
  25158. function Clock(autoStart) {
  25159. this.autoStart = autoStart !== undefined ? autoStart : true;
  25160. this.startTime = 0;
  25161. this.oldTime = 0;
  25162. this.elapsedTime = 0;
  25163. this.running = false;
  25164. }
  25165. Object.assign(Clock.prototype, {
  25166. start: function () {
  25167. this.startTime = (typeof performance === 'undefined' ? Date : performance).now(); // see #10732
  25168. this.oldTime = this.startTime;
  25169. this.elapsedTime = 0;
  25170. this.running = true;
  25171. },
  25172. stop: function () {
  25173. this.getElapsedTime();
  25174. this.running = false;
  25175. this.autoStart = false;
  25176. },
  25177. getElapsedTime: function () {
  25178. this.getDelta();
  25179. return this.elapsedTime;
  25180. },
  25181. getDelta: function () {
  25182. var diff = 0;
  25183. if (this.autoStart && !this.running) {
  25184. this.start();
  25185. return 0;
  25186. }
  25187. if (this.running) {
  25188. var newTime = (typeof performance === 'undefined' ? Date : performance).now();
  25189. diff = (newTime - this.oldTime) / 1000;
  25190. this.oldTime = newTime;
  25191. this.elapsedTime += diff;
  25192. }
  25193. return diff;
  25194. }
  25195. });
  25196. /**
  25197. * @author bhouston / http://clara.io
  25198. * @author WestLangley / http://github.com/WestLangley
  25199. *
  25200. * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
  25201. *
  25202. * The poles (phi) are at the positive and negative y axis.
  25203. * The equator starts at positive z.
  25204. */
  25205. function Spherical(radius, phi, theta) {
  25206. this.radius = radius !== undefined ? radius : 1.0;
  25207. this.phi = phi !== undefined ? phi : 0; // up / down towards top and bottom pole
  25208. this.theta = theta !== undefined ? theta : 0; // around the equator of the sphere
  25209. return this;
  25210. }
  25211. Object.assign(Spherical.prototype, {
  25212. set: function (radius, phi, theta) {
  25213. this.radius = radius;
  25214. this.phi = phi;
  25215. this.theta = theta;
  25216. return this;
  25217. },
  25218. clone: function () {
  25219. return new this.constructor().copy(this);
  25220. },
  25221. copy: function (other) {
  25222. this.radius = other.radius;
  25223. this.phi = other.phi;
  25224. this.theta = other.theta;
  25225. return this;
  25226. },
  25227. // restrict phi to be betwee EPS and PI-EPS
  25228. makeSafe: function () {
  25229. var EPS = 0.000001;
  25230. this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi));
  25231. return this;
  25232. },
  25233. setFromVector3: function (vec3) {
  25234. this.radius = vec3.length();
  25235. if (this.radius === 0) {
  25236. this.theta = 0;
  25237. this.phi = 0;
  25238. } else {
  25239. this.theta = Math.atan2(vec3.x, vec3.z); // equator angle around y-up axis
  25240. this.phi = Math.acos(_Math.clamp(vec3.y / this.radius, -1, 1)); // polar angle
  25241. }
  25242. return this;
  25243. }
  25244. });
  25245. /**
  25246. * @author Mugen87 / https://github.com/Mugen87
  25247. *
  25248. * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
  25249. *
  25250. */
  25251. function Cylindrical(radius, theta, y) {
  25252. this.radius = radius !== undefined ? radius : 1.0; // distance from the origin to a point in the x-z plane
  25253. this.theta = theta !== undefined ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
  25254. this.y = y !== undefined ? y : 0; // height above the x-z plane
  25255. return this;
  25256. }
  25257. Object.assign(Cylindrical.prototype, {
  25258. set: function (radius, theta, y) {
  25259. this.radius = radius;
  25260. this.theta = theta;
  25261. this.y = y;
  25262. return this;
  25263. },
  25264. clone: function () {
  25265. return new this.constructor().copy(this);
  25266. },
  25267. copy: function (other) {
  25268. this.radius = other.radius;
  25269. this.theta = other.theta;
  25270. this.y = other.y;
  25271. return this;
  25272. },
  25273. setFromVector3: function (vec3) {
  25274. this.radius = Math.sqrt(vec3.x * vec3.x + vec3.z * vec3.z);
  25275. this.theta = Math.atan2(vec3.x, vec3.z);
  25276. this.y = vec3.y;
  25277. return this;
  25278. }
  25279. });
  25280. /**
  25281. * @author bhouston / http://clara.io
  25282. */
  25283. function Box2(min, max) {
  25284. this.min = min !== undefined ? min : new Vector2(+Infinity, +Infinity);
  25285. this.max = max !== undefined ? max : new Vector2(-Infinity, -Infinity);
  25286. }
  25287. Object.assign(Box2.prototype, {
  25288. set: function (min, max) {
  25289. this.min.copy(min);
  25290. this.max.copy(max);
  25291. return this;
  25292. },
  25293. setFromPoints: function (points) {
  25294. this.makeEmpty();
  25295. for (var i = 0, il = points.length; i < il; i++) {
  25296. this.expandByPoint(points[i]);
  25297. }
  25298. return this;
  25299. },
  25300. setFromCenterAndSize: function () {
  25301. var v1 = new Vector2();
  25302. return function setFromCenterAndSize(center, size) {
  25303. var halfSize = v1.copy(size).multiplyScalar(0.5);
  25304. this.min.copy(center).sub(halfSize);
  25305. this.max.copy(center).add(halfSize);
  25306. return this;
  25307. };
  25308. }(),
  25309. clone: function () {
  25310. return new this.constructor().copy(this);
  25311. },
  25312. copy: function (box) {
  25313. this.min.copy(box.min);
  25314. this.max.copy(box.max);
  25315. return this;
  25316. },
  25317. makeEmpty: function () {
  25318. this.min.x = this.min.y = +Infinity;
  25319. this.max.x = this.max.y = -Infinity;
  25320. return this;
  25321. },
  25322. isEmpty: function () {
  25323. // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  25324. return this.max.x < this.min.x || this.max.y < this.min.y;
  25325. },
  25326. getCenter: function (target) {
  25327. if (target === undefined) {
  25328. console.warn('THREE.Box2: .getCenter() target is now required');
  25329. target = new Vector2();
  25330. }
  25331. return this.isEmpty() ? target.set(0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5);
  25332. },
  25333. getSize: function (target) {
  25334. if (target === undefined) {
  25335. console.warn('THREE.Box2: .getSize() target is now required');
  25336. target = new Vector2();
  25337. }
  25338. return this.isEmpty() ? target.set(0, 0) : target.subVectors(this.max, this.min);
  25339. },
  25340. expandByPoint: function (point) {
  25341. this.min.min(point);
  25342. this.max.max(point);
  25343. return this;
  25344. },
  25345. expandByVector: function (vector) {
  25346. this.min.sub(vector);
  25347. this.max.add(vector);
  25348. return this;
  25349. },
  25350. expandByScalar: function (scalar) {
  25351. this.min.addScalar(-scalar);
  25352. this.max.addScalar(scalar);
  25353. return this;
  25354. },
  25355. containsPoint: function (point) {
  25356. return point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y ? false : true;
  25357. },
  25358. containsBox: function (box) {
  25359. 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;
  25360. },
  25361. getParameter: function (point, target) {
  25362. // This can potentially have a divide by zero if the box
  25363. // has a size dimension of 0.
  25364. if (target === undefined) {
  25365. console.warn('THREE.Box2: .getParameter() target is now required');
  25366. target = new Vector2();
  25367. }
  25368. return target.set((point.x - this.min.x) / (this.max.x - this.min.x), (point.y - this.min.y) / (this.max.y - this.min.y));
  25369. },
  25370. intersectsBox: function (box) {
  25371. // using 4 splitting planes to rule out intersections
  25372. 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;
  25373. },
  25374. clampPoint: function (point, target) {
  25375. if (target === undefined) {
  25376. console.warn('THREE.Box2: .clampPoint() target is now required');
  25377. target = new Vector2();
  25378. }
  25379. return target.copy(point).clamp(this.min, this.max);
  25380. },
  25381. distanceToPoint: function () {
  25382. var v1 = new Vector2();
  25383. return function distanceToPoint(point) {
  25384. var clampedPoint = v1.copy(point).clamp(this.min, this.max);
  25385. return clampedPoint.sub(point).length();
  25386. };
  25387. }(),
  25388. intersect: function (box) {
  25389. this.min.max(box.min);
  25390. this.max.min(box.max);
  25391. return this;
  25392. },
  25393. union: function (box) {
  25394. this.min.min(box.min);
  25395. this.max.max(box.max);
  25396. return this;
  25397. },
  25398. translate: function (offset) {
  25399. this.min.add(offset);
  25400. this.max.add(offset);
  25401. return this;
  25402. },
  25403. equals: function (box) {
  25404. return box.min.equals(this.min) && box.max.equals(this.max);
  25405. }
  25406. });
  25407. /**
  25408. * @author alteredq / http://alteredqualia.com/
  25409. */
  25410. function ImmediateRenderObject(material) {
  25411. Object3D.call(this);
  25412. this.material = material;
  25413. this.render = function () /* renderCallback */{};
  25414. }
  25415. ImmediateRenderObject.prototype = Object.create(Object3D.prototype);
  25416. ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
  25417. ImmediateRenderObject.prototype.isImmediateRenderObject = true;
  25418. /**
  25419. * @author mrdoob / http://mrdoob.com/
  25420. * @author WestLangley / http://github.com/WestLangley
  25421. */
  25422. function VertexNormalsHelper(object, size, hex, linewidth) {
  25423. this.object = object;
  25424. this.size = size !== undefined ? size : 1;
  25425. var color = hex !== undefined ? hex : 0xff0000;
  25426. var width = linewidth !== undefined ? linewidth : 1;
  25427. //
  25428. var nNormals = 0;
  25429. var objGeometry = this.object.geometry;
  25430. if (objGeometry && objGeometry.isGeometry) {
  25431. nNormals = objGeometry.faces.length * 3;
  25432. } else if (objGeometry && objGeometry.isBufferGeometry) {
  25433. nNormals = objGeometry.attributes.normal.count;
  25434. }
  25435. //
  25436. var geometry = new BufferGeometry();
  25437. var positions = new Float32BufferAttribute(nNormals * 2 * 3, 3);
  25438. geometry.addAttribute('position', positions);
  25439. LineSegments.call(this, geometry, new LineBasicMaterial({ color: color, linewidth: width }));
  25440. //
  25441. this.matrixAutoUpdate = false;
  25442. this.update();
  25443. }
  25444. VertexNormalsHelper.prototype = Object.create(LineSegments.prototype);
  25445. VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;
  25446. VertexNormalsHelper.prototype.update = function () {
  25447. var v1 = new Vector3();
  25448. var v2 = new Vector3();
  25449. var normalMatrix = new Matrix3();
  25450. return function update() {
  25451. var keys = ['a', 'b', 'c'];
  25452. this.object.updateMatrixWorld(true);
  25453. normalMatrix.getNormalMatrix(this.object.matrixWorld);
  25454. var matrixWorld = this.object.matrixWorld;
  25455. var position = this.geometry.attributes.position;
  25456. //
  25457. var objGeometry = this.object.geometry;
  25458. if (objGeometry && objGeometry.isGeometry) {
  25459. var vertices = objGeometry.vertices;
  25460. var faces = objGeometry.faces;
  25461. var idx = 0;
  25462. for (var i = 0, l = faces.length; i < l; i++) {
  25463. var face = faces[i];
  25464. for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) {
  25465. var vertex = vertices[face[keys[j]]];
  25466. var normal = face.vertexNormals[j];
  25467. v1.copy(vertex).applyMatrix4(matrixWorld);
  25468. v2.copy(normal).applyMatrix3(normalMatrix).normalize().multiplyScalar(this.size).add(v1);
  25469. position.setXYZ(idx, v1.x, v1.y, v1.z);
  25470. idx = idx + 1;
  25471. position.setXYZ(idx, v2.x, v2.y, v2.z);
  25472. idx = idx + 1;
  25473. }
  25474. }
  25475. } else if (objGeometry && objGeometry.isBufferGeometry) {
  25476. var objPos = objGeometry.attributes.position;
  25477. var objNorm = objGeometry.attributes.normal;
  25478. var idx = 0;
  25479. // for simplicity, ignore index and drawcalls, and render every normal
  25480. for (var j = 0, jl = objPos.count; j < jl; j++) {
  25481. v1.set(objPos.getX(j), objPos.getY(j), objPos.getZ(j)).applyMatrix4(matrixWorld);
  25482. v2.set(objNorm.getX(j), objNorm.getY(j), objNorm.getZ(j));
  25483. v2.applyMatrix3(normalMatrix).normalize().multiplyScalar(this.size).add(v1);
  25484. position.setXYZ(idx, v1.x, v1.y, v1.z);
  25485. idx = idx + 1;
  25486. position.setXYZ(idx, v2.x, v2.y, v2.z);
  25487. idx = idx + 1;
  25488. }
  25489. }
  25490. position.needsUpdate = true;
  25491. };
  25492. }();
  25493. /**
  25494. * @author alteredq / http://alteredqualia.com/
  25495. * @author mrdoob / http://mrdoob.com/
  25496. * @author WestLangley / http://github.com/WestLangley
  25497. */
  25498. function SpotLightHelper(light, color) {
  25499. Object3D.call(this);
  25500. this.light = light;
  25501. this.light.updateMatrixWorld();
  25502. this.matrix = light.matrixWorld;
  25503. this.matrixAutoUpdate = false;
  25504. this.color = color;
  25505. var geometry = new BufferGeometry();
  25506. var positions = [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, 1];
  25507. for (var i = 0, j = 1, l = 32; i < l; i++, j++) {
  25508. var p1 = i / l * Math.PI * 2;
  25509. var p2 = j / l * Math.PI * 2;
  25510. positions.push(Math.cos(p1), Math.sin(p1), 1, Math.cos(p2), Math.sin(p2), 1);
  25511. }
  25512. geometry.addAttribute('position', new Float32BufferAttribute(positions, 3));
  25513. var material = new LineBasicMaterial({ fog: false });
  25514. this.cone = new LineSegments(geometry, material);
  25515. this.add(this.cone);
  25516. this.update();
  25517. }
  25518. SpotLightHelper.prototype = Object.create(Object3D.prototype);
  25519. SpotLightHelper.prototype.constructor = SpotLightHelper;
  25520. SpotLightHelper.prototype.dispose = function () {
  25521. this.cone.geometry.dispose();
  25522. this.cone.material.dispose();
  25523. };
  25524. SpotLightHelper.prototype.update = function () {
  25525. var vector = new Vector3();
  25526. var vector2 = new Vector3();
  25527. return function update() {
  25528. this.light.updateMatrixWorld();
  25529. var coneLength = this.light.distance ? this.light.distance : 1000;
  25530. var coneWidth = coneLength * Math.tan(this.light.angle);
  25531. this.cone.scale.set(coneWidth, coneWidth, coneLength);
  25532. vector.setFromMatrixPosition(this.light.matrixWorld);
  25533. vector2.setFromMatrixPosition(this.light.target.matrixWorld);
  25534. this.cone.lookAt(vector2.sub(vector));
  25535. if (this.color !== undefined) {
  25536. this.cone.material.color.set(this.color);
  25537. } else {
  25538. this.cone.material.color.copy(this.light.color);
  25539. }
  25540. };
  25541. }();
  25542. /**
  25543. * @author Sean Griffin / http://twitter.com/sgrif
  25544. * @author Michael Guerrero / http://realitymeltdown.com
  25545. * @author mrdoob / http://mrdoob.com/
  25546. * @author ikerr / http://verold.com
  25547. * @author Mugen87 / https://github.com/Mugen87
  25548. */
  25549. function getBoneList(object) {
  25550. var boneList = [];
  25551. if (object && object.isBone) {
  25552. boneList.push(object);
  25553. }
  25554. for (var i = 0; i < object.children.length; i++) {
  25555. boneList.push.apply(boneList, getBoneList(object.children[i]));
  25556. }
  25557. return boneList;
  25558. }
  25559. function SkeletonHelper(object) {
  25560. var bones = getBoneList(object);
  25561. var geometry = new BufferGeometry();
  25562. var vertices = [];
  25563. var colors = [];
  25564. var color1 = new Color(0, 0, 1);
  25565. var color2 = new Color(0, 1, 0);
  25566. for (var i = 0; i < bones.length; i++) {
  25567. var bone = bones[i];
  25568. if (bone.parent && bone.parent.isBone) {
  25569. vertices.push(0, 0, 0);
  25570. vertices.push(0, 0, 0);
  25571. colors.push(color1.r, color1.g, color1.b);
  25572. colors.push(color2.r, color2.g, color2.b);
  25573. }
  25574. }
  25575. geometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  25576. geometry.addAttribute('color', new Float32BufferAttribute(colors, 3));
  25577. var material = new LineBasicMaterial({ vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true });
  25578. LineSegments.call(this, geometry, material);
  25579. this.root = object;
  25580. this.bones = bones;
  25581. this.matrix = object.matrixWorld;
  25582. this.matrixAutoUpdate = false;
  25583. }
  25584. SkeletonHelper.prototype = Object.create(LineSegments.prototype);
  25585. SkeletonHelper.prototype.constructor = SkeletonHelper;
  25586. SkeletonHelper.prototype.updateMatrixWorld = function () {
  25587. var vector = new Vector3();
  25588. var boneMatrix = new Matrix4();
  25589. var matrixWorldInv = new Matrix4();
  25590. return function updateMatrixWorld(force) {
  25591. var bones = this.bones;
  25592. var geometry = this.geometry;
  25593. var position = geometry.getAttribute('position');
  25594. matrixWorldInv.getInverse(this.root.matrixWorld);
  25595. for (var i = 0, j = 0; i < bones.length; i++) {
  25596. var bone = bones[i];
  25597. if (bone.parent && bone.parent.isBone) {
  25598. boneMatrix.multiplyMatrices(matrixWorldInv, bone.matrixWorld);
  25599. vector.setFromMatrixPosition(boneMatrix);
  25600. position.setXYZ(j, vector.x, vector.y, vector.z);
  25601. boneMatrix.multiplyMatrices(matrixWorldInv, bone.parent.matrixWorld);
  25602. vector.setFromMatrixPosition(boneMatrix);
  25603. position.setXYZ(j + 1, vector.x, vector.y, vector.z);
  25604. j += 2;
  25605. }
  25606. }
  25607. geometry.getAttribute('position').needsUpdate = true;
  25608. Object3D.prototype.updateMatrixWorld.call(this, force);
  25609. };
  25610. }();
  25611. /**
  25612. * @author alteredq / http://alteredqualia.com/
  25613. * @author mrdoob / http://mrdoob.com/
  25614. */
  25615. function PointLightHelper(light, sphereSize, color) {
  25616. this.light = light;
  25617. this.light.updateMatrixWorld();
  25618. this.color = color;
  25619. var geometry = new SphereBufferGeometry(sphereSize, 4, 2);
  25620. var material = new MeshBasicMaterial({ wireframe: true, fog: false });
  25621. Mesh.call(this, geometry, material);
  25622. this.matrix = this.light.matrixWorld;
  25623. this.matrixAutoUpdate = false;
  25624. this.update();
  25625. /*
  25626. var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
  25627. var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
  25628. this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
  25629. this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
  25630. var d = light.distance;
  25631. if ( d === 0.0 ) {
  25632. this.lightDistance.visible = false;
  25633. } else {
  25634. this.lightDistance.scale.set( d, d, d );
  25635. }
  25636. this.add( this.lightDistance );
  25637. */
  25638. }
  25639. PointLightHelper.prototype = Object.create(Mesh.prototype);
  25640. PointLightHelper.prototype.constructor = PointLightHelper;
  25641. PointLightHelper.prototype.dispose = function () {
  25642. this.geometry.dispose();
  25643. this.material.dispose();
  25644. };
  25645. PointLightHelper.prototype.update = function () {
  25646. if (this.color !== undefined) {
  25647. this.material.color.set(this.color);
  25648. } else {
  25649. this.material.color.copy(this.light.color);
  25650. }
  25651. /*
  25652. var d = this.light.distance;
  25653. if ( d === 0.0 ) {
  25654. this.lightDistance.visible = false;
  25655. } else {
  25656. this.lightDistance.visible = true;
  25657. this.lightDistance.scale.set( d, d, d );
  25658. }
  25659. */
  25660. };
  25661. /**
  25662. * @author abelnation / http://github.com/abelnation
  25663. * @author Mugen87 / http://github.com/Mugen87
  25664. * @author WestLangley / http://github.com/WestLangley
  25665. */
  25666. function RectAreaLightHelper(light, color) {
  25667. Object3D.call(this);
  25668. this.light = light;
  25669. this.light.updateMatrixWorld();
  25670. this.matrix = light.matrixWorld;
  25671. this.matrixAutoUpdate = false;
  25672. this.color = color;
  25673. var material = new LineBasicMaterial({ fog: false });
  25674. var geometry = new BufferGeometry();
  25675. geometry.addAttribute('position', new BufferAttribute(new Float32Array(5 * 3), 3));
  25676. this.line = new Line(geometry, material);
  25677. this.add(this.line);
  25678. this.update();
  25679. }
  25680. RectAreaLightHelper.prototype = Object.create(Object3D.prototype);
  25681. RectAreaLightHelper.prototype.constructor = RectAreaLightHelper;
  25682. RectAreaLightHelper.prototype.dispose = function () {
  25683. this.children[0].geometry.dispose();
  25684. this.children[0].material.dispose();
  25685. };
  25686. RectAreaLightHelper.prototype.update = function () {
  25687. // calculate new dimensions of the helper
  25688. var hx = this.light.width * 0.5;
  25689. var hy = this.light.height * 0.5;
  25690. var position = this.line.geometry.attributes.position;
  25691. var array = position.array;
  25692. // update vertices
  25693. array[0] = hx;array[1] = -hy;array[2] = 0;
  25694. array[3] = hx;array[4] = hy;array[5] = 0;
  25695. array[6] = -hx;array[7] = hy;array[8] = 0;
  25696. array[9] = -hx;array[10] = -hy;array[11] = 0;
  25697. array[12] = hx;array[13] = -hy;array[14] = 0;
  25698. position.needsUpdate = true;
  25699. if (this.color !== undefined) {
  25700. this.line.material.color.set(this.color);
  25701. } else {
  25702. this.line.material.color.copy(this.light.color);
  25703. }
  25704. };
  25705. /**
  25706. * @author alteredq / http://alteredqualia.com/
  25707. * @author mrdoob / http://mrdoob.com/
  25708. * @author Mugen87 / https://github.com/Mugen87
  25709. */
  25710. function HemisphereLightHelper(light, size, color) {
  25711. Object3D.call(this);
  25712. this.light = light;
  25713. this.light.updateMatrixWorld();
  25714. this.matrix = light.matrixWorld;
  25715. this.matrixAutoUpdate = false;
  25716. this.color = color;
  25717. var geometry = new OctahedronBufferGeometry(size);
  25718. geometry.rotateY(Math.PI * 0.5);
  25719. this.material = new MeshBasicMaterial({ wireframe: true, fog: false });
  25720. if (this.color === undefined) this.material.vertexColors = VertexColors;
  25721. var position = geometry.getAttribute('position');
  25722. var colors = new Float32Array(position.count * 3);
  25723. geometry.addAttribute('color', new BufferAttribute(colors, 3));
  25724. this.add(new Mesh(geometry, this.material));
  25725. this.update();
  25726. }
  25727. HemisphereLightHelper.prototype = Object.create(Object3D.prototype);
  25728. HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;
  25729. HemisphereLightHelper.prototype.dispose = function () {
  25730. this.children[0].geometry.dispose();
  25731. this.children[0].material.dispose();
  25732. };
  25733. HemisphereLightHelper.prototype.update = function () {
  25734. var vector = new Vector3();
  25735. var color1 = new Color();
  25736. var color2 = new Color();
  25737. return function update() {
  25738. var mesh = this.children[0];
  25739. if (this.color !== undefined) {
  25740. this.material.color.set(this.color);
  25741. } else {
  25742. var colors = mesh.geometry.getAttribute('color');
  25743. color1.copy(this.light.color);
  25744. color2.copy(this.light.groundColor);
  25745. for (var i = 0, l = colors.count; i < l; i++) {
  25746. var color = i < l / 2 ? color1 : color2;
  25747. colors.setXYZ(i, color.r, color.g, color.b);
  25748. }
  25749. colors.needsUpdate = true;
  25750. }
  25751. mesh.lookAt(vector.setFromMatrixPosition(this.light.matrixWorld).negate());
  25752. };
  25753. }();
  25754. /**
  25755. * @author mrdoob / http://mrdoob.com/
  25756. */
  25757. function GridHelper(size, divisions, color1, color2) {
  25758. size = size || 10;
  25759. divisions = divisions || 10;
  25760. color1 = new Color(color1 !== undefined ? color1 : 0x444444);
  25761. color2 = new Color(color2 !== undefined ? color2 : 0x888888);
  25762. var center = divisions / 2;
  25763. var step = size / divisions;
  25764. var halfSize = size / 2;
  25765. var vertices = [],
  25766. colors = [];
  25767. for (var i = 0, j = 0, k = -halfSize; i <= divisions; i++, k += step) {
  25768. vertices.push(-halfSize, 0, k, halfSize, 0, k);
  25769. vertices.push(k, 0, -halfSize, k, 0, halfSize);
  25770. var color = i === center ? color1 : color2;
  25771. color.toArray(colors, j);j += 3;
  25772. color.toArray(colors, j);j += 3;
  25773. color.toArray(colors, j);j += 3;
  25774. color.toArray(colors, j);j += 3;
  25775. }
  25776. var geometry = new BufferGeometry();
  25777. geometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  25778. geometry.addAttribute('color', new Float32BufferAttribute(colors, 3));
  25779. var material = new LineBasicMaterial({ vertexColors: VertexColors });
  25780. LineSegments.call(this, geometry, material);
  25781. }
  25782. GridHelper.prototype = Object.create(LineSegments.prototype);
  25783. GridHelper.prototype.constructor = GridHelper;
  25784. /**
  25785. * @author mrdoob / http://mrdoob.com/
  25786. * @author Mugen87 / http://github.com/Mugen87
  25787. * @author Hectate / http://www.github.com/Hectate
  25788. */
  25789. function PolarGridHelper(radius, radials, circles, divisions, color1, color2) {
  25790. radius = radius || 10;
  25791. radials = radials || 16;
  25792. circles = circles || 8;
  25793. divisions = divisions || 64;
  25794. color1 = new Color(color1 !== undefined ? color1 : 0x444444);
  25795. color2 = new Color(color2 !== undefined ? color2 : 0x888888);
  25796. var vertices = [];
  25797. var colors = [];
  25798. var x, z;
  25799. var v, i, j, r, color;
  25800. // create the radials
  25801. for (i = 0; i <= radials; i++) {
  25802. v = i / radials * (Math.PI * 2);
  25803. x = Math.sin(v) * radius;
  25804. z = Math.cos(v) * radius;
  25805. vertices.push(0, 0, 0);
  25806. vertices.push(x, 0, z);
  25807. color = i & 1 ? color1 : color2;
  25808. colors.push(color.r, color.g, color.b);
  25809. colors.push(color.r, color.g, color.b);
  25810. }
  25811. // create the circles
  25812. for (i = 0; i <= circles; i++) {
  25813. color = i & 1 ? color1 : color2;
  25814. r = radius - radius / circles * i;
  25815. for (j = 0; j < divisions; j++) {
  25816. // first vertex
  25817. v = j / divisions * (Math.PI * 2);
  25818. x = Math.sin(v) * r;
  25819. z = Math.cos(v) * r;
  25820. vertices.push(x, 0, z);
  25821. colors.push(color.r, color.g, color.b);
  25822. // second vertex
  25823. v = (j + 1) / divisions * (Math.PI * 2);
  25824. x = Math.sin(v) * r;
  25825. z = Math.cos(v) * r;
  25826. vertices.push(x, 0, z);
  25827. colors.push(color.r, color.g, color.b);
  25828. }
  25829. }
  25830. var geometry = new BufferGeometry();
  25831. geometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  25832. geometry.addAttribute('color', new Float32BufferAttribute(colors, 3));
  25833. var material = new LineBasicMaterial({ vertexColors: VertexColors });
  25834. LineSegments.call(this, geometry, material);
  25835. }
  25836. PolarGridHelper.prototype = Object.create(LineSegments.prototype);
  25837. PolarGridHelper.prototype.constructor = PolarGridHelper;
  25838. /**
  25839. * @author mrdoob / http://mrdoob.com/
  25840. * @author WestLangley / http://github.com/WestLangley
  25841. */
  25842. function FaceNormalsHelper(object, size, hex, linewidth) {
  25843. // FaceNormalsHelper only supports THREE.Geometry
  25844. this.object = object;
  25845. this.size = size !== undefined ? size : 1;
  25846. var color = hex !== undefined ? hex : 0xffff00;
  25847. var width = linewidth !== undefined ? linewidth : 1;
  25848. //
  25849. var nNormals = 0;
  25850. var objGeometry = this.object.geometry;
  25851. if (objGeometry && objGeometry.isGeometry) {
  25852. nNormals = objGeometry.faces.length;
  25853. } else {
  25854. console.warn('THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.');
  25855. }
  25856. //
  25857. var geometry = new BufferGeometry();
  25858. var positions = new Float32BufferAttribute(nNormals * 2 * 3, 3);
  25859. geometry.addAttribute('position', positions);
  25860. LineSegments.call(this, geometry, new LineBasicMaterial({ color: color, linewidth: width }));
  25861. //
  25862. this.matrixAutoUpdate = false;
  25863. this.update();
  25864. }
  25865. FaceNormalsHelper.prototype = Object.create(LineSegments.prototype);
  25866. FaceNormalsHelper.prototype.constructor = FaceNormalsHelper;
  25867. FaceNormalsHelper.prototype.update = function () {
  25868. var v1 = new Vector3();
  25869. var v2 = new Vector3();
  25870. var normalMatrix = new Matrix3();
  25871. return function update() {
  25872. this.object.updateMatrixWorld(true);
  25873. normalMatrix.getNormalMatrix(this.object.matrixWorld);
  25874. var matrixWorld = this.object.matrixWorld;
  25875. var position = this.geometry.attributes.position;
  25876. //
  25877. var objGeometry = this.object.geometry;
  25878. var vertices = objGeometry.vertices;
  25879. var faces = objGeometry.faces;
  25880. var idx = 0;
  25881. for (var i = 0, l = faces.length; i < l; i++) {
  25882. var face = faces[i];
  25883. var normal = face.normal;
  25884. v1.copy(vertices[face.a]).add(vertices[face.b]).add(vertices[face.c]).divideScalar(3).applyMatrix4(matrixWorld);
  25885. v2.copy(normal).applyMatrix3(normalMatrix).normalize().multiplyScalar(this.size).add(v1);
  25886. position.setXYZ(idx, v1.x, v1.y, v1.z);
  25887. idx = idx + 1;
  25888. position.setXYZ(idx, v2.x, v2.y, v2.z);
  25889. idx = idx + 1;
  25890. }
  25891. position.needsUpdate = true;
  25892. };
  25893. }();
  25894. /**
  25895. * @author alteredq / http://alteredqualia.com/
  25896. * @author mrdoob / http://mrdoob.com/
  25897. * @author WestLangley / http://github.com/WestLangley
  25898. */
  25899. function DirectionalLightHelper(light, size, color) {
  25900. Object3D.call(this);
  25901. this.light = light;
  25902. this.light.updateMatrixWorld();
  25903. this.matrix = light.matrixWorld;
  25904. this.matrixAutoUpdate = false;
  25905. this.color = color;
  25906. if (size === undefined) size = 1;
  25907. var geometry = new BufferGeometry();
  25908. geometry.addAttribute('position', new Float32BufferAttribute([-size, size, 0, size, size, 0, size, -size, 0, -size, -size, 0, -size, size, 0], 3));
  25909. var material = new LineBasicMaterial({ fog: false });
  25910. this.lightPlane = new Line(geometry, material);
  25911. this.add(this.lightPlane);
  25912. geometry = new BufferGeometry();
  25913. geometry.addAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 0, 1], 3));
  25914. this.targetLine = new Line(geometry, material);
  25915. this.add(this.targetLine);
  25916. this.update();
  25917. }
  25918. DirectionalLightHelper.prototype = Object.create(Object3D.prototype);
  25919. DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;
  25920. DirectionalLightHelper.prototype.dispose = function () {
  25921. this.lightPlane.geometry.dispose();
  25922. this.lightPlane.material.dispose();
  25923. this.targetLine.geometry.dispose();
  25924. this.targetLine.material.dispose();
  25925. };
  25926. DirectionalLightHelper.prototype.update = function () {
  25927. var v1 = new Vector3();
  25928. var v2 = new Vector3();
  25929. var v3 = new Vector3();
  25930. return function update() {
  25931. v1.setFromMatrixPosition(this.light.matrixWorld);
  25932. v2.setFromMatrixPosition(this.light.target.matrixWorld);
  25933. v3.subVectors(v2, v1);
  25934. this.lightPlane.lookAt(v3);
  25935. if (this.color !== undefined) {
  25936. this.lightPlane.material.color.set(this.color);
  25937. this.targetLine.material.color.set(this.color);
  25938. } else {
  25939. this.lightPlane.material.color.copy(this.light.color);
  25940. this.targetLine.material.color.copy(this.light.color);
  25941. }
  25942. this.targetLine.lookAt(v3);
  25943. this.targetLine.scale.z = v3.length();
  25944. };
  25945. }();
  25946. /**
  25947. * @author alteredq / http://alteredqualia.com/
  25948. * @author Mugen87 / https://github.com/Mugen87
  25949. *
  25950. * - shows frustum, line of sight and up of the camera
  25951. * - suitable for fast updates
  25952. * - based on frustum visualization in lightgl.js shadowmap example
  25953. * http://evanw.github.com/lightgl.js/tests/shadowmap.html
  25954. */
  25955. function CameraHelper(camera) {
  25956. var geometry = new BufferGeometry();
  25957. var material = new LineBasicMaterial({ color: 0xffffff, vertexColors: FaceColors });
  25958. var vertices = [];
  25959. var colors = [];
  25960. var pointMap = {};
  25961. // colors
  25962. var colorFrustum = new Color(0xffaa00);
  25963. var colorCone = new Color(0xff0000);
  25964. var colorUp = new Color(0x00aaff);
  25965. var colorTarget = new Color(0xffffff);
  25966. var colorCross = new Color(0x333333);
  25967. // near
  25968. addLine('n1', 'n2', colorFrustum);
  25969. addLine('n2', 'n4', colorFrustum);
  25970. addLine('n4', 'n3', colorFrustum);
  25971. addLine('n3', 'n1', colorFrustum);
  25972. // far
  25973. addLine('f1', 'f2', colorFrustum);
  25974. addLine('f2', 'f4', colorFrustum);
  25975. addLine('f4', 'f3', colorFrustum);
  25976. addLine('f3', 'f1', colorFrustum);
  25977. // sides
  25978. addLine('n1', 'f1', colorFrustum);
  25979. addLine('n2', 'f2', colorFrustum);
  25980. addLine('n3', 'f3', colorFrustum);
  25981. addLine('n4', 'f4', colorFrustum);
  25982. // cone
  25983. addLine('p', 'n1', colorCone);
  25984. addLine('p', 'n2', colorCone);
  25985. addLine('p', 'n3', colorCone);
  25986. addLine('p', 'n4', colorCone);
  25987. // up
  25988. addLine('u1', 'u2', colorUp);
  25989. addLine('u2', 'u3', colorUp);
  25990. addLine('u3', 'u1', colorUp);
  25991. // target
  25992. addLine('c', 't', colorTarget);
  25993. addLine('p', 'c', colorCross);
  25994. // cross
  25995. addLine('cn1', 'cn2', colorCross);
  25996. addLine('cn3', 'cn4', colorCross);
  25997. addLine('cf1', 'cf2', colorCross);
  25998. addLine('cf3', 'cf4', colorCross);
  25999. function addLine(a, b, color) {
  26000. addPoint(a, color);
  26001. addPoint(b, color);
  26002. }
  26003. function addPoint(id, color) {
  26004. vertices.push(0, 0, 0);
  26005. colors.push(color.r, color.g, color.b);
  26006. if (pointMap[id] === undefined) {
  26007. pointMap[id] = [];
  26008. }
  26009. pointMap[id].push(vertices.length / 3 - 1);
  26010. }
  26011. geometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  26012. geometry.addAttribute('color', new Float32BufferAttribute(colors, 3));
  26013. LineSegments.call(this, geometry, material);
  26014. this.camera = camera;
  26015. if (this.camera.updateProjectionMatrix) this.camera.updateProjectionMatrix();
  26016. this.matrix = camera.matrixWorld;
  26017. this.matrixAutoUpdate = false;
  26018. this.pointMap = pointMap;
  26019. this.update();
  26020. }
  26021. CameraHelper.prototype = Object.create(LineSegments.prototype);
  26022. CameraHelper.prototype.constructor = CameraHelper;
  26023. CameraHelper.prototype.update = function () {
  26024. var geometry, pointMap;
  26025. var vector = new Vector3();
  26026. var camera = new Camera();
  26027. function setPoint(point, x, y, z) {
  26028. vector.set(x, y, z).unproject(camera);
  26029. var points = pointMap[point];
  26030. if (points !== undefined) {
  26031. var position = geometry.getAttribute('position');
  26032. for (var i = 0, l = points.length; i < l; i++) {
  26033. position.setXYZ(points[i], vector.x, vector.y, vector.z);
  26034. }
  26035. }
  26036. }
  26037. return function update() {
  26038. geometry = this.geometry;
  26039. pointMap = this.pointMap;
  26040. var w = 1,
  26041. h = 1;
  26042. // we need just camera projection matrix
  26043. // world matrix must be identity
  26044. camera.projectionMatrix.copy(this.camera.projectionMatrix);
  26045. // center / target
  26046. setPoint('c', 0, 0, -1);
  26047. setPoint('t', 0, 0, 1);
  26048. // near
  26049. setPoint('n1', -w, -h, -1);
  26050. setPoint('n2', w, -h, -1);
  26051. setPoint('n3', -w, h, -1);
  26052. setPoint('n4', w, h, -1);
  26053. // far
  26054. setPoint('f1', -w, -h, 1);
  26055. setPoint('f2', w, -h, 1);
  26056. setPoint('f3', -w, h, 1);
  26057. setPoint('f4', w, h, 1);
  26058. // up
  26059. setPoint('u1', w * 0.7, h * 1.1, -1);
  26060. setPoint('u2', -w * 0.7, h * 1.1, -1);
  26061. setPoint('u3', 0, h * 2, -1);
  26062. // cross
  26063. setPoint('cf1', -w, 0, 1);
  26064. setPoint('cf2', w, 0, 1);
  26065. setPoint('cf3', 0, -h, 1);
  26066. setPoint('cf4', 0, h, 1);
  26067. setPoint('cn1', -w, 0, -1);
  26068. setPoint('cn2', w, 0, -1);
  26069. setPoint('cn3', 0, -h, -1);
  26070. setPoint('cn4', 0, h, -1);
  26071. geometry.getAttribute('position').needsUpdate = true;
  26072. };
  26073. }();
  26074. /**
  26075. * @author mrdoob / http://mrdoob.com/
  26076. * @author Mugen87 / http://github.com/Mugen87
  26077. */
  26078. function BoxHelper(object, color) {
  26079. this.object = object;
  26080. if (color === undefined) color = 0xffff00;
  26081. 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]);
  26082. var positions = new Float32Array(8 * 3);
  26083. var geometry = new BufferGeometry();
  26084. geometry.setIndex(new BufferAttribute(indices, 1));
  26085. geometry.addAttribute('position', new BufferAttribute(positions, 3));
  26086. LineSegments.call(this, geometry, new LineBasicMaterial({ color: color }));
  26087. this.matrixAutoUpdate = false;
  26088. this.update();
  26089. }
  26090. BoxHelper.prototype = Object.create(LineSegments.prototype);
  26091. BoxHelper.prototype.constructor = BoxHelper;
  26092. BoxHelper.prototype.update = function () {
  26093. var box = new Box3();
  26094. return function update(object) {
  26095. if (object !== undefined) {
  26096. console.warn('THREE.BoxHelper: .update() has no longer arguments.');
  26097. }
  26098. if (this.object !== undefined) {
  26099. box.setFromObject(this.object);
  26100. }
  26101. if (box.isEmpty()) return;
  26102. var min = box.min;
  26103. var max = box.max;
  26104. /*
  26105. 5____4
  26106. 1/___0/|
  26107. | 6__|_7
  26108. 2/___3/
  26109. 0: max.x, max.y, max.z
  26110. 1: min.x, max.y, max.z
  26111. 2: min.x, min.y, max.z
  26112. 3: max.x, min.y, max.z
  26113. 4: max.x, max.y, min.z
  26114. 5: min.x, max.y, min.z
  26115. 6: min.x, min.y, min.z
  26116. 7: max.x, min.y, min.z
  26117. */
  26118. var position = this.geometry.attributes.position;
  26119. var array = position.array;
  26120. array[0] = max.x;array[1] = max.y;array[2] = max.z;
  26121. array[3] = min.x;array[4] = max.y;array[5] = max.z;
  26122. array[6] = min.x;array[7] = min.y;array[8] = max.z;
  26123. array[9] = max.x;array[10] = min.y;array[11] = max.z;
  26124. array[12] = max.x;array[13] = max.y;array[14] = min.z;
  26125. array[15] = min.x;array[16] = max.y;array[17] = min.z;
  26126. array[18] = min.x;array[19] = min.y;array[20] = min.z;
  26127. array[21] = max.x;array[22] = min.y;array[23] = min.z;
  26128. position.needsUpdate = true;
  26129. this.geometry.computeBoundingSphere();
  26130. };
  26131. }();
  26132. BoxHelper.prototype.setFromObject = function (object) {
  26133. this.object = object;
  26134. this.update();
  26135. return this;
  26136. };
  26137. /**
  26138. * @author WestLangley / http://github.com/WestLangley
  26139. */
  26140. function Box3Helper(box, hex) {
  26141. this.type = 'Box3Helper';
  26142. this.box = box;
  26143. var color = hex !== undefined ? hex : 0xffff00;
  26144. 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]);
  26145. var positions = [1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1];
  26146. var geometry = new BufferGeometry();
  26147. geometry.setIndex(new BufferAttribute(indices, 1));
  26148. geometry.addAttribute('position', new Float32BufferAttribute(positions, 3));
  26149. LineSegments.call(this, geometry, new LineBasicMaterial({ color: color }));
  26150. this.geometry.computeBoundingSphere();
  26151. }
  26152. Box3Helper.prototype = Object.create(LineSegments.prototype);
  26153. Box3Helper.prototype.constructor = Box3Helper;
  26154. Box3Helper.prototype.updateMatrixWorld = function (force) {
  26155. var box = this.box;
  26156. if (box.isEmpty()) return;
  26157. box.getCenter(this.position);
  26158. box.getSize(this.scale);
  26159. this.scale.multiplyScalar(0.5);
  26160. Object3D.prototype.updateMatrixWorld.call(this, force);
  26161. };
  26162. /**
  26163. * @author WestLangley / http://github.com/WestLangley
  26164. */
  26165. function PlaneHelper(plane, size, hex) {
  26166. this.type = 'PlaneHelper';
  26167. this.plane = plane;
  26168. this.size = size === undefined ? 1 : size;
  26169. var color = hex !== undefined ? hex : 0xffff00;
  26170. var positions = [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, 0, 1, 0, 0, 0];
  26171. var geometry = new BufferGeometry();
  26172. geometry.addAttribute('position', new Float32BufferAttribute(positions, 3));
  26173. geometry.computeBoundingSphere();
  26174. Line.call(this, geometry, new LineBasicMaterial({ color: color }));
  26175. //
  26176. var positions2 = [1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1];
  26177. var geometry2 = new BufferGeometry();
  26178. geometry2.addAttribute('position', new Float32BufferAttribute(positions2, 3));
  26179. geometry2.computeBoundingSphere();
  26180. this.add(new Mesh(geometry2, new MeshBasicMaterial({ color: color, opacity: 0.2, transparent: true, depthWrite: false })));
  26181. }
  26182. PlaneHelper.prototype = Object.create(Line.prototype);
  26183. PlaneHelper.prototype.constructor = PlaneHelper;
  26184. PlaneHelper.prototype.updateMatrixWorld = function (force) {
  26185. var scale = -this.plane.constant;
  26186. if (Math.abs(scale) < 1e-8) scale = 1e-8; // sign does not matter
  26187. this.scale.set(0.5 * this.size, 0.5 * this.size, scale);
  26188. this.children[0].material.side = scale < 0 ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
  26189. this.lookAt(this.plane.normal);
  26190. Object3D.prototype.updateMatrixWorld.call(this, force);
  26191. };
  26192. /**
  26193. * @author WestLangley / http://github.com/WestLangley
  26194. * @author zz85 / http://github.com/zz85
  26195. * @author bhouston / http://clara.io
  26196. *
  26197. * Creates an arrow for visualizing directions
  26198. *
  26199. * Parameters:
  26200. * dir - Vector3
  26201. * origin - Vector3
  26202. * length - Number
  26203. * color - color in hex value
  26204. * headLength - Number
  26205. * headWidth - Number
  26206. */
  26207. var lineGeometry, coneGeometry;
  26208. function ArrowHelper(dir, origin, length, color, headLength, headWidth) {
  26209. // dir is assumed to be normalized
  26210. Object3D.call(this);
  26211. if (color === undefined) color = 0xffff00;
  26212. if (length === undefined) length = 1;
  26213. if (headLength === undefined) headLength = 0.2 * length;
  26214. if (headWidth === undefined) headWidth = 0.2 * headLength;
  26215. if (lineGeometry === undefined) {
  26216. lineGeometry = new BufferGeometry();
  26217. lineGeometry.addAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 1, 0], 3));
  26218. coneGeometry = new CylinderBufferGeometry(0, 0.5, 1, 5, 1);
  26219. coneGeometry.translate(0, -0.5, 0);
  26220. }
  26221. this.position.copy(origin);
  26222. this.line = new Line(lineGeometry, new LineBasicMaterial({ color: color }));
  26223. this.line.matrixAutoUpdate = false;
  26224. this.add(this.line);
  26225. this.cone = new Mesh(coneGeometry, new MeshBasicMaterial({ color: color }));
  26226. this.cone.matrixAutoUpdate = false;
  26227. this.add(this.cone);
  26228. this.setDirection(dir);
  26229. this.setLength(length, headLength, headWidth);
  26230. }
  26231. ArrowHelper.prototype = Object.create(Object3D.prototype);
  26232. ArrowHelper.prototype.constructor = ArrowHelper;
  26233. ArrowHelper.prototype.setDirection = function () {
  26234. var axis = new Vector3();
  26235. var radians;
  26236. return function setDirection(dir) {
  26237. // dir is assumed to be normalized
  26238. if (dir.y > 0.99999) {
  26239. this.quaternion.set(0, 0, 0, 1);
  26240. } else if (dir.y < -0.99999) {
  26241. this.quaternion.set(1, 0, 0, 0);
  26242. } else {
  26243. axis.set(dir.z, 0, -dir.x).normalize();
  26244. radians = Math.acos(dir.y);
  26245. this.quaternion.setFromAxisAngle(axis, radians);
  26246. }
  26247. };
  26248. }();
  26249. ArrowHelper.prototype.setLength = function (length, headLength, headWidth) {
  26250. if (headLength === undefined) headLength = 0.2 * length;
  26251. if (headWidth === undefined) headWidth = 0.2 * headLength;
  26252. this.line.scale.set(1, Math.max(0, length - headLength), 1);
  26253. this.line.updateMatrix();
  26254. this.cone.scale.set(headWidth, headLength, headWidth);
  26255. this.cone.position.y = length;
  26256. this.cone.updateMatrix();
  26257. };
  26258. ArrowHelper.prototype.setColor = function (color) {
  26259. this.line.material.color.copy(color);
  26260. this.cone.material.color.copy(color);
  26261. };
  26262. /**
  26263. * @author sroucheray / http://sroucheray.org/
  26264. * @author mrdoob / http://mrdoob.com/
  26265. */
  26266. function AxesHelper(size) {
  26267. size = size || 1;
  26268. var vertices = [0, 0, 0, size, 0, 0, 0, 0, 0, 0, size, 0, 0, 0, 0, 0, 0, size];
  26269. var colors = [1, 0, 0, 1, 0.6, 0, 0, 1, 0, 0.6, 1, 0, 0, 0, 1, 0, 0.6, 1];
  26270. var geometry = new BufferGeometry();
  26271. geometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  26272. geometry.addAttribute('color', new Float32BufferAttribute(colors, 3));
  26273. var material = new LineBasicMaterial({ vertexColors: VertexColors });
  26274. LineSegments.call(this, geometry, material);
  26275. }
  26276. AxesHelper.prototype = Object.create(LineSegments.prototype);
  26277. AxesHelper.prototype.constructor = AxesHelper;
  26278. /**
  26279. * @author mrdoob / http://mrdoob.com/
  26280. */
  26281. function Face4(a, b, c, d, normal, color, materialIndex) {
  26282. console.warn('THREE.Face4 has been removed. A THREE.Face3 will be created instead.');
  26283. return new Face3(a, b, c, normal, color, materialIndex);
  26284. }
  26285. var LineStrip = 0;
  26286. var LinePieces = 1;
  26287. function MeshFaceMaterial(materials) {
  26288. console.warn('THREE.MeshFaceMaterial has been removed. Use an Array instead.');
  26289. return materials;
  26290. }
  26291. function MultiMaterial(materials) {
  26292. if (materials === undefined) materials = [];
  26293. console.warn('THREE.MultiMaterial has been removed. Use an Array instead.');
  26294. materials.isMultiMaterial = true;
  26295. materials.materials = materials;
  26296. materials.clone = function () {
  26297. return materials.slice();
  26298. };
  26299. return materials;
  26300. }
  26301. function PointCloud(geometry, material) {
  26302. console.warn('THREE.PointCloud has been renamed to THREE.Points.');
  26303. return new Points(geometry, material);
  26304. }
  26305. function Particle(material) {
  26306. console.warn('THREE.Particle has been renamed to THREE.Sprite.');
  26307. return new Sprite(material);
  26308. }
  26309. function ParticleSystem(geometry, material) {
  26310. console.warn('THREE.ParticleSystem has been renamed to THREE.Points.');
  26311. return new Points(geometry, material);
  26312. }
  26313. function PointCloudMaterial(parameters) {
  26314. console.warn('THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.');
  26315. return new PointsMaterial(parameters);
  26316. }
  26317. function ParticleBasicMaterial(parameters) {
  26318. console.warn('THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.');
  26319. return new PointsMaterial(parameters);
  26320. }
  26321. function ParticleSystemMaterial(parameters) {
  26322. console.warn('THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.');
  26323. return new PointsMaterial(parameters);
  26324. }
  26325. function Vertex(x, y, z) {
  26326. console.warn('THREE.Vertex has been removed. Use THREE.Vector3 instead.');
  26327. return new Vector3(x, y, z);
  26328. }
  26329. //
  26330. function DynamicBufferAttribute(array, itemSize) {
  26331. console.warn('THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.');
  26332. return new BufferAttribute(array, itemSize).setDynamic(true);
  26333. }
  26334. function Int8Attribute(array, itemSize) {
  26335. console.warn('THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.');
  26336. return new Int8BufferAttribute(array, itemSize);
  26337. }
  26338. function Uint8Attribute(array, itemSize) {
  26339. console.warn('THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.');
  26340. return new Uint8BufferAttribute(array, itemSize);
  26341. }
  26342. function Uint8ClampedAttribute(array, itemSize) {
  26343. console.warn('THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.');
  26344. return new Uint8ClampedBufferAttribute(array, itemSize);
  26345. }
  26346. function Int16Attribute(array, itemSize) {
  26347. console.warn('THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.');
  26348. return new Int16BufferAttribute(array, itemSize);
  26349. }
  26350. function Uint16Attribute(array, itemSize) {
  26351. console.warn('THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.');
  26352. return new Uint16BufferAttribute(array, itemSize);
  26353. }
  26354. function Int32Attribute(array, itemSize) {
  26355. console.warn('THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.');
  26356. return new Int32BufferAttribute(array, itemSize);
  26357. }
  26358. function Uint32Attribute(array, itemSize) {
  26359. console.warn('THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.');
  26360. return new Uint32BufferAttribute(array, itemSize);
  26361. }
  26362. function Float32Attribute(array, itemSize) {
  26363. console.warn('THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.');
  26364. return new Float32BufferAttribute(array, itemSize);
  26365. }
  26366. function Float64Attribute(array, itemSize) {
  26367. console.warn('THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.');
  26368. return new Float64BufferAttribute(array, itemSize);
  26369. }
  26370. //
  26371. Curve.create = function (construct, getPoint) {
  26372. console.log('THREE.Curve.create() has been deprecated');
  26373. construct.prototype = Object.create(Curve.prototype);
  26374. construct.prototype.constructor = construct;
  26375. construct.prototype.getPoint = getPoint;
  26376. return construct;
  26377. };
  26378. //
  26379. Object.assign(CurvePath.prototype, {
  26380. createPointsGeometry: function (divisions) {
  26381. console.warn('THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.');
  26382. // generate geometry from path points (for Line or Points objects)
  26383. var pts = this.getPoints(divisions);
  26384. return this.createGeometry(pts);
  26385. },
  26386. createSpacedPointsGeometry: function (divisions) {
  26387. console.warn('THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.');
  26388. // generate geometry from equidistant sampling along the path
  26389. var pts = this.getSpacedPoints(divisions);
  26390. return this.createGeometry(pts);
  26391. },
  26392. createGeometry: function (points) {
  26393. console.warn('THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.');
  26394. var geometry = new Geometry();
  26395. for (var i = 0, l = points.length; i < l; i++) {
  26396. var point = points[i];
  26397. geometry.vertices.push(new Vector3(point.x, point.y, point.z || 0));
  26398. }
  26399. return geometry;
  26400. }
  26401. });
  26402. //
  26403. Object.assign(Path.prototype, {
  26404. fromPoints: function (points) {
  26405. console.warn('THREE.Path: .fromPoints() has been renamed to .setFromPoints().');
  26406. this.setFromPoints(points);
  26407. }
  26408. });
  26409. //
  26410. function ClosedSplineCurve3(points) {
  26411. console.warn('THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.');
  26412. CatmullRomCurve3.call(this, points);
  26413. this.type = 'catmullrom';
  26414. this.closed = true;
  26415. }
  26416. ClosedSplineCurve3.prototype = Object.create(CatmullRomCurve3.prototype);
  26417. //
  26418. function SplineCurve3(points) {
  26419. console.warn('THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.');
  26420. CatmullRomCurve3.call(this, points);
  26421. this.type = 'catmullrom';
  26422. }
  26423. SplineCurve3.prototype = Object.create(CatmullRomCurve3.prototype);
  26424. //
  26425. function Spline(points) {
  26426. console.warn('THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.');
  26427. CatmullRomCurve3.call(this, points);
  26428. this.type = 'catmullrom';
  26429. }
  26430. Spline.prototype = Object.create(CatmullRomCurve3.prototype);
  26431. Object.assign(Spline.prototype, {
  26432. initFromArray: function () /* a */{
  26433. console.error('THREE.Spline: .initFromArray() has been removed.');
  26434. },
  26435. getControlPointsArray: function () /* optionalTarget */{
  26436. console.error('THREE.Spline: .getControlPointsArray() has been removed.');
  26437. },
  26438. reparametrizeByArcLength: function () /* samplingCoef */{
  26439. console.error('THREE.Spline: .reparametrizeByArcLength() has been removed.');
  26440. }
  26441. });
  26442. //
  26443. function AxisHelper(size) {
  26444. console.warn('THREE.AxisHelper has been renamed to THREE.AxesHelper.');
  26445. return new AxesHelper(size);
  26446. }
  26447. function BoundingBoxHelper(object, color) {
  26448. console.warn('THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.');
  26449. return new BoxHelper(object, color);
  26450. }
  26451. function EdgesHelper(object, hex) {
  26452. console.warn('THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.');
  26453. return new LineSegments(new EdgesGeometry(object.geometry), new LineBasicMaterial({ color: hex !== undefined ? hex : 0xffffff }));
  26454. }
  26455. GridHelper.prototype.setColors = function () {
  26456. console.error('THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.');
  26457. };
  26458. SkeletonHelper.prototype.update = function () {
  26459. console.error('THREE.SkeletonHelper: update() no longer needs to be called.');
  26460. };
  26461. function WireframeHelper(object, hex) {
  26462. console.warn('THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.');
  26463. return new LineSegments(new WireframeGeometry(object.geometry), new LineBasicMaterial({ color: hex !== undefined ? hex : 0xffffff }));
  26464. }
  26465. //
  26466. Object.assign(Loader.prototype, {
  26467. extractUrlBase: function (url) {
  26468. console.warn('THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.');
  26469. return LoaderUtils.extractUrlBase(url);
  26470. }
  26471. });
  26472. function XHRLoader(manager) {
  26473. console.warn('THREE.XHRLoader has been renamed to THREE.FileLoader.');
  26474. return new FileLoader(manager);
  26475. }
  26476. function BinaryTextureLoader(manager) {
  26477. console.warn('THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.');
  26478. return new DataTextureLoader(manager);
  26479. }
  26480. //
  26481. Object.assign(Box2.prototype, {
  26482. center: function (optionalTarget) {
  26483. console.warn('THREE.Box2: .center() has been renamed to .getCenter().');
  26484. return this.getCenter(optionalTarget);
  26485. },
  26486. empty: function () {
  26487. console.warn('THREE.Box2: .empty() has been renamed to .isEmpty().');
  26488. return this.isEmpty();
  26489. },
  26490. isIntersectionBox: function (box) {
  26491. console.warn('THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().');
  26492. return this.intersectsBox(box);
  26493. },
  26494. size: function (optionalTarget) {
  26495. console.warn('THREE.Box2: .size() has been renamed to .getSize().');
  26496. return this.getSize(optionalTarget);
  26497. }
  26498. });
  26499. Object.assign(Box3.prototype, {
  26500. center: function (optionalTarget) {
  26501. console.warn('THREE.Box3: .center() has been renamed to .getCenter().');
  26502. return this.getCenter(optionalTarget);
  26503. },
  26504. empty: function () {
  26505. console.warn('THREE.Box3: .empty() has been renamed to .isEmpty().');
  26506. return this.isEmpty();
  26507. },
  26508. isIntersectionBox: function (box) {
  26509. console.warn('THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().');
  26510. return this.intersectsBox(box);
  26511. },
  26512. isIntersectionSphere: function (sphere) {
  26513. console.warn('THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().');
  26514. return this.intersectsSphere(sphere);
  26515. },
  26516. size: function (optionalTarget) {
  26517. console.warn('THREE.Box3: .size() has been renamed to .getSize().');
  26518. return this.getSize(optionalTarget);
  26519. }
  26520. });
  26521. Line3.prototype.center = function (optionalTarget) {
  26522. console.warn('THREE.Line3: .center() has been renamed to .getCenter().');
  26523. return this.getCenter(optionalTarget);
  26524. };
  26525. Object.assign(_Math, {
  26526. random16: function () {
  26527. console.warn('THREE.Math: .random16() has been deprecated. Use Math.random() instead.');
  26528. return Math.random();
  26529. },
  26530. nearestPowerOfTwo: function (value) {
  26531. console.warn('THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().');
  26532. return _Math.floorPowerOfTwo(value);
  26533. },
  26534. nextPowerOfTwo: function (value) {
  26535. console.warn('THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().');
  26536. return _Math.ceilPowerOfTwo(value);
  26537. }
  26538. });
  26539. Object.assign(Matrix3.prototype, {
  26540. flattenToArrayOffset: function (array, offset) {
  26541. console.warn("THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.");
  26542. return this.toArray(array, offset);
  26543. },
  26544. multiplyVector3: function (vector) {
  26545. console.warn('THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.');
  26546. return vector.applyMatrix3(this);
  26547. },
  26548. multiplyVector3Array: function () /* a */{
  26549. console.error('THREE.Matrix3: .multiplyVector3Array() has been removed.');
  26550. },
  26551. applyToBuffer: function (buffer /*, offset, length */) {
  26552. console.warn('THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.');
  26553. return this.applyToBufferAttribute(buffer);
  26554. },
  26555. applyToVector3Array: function () /* array, offset, length */{
  26556. console.error('THREE.Matrix3: .applyToVector3Array() has been removed.');
  26557. }
  26558. });
  26559. Object.assign(Matrix4.prototype, {
  26560. extractPosition: function (m) {
  26561. console.warn('THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().');
  26562. return this.copyPosition(m);
  26563. },
  26564. flattenToArrayOffset: function (array, offset) {
  26565. console.warn("THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.");
  26566. return this.toArray(array, offset);
  26567. },
  26568. getPosition: function () {
  26569. var v1;
  26570. return function getPosition() {
  26571. if (v1 === undefined) v1 = new Vector3();
  26572. console.warn('THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.');
  26573. return v1.setFromMatrixColumn(this, 3);
  26574. };
  26575. }(),
  26576. setRotationFromQuaternion: function (q) {
  26577. console.warn('THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().');
  26578. return this.makeRotationFromQuaternion(q);
  26579. },
  26580. multiplyToArray: function () {
  26581. console.warn('THREE.Matrix4: .multiplyToArray() has been removed.');
  26582. },
  26583. multiplyVector3: function (vector) {
  26584. console.warn('THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.');
  26585. return vector.applyMatrix4(this);
  26586. },
  26587. multiplyVector4: function (vector) {
  26588. console.warn('THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.');
  26589. return vector.applyMatrix4(this);
  26590. },
  26591. multiplyVector3Array: function () /* a */{
  26592. console.error('THREE.Matrix4: .multiplyVector3Array() has been removed.');
  26593. },
  26594. rotateAxis: function (v) {
  26595. console.warn('THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.');
  26596. v.transformDirection(this);
  26597. },
  26598. crossVector: function (vector) {
  26599. console.warn('THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.');
  26600. return vector.applyMatrix4(this);
  26601. },
  26602. translate: function () {
  26603. console.error('THREE.Matrix4: .translate() has been removed.');
  26604. },
  26605. rotateX: function () {
  26606. console.error('THREE.Matrix4: .rotateX() has been removed.');
  26607. },
  26608. rotateY: function () {
  26609. console.error('THREE.Matrix4: .rotateY() has been removed.');
  26610. },
  26611. rotateZ: function () {
  26612. console.error('THREE.Matrix4: .rotateZ() has been removed.');
  26613. },
  26614. rotateByAxis: function () {
  26615. console.error('THREE.Matrix4: .rotateByAxis() has been removed.');
  26616. },
  26617. applyToBuffer: function (buffer /*, offset, length */) {
  26618. console.warn('THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.');
  26619. return this.applyToBufferAttribute(buffer);
  26620. },
  26621. applyToVector3Array: function () /* array, offset, length */{
  26622. console.error('THREE.Matrix4: .applyToVector3Array() has been removed.');
  26623. },
  26624. makeFrustum: function (left, right, bottom, top, near, far) {
  26625. console.warn('THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.');
  26626. return this.makePerspective(left, right, top, bottom, near, far);
  26627. }
  26628. });
  26629. Plane.prototype.isIntersectionLine = function (line) {
  26630. console.warn('THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().');
  26631. return this.intersectsLine(line);
  26632. };
  26633. Quaternion.prototype.multiplyVector3 = function (vector) {
  26634. console.warn('THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.');
  26635. return vector.applyQuaternion(this);
  26636. };
  26637. Object.assign(Ray.prototype, {
  26638. isIntersectionBox: function (box) {
  26639. console.warn('THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().');
  26640. return this.intersectsBox(box);
  26641. },
  26642. isIntersectionPlane: function (plane) {
  26643. console.warn('THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().');
  26644. return this.intersectsPlane(plane);
  26645. },
  26646. isIntersectionSphere: function (sphere) {
  26647. console.warn('THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().');
  26648. return this.intersectsSphere(sphere);
  26649. }
  26650. });
  26651. Object.assign(Triangle.prototype, {
  26652. area: function () {
  26653. console.warn('THREE.Triangle: .area() has been renamed to .getArea().');
  26654. return this.getArea();
  26655. },
  26656. barycoordFromPoint: function (point, target) {
  26657. console.warn('THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().');
  26658. return this.getBarycoord(point, target);
  26659. },
  26660. midpoint: function (target) {
  26661. console.warn('THREE.Triangle: .midpoint() has been renamed to .getMidpoint().');
  26662. return this.getMidpoint(target);
  26663. },
  26664. normal: function (target) {
  26665. console.warn('THREE.Triangle: .normal() has been renamed to .getNormal().');
  26666. return this.getNormal(target);
  26667. },
  26668. plane: function (target) {
  26669. console.warn('THREE.Triangle: .plane() has been renamed to .getPlane().');
  26670. return this.getPlane(target);
  26671. }
  26672. });
  26673. Object.assign(Triangle, {
  26674. barycoordFromPoint: function (point, a, b, c, target) {
  26675. console.warn('THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().');
  26676. return Triangle.getBarycoord(point, a, b, c, target);
  26677. },
  26678. normal: function (a, b, c, target) {
  26679. console.warn('THREE.Triangle: .normal() has been renamed to .getNormal().');
  26680. return Triangle.getNormal(a, b, c, target);
  26681. }
  26682. });
  26683. Object.assign(Shape.prototype, {
  26684. extractAllPoints: function (divisions) {
  26685. console.warn('THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.');
  26686. return this.extractPoints(divisions);
  26687. },
  26688. extrude: function (options) {
  26689. console.warn('THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.');
  26690. return new ExtrudeGeometry(this, options);
  26691. },
  26692. makeGeometry: function (options) {
  26693. console.warn('THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.');
  26694. return new ShapeGeometry(this, options);
  26695. }
  26696. });
  26697. Object.assign(Vector2.prototype, {
  26698. fromAttribute: function (attribute, index, offset) {
  26699. console.warn('THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().');
  26700. return this.fromBufferAttribute(attribute, index, offset);
  26701. },
  26702. distanceToManhattan: function (v) {
  26703. console.warn('THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().');
  26704. return this.manhattanDistanceTo(v);
  26705. },
  26706. lengthManhattan: function () {
  26707. console.warn('THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().');
  26708. return this.manhattanLength();
  26709. }
  26710. });
  26711. Object.assign(Vector3.prototype, {
  26712. setEulerFromRotationMatrix: function () {
  26713. console.error('THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.');
  26714. },
  26715. setEulerFromQuaternion: function () {
  26716. console.error('THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.');
  26717. },
  26718. getPositionFromMatrix: function (m) {
  26719. console.warn('THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().');
  26720. return this.setFromMatrixPosition(m);
  26721. },
  26722. getScaleFromMatrix: function (m) {
  26723. console.warn('THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().');
  26724. return this.setFromMatrixScale(m);
  26725. },
  26726. getColumnFromMatrix: function (index, matrix) {
  26727. console.warn('THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().');
  26728. return this.setFromMatrixColumn(matrix, index);
  26729. },
  26730. applyProjection: function (m) {
  26731. console.warn('THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.');
  26732. return this.applyMatrix4(m);
  26733. },
  26734. fromAttribute: function (attribute, index, offset) {
  26735. console.warn('THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().');
  26736. return this.fromBufferAttribute(attribute, index, offset);
  26737. },
  26738. distanceToManhattan: function (v) {
  26739. console.warn('THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().');
  26740. return this.manhattanDistanceTo(v);
  26741. },
  26742. lengthManhattan: function () {
  26743. console.warn('THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().');
  26744. return this.manhattanLength();
  26745. }
  26746. });
  26747. Object.assign(Vector4.prototype, {
  26748. fromAttribute: function (attribute, index, offset) {
  26749. console.warn('THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().');
  26750. return this.fromBufferAttribute(attribute, index, offset);
  26751. },
  26752. lengthManhattan: function () {
  26753. console.warn('THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().');
  26754. return this.manhattanLength();
  26755. }
  26756. });
  26757. //
  26758. Object.assign(Geometry.prototype, {
  26759. computeTangents: function () {
  26760. console.error('THREE.Geometry: .computeTangents() has been removed.');
  26761. },
  26762. computeLineDistances: function () {
  26763. console.error('THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.');
  26764. }
  26765. });
  26766. Object.assign(Object3D.prototype, {
  26767. getChildByName: function (name) {
  26768. console.warn('THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().');
  26769. return this.getObjectByName(name);
  26770. },
  26771. renderDepth: function () {
  26772. console.warn('THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.');
  26773. },
  26774. translate: function (distance, axis) {
  26775. console.warn('THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.');
  26776. return this.translateOnAxis(axis, distance);
  26777. },
  26778. getWorldRotation: function () {
  26779. console.error('THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.');
  26780. }
  26781. });
  26782. Object.defineProperties(Object3D.prototype, {
  26783. eulerOrder: {
  26784. get: function () {
  26785. console.warn('THREE.Object3D: .eulerOrder is now .rotation.order.');
  26786. return this.rotation.order;
  26787. },
  26788. set: function (value) {
  26789. console.warn('THREE.Object3D: .eulerOrder is now .rotation.order.');
  26790. this.rotation.order = value;
  26791. }
  26792. },
  26793. useQuaternion: {
  26794. get: function () {
  26795. console.warn('THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.');
  26796. },
  26797. set: function () {
  26798. console.warn('THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.');
  26799. }
  26800. }
  26801. });
  26802. Object.defineProperties(LOD.prototype, {
  26803. objects: {
  26804. get: function () {
  26805. console.warn('THREE.LOD: .objects has been renamed to .levels.');
  26806. return this.levels;
  26807. }
  26808. }
  26809. });
  26810. Object.defineProperty(Skeleton.prototype, 'useVertexTexture', {
  26811. get: function () {
  26812. console.warn('THREE.Skeleton: useVertexTexture has been removed.');
  26813. },
  26814. set: function () {
  26815. console.warn('THREE.Skeleton: useVertexTexture has been removed.');
  26816. }
  26817. });
  26818. Object.defineProperty(Curve.prototype, '__arcLengthDivisions', {
  26819. get: function () {
  26820. console.warn('THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.');
  26821. return this.arcLengthDivisions;
  26822. },
  26823. set: function (value) {
  26824. console.warn('THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.');
  26825. this.arcLengthDivisions = value;
  26826. }
  26827. });
  26828. //
  26829. PerspectiveCamera.prototype.setLens = function (focalLength, filmGauge) {
  26830. console.warn("THREE.PerspectiveCamera.setLens is deprecated. " + "Use .setFocalLength and .filmGauge for a photographic setup.");
  26831. if (filmGauge !== undefined) this.filmGauge = filmGauge;
  26832. this.setFocalLength(focalLength);
  26833. };
  26834. //
  26835. Object.defineProperties(Light.prototype, {
  26836. onlyShadow: {
  26837. set: function () {
  26838. console.warn('THREE.Light: .onlyShadow has been removed.');
  26839. }
  26840. },
  26841. shadowCameraFov: {
  26842. set: function (value) {
  26843. console.warn('THREE.Light: .shadowCameraFov is now .shadow.camera.fov.');
  26844. this.shadow.camera.fov = value;
  26845. }
  26846. },
  26847. shadowCameraLeft: {
  26848. set: function (value) {
  26849. console.warn('THREE.Light: .shadowCameraLeft is now .shadow.camera.left.');
  26850. this.shadow.camera.left = value;
  26851. }
  26852. },
  26853. shadowCameraRight: {
  26854. set: function (value) {
  26855. console.warn('THREE.Light: .shadowCameraRight is now .shadow.camera.right.');
  26856. this.shadow.camera.right = value;
  26857. }
  26858. },
  26859. shadowCameraTop: {
  26860. set: function (value) {
  26861. console.warn('THREE.Light: .shadowCameraTop is now .shadow.camera.top.');
  26862. this.shadow.camera.top = value;
  26863. }
  26864. },
  26865. shadowCameraBottom: {
  26866. set: function (value) {
  26867. console.warn('THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.');
  26868. this.shadow.camera.bottom = value;
  26869. }
  26870. },
  26871. shadowCameraNear: {
  26872. set: function (value) {
  26873. console.warn('THREE.Light: .shadowCameraNear is now .shadow.camera.near.');
  26874. this.shadow.camera.near = value;
  26875. }
  26876. },
  26877. shadowCameraFar: {
  26878. set: function (value) {
  26879. console.warn('THREE.Light: .shadowCameraFar is now .shadow.camera.far.');
  26880. this.shadow.camera.far = value;
  26881. }
  26882. },
  26883. shadowCameraVisible: {
  26884. set: function () {
  26885. console.warn('THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.');
  26886. }
  26887. },
  26888. shadowBias: {
  26889. set: function (value) {
  26890. console.warn('THREE.Light: .shadowBias is now .shadow.bias.');
  26891. this.shadow.bias = value;
  26892. }
  26893. },
  26894. shadowDarkness: {
  26895. set: function () {
  26896. console.warn('THREE.Light: .shadowDarkness has been removed.');
  26897. }
  26898. },
  26899. shadowMapWidth: {
  26900. set: function (value) {
  26901. console.warn('THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.');
  26902. this.shadow.mapSize.width = value;
  26903. }
  26904. },
  26905. shadowMapHeight: {
  26906. set: function (value) {
  26907. console.warn('THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.');
  26908. this.shadow.mapSize.height = value;
  26909. }
  26910. }
  26911. });
  26912. //
  26913. Object.defineProperties(BufferAttribute.prototype, {
  26914. length: {
  26915. get: function () {
  26916. console.warn('THREE.BufferAttribute: .length has been deprecated. Use .count instead.');
  26917. return this.array.length;
  26918. }
  26919. },
  26920. copyIndicesArray: function () /* indices */{
  26921. console.error('THREE.BufferAttribute: .copyIndicesArray() has been removed.');
  26922. }
  26923. });
  26924. Object.assign(BufferGeometry.prototype, {
  26925. addIndex: function (index) {
  26926. console.warn('THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().');
  26927. this.setIndex(index);
  26928. },
  26929. addDrawCall: function (start, count, indexOffset) {
  26930. if (indexOffset !== undefined) {
  26931. console.warn('THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.');
  26932. }
  26933. console.warn('THREE.BufferGeometry: .addDrawCall() is now .addGroup().');
  26934. this.addGroup(start, count);
  26935. },
  26936. clearDrawCalls: function () {
  26937. console.warn('THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().');
  26938. this.clearGroups();
  26939. },
  26940. computeTangents: function () {
  26941. console.warn('THREE.BufferGeometry: .computeTangents() has been removed.');
  26942. },
  26943. computeOffsets: function () {
  26944. console.warn('THREE.BufferGeometry: .computeOffsets() has been removed.');
  26945. }
  26946. });
  26947. Object.defineProperties(BufferGeometry.prototype, {
  26948. drawcalls: {
  26949. get: function () {
  26950. console.error('THREE.BufferGeometry: .drawcalls has been renamed to .groups.');
  26951. return this.groups;
  26952. }
  26953. },
  26954. offsets: {
  26955. get: function () {
  26956. console.warn('THREE.BufferGeometry: .offsets has been renamed to .groups.');
  26957. return this.groups;
  26958. }
  26959. }
  26960. });
  26961. //
  26962. Object.assign(ExtrudeBufferGeometry.prototype, {
  26963. getArrays: function () {
  26964. console.error('THREE.ExtrudeBufferGeometry: .getArrays() has been removed.');
  26965. },
  26966. addShapeList: function () {
  26967. console.error('THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.');
  26968. },
  26969. addShape: function () {
  26970. console.error('THREE.ExtrudeBufferGeometry: .addShape() has been removed.');
  26971. }
  26972. });
  26973. //
  26974. Object.defineProperties(Uniform.prototype, {
  26975. dynamic: {
  26976. set: function () {
  26977. console.warn('THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.');
  26978. }
  26979. },
  26980. onUpdate: {
  26981. value: function () {
  26982. console.warn('THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.');
  26983. return this;
  26984. }
  26985. }
  26986. });
  26987. //
  26988. Object.defineProperties(Material.prototype, {
  26989. wrapAround: {
  26990. get: function () {
  26991. console.warn('THREE.Material: .wrapAround has been removed.');
  26992. },
  26993. set: function () {
  26994. console.warn('THREE.Material: .wrapAround has been removed.');
  26995. }
  26996. },
  26997. wrapRGB: {
  26998. get: function () {
  26999. console.warn('THREE.Material: .wrapRGB has been removed.');
  27000. return new Color();
  27001. }
  27002. },
  27003. shading: {
  27004. get: function () {
  27005. console.error('THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.');
  27006. },
  27007. set: function (value) {
  27008. console.warn('THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.');
  27009. this.flatShading = value === FlatShading;
  27010. }
  27011. }
  27012. });
  27013. Object.defineProperties(MeshPhongMaterial.prototype, {
  27014. metal: {
  27015. get: function () {
  27016. console.warn('THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.');
  27017. return false;
  27018. },
  27019. set: function () {
  27020. console.warn('THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead');
  27021. }
  27022. }
  27023. });
  27024. Object.defineProperties(ShaderMaterial.prototype, {
  27025. derivatives: {
  27026. get: function () {
  27027. console.warn('THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.');
  27028. return this.extensions.derivatives;
  27029. },
  27030. set: function (value) {
  27031. console.warn('THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.');
  27032. this.extensions.derivatives = value;
  27033. }
  27034. }
  27035. });
  27036. //
  27037. Object.assign(WebGLRenderer.prototype, {
  27038. animate: function (callback) {
  27039. console.warn('THREE.WebGLRenderer: .animate() is now .setAnimationLoop().');
  27040. this.setAnimationLoop(callback);
  27041. },
  27042. getCurrentRenderTarget: function () {
  27043. console.warn('THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().');
  27044. return this.getRenderTarget();
  27045. },
  27046. getMaxAnisotropy: function () {
  27047. console.warn('THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().');
  27048. return this.capabilities.getMaxAnisotropy();
  27049. },
  27050. getPrecision: function () {
  27051. console.warn('THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.');
  27052. return this.capabilities.precision;
  27053. },
  27054. resetGLState: function () {
  27055. console.warn('THREE.WebGLRenderer: .resetGLState() is now .state.reset().');
  27056. return this.state.reset();
  27057. },
  27058. supportsFloatTextures: function () {
  27059. console.warn('THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).');
  27060. return this.extensions.get('OES_texture_float');
  27061. },
  27062. supportsHalfFloatTextures: function () {
  27063. console.warn('THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).');
  27064. return this.extensions.get('OES_texture_half_float');
  27065. },
  27066. supportsStandardDerivatives: function () {
  27067. console.warn('THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).');
  27068. return this.extensions.get('OES_standard_derivatives');
  27069. },
  27070. supportsCompressedTextureS3TC: function () {
  27071. console.warn('THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).');
  27072. return this.extensions.get('WEBGL_compressed_texture_s3tc');
  27073. },
  27074. supportsCompressedTexturePVRTC: function () {
  27075. console.warn('THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).');
  27076. return this.extensions.get('WEBGL_compressed_texture_pvrtc');
  27077. },
  27078. supportsBlendMinMax: function () {
  27079. console.warn('THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).');
  27080. return this.extensions.get('EXT_blend_minmax');
  27081. },
  27082. supportsVertexTextures: function () {
  27083. console.warn('THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.');
  27084. return this.capabilities.vertexTextures;
  27085. },
  27086. supportsInstancedArrays: function () {
  27087. console.warn('THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).');
  27088. return this.extensions.get('ANGLE_instanced_arrays');
  27089. },
  27090. enableScissorTest: function (boolean) {
  27091. console.warn('THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().');
  27092. this.setScissorTest(boolean);
  27093. },
  27094. initMaterial: function () {
  27095. console.warn('THREE.WebGLRenderer: .initMaterial() has been removed.');
  27096. },
  27097. addPrePlugin: function () {
  27098. console.warn('THREE.WebGLRenderer: .addPrePlugin() has been removed.');
  27099. },
  27100. addPostPlugin: function () {
  27101. console.warn('THREE.WebGLRenderer: .addPostPlugin() has been removed.');
  27102. },
  27103. updateShadowMap: function () {
  27104. console.warn('THREE.WebGLRenderer: .updateShadowMap() has been removed.');
  27105. },
  27106. setFaceCulling: function () {
  27107. console.warn('THREE.WebGLRenderer: .setFaceCulling() has been removed.');
  27108. }
  27109. });
  27110. Object.defineProperties(WebGLRenderer.prototype, {
  27111. shadowMapEnabled: {
  27112. get: function () {
  27113. return this.shadowMap.enabled;
  27114. },
  27115. set: function (value) {
  27116. console.warn('THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.');
  27117. this.shadowMap.enabled = value;
  27118. }
  27119. },
  27120. shadowMapType: {
  27121. get: function () {
  27122. return this.shadowMap.type;
  27123. },
  27124. set: function (value) {
  27125. console.warn('THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.');
  27126. this.shadowMap.type = value;
  27127. }
  27128. },
  27129. shadowMapCullFace: {
  27130. get: function () {
  27131. console.warn('THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.');
  27132. return undefined;
  27133. },
  27134. set: function () /* value */{
  27135. console.warn('THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.');
  27136. }
  27137. }
  27138. });
  27139. Object.defineProperties(WebGLShadowMap.prototype, {
  27140. cullFace: {
  27141. get: function () {
  27142. console.warn('THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.');
  27143. return undefined;
  27144. },
  27145. set: function () /* cullFace */{
  27146. console.warn('THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.');
  27147. }
  27148. },
  27149. renderReverseSided: {
  27150. get: function () {
  27151. console.warn('THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.');
  27152. return undefined;
  27153. },
  27154. set: function () {
  27155. console.warn('THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.');
  27156. }
  27157. },
  27158. renderSingleSided: {
  27159. get: function () {
  27160. console.warn('THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.');
  27161. return undefined;
  27162. },
  27163. set: function () {
  27164. console.warn('THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.');
  27165. }
  27166. }
  27167. });
  27168. //
  27169. Object.defineProperties(WebGLRenderTarget.prototype, {
  27170. wrapS: {
  27171. get: function () {
  27172. console.warn('THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.');
  27173. return this.texture.wrapS;
  27174. },
  27175. set: function (value) {
  27176. console.warn('THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.');
  27177. this.texture.wrapS = value;
  27178. }
  27179. },
  27180. wrapT: {
  27181. get: function () {
  27182. console.warn('THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.');
  27183. return this.texture.wrapT;
  27184. },
  27185. set: function (value) {
  27186. console.warn('THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.');
  27187. this.texture.wrapT = value;
  27188. }
  27189. },
  27190. magFilter: {
  27191. get: function () {
  27192. console.warn('THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.');
  27193. return this.texture.magFilter;
  27194. },
  27195. set: function (value) {
  27196. console.warn('THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.');
  27197. this.texture.magFilter = value;
  27198. }
  27199. },
  27200. minFilter: {
  27201. get: function () {
  27202. console.warn('THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.');
  27203. return this.texture.minFilter;
  27204. },
  27205. set: function (value) {
  27206. console.warn('THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.');
  27207. this.texture.minFilter = value;
  27208. }
  27209. },
  27210. anisotropy: {
  27211. get: function () {
  27212. console.warn('THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.');
  27213. return this.texture.anisotropy;
  27214. },
  27215. set: function (value) {
  27216. console.warn('THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.');
  27217. this.texture.anisotropy = value;
  27218. }
  27219. },
  27220. offset: {
  27221. get: function () {
  27222. console.warn('THREE.WebGLRenderTarget: .offset is now .texture.offset.');
  27223. return this.texture.offset;
  27224. },
  27225. set: function (value) {
  27226. console.warn('THREE.WebGLRenderTarget: .offset is now .texture.offset.');
  27227. this.texture.offset = value;
  27228. }
  27229. },
  27230. repeat: {
  27231. get: function () {
  27232. console.warn('THREE.WebGLRenderTarget: .repeat is now .texture.repeat.');
  27233. return this.texture.repeat;
  27234. },
  27235. set: function (value) {
  27236. console.warn('THREE.WebGLRenderTarget: .repeat is now .texture.repeat.');
  27237. this.texture.repeat = value;
  27238. }
  27239. },
  27240. format: {
  27241. get: function () {
  27242. console.warn('THREE.WebGLRenderTarget: .format is now .texture.format.');
  27243. return this.texture.format;
  27244. },
  27245. set: function (value) {
  27246. console.warn('THREE.WebGLRenderTarget: .format is now .texture.format.');
  27247. this.texture.format = value;
  27248. }
  27249. },
  27250. type: {
  27251. get: function () {
  27252. console.warn('THREE.WebGLRenderTarget: .type is now .texture.type.');
  27253. return this.texture.type;
  27254. },
  27255. set: function (value) {
  27256. console.warn('THREE.WebGLRenderTarget: .type is now .texture.type.');
  27257. this.texture.type = value;
  27258. }
  27259. },
  27260. generateMipmaps: {
  27261. get: function () {
  27262. console.warn('THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.');
  27263. return this.texture.generateMipmaps;
  27264. },
  27265. set: function (value) {
  27266. console.warn('THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.');
  27267. this.texture.generateMipmaps = value;
  27268. }
  27269. }
  27270. });
  27271. //
  27272. Object.defineProperties(WebVRManager.prototype, {
  27273. standing: {
  27274. set: function () /* value */{
  27275. console.warn('THREE.WebVRManager: .standing has been removed.');
  27276. }
  27277. }
  27278. });
  27279. //
  27280. Audio.prototype.load = function (file) {
  27281. console.warn('THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.');
  27282. var scope = this;
  27283. var audioLoader = new AudioLoader();
  27284. audioLoader.load(file, function (buffer) {
  27285. scope.setBuffer(buffer);
  27286. });
  27287. return this;
  27288. };
  27289. AudioAnalyser.prototype.getData = function () {
  27290. console.warn('THREE.AudioAnalyser: .getData() is now .getFrequencyData().');
  27291. return this.getFrequencyData();
  27292. };
  27293. //
  27294. CubeCamera.prototype.updateCubeMap = function (renderer, scene) {
  27295. console.warn('THREE.CubeCamera: .updateCubeMap() is now .update().');
  27296. return this.update(renderer, scene);
  27297. };
  27298. //
  27299. var GeometryUtils = {
  27300. merge: function (geometry1, geometry2, materialIndexOffset) {
  27301. console.warn('THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.');
  27302. var matrix;
  27303. if (geometry2.isMesh) {
  27304. geometry2.matrixAutoUpdate && geometry2.updateMatrix();
  27305. matrix = geometry2.matrix;
  27306. geometry2 = geometry2.geometry;
  27307. }
  27308. geometry1.merge(geometry2, matrix, materialIndexOffset);
  27309. },
  27310. center: function (geometry) {
  27311. console.warn('THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.');
  27312. return geometry.center();
  27313. }
  27314. };
  27315. var ImageUtils = {
  27316. crossOrigin: undefined,
  27317. loadTexture: function (url, mapping, onLoad, onError) {
  27318. console.warn('THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.');
  27319. var loader = new TextureLoader();
  27320. loader.setCrossOrigin(this.crossOrigin);
  27321. var texture = loader.load(url, onLoad, undefined, onError);
  27322. if (mapping) texture.mapping = mapping;
  27323. return texture;
  27324. },
  27325. loadTextureCube: function (urls, mapping, onLoad, onError) {
  27326. console.warn('THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.');
  27327. var loader = new CubeTextureLoader();
  27328. loader.setCrossOrigin(this.crossOrigin);
  27329. var texture = loader.load(urls, onLoad, undefined, onError);
  27330. if (mapping) texture.mapping = mapping;
  27331. return texture;
  27332. },
  27333. loadCompressedTexture: function () {
  27334. console.error('THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.');
  27335. },
  27336. loadCompressedTextureCube: function () {
  27337. console.error('THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.');
  27338. }
  27339. };
  27340. //
  27341. function Projector() {
  27342. console.error('THREE.Projector has been moved to /examples/js/renderers/Projector.js.');
  27343. this.projectVector = function (vector, camera) {
  27344. console.warn('THREE.Projector: .projectVector() is now vector.project().');
  27345. vector.project(camera);
  27346. };
  27347. this.unprojectVector = function (vector, camera) {
  27348. console.warn('THREE.Projector: .unprojectVector() is now vector.unproject().');
  27349. vector.unproject(camera);
  27350. };
  27351. this.pickingRay = function () {
  27352. console.error('THREE.Projector: .pickingRay() is now raycaster.setFromCamera().');
  27353. };
  27354. }
  27355. //
  27356. function CanvasRenderer() {
  27357. console.error('THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js');
  27358. this.domElement = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
  27359. this.clear = function () {};
  27360. this.render = function () {};
  27361. this.setClearColor = function () {};
  27362. this.setSize = function () {};
  27363. }
  27364. //
  27365. var SceneUtils = {
  27366. createMultiMaterialObject: function () /* geometry, materials */{
  27367. console.error('THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js');
  27368. },
  27369. detach: function () /* child, parent, scene */{
  27370. console.error('THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js');
  27371. },
  27372. attach: function () /* child, scene, parent */{
  27373. console.error('THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js');
  27374. }
  27375. };
  27376. //
  27377. function LensFlare() {
  27378. console.error('THREE.LensFlare has been moved to /examples/js/objects/Lensflare.js');
  27379. }
  27380. exports.WebGLRenderTargetCube = WebGLRenderTargetCube;
  27381. exports.WebGLRenderTarget = WebGLRenderTarget;
  27382. exports.WebGLRenderer = WebGLRenderer;
  27383. exports.ShaderLib = ShaderLib;
  27384. exports.UniformsLib = UniformsLib;
  27385. exports.UniformsUtils = UniformsUtils;
  27386. exports.ShaderChunk = ShaderChunk;
  27387. exports.FogExp2 = FogExp2;
  27388. exports.Fog = Fog;
  27389. exports.Scene = Scene;
  27390. exports.Sprite = Sprite;
  27391. exports.LOD = LOD;
  27392. exports.SkinnedMesh = SkinnedMesh;
  27393. exports.Skeleton = Skeleton;
  27394. exports.Bone = Bone;
  27395. exports.Mesh = Mesh;
  27396. exports.LineSegments = LineSegments;
  27397. exports.LineLoop = LineLoop;
  27398. exports.Line = Line;
  27399. exports.Points = Points;
  27400. exports.Group = Group;
  27401. exports.VideoTexture = VideoTexture;
  27402. exports.DataTexture = DataTexture;
  27403. exports.CompressedTexture = CompressedTexture;
  27404. exports.CubeTexture = CubeTexture;
  27405. exports.CanvasTexture = CanvasTexture;
  27406. exports.DepthTexture = DepthTexture;
  27407. exports.Texture = Texture;
  27408. exports.CompressedTextureLoader = CompressedTextureLoader;
  27409. exports.DataTextureLoader = DataTextureLoader;
  27410. exports.CubeTextureLoader = CubeTextureLoader;
  27411. exports.TextureLoader = TextureLoader;
  27412. exports.ObjectLoader = ObjectLoader;
  27413. exports.MaterialLoader = MaterialLoader;
  27414. exports.BufferGeometryLoader = BufferGeometryLoader;
  27415. exports.DefaultLoadingManager = DefaultLoadingManager;
  27416. exports.LoadingManager = LoadingManager;
  27417. exports.JSONLoader = JSONLoader;
  27418. exports.ImageLoader = ImageLoader;
  27419. exports.ImageBitmapLoader = ImageBitmapLoader;
  27420. exports.FontLoader = FontLoader;
  27421. exports.FileLoader = FileLoader;
  27422. exports.Loader = Loader;
  27423. exports.LoaderUtils = LoaderUtils;
  27424. exports.Cache = Cache;
  27425. exports.AudioLoader = AudioLoader;
  27426. exports.SpotLightShadow = SpotLightShadow;
  27427. exports.SpotLight = SpotLight;
  27428. exports.PointLight = PointLight;
  27429. exports.RectAreaLight = RectAreaLight;
  27430. exports.HemisphereLight = HemisphereLight;
  27431. exports.DirectionalLightShadow = DirectionalLightShadow;
  27432. exports.DirectionalLight = DirectionalLight;
  27433. exports.AmbientLight = AmbientLight;
  27434. exports.LightShadow = LightShadow;
  27435. exports.Light = Light;
  27436. exports.StereoCamera = StereoCamera;
  27437. exports.PerspectiveCamera = PerspectiveCamera;
  27438. exports.OrthographicCamera = OrthographicCamera;
  27439. exports.CubeCamera = CubeCamera;
  27440. exports.ArrayCamera = ArrayCamera;
  27441. exports.Camera = Camera;
  27442. exports.AudioListener = AudioListener;
  27443. exports.PositionalAudio = PositionalAudio;
  27444. exports.AudioContext = AudioContext;
  27445. exports.AudioAnalyser = AudioAnalyser;
  27446. exports.Audio = Audio;
  27447. exports.VectorKeyframeTrack = VectorKeyframeTrack;
  27448. exports.StringKeyframeTrack = StringKeyframeTrack;
  27449. exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;
  27450. exports.NumberKeyframeTrack = NumberKeyframeTrack;
  27451. exports.ColorKeyframeTrack = ColorKeyframeTrack;
  27452. exports.BooleanKeyframeTrack = BooleanKeyframeTrack;
  27453. exports.PropertyMixer = PropertyMixer;
  27454. exports.PropertyBinding = PropertyBinding;
  27455. exports.KeyframeTrack = KeyframeTrack;
  27456. exports.AnimationUtils = AnimationUtils;
  27457. exports.AnimationObjectGroup = AnimationObjectGroup;
  27458. exports.AnimationMixer = AnimationMixer;
  27459. exports.AnimationClip = AnimationClip;
  27460. exports.Uniform = Uniform;
  27461. exports.InstancedBufferGeometry = InstancedBufferGeometry;
  27462. exports.BufferGeometry = BufferGeometry;
  27463. exports.Geometry = Geometry;
  27464. exports.InterleavedBufferAttribute = InterleavedBufferAttribute;
  27465. exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;
  27466. exports.InterleavedBuffer = InterleavedBuffer;
  27467. exports.InstancedBufferAttribute = InstancedBufferAttribute;
  27468. exports.Face3 = Face3;
  27469. exports.Object3D = Object3D;
  27470. exports.Raycaster = Raycaster;
  27471. exports.Layers = Layers;
  27472. exports.EventDispatcher = EventDispatcher;
  27473. exports.Clock = Clock;
  27474. exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;
  27475. exports.LinearInterpolant = LinearInterpolant;
  27476. exports.DiscreteInterpolant = DiscreteInterpolant;
  27477. exports.CubicInterpolant = CubicInterpolant;
  27478. exports.Interpolant = Interpolant;
  27479. exports.Triangle = Triangle;
  27480. exports.Math = _Math;
  27481. exports.Spherical = Spherical;
  27482. exports.Cylindrical = Cylindrical;
  27483. exports.Plane = Plane;
  27484. exports.Frustum = Frustum;
  27485. exports.Sphere = Sphere;
  27486. exports.Ray = Ray;
  27487. exports.Matrix4 = Matrix4;
  27488. exports.Matrix3 = Matrix3;
  27489. exports.Box3 = Box3;
  27490. exports.Box2 = Box2;
  27491. exports.Line3 = Line3;
  27492. exports.Euler = Euler;
  27493. exports.Vector4 = Vector4;
  27494. exports.Vector3 = Vector3;
  27495. exports.Vector2 = Vector2;
  27496. exports.Quaternion = Quaternion;
  27497. exports.Color = Color;
  27498. exports.ImmediateRenderObject = ImmediateRenderObject;
  27499. exports.VertexNormalsHelper = VertexNormalsHelper;
  27500. exports.SpotLightHelper = SpotLightHelper;
  27501. exports.SkeletonHelper = SkeletonHelper;
  27502. exports.PointLightHelper = PointLightHelper;
  27503. exports.RectAreaLightHelper = RectAreaLightHelper;
  27504. exports.HemisphereLightHelper = HemisphereLightHelper;
  27505. exports.GridHelper = GridHelper;
  27506. exports.PolarGridHelper = PolarGridHelper;
  27507. exports.FaceNormalsHelper = FaceNormalsHelper;
  27508. exports.DirectionalLightHelper = DirectionalLightHelper;
  27509. exports.CameraHelper = CameraHelper;
  27510. exports.BoxHelper = BoxHelper;
  27511. exports.Box3Helper = Box3Helper;
  27512. exports.PlaneHelper = PlaneHelper;
  27513. exports.ArrowHelper = ArrowHelper;
  27514. exports.AxesHelper = AxesHelper;
  27515. exports.Shape = Shape;
  27516. exports.Path = Path;
  27517. exports.ShapePath = ShapePath;
  27518. exports.Font = Font;
  27519. exports.CurvePath = CurvePath;
  27520. exports.Curve = Curve;
  27521. exports.ShapeUtils = ShapeUtils;
  27522. exports.WebGLUtils = WebGLUtils;
  27523. exports.WireframeGeometry = WireframeGeometry;
  27524. exports.ParametricGeometry = ParametricGeometry;
  27525. exports.ParametricBufferGeometry = ParametricBufferGeometry;
  27526. exports.TetrahedronGeometry = TetrahedronGeometry;
  27527. exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry;
  27528. exports.OctahedronGeometry = OctahedronGeometry;
  27529. exports.OctahedronBufferGeometry = OctahedronBufferGeometry;
  27530. exports.IcosahedronGeometry = IcosahedronGeometry;
  27531. exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry;
  27532. exports.DodecahedronGeometry = DodecahedronGeometry;
  27533. exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry;
  27534. exports.PolyhedronGeometry = PolyhedronGeometry;
  27535. exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry;
  27536. exports.TubeGeometry = TubeGeometry;
  27537. exports.TubeBufferGeometry = TubeBufferGeometry;
  27538. exports.TorusKnotGeometry = TorusKnotGeometry;
  27539. exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry;
  27540. exports.TorusGeometry = TorusGeometry;
  27541. exports.TorusBufferGeometry = TorusBufferGeometry;
  27542. exports.TextGeometry = TextGeometry;
  27543. exports.TextBufferGeometry = TextBufferGeometry;
  27544. exports.SphereGeometry = SphereGeometry;
  27545. exports.SphereBufferGeometry = SphereBufferGeometry;
  27546. exports.RingGeometry = RingGeometry;
  27547. exports.RingBufferGeometry = RingBufferGeometry;
  27548. exports.PlaneGeometry = PlaneGeometry;
  27549. exports.PlaneBufferGeometry = PlaneBufferGeometry;
  27550. exports.LatheGeometry = LatheGeometry;
  27551. exports.LatheBufferGeometry = LatheBufferGeometry;
  27552. exports.ShapeGeometry = ShapeGeometry;
  27553. exports.ShapeBufferGeometry = ShapeBufferGeometry;
  27554. exports.ExtrudeGeometry = ExtrudeGeometry;
  27555. exports.ExtrudeBufferGeometry = ExtrudeBufferGeometry;
  27556. exports.EdgesGeometry = EdgesGeometry;
  27557. exports.ConeGeometry = ConeGeometry;
  27558. exports.ConeBufferGeometry = ConeBufferGeometry;
  27559. exports.CylinderGeometry = CylinderGeometry;
  27560. exports.CylinderBufferGeometry = CylinderBufferGeometry;
  27561. exports.CircleGeometry = CircleGeometry;
  27562. exports.CircleBufferGeometry = CircleBufferGeometry;
  27563. exports.BoxGeometry = BoxGeometry;
  27564. exports.BoxBufferGeometry = BoxBufferGeometry;
  27565. exports.ShadowMaterial = ShadowMaterial;
  27566. exports.SpriteMaterial = SpriteMaterial;
  27567. exports.RawShaderMaterial = RawShaderMaterial;
  27568. exports.ShaderMaterial = ShaderMaterial;
  27569. exports.PointsMaterial = PointsMaterial;
  27570. exports.MeshPhysicalMaterial = MeshPhysicalMaterial;
  27571. exports.MeshStandardMaterial = MeshStandardMaterial;
  27572. exports.MeshPhongMaterial = MeshPhongMaterial;
  27573. exports.MeshToonMaterial = MeshToonMaterial;
  27574. exports.MeshNormalMaterial = MeshNormalMaterial;
  27575. exports.MeshLambertMaterial = MeshLambertMaterial;
  27576. exports.MeshDepthMaterial = MeshDepthMaterial;
  27577. exports.MeshDistanceMaterial = MeshDistanceMaterial;
  27578. exports.MeshBasicMaterial = MeshBasicMaterial;
  27579. exports.LineDashedMaterial = LineDashedMaterial;
  27580. exports.LineBasicMaterial = LineBasicMaterial;
  27581. exports.Material = Material;
  27582. exports.Float64BufferAttribute = Float64BufferAttribute;
  27583. exports.Float32BufferAttribute = Float32BufferAttribute;
  27584. exports.Uint32BufferAttribute = Uint32BufferAttribute;
  27585. exports.Int32BufferAttribute = Int32BufferAttribute;
  27586. exports.Uint16BufferAttribute = Uint16BufferAttribute;
  27587. exports.Int16BufferAttribute = Int16BufferAttribute;
  27588. exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;
  27589. exports.Uint8BufferAttribute = Uint8BufferAttribute;
  27590. exports.Int8BufferAttribute = Int8BufferAttribute;
  27591. exports.BufferAttribute = BufferAttribute;
  27592. exports.ArcCurve = ArcCurve;
  27593. exports.CatmullRomCurve3 = CatmullRomCurve3;
  27594. exports.CubicBezierCurve = CubicBezierCurve;
  27595. exports.CubicBezierCurve3 = CubicBezierCurve3;
  27596. exports.EllipseCurve = EllipseCurve;
  27597. exports.LineCurve = LineCurve;
  27598. exports.LineCurve3 = LineCurve3;
  27599. exports.QuadraticBezierCurve = QuadraticBezierCurve;
  27600. exports.QuadraticBezierCurve3 = QuadraticBezierCurve3;
  27601. exports.SplineCurve = SplineCurve;
  27602. exports.REVISION = REVISION;
  27603. exports.MOUSE = MOUSE;
  27604. exports.CullFaceNone = CullFaceNone;
  27605. exports.CullFaceBack = CullFaceBack;
  27606. exports.CullFaceFront = CullFaceFront;
  27607. exports.CullFaceFrontBack = CullFaceFrontBack;
  27608. exports.FrontFaceDirectionCW = FrontFaceDirectionCW;
  27609. exports.FrontFaceDirectionCCW = FrontFaceDirectionCCW;
  27610. exports.BasicShadowMap = BasicShadowMap;
  27611. exports.PCFShadowMap = PCFShadowMap;
  27612. exports.PCFSoftShadowMap = PCFSoftShadowMap;
  27613. exports.FrontSide = FrontSide;
  27614. exports.BackSide = BackSide;
  27615. exports.DoubleSide = DoubleSide;
  27616. exports.FlatShading = FlatShading;
  27617. exports.SmoothShading = SmoothShading;
  27618. exports.NoColors = NoColors;
  27619. exports.FaceColors = FaceColors;
  27620. exports.VertexColors = VertexColors;
  27621. exports.NoBlending = NoBlending;
  27622. exports.NormalBlending = NormalBlending;
  27623. exports.AdditiveBlending = AdditiveBlending;
  27624. exports.SubtractiveBlending = SubtractiveBlending;
  27625. exports.MultiplyBlending = MultiplyBlending;
  27626. exports.CustomBlending = CustomBlending;
  27627. exports.AddEquation = AddEquation;
  27628. exports.SubtractEquation = SubtractEquation;
  27629. exports.ReverseSubtractEquation = ReverseSubtractEquation;
  27630. exports.MinEquation = MinEquation;
  27631. exports.MaxEquation = MaxEquation;
  27632. exports.ZeroFactor = ZeroFactor;
  27633. exports.OneFactor = OneFactor;
  27634. exports.SrcColorFactor = SrcColorFactor;
  27635. exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;
  27636. exports.SrcAlphaFactor = SrcAlphaFactor;
  27637. exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;
  27638. exports.DstAlphaFactor = DstAlphaFactor;
  27639. exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;
  27640. exports.DstColorFactor = DstColorFactor;
  27641. exports.OneMinusDstColorFactor = OneMinusDstColorFactor;
  27642. exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;
  27643. exports.NeverDepth = NeverDepth;
  27644. exports.AlwaysDepth = AlwaysDepth;
  27645. exports.LessDepth = LessDepth;
  27646. exports.LessEqualDepth = LessEqualDepth;
  27647. exports.EqualDepth = EqualDepth;
  27648. exports.GreaterEqualDepth = GreaterEqualDepth;
  27649. exports.GreaterDepth = GreaterDepth;
  27650. exports.NotEqualDepth = NotEqualDepth;
  27651. exports.MultiplyOperation = MultiplyOperation;
  27652. exports.MixOperation = MixOperation;
  27653. exports.AddOperation = AddOperation;
  27654. exports.NoToneMapping = NoToneMapping;
  27655. exports.LinearToneMapping = LinearToneMapping;
  27656. exports.ReinhardToneMapping = ReinhardToneMapping;
  27657. exports.Uncharted2ToneMapping = Uncharted2ToneMapping;
  27658. exports.CineonToneMapping = CineonToneMapping;
  27659. exports.UVMapping = UVMapping;
  27660. exports.CubeReflectionMapping = CubeReflectionMapping;
  27661. exports.CubeRefractionMapping = CubeRefractionMapping;
  27662. exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;
  27663. exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;
  27664. exports.SphericalReflectionMapping = SphericalReflectionMapping;
  27665. exports.CubeUVReflectionMapping = CubeUVReflectionMapping;
  27666. exports.CubeUVRefractionMapping = CubeUVRefractionMapping;
  27667. exports.RepeatWrapping = RepeatWrapping;
  27668. exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
  27669. exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
  27670. exports.NearestFilter = NearestFilter;
  27671. exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
  27672. exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;
  27673. exports.LinearFilter = LinearFilter;
  27674. exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;
  27675. exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;
  27676. exports.UnsignedByteType = UnsignedByteType;
  27677. exports.ByteType = ByteType;
  27678. exports.ShortType = ShortType;
  27679. exports.UnsignedShortType = UnsignedShortType;
  27680. exports.IntType = IntType;
  27681. exports.UnsignedIntType = UnsignedIntType;
  27682. exports.FloatType = FloatType;
  27683. exports.HalfFloatType = HalfFloatType;
  27684. exports.UnsignedShort4444Type = UnsignedShort4444Type;
  27685. exports.UnsignedShort5551Type = UnsignedShort5551Type;
  27686. exports.UnsignedShort565Type = UnsignedShort565Type;
  27687. exports.UnsignedInt248Type = UnsignedInt248Type;
  27688. exports.AlphaFormat = AlphaFormat;
  27689. exports.RGBFormat = RGBFormat;
  27690. exports.RGBAFormat = RGBAFormat;
  27691. exports.LuminanceFormat = LuminanceFormat;
  27692. exports.LuminanceAlphaFormat = LuminanceAlphaFormat;
  27693. exports.RGBEFormat = RGBEFormat;
  27694. exports.DepthFormat = DepthFormat;
  27695. exports.DepthStencilFormat = DepthStencilFormat;
  27696. exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;
  27697. exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
  27698. exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
  27699. exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
  27700. exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;
  27701. exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
  27702. exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
  27703. exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;
  27704. exports.RGB_ETC1_Format = RGB_ETC1_Format;
  27705. exports.RGBA_ASTC_4x4_Format = RGBA_ASTC_4x4_Format;
  27706. exports.RGBA_ASTC_5x4_Format = RGBA_ASTC_5x4_Format;
  27707. exports.RGBA_ASTC_5x5_Format = RGBA_ASTC_5x5_Format;
  27708. exports.RGBA_ASTC_6x5_Format = RGBA_ASTC_6x5_Format;
  27709. exports.RGBA_ASTC_6x6_Format = RGBA_ASTC_6x6_Format;
  27710. exports.RGBA_ASTC_8x5_Format = RGBA_ASTC_8x5_Format;
  27711. exports.RGBA_ASTC_8x6_Format = RGBA_ASTC_8x6_Format;
  27712. exports.RGBA_ASTC_8x8_Format = RGBA_ASTC_8x8_Format;
  27713. exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format;
  27714. exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format;
  27715. exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format;
  27716. exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format;
  27717. exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format;
  27718. exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format;
  27719. exports.LoopOnce = LoopOnce;
  27720. exports.LoopRepeat = LoopRepeat;
  27721. exports.LoopPingPong = LoopPingPong;
  27722. exports.InterpolateDiscrete = InterpolateDiscrete;
  27723. exports.InterpolateLinear = InterpolateLinear;
  27724. exports.InterpolateSmooth = InterpolateSmooth;
  27725. exports.ZeroCurvatureEnding = ZeroCurvatureEnding;
  27726. exports.ZeroSlopeEnding = ZeroSlopeEnding;
  27727. exports.WrapAroundEnding = WrapAroundEnding;
  27728. exports.TrianglesDrawMode = TrianglesDrawMode;
  27729. exports.TriangleStripDrawMode = TriangleStripDrawMode;
  27730. exports.TriangleFanDrawMode = TriangleFanDrawMode;
  27731. exports.LinearEncoding = LinearEncoding;
  27732. exports.sRGBEncoding = sRGBEncoding;
  27733. exports.GammaEncoding = GammaEncoding;
  27734. exports.RGBEEncoding = RGBEEncoding;
  27735. exports.LogLuvEncoding = LogLuvEncoding;
  27736. exports.RGBM7Encoding = RGBM7Encoding;
  27737. exports.RGBM16Encoding = RGBM16Encoding;
  27738. exports.RGBDEncoding = RGBDEncoding;
  27739. exports.BasicDepthPacking = BasicDepthPacking;
  27740. exports.RGBADepthPacking = RGBADepthPacking;
  27741. exports.CubeGeometry = BoxGeometry;
  27742. exports.Face4 = Face4;
  27743. exports.LineStrip = LineStrip;
  27744. exports.LinePieces = LinePieces;
  27745. exports.MeshFaceMaterial = MeshFaceMaterial;
  27746. exports.MultiMaterial = MultiMaterial;
  27747. exports.PointCloud = PointCloud;
  27748. exports.Particle = Particle;
  27749. exports.ParticleSystem = ParticleSystem;
  27750. exports.PointCloudMaterial = PointCloudMaterial;
  27751. exports.ParticleBasicMaterial = ParticleBasicMaterial;
  27752. exports.ParticleSystemMaterial = ParticleSystemMaterial;
  27753. exports.Vertex = Vertex;
  27754. exports.DynamicBufferAttribute = DynamicBufferAttribute;
  27755. exports.Int8Attribute = Int8Attribute;
  27756. exports.Uint8Attribute = Uint8Attribute;
  27757. exports.Uint8ClampedAttribute = Uint8ClampedAttribute;
  27758. exports.Int16Attribute = Int16Attribute;
  27759. exports.Uint16Attribute = Uint16Attribute;
  27760. exports.Int32Attribute = Int32Attribute;
  27761. exports.Uint32Attribute = Uint32Attribute;
  27762. exports.Float32Attribute = Float32Attribute;
  27763. exports.Float64Attribute = Float64Attribute;
  27764. exports.ClosedSplineCurve3 = ClosedSplineCurve3;
  27765. exports.SplineCurve3 = SplineCurve3;
  27766. exports.Spline = Spline;
  27767. exports.AxisHelper = AxisHelper;
  27768. exports.BoundingBoxHelper = BoundingBoxHelper;
  27769. exports.EdgesHelper = EdgesHelper;
  27770. exports.WireframeHelper = WireframeHelper;
  27771. exports.XHRLoader = XHRLoader;
  27772. exports.BinaryTextureLoader = BinaryTextureLoader;
  27773. exports.GeometryUtils = GeometryUtils;
  27774. exports.ImageUtils = ImageUtils;
  27775. exports.Projector = Projector;
  27776. exports.CanvasRenderer = CanvasRenderer;
  27777. exports.SceneUtils = SceneUtils;
  27778. exports.LensFlare = LensFlare;
  27779. },{}],149:[function(require,module,exports) {
  27780. // shim for using process in browser
  27781. var process = module.exports = {};
  27782. // cached from whatever global is present so that test runners that stub it
  27783. // don't break things. But we need to wrap it in a try catch in case it is
  27784. // wrapped in strict mode code which doesn't define any globals. It's inside a
  27785. // function because try/catches deoptimize in certain engines.
  27786. var cachedSetTimeout;
  27787. var cachedClearTimeout;
  27788. function defaultSetTimout() {
  27789. throw new Error('setTimeout has not been defined');
  27790. }
  27791. function defaultClearTimeout() {
  27792. throw new Error('clearTimeout has not been defined');
  27793. }
  27794. (function () {
  27795. try {
  27796. if (typeof setTimeout === 'function') {
  27797. cachedSetTimeout = setTimeout;
  27798. } else {
  27799. cachedSetTimeout = defaultSetTimout;
  27800. }
  27801. } catch (e) {
  27802. cachedSetTimeout = defaultSetTimout;
  27803. }
  27804. try {
  27805. if (typeof clearTimeout === 'function') {
  27806. cachedClearTimeout = clearTimeout;
  27807. } else {
  27808. cachedClearTimeout = defaultClearTimeout;
  27809. }
  27810. } catch (e) {
  27811. cachedClearTimeout = defaultClearTimeout;
  27812. }
  27813. })();
  27814. function runTimeout(fun) {
  27815. if (cachedSetTimeout === setTimeout) {
  27816. //normal enviroments in sane situations
  27817. return setTimeout(fun, 0);
  27818. }
  27819. // if setTimeout wasn't available but was latter defined
  27820. if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
  27821. cachedSetTimeout = setTimeout;
  27822. return setTimeout(fun, 0);
  27823. }
  27824. try {
  27825. // when when somebody has screwed with setTimeout but no I.E. maddness
  27826. return cachedSetTimeout(fun, 0);
  27827. } catch (e) {
  27828. try {
  27829. // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
  27830. return cachedSetTimeout.call(null, fun, 0);
  27831. } catch (e) {
  27832. // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
  27833. return cachedSetTimeout.call(this, fun, 0);
  27834. }
  27835. }
  27836. }
  27837. function runClearTimeout(marker) {
  27838. if (cachedClearTimeout === clearTimeout) {
  27839. //normal enviroments in sane situations
  27840. return clearTimeout(marker);
  27841. }
  27842. // if clearTimeout wasn't available but was latter defined
  27843. if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
  27844. cachedClearTimeout = clearTimeout;
  27845. return clearTimeout(marker);
  27846. }
  27847. try {
  27848. // when when somebody has screwed with setTimeout but no I.E. maddness
  27849. return cachedClearTimeout(marker);
  27850. } catch (e) {
  27851. try {
  27852. // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
  27853. return cachedClearTimeout.call(null, marker);
  27854. } catch (e) {
  27855. // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
  27856. // Some versions of I.E. have different rules for clearTimeout vs setTimeout
  27857. return cachedClearTimeout.call(this, marker);
  27858. }
  27859. }
  27860. }
  27861. var queue = [];
  27862. var draining = false;
  27863. var currentQueue;
  27864. var queueIndex = -1;
  27865. function cleanUpNextTick() {
  27866. if (!draining || !currentQueue) {
  27867. return;
  27868. }
  27869. draining = false;
  27870. if (currentQueue.length) {
  27871. queue = currentQueue.concat(queue);
  27872. } else {
  27873. queueIndex = -1;
  27874. }
  27875. if (queue.length) {
  27876. drainQueue();
  27877. }
  27878. }
  27879. function drainQueue() {
  27880. if (draining) {
  27881. return;
  27882. }
  27883. var timeout = runTimeout(cleanUpNextTick);
  27884. draining = true;
  27885. var len = queue.length;
  27886. while (len) {
  27887. currentQueue = queue;
  27888. queue = [];
  27889. while (++queueIndex < len) {
  27890. if (currentQueue) {
  27891. currentQueue[queueIndex].run();
  27892. }
  27893. }
  27894. queueIndex = -1;
  27895. len = queue.length;
  27896. }
  27897. currentQueue = null;
  27898. draining = false;
  27899. runClearTimeout(timeout);
  27900. }
  27901. process.nextTick = function (fun) {
  27902. var args = new Array(arguments.length - 1);
  27903. if (arguments.length > 1) {
  27904. for (var i = 1; i < arguments.length; i++) {
  27905. args[i - 1] = arguments[i];
  27906. }
  27907. }
  27908. queue.push(new Item(fun, args));
  27909. if (queue.length === 1 && !draining) {
  27910. runTimeout(drainQueue);
  27911. }
  27912. };
  27913. // v8 likes predictible objects
  27914. function Item(fun, array) {
  27915. this.fun = fun;
  27916. this.array = array;
  27917. }
  27918. Item.prototype.run = function () {
  27919. this.fun.apply(null, this.array);
  27920. };
  27921. process.title = 'browser';
  27922. process.browser = true;
  27923. process.env = {};
  27924. process.argv = [];
  27925. process.version = ''; // empty string to avoid regexp issues
  27926. process.versions = {};
  27927. function noop() {}
  27928. process.on = noop;
  27929. process.addListener = noop;
  27930. process.once = noop;
  27931. process.off = noop;
  27932. process.removeListener = noop;
  27933. process.removeAllListeners = noop;
  27934. process.emit = noop;
  27935. process.prependListener = noop;
  27936. process.prependOnceListener = noop;
  27937. process.listeners = function (name) {
  27938. return [];
  27939. };
  27940. process.binding = function (name) {
  27941. throw new Error('process.binding is not supported');
  27942. };
  27943. process.cwd = function () {
  27944. return '/';
  27945. };
  27946. process.chdir = function (dir) {
  27947. throw new Error('process.chdir is not supported');
  27948. };
  27949. process.umask = function () {
  27950. return 0;
  27951. };
  27952. },{}],144:[function(require,module,exports) {
  27953. var process = require("process");
  27954. var define;
  27955. /**
  27956. * attempt of a simple defer/promise library for mobile development
  27957. * @author Jonathan Gotti < jgotti at jgotti dot net>
  27958. * @since 2012-10
  27959. * @version 0.7.5
  27960. */
  27961. (function (undef) {
  27962. "use strict";
  27963. var nextTick,
  27964. isFunc = function (f) {
  27965. return typeof f === 'function';
  27966. },
  27967. isArray = function (a) {
  27968. return Array.isArray ? Array.isArray(a) : a instanceof Array;
  27969. },
  27970. isObjOrFunc = function (o) {
  27971. return !!(o && (typeof o).match(/function|object/));
  27972. },
  27973. isNotVal = function (v) {
  27974. return v === false || v === undef || v === null;
  27975. },
  27976. slice = function (a, offset) {
  27977. return [].slice.call(a, offset);
  27978. },
  27979. undefStr = 'undefined',
  27980. tErr = typeof TypeError === undefStr ? Error : TypeError;
  27981. if (typeof process !== undefStr && process.nextTick) {
  27982. nextTick = process.nextTick;
  27983. } else if (typeof MessageChannel !== undefStr) {
  27984. var ntickChannel = new MessageChannel(),
  27985. queue = [];
  27986. ntickChannel.port1.onmessage = function () {
  27987. queue.length && queue.shift()();
  27988. };
  27989. nextTick = function (cb) {
  27990. queue.push(cb);
  27991. ntickChannel.port2.postMessage(0);
  27992. };
  27993. } else {
  27994. nextTick = function (cb) {
  27995. setTimeout(cb, 0);
  27996. };
  27997. }
  27998. function rethrow(e) {
  27999. nextTick(function () {
  28000. throw e;
  28001. });
  28002. }
  28003. /**
  28004. * a function called on fulfilled promise resolution
  28005. * @typedef {function} fulfilled
  28006. * @param {*} value promise resolved value
  28007. * @returns {*} next promise resolution value
  28008. */
  28009. /**
  28010. * a function called on failed promise resolution
  28011. * @typedef {function} failed
  28012. * @param {*} reason promise rejection reason
  28013. * @returns {*} next promise resolution value or rethrow the reason
  28014. */
  28015. //-- defining unenclosed promise methods --//
  28016. /**
  28017. * same as then without failed callback
  28018. * @param {fulfilled} fulfilled callback
  28019. * @returns {promise} a new promise
  28020. */
  28021. function promise_success(fulfilled) {
  28022. return this.then(fulfilled, undef);
  28023. }
  28024. /**
  28025. * same as then with only a failed callback
  28026. * @param {failed} failed callback
  28027. * @returns {promise} a new promise
  28028. */
  28029. function promise_error(failed) {
  28030. return this.then(undef, failed);
  28031. }
  28032. /**
  28033. * same as then but fulfilled callback will receive multiple parameters when promise is fulfilled with an Array
  28034. * @param {fulfilled} fulfilled callback
  28035. * @param {failed} failed callback
  28036. * @returns {promise} a new promise
  28037. */
  28038. function promise_apply(fulfilled, failed) {
  28039. return this.then(function (a) {
  28040. return isFunc(fulfilled) ? fulfilled.apply(null, isArray(a) ? a : [a]) : defer.onlyFuncs ? a : fulfilled;
  28041. }, failed || undef);
  28042. }
  28043. /**
  28044. * cleanup method which will be always executed regardless fulfillment or rejection
  28045. * @param {function} cb a callback called regardless of the fulfillment or rejection of the promise which will be called
  28046. * when the promise is not pending anymore
  28047. * @returns {promise} the same promise untouched
  28048. */
  28049. function promise_ensure(cb) {
  28050. function _cb() {
  28051. cb();
  28052. }
  28053. this.then(_cb, _cb);
  28054. return this;
  28055. }
  28056. /**
  28057. * take a single callback which wait for an error as first parameter. other resolution values are passed as with the apply/spread method
  28058. * @param {function} cb a callback called regardless of the fulfillment or rejection of the promise which will be called
  28059. * when the promise is not pending anymore with error as first parameter if any as in node style
  28060. * callback. Rest of parameters will be applied as with the apply method.
  28061. * @returns {promise} a new promise
  28062. */
  28063. function promise_nodify(cb) {
  28064. return this.then(function (a) {
  28065. return isFunc(cb) ? cb.apply(null, isArray(a) ? a.splice(0, 0, undefined) && a : [undefined, a]) : defer.onlyFuncs ? a : cb;
  28066. }, function (e) {
  28067. return cb(e);
  28068. });
  28069. }
  28070. /**
  28071. *
  28072. * @param {function} [failed] without parameter will only rethrow promise rejection reason outside of the promise library on next tick
  28073. * if passed a failed method then will call failed on rejection and throw the error again if failed didn't
  28074. * @returns {promise} a new promise
  28075. */
  28076. function promise_rethrow(failed) {
  28077. return this.then(undef, failed ? function (e) {
  28078. failed(e);throw e;
  28079. } : rethrow);
  28080. }
  28081. /**
  28082. * return a defer object
  28083. * @param {boolean} [alwaysAsync] if set force the async resolution for this promise independantly of the D.alwaysAsync option
  28084. * @returns {deferred} defered object with property 'promise' and methods reject,fulfill,resolve (fulfill being an alias for resolve)
  28085. */
  28086. var defer = function (alwaysAsync) {
  28087. var alwaysAsyncFn = (undef !== alwaysAsync ? alwaysAsync : defer.alwaysAsync) ? nextTick : function (fn) {
  28088. fn();
  28089. },
  28090. status = 0 // -1 failed | 1 fulfilled
  28091. ,
  28092. pendings = [],
  28093. value
  28094. /**
  28095. * @typedef promise
  28096. */
  28097. ,
  28098. _promise = {
  28099. /**
  28100. * @param {fulfilled|function} fulfilled callback
  28101. * @param {failed|function} failed callback
  28102. * @returns {promise} a new promise
  28103. */
  28104. then: function (fulfilled, failed) {
  28105. var d = defer();
  28106. pendings.push([function (value) {
  28107. try {
  28108. if (isNotVal(fulfilled)) {
  28109. d.resolve(value);
  28110. } else {
  28111. d.resolve(isFunc(fulfilled) ? fulfilled(value) : defer.onlyFuncs ? value : fulfilled);
  28112. }
  28113. } catch (e) {
  28114. d.reject(e);
  28115. }
  28116. }, function (err) {
  28117. if (isNotVal(failed) || !isFunc(failed) && defer.onlyFuncs) {
  28118. d.reject(err);
  28119. }
  28120. if (failed) {
  28121. try {
  28122. d.resolve(isFunc(failed) ? failed(err) : failed);
  28123. } catch (e) {
  28124. d.reject(e);
  28125. }
  28126. }
  28127. }]);
  28128. status !== 0 && alwaysAsyncFn(execCallbacks);
  28129. return d.promise;
  28130. },
  28131. success: promise_success,
  28132. error: promise_error,
  28133. otherwise: promise_error,
  28134. apply: promise_apply,
  28135. spread: promise_apply,
  28136. ensure: promise_ensure,
  28137. nodify: promise_nodify,
  28138. rethrow: promise_rethrow,
  28139. isPending: function () {
  28140. return status === 0;
  28141. },
  28142. getStatus: function () {
  28143. return status;
  28144. }
  28145. };
  28146. _promise.toSource = _promise.toString = _promise.valueOf = function () {
  28147. return value === undef ? this : value;
  28148. };
  28149. function execCallbacks() {
  28150. /*jshint bitwise:false*/
  28151. if (status === 0) {
  28152. return;
  28153. }
  28154. var cbs = pendings,
  28155. i = 0,
  28156. l = cbs.length,
  28157. cbIndex = ~status ? 0 : 1,
  28158. cb;
  28159. pendings = [];
  28160. for (; i < l; i++) {
  28161. (cb = cbs[i][cbIndex]) && cb(value);
  28162. }
  28163. }
  28164. /**
  28165. * fulfill deferred with given value
  28166. * @param {*} val
  28167. * @returns {deferred} this for method chaining
  28168. */
  28169. function _resolve(val) {
  28170. var done = false;
  28171. function once(f) {
  28172. return function (x) {
  28173. if (done) {
  28174. return undefined;
  28175. } else {
  28176. done = true;
  28177. return f(x);
  28178. }
  28179. };
  28180. }
  28181. if (status) {
  28182. return this;
  28183. }
  28184. try {
  28185. var then = isObjOrFunc(val) && val.then;
  28186. if (isFunc(then)) {
  28187. // managing a promise
  28188. if (val === _promise) {
  28189. throw new tErr("Promise can't resolve itself");
  28190. }
  28191. then.call(val, once(_resolve), once(_reject));
  28192. return this;
  28193. }
  28194. } catch (e) {
  28195. once(_reject)(e);
  28196. return this;
  28197. }
  28198. alwaysAsyncFn(function () {
  28199. value = val;
  28200. status = 1;
  28201. execCallbacks();
  28202. });
  28203. return this;
  28204. }
  28205. /**
  28206. * reject deferred with given reason
  28207. * @param {*} Err
  28208. * @returns {deferred} this for method chaining
  28209. */
  28210. function _reject(Err) {
  28211. status || alwaysAsyncFn(function () {
  28212. try {
  28213. throw Err;
  28214. } catch (e) {
  28215. value = e;
  28216. }
  28217. status = -1;
  28218. execCallbacks();
  28219. });
  28220. return this;
  28221. }
  28222. return (/**@type deferred */{
  28223. promise: _promise,
  28224. resolve: _resolve,
  28225. fulfill: _resolve // alias
  28226. , reject: _reject
  28227. }
  28228. );
  28229. };
  28230. defer.deferred = defer.defer = defer;
  28231. defer.nextTick = nextTick;
  28232. defer.alwaysAsync = true; // setting this will change default behaviour. use it only if necessary as asynchronicity will force some delay between your promise resolutions and is not always what you want.
  28233. /**
  28234. * setting onlyFuncs to false will break promises/A+ conformity by allowing you to pass non undefined/null values instead of callbacks
  28235. * instead of just ignoring any non function parameters to then,success,error... it will accept non null|undefined values.
  28236. * this will allow you shortcuts like promise.then('val','handled error'')
  28237. * to be equivalent of promise.then(function(){ return 'val';},function(){ return 'handled error'})
  28238. */
  28239. defer.onlyFuncs = true;
  28240. /**
  28241. * return a fulfilled promise of given value (always async resolution)
  28242. * @param {*} value
  28243. * @returns {promise}
  28244. */
  28245. defer.resolve = defer.resolved = defer.fulfilled = function (value) {
  28246. return defer(true).resolve(value).promise;
  28247. };
  28248. /**
  28249. * return a rejected promise with given reason of rejection (always async rejection)
  28250. * @param {*} reason
  28251. * @returns {promise}
  28252. */
  28253. defer.reject = defer.rejected = function (reason) {
  28254. return defer(true).reject(reason).promise;
  28255. };
  28256. /**
  28257. * return a promise with no resolution value which will be resolved in time ms (using setTimeout)
  28258. * @param {int} [time] in ms default to 0
  28259. * @returns {promise}
  28260. */
  28261. defer.wait = function (time) {
  28262. var d = defer();
  28263. setTimeout(d.resolve, time || 0);
  28264. return d.promise;
  28265. };
  28266. /**
  28267. * return a promise for the return value of function call which will be fulfilled in delay ms or rejected if given fn throw an error
  28268. * @param {*} fn to execute or value to return after given delay
  28269. * @param {int} [delay] in ms default to 0
  28270. * @returns {promise}
  28271. */
  28272. defer.delay = function (fn, delay) {
  28273. var d = defer();
  28274. setTimeout(function () {
  28275. try {
  28276. d.resolve(isFunc(fn) ? fn.apply(null) : fn);
  28277. } catch (e) {
  28278. d.reject(e);
  28279. }
  28280. }, delay || 0);
  28281. return d.promise;
  28282. };
  28283. /**
  28284. * if given value is not a promise return a fulfilled promise resolved to given value
  28285. * @param {*} promise a value or a promise
  28286. * @returns {promise}
  28287. */
  28288. defer.promisify = function (promise) {
  28289. if (promise && isFunc(promise.then)) {
  28290. return promise;
  28291. }
  28292. return defer.resolved(promise);
  28293. };
  28294. function multiPromiseResolver(callerArguments, returnPromises) {
  28295. var promises = slice(callerArguments);
  28296. if (promises.length === 1 && isArray(promises[0])) {
  28297. if (!promises[0].length) {
  28298. return defer.fulfilled([]);
  28299. }
  28300. promises = promises[0];
  28301. }
  28302. var args = [],
  28303. d = defer(),
  28304. c = promises.length;
  28305. if (!c) {
  28306. d.resolve(args);
  28307. } else {
  28308. var resolver = function (i) {
  28309. promises[i] = defer.promisify(promises[i]);
  28310. promises[i].then(function (v) {
  28311. args[i] = returnPromises ? promises[i] : v;
  28312. --c || d.resolve(args);
  28313. }, function (e) {
  28314. if (!returnPromises) {
  28315. d.reject(e);
  28316. } else {
  28317. args[i] = promises[i];
  28318. --c || d.resolve(args);
  28319. }
  28320. });
  28321. };
  28322. for (var i = 0, l = c; i < l; i++) {
  28323. resolver(i);
  28324. }
  28325. }
  28326. return d.promise;
  28327. }
  28328. function sequenceZenifier(promise, zenValue) {
  28329. return promise.then(isFunc(zenValue) ? zenValue : function () {
  28330. return zenValue;
  28331. });
  28332. }
  28333. function sequencePromiseResolver(callerArguments) {
  28334. var funcs = slice(callerArguments);
  28335. if (funcs.length === 1 && isArray(funcs[0])) {
  28336. funcs = funcs[0];
  28337. }
  28338. var d = defer(),
  28339. i = 0,
  28340. l = funcs.length,
  28341. promise = defer.resolved();
  28342. for (; i < l; i++) {
  28343. promise = sequenceZenifier(promise, funcs[i]);
  28344. }
  28345. d.resolve(promise);
  28346. return d.promise;
  28347. }
  28348. /**
  28349. * return a promise for all given promises / values.
  28350. * the returned promises will be fulfilled with a list of resolved value.
  28351. * if any given promise is rejected then on the first rejection the returned promised will be rejected with the same reason
  28352. * @param {array|...*} [promise] can be a single array of promise/values as first parameter or a list of direct parameters promise/value
  28353. * @returns {promise} of a list of given promise resolution value
  28354. */
  28355. defer.all = function () {
  28356. return multiPromiseResolver(arguments, false);
  28357. };
  28358. /**
  28359. * return an always fulfilled promise of array<promise> list of promises/values regardless they resolve fulfilled or rejected
  28360. * @param {array|...*} [promise] can be a single array of promise/values as first parameter or a list of direct parameters promise/value
  28361. * (non promise values will be promisified)
  28362. * @returns {promise} of the list of given promises
  28363. */
  28364. defer.resolveAll = function () {
  28365. return multiPromiseResolver(arguments, true);
  28366. };
  28367. /**
  28368. * execute given function in sequence passing their returned values to the next one in sequence.
  28369. * You can pass values or promise instead of functions they will be passed in the sequence as if a function returned them.
  28370. * if any function throw an error or a rejected promise the final returned promise will be rejected with that reason.
  28371. * @param {array|...*} [function] list of function to call in sequence receiving previous one as a parameter
  28372. * (non function values will be treated as if returned by a function)
  28373. * @returns {promise} of the list of given promises
  28374. */
  28375. defer.sequence = function () {
  28376. return sequencePromiseResolver(arguments);
  28377. };
  28378. /**
  28379. * transform a typical nodejs async method awaiting a callback as last parameter, receiving error as first parameter to a function that
  28380. * will return a promise instead. the returned promise will resolve with normal callback value minus the first error parameter on
  28381. * fulfill and will be rejected with that error as reason in case of error.
  28382. * @param {object} [subject] optional subject of the method to encapsulate
  28383. * @param {function} fn the function to encapsulate if the normal callback should receive more than a single parameter (minus the error)
  28384. * the promise will resolve with the list or parameters as fulfillment value. If only one parameter is sent to the
  28385. * callback then it will be used as the resolution value.
  28386. * @returns {Function}
  28387. */
  28388. defer.nodeCapsule = function (subject, fn) {
  28389. if (!fn) {
  28390. fn = subject;
  28391. subject = void 0;
  28392. }
  28393. return function () {
  28394. var d = defer(),
  28395. args = slice(arguments);
  28396. args.push(function (err, res) {
  28397. err ? d.reject(err) : d.resolve(arguments.length > 2 ? slice(arguments, 1) : res);
  28398. });
  28399. try {
  28400. fn.apply(subject, args);
  28401. } catch (e) {
  28402. d.reject(e);
  28403. }
  28404. return d.promise;
  28405. };
  28406. };
  28407. /*global define*/
  28408. if (typeof define === 'function' && define.amd) {
  28409. define('D.js', [], function () {
  28410. return defer;
  28411. });
  28412. } else if (typeof module !== undefStr && module.exports) {
  28413. module.exports = defer;
  28414. } else if (typeof window !== undefStr) {
  28415. var oldD = window.D;
  28416. /**
  28417. * restore global D variable to its previous value and return D to the user
  28418. * @returns {Function}
  28419. */
  28420. defer.noConflict = function () {
  28421. window.D = oldD;
  28422. return defer;
  28423. };
  28424. window.D = defer;
  28425. }
  28426. })();
  28427. },{"process":149}],146:[function(require,module,exports) {
  28428. var define;
  28429. /*!
  28430. * uEvent - to make any js object an event emitter
  28431. * Copyright 2011 Jerome Etienne (http://jetienne.com)
  28432. * Copyright 2015-2016 Damien "Mistic" Sorel (http://www.strangeplanet.fr)
  28433. * Licensed under MIT (http://opensource.org/licenses/MIT)
  28434. */
  28435. (function(root, factory) {
  28436. if (typeof module !== 'undefined' && module.exports) {
  28437. module.exports = factory();
  28438. }
  28439. else if (typeof define === 'function' && define.amd) {
  28440. define([], factory);
  28441. }
  28442. else {
  28443. root.uEvent = factory();
  28444. }
  28445. }(this, function() {
  28446. "use strict";
  28447. var returnTrue = function() {
  28448. return true;
  28449. };
  28450. var returnFalse = function() {
  28451. return false;
  28452. };
  28453. var uEvent = function() {
  28454. };
  28455. /**
  28456. * Event object used to stop propagations and prevent default
  28457. */
  28458. uEvent.Event = function(type, args) {
  28459. var typeReadOnly = type;
  28460. var argsReadonly = args;
  28461. Object.defineProperties(this, {
  28462. 'type': {
  28463. get: function() {
  28464. return typeReadOnly;
  28465. },
  28466. set: function(value) {
  28467. },
  28468. enumerable: true
  28469. },
  28470. 'args': {
  28471. get: function() {
  28472. return argsReadonly;
  28473. },
  28474. set: function(value) {
  28475. },
  28476. enumerable: true
  28477. }
  28478. });
  28479. };
  28480. uEvent.Event.prototype = {
  28481. constructor: uEvent.Event,
  28482. isDefaultPrevented: returnFalse,
  28483. isPropagationStopped: returnFalse,
  28484. preventDefault: function() {
  28485. this.isDefaultPrevented = returnTrue;
  28486. },
  28487. stopPropagation: function() {
  28488. this.isPropagationStopped = returnTrue;
  28489. }
  28490. };
  28491. uEvent.prototype = {
  28492. constructor: uEvent,
  28493. /**
  28494. * Add one or many event handlers
  28495. *
  28496. * obj.on('event', callback)
  28497. * obj.on('event', listener) -- listener has an handleEvent method
  28498. * obj.on('event1 event2', callback)
  28499. * obj.on({ event1: callback1, event2: callback2 })
  28500. *
  28501. * @param {String,Object} events
  28502. * @param {Function,optional} callback
  28503. * @return {Object} main object
  28504. */
  28505. on: function(events, callback) {
  28506. this.__events = this.__events || {};
  28507. if (typeof events === 'object') {
  28508. for (var event in events) {
  28509. if (events.hasOwnProperty(event)) {
  28510. this.__events[event] = this.__events[event] || [];
  28511. this.__events[event].push(events[event]);
  28512. }
  28513. }
  28514. }
  28515. else {
  28516. events.split(' ').forEach(function(event) {
  28517. this.__events[event] = this.__events[event] || [];
  28518. this.__events[event].push(callback);
  28519. }, this);
  28520. }
  28521. return this;
  28522. },
  28523. /**
  28524. * Remove one or many or all event handlers
  28525. *
  28526. * obj.off('event')
  28527. * obj.off('event', callback)
  28528. * obj.off('event1 event2')
  28529. * obj.off({ event1: callback1, event2: callback2 })
  28530. * obj.off()
  28531. *
  28532. * @param {String|Object,optional} events
  28533. * @param {Function,optional} callback
  28534. * @return {Object} main object
  28535. */
  28536. off: function(events, callback) {
  28537. this.__events = this.__events || {};
  28538. if (typeof events === 'object') {
  28539. for (var event in events) {
  28540. if (events.hasOwnProperty(event) && (event in this.__events)) {
  28541. var index = this.__events[event].indexOf(events[event]);
  28542. if (index !== -1) this.__events[event].splice(index, 1);
  28543. }
  28544. }
  28545. }
  28546. else if (!!events) {
  28547. events.split(' ').forEach(function(event) {
  28548. if (event in this.__events) {
  28549. if (callback) {
  28550. var index = this.__events[event].indexOf(callback);
  28551. if (index !== -1) this.__events[event].splice(index, 1);
  28552. }
  28553. else {
  28554. this.__events[event].length = 0;
  28555. }
  28556. }
  28557. }, this);
  28558. }
  28559. else {
  28560. this.__events = {};
  28561. }
  28562. return this;
  28563. },
  28564. /**
  28565. * Add one or many event handlers that will be called only once
  28566. * This handlers are only applicable to "trigger", not "change"
  28567. *
  28568. * obj.once('event', callback)
  28569. * obj.once('event1 event2', callback)
  28570. * obj.once({ event1: callback1, event2: callback2 })
  28571. *
  28572. * @param {String|Object} events
  28573. * @param {Function,optional} callback
  28574. * @return {Object} main object
  28575. */
  28576. once: function(events, callback) {
  28577. this.__once = this.__once || {};
  28578. if (typeof events === 'object') {
  28579. for (var event in events) {
  28580. if (events.hasOwnProperty(event)) {
  28581. this.__once[event] = this.__once[event] || [];
  28582. this.__once[event].push(events[event]);
  28583. }
  28584. }
  28585. }
  28586. else {
  28587. events.split(' ').forEach(function(event) {
  28588. this.__once[event] = this.__once[event] || [];
  28589. this.__once[event].push(callback);
  28590. }, this);
  28591. }
  28592. return this;
  28593. },
  28594. /**
  28595. * Trigger all handlers for an event
  28596. *
  28597. * @param {String} event name
  28598. * @param {mixed...,optional} arguments
  28599. * @return {uEvent.Event}
  28600. */
  28601. trigger: function(event /* , args... */) {
  28602. var args = Array.prototype.slice.call(arguments, 1);
  28603. var e = new uEvent.Event(event, args);
  28604. var i, l, f;
  28605. args.push(e);
  28606. if (this.__events && event in this.__events) {
  28607. for (i = 0, l = this.__events[event].length; i < l; i++) {
  28608. f = this.__events[event][i];
  28609. if (typeof f === 'object') {
  28610. f.handleEvent(e);
  28611. }
  28612. else {
  28613. f.apply(this, args);
  28614. }
  28615. if (e.isPropagationStopped()) {
  28616. return e;
  28617. }
  28618. }
  28619. }
  28620. if (this.__once && event in this.__once) {
  28621. for (i = 0, l = this.__once[event].length; i < l; i++) {
  28622. f = this.__once[event][i];
  28623. if (typeof f === 'object') {
  28624. f.handleEvent(e);
  28625. }
  28626. else {
  28627. f.apply(this, args);
  28628. }
  28629. if (e.isPropagationStopped()) {
  28630. delete this.__once[event];
  28631. return e;
  28632. }
  28633. }
  28634. delete this.__once[event];
  28635. }
  28636. return e;
  28637. },
  28638. /**
  28639. * Trigger all modificators for an event, each handler must return a value
  28640. *
  28641. * @param {String} event name
  28642. * @param {mixed} event value
  28643. * @param {mixed...,optional} arguments
  28644. * @return {mixed} modified value
  28645. */
  28646. change: function(event, value /* , args... */) {
  28647. var args = Array.prototype.slice.call(arguments, 1);
  28648. var e = new uEvent.Event(event, args);
  28649. var i, l, f;
  28650. args.push(e);
  28651. if (this.__events && event in this.__events) {
  28652. for (i = 0, l = this.__events[event].length; i < l; i++) {
  28653. args[0] = value;
  28654. f = this.__events[event][i];
  28655. if (typeof f === 'object') {
  28656. value = f.handleEvent(e);
  28657. }
  28658. else {
  28659. value = f.apply(this, args);
  28660. }
  28661. if (e.isPropagationStopped()) {
  28662. return value;
  28663. }
  28664. }
  28665. }
  28666. return value;
  28667. }
  28668. };
  28669. /**
  28670. * Copy all uEvent functions in the destination object
  28671. *
  28672. * @param {Object} target, the object which will support uEvent
  28673. * @param {Object,optional} names, strings map to rename methods
  28674. */
  28675. uEvent.mixin = function(target, names) {
  28676. names = names || {};
  28677. target = typeof target === 'function' ? target.prototype : target;
  28678. ['on', 'off', 'once', 'trigger', 'change'].forEach(function(name) {
  28679. var method = names[name] || name;
  28680. target[method] = uEvent.prototype[name];
  28681. });
  28682. Object.defineProperties(target, {
  28683. '__events': {
  28684. value: null,
  28685. writable: true
  28686. },
  28687. '__once': {
  28688. value: null,
  28689. writable: true
  28690. }
  28691. });
  28692. };
  28693. return uEvent;
  28694. }));
  28695. },{}],147:[function(require,module,exports) {
  28696. var define;
  28697. // doT.js
  28698. // 2011-2014, Laura Doktorova, https://github.com/olado/doT
  28699. // Licensed under the MIT license.
  28700. (function () {
  28701. "use strict";
  28702. var doT = {
  28703. name: "doT",
  28704. version: "1.1.1",
  28705. templateSettings: {
  28706. evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
  28707. interpolate: /\{\{=([\s\S]+?)\}\}/g,
  28708. encode: /\{\{!([\s\S]+?)\}\}/g,
  28709. use: /\{\{#([\s\S]+?)\}\}/g,
  28710. useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
  28711. define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
  28712. defineParams:/^\s*([\w$]+):([\s\S]+)/,
  28713. conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
  28714. iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
  28715. varname: "it",
  28716. strip: true,
  28717. append: true,
  28718. selfcontained: false,
  28719. doNotSkipEncoded: false
  28720. },
  28721. template: undefined, //fn, compile template
  28722. compile: undefined, //fn, for express
  28723. log: true
  28724. }, _globals;
  28725. doT.encodeHTMLSource = function(doNotSkipEncoded) {
  28726. var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': "&#34;", "'": "&#39;", "/": "&#47;" },
  28727. matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
  28728. return function(code) {
  28729. return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
  28730. };
  28731. };
  28732. _globals = (function(){ return this || (0,eval)("this"); }());
  28733. /* istanbul ignore else */
  28734. if (typeof module !== "undefined" && module.exports) {
  28735. module.exports = doT;
  28736. } else if (typeof define === "function" && define.amd) {
  28737. define(function(){return doT;});
  28738. } else {
  28739. _globals.doT = doT;
  28740. }
  28741. var startend = {
  28742. append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
  28743. split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
  28744. }, skip = /$^/;
  28745. function resolveDefs(c, block, def) {
  28746. return ((typeof block === "string") ? block : block.toString())
  28747. .replace(c.define || skip, function(m, code, assign, value) {
  28748. if (code.indexOf("def.") === 0) {
  28749. code = code.substring(4);
  28750. }
  28751. if (!(code in def)) {
  28752. if (assign === ":") {
  28753. if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
  28754. def[code] = {arg: param, text: v};
  28755. });
  28756. if (!(code in def)) def[code]= value;
  28757. } else {
  28758. new Function("def", "def['"+code+"']=" + value)(def);
  28759. }
  28760. }
  28761. return "";
  28762. })
  28763. .replace(c.use || skip, function(m, code) {
  28764. if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
  28765. if (def[d] && def[d].arg && param) {
  28766. var rw = (d+":"+param).replace(/'|\\/g, "_");
  28767. def.__exp = def.__exp || {};
  28768. def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
  28769. return s + "def.__exp['"+rw+"']";
  28770. }
  28771. });
  28772. var v = new Function("def", "return " + code)(def);
  28773. return v ? resolveDefs(c, v, def) : v;
  28774. });
  28775. }
  28776. function unescape(code) {
  28777. return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
  28778. }
  28779. doT.template = function(tmpl, c, def) {
  28780. c = c || doT.templateSettings;
  28781. var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
  28782. str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
  28783. str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
  28784. .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
  28785. .replace(/'|\\/g, "\\$&")
  28786. .replace(c.interpolate || skip, function(m, code) {
  28787. return cse.start + unescape(code) + cse.end;
  28788. })
  28789. .replace(c.encode || skip, function(m, code) {
  28790. needhtmlencode = true;
  28791. return cse.startencode + unescape(code) + cse.end;
  28792. })
  28793. .replace(c.conditional || skip, function(m, elsecase, code) {
  28794. return elsecase ?
  28795. (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
  28796. (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
  28797. })
  28798. .replace(c.iterate || skip, function(m, iterate, vname, iname) {
  28799. if (!iterate) return "';} } out+='";
  28800. sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
  28801. return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
  28802. +vname+"=arr"+sid+"["+indv+"+=1];out+='";
  28803. })
  28804. .replace(c.evaluate || skip, function(m, code) {
  28805. return "';" + unescape(code) + "out+='";
  28806. })
  28807. + "';return out;")
  28808. .replace(/\n/g, "\\n").replace(/\t/g, '\\t').replace(/\r/g, "\\r")
  28809. .replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, "");
  28810. //.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');
  28811. if (needhtmlencode) {
  28812. if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded);
  28813. str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("
  28814. + doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));"
  28815. + str;
  28816. }
  28817. try {
  28818. return new Function(c.varname, str);
  28819. } catch (e) {
  28820. /* istanbul ignore else */
  28821. if (typeof console !== "undefined") console.log("Could not create a template function: " + str);
  28822. throw e;
  28823. }
  28824. };
  28825. doT.compile = function(tmpl, def) {
  28826. return doT.template(tmpl, null, def);
  28827. };
  28828. }());
  28829. },{}],113:[function(require,module,exports) {
  28830. var define;
  28831. /*!
  28832. * Photo Sphere Viewer 3.3.3
  28833. * Copyright (c) 2014-2015 Jérémy Heleine
  28834. * Copyright (c) 2015-2018 Damien "Mistic" Sorel
  28835. * Licensed under MIT (https://opensource.org/licenses/MIT)
  28836. */
  28837. (function(root, factory) {
  28838. if (typeof define === 'function' && define.amd) {
  28839. define(['three', 'd.js', 'uevent', 'dot/doT'], factory);
  28840. }
  28841. else if (typeof module === 'object' && module.exports) {
  28842. module.exports = factory(require('three'), require('d.js'), require('uevent'), require('dot/doT'));
  28843. }
  28844. else {
  28845. root.PhotoSphereViewer = factory(root.THREE, root.D, root.uEvent, root.doT);
  28846. }
  28847. }(this, function(THREE, D, uEvent, doT) {
  28848. "use strict";
  28849. /**
  28850. * @typedef {Object} PhotoSphereViewer.Point
  28851. * @summary Object defining a point
  28852. * @property {int} x
  28853. * @property {int} y
  28854. */
  28855. /**
  28856. * @typedef {Object} PhotoSphereViewer.Size
  28857. * @summary Object defining a size
  28858. * @property {int} width
  28859. * @property {int} height
  28860. */
  28861. /**
  28862. * @typedef {Object} PhotoSphereViewer.CssSize
  28863. * @summary Object defining a size in CSS (px, % or auto)
  28864. * @property {string} [width]
  28865. * @property {string} [height]
  28866. */
  28867. /**
  28868. * @typedef {Object} PhotoSphereViewer.Position
  28869. * @summary Object defining a spherical position
  28870. * @property {float} longitude
  28871. * @property {float} latitude
  28872. */
  28873. /**
  28874. * @typedef {Object} PhotoSphereViewer.ExtendedPosition
  28875. * @summary Object defining a spherical or texture position
  28876. * @description A position that can be expressed either in spherical coordinates (radians or degrees) or in texture coordinates (pixels)
  28877. * @property {float} longitude
  28878. * @property {float} latitude
  28879. * @property {int} x
  28880. * @property {int} y
  28881. */
  28882. /**
  28883. * @typedef {Object} PhotoSphereViewer.CacheItem
  28884. * @summary An entry in the memory cache
  28885. * @property {string} panorama
  28886. * @property {THREE.Texture} image
  28887. * @property {PhotoSphereViewer.PanoData} pano_data
  28888. */
  28889. /**
  28890. * @typedef {Object} PhotoSphereViewer.PanoData
  28891. * @summary Crop information of the panorama
  28892. * @property {int} full_width
  28893. * @property {int} full_height
  28894. * @property {int} cropped_width
  28895. * @property {int} cropped_height
  28896. * @property {int} cropped_x
  28897. * @property {int} cropped_y
  28898. */
  28899. /**
  28900. * @typedef {Object} PhotoSphereViewer.ClickData
  28901. * @summary Data of the `click` event
  28902. * @property {int} client_x - position in the browser window
  28903. * @property {int} client_y - position in the browser window
  28904. * @property {int} viewer_x - position in the viewer
  28905. * @property {int} viewer_y - position in the viewer
  28906. * @property {float} longitude - position in spherical coordinates
  28907. * @property {float} latitude - position in spherical coordinates
  28908. * @property {int} texture_x - position on the texture
  28909. * @property {int} texture_y - position on the texture
  28910. * @property {PSVMarker} [marker] - clicked marker
  28911. */
  28912. /**
  28913. * Viewer class
  28914. * @param {Object} options - see {@link http://photo-sphere-viewer.js.org/#options}
  28915. * @constructor
  28916. * @fires PhotoSphereViewer.ready
  28917. * @throws {PSVError} when the configuration is incorrect
  28918. */
  28919. function PhotoSphereViewer(options) {
  28920. // return instance if called as a function
  28921. if (!(this instanceof PhotoSphereViewer)) {
  28922. return new PhotoSphereViewer(options);
  28923. }
  28924. // init global system variables
  28925. if (!PhotoSphereViewer.SYSTEM.loaded) {
  28926. PhotoSphereViewer._loadSystem();
  28927. }
  28928. /**
  28929. * @summary Configuration object
  28930. * @member {Object}
  28931. * @readonly
  28932. */
  28933. this.config = PSVUtils.clone(PhotoSphereViewer.DEFAULTS);
  28934. PSVUtils.deepmerge(this.config, options);
  28935. // check container
  28936. if (!options.container) {
  28937. throw new PSVError('No value given for container.');
  28938. }
  28939. // must support canvas
  28940. if (!PhotoSphereViewer.SYSTEM.isCanvasSupported) {
  28941. throw new PSVError('Canvas is not supported.');
  28942. }
  28943. // additional scripts if webgl not supported/disabled
  28944. if ((!PhotoSphereViewer.SYSTEM.isWebGLSupported || !this.config.webgl) && !PSVUtils.checkTHREE('CanvasRenderer', 'Projector')) {
  28945. throw new PSVError('Missing Three.js components: CanvasRenderer, Projector. Get them from three.js-examples package.');
  28946. }
  28947. // longitude range must have two values
  28948. if (this.config.longitude_range && this.config.longitude_range.length !== 2) {
  28949. this.config.longitude_range = null;
  28950. console.warn('PhotoSphereViewer: longitude_range must have exactly two elements.');
  28951. }
  28952. if (this.config.latitude_range) {
  28953. // latitude range must have two values
  28954. if (this.config.latitude_range.length !== 2) {
  28955. this.config.latitude_range = null;
  28956. console.warn('PhotoSphereViewer: latitude_range must have exactly two elements.');
  28957. }
  28958. // latitude range must be ordered
  28959. else if (this.config.latitude_range[0] > this.config.latitude_range[1]) {
  28960. this.config.latitude_range = [this.config.latitude_range[1], this.config.latitude_range[0]];
  28961. console.warn('PhotoSphereViewer: latitude_range values must be ordered.');
  28962. }
  28963. }
  28964. // migrate legacy tilt_up_max and tilt_down_max
  28965. else if (this.config.tilt_up_max !== undefined || this.config.tilt_down_max !== undefined) {
  28966. this.config.latitude_range = [
  28967. this.config.tilt_down_max !== undefined ? this.config.tilt_down_max - Math.PI / 4 : -PSVUtils.HalfPI,
  28968. this.config.tilt_up_max !== undefined ? this.config.tilt_up_max + Math.PI / 4 : PSVUtils.HalfPI
  28969. ];
  28970. console.warn('PhotoSphereViewer: tilt_up_max and tilt_down_max are deprecated, use latitude_range instead.');
  28971. }
  28972. // min_fov and max_fov must be ordered
  28973. if (this.config.max_fov < this.config.min_fov) {
  28974. var temp_fov = this.config.max_fov;
  28975. this.config.max_fov = this.config.min_fov;
  28976. this.config.min_fov = temp_fov;
  28977. console.warn('PhotoSphereViewer: max_fov cannot be lower than min_fov.');
  28978. }
  28979. if (this.config.cache_texture && (!PSVUtils.isInteger(this.config.cache_texture) || this.config.cache_texture < 0)) {
  28980. this.config.cache_texture = PhotoSphereViewer.DEFAULTS.cache_texture;
  28981. console.warn('PhotoSphereViewer: invalid value for cache_texture');
  28982. }
  28983. if ('panorama_roll' in this.config) {
  28984. this.config.sphere_correction.roll = this.config.panorama_roll;
  28985. console.warn('PhotoSphereViewer: panorama_roll is deprecated, use sphere_correction.roll instead');
  28986. }
  28987. // min_fov/max_fov between 1 and 179
  28988. this.config.min_fov = PSVUtils.bound(this.config.min_fov, 1, 179);
  28989. this.config.max_fov = PSVUtils.bound(this.config.max_fov, 1, 179);
  28990. // default default_fov is middle point between min_fov and max_fov
  28991. if (this.config.default_fov === null) {
  28992. this.config.default_fov = this.config.max_fov / 2 + this.config.min_fov / 2;
  28993. }
  28994. // default_fov between min_fov and max_fov
  28995. else {
  28996. this.config.default_fov = PSVUtils.bound(this.config.default_fov, this.config.min_fov, this.config.max_fov);
  28997. }
  28998. // parse default_long, is between 0 and 2*PI
  28999. this.config.default_long = PSVUtils.parseAngle(this.config.default_long);
  29000. // parse default_lat, is between -PI/2 and PI/2
  29001. this.config.default_lat = PSVUtils.parseAngle(this.config.default_lat, true);
  29002. // parse camera_correction, is between -PI/2 and PI/2
  29003. this.config.sphere_correction.pan = PSVUtils.parseAngle(this.config.sphere_correction.pan, true);
  29004. this.config.sphere_correction.tilt = PSVUtils.parseAngle(this.config.sphere_correction.tilt, true);
  29005. this.config.sphere_correction.roll = PSVUtils.parseAngle(this.config.sphere_correction.roll, true);
  29006. // default anim_lat is default_lat
  29007. if (this.config.anim_lat === null) {
  29008. this.config.anim_lat = this.config.default_lat;
  29009. }
  29010. // parse anim_lat, is between -PI/2 and PI/2
  29011. else {
  29012. this.config.anim_lat = PSVUtils.parseAngle(this.config.anim_lat, true);
  29013. }
  29014. // parse longitude_range, between 0 and 2*PI
  29015. if (this.config.longitude_range) {
  29016. this.config.longitude_range = this.config.longitude_range.map(function(angle) {
  29017. return PSVUtils.parseAngle(angle);
  29018. });
  29019. }
  29020. // parse latitude_range, between -PI/2 and PI/2
  29021. if (this.config.latitude_range) {
  29022. this.config.latitude_range = this.config.latitude_range.map(function(angle) {
  29023. return PSVUtils.parseAngle(angle, true);
  29024. });
  29025. }
  29026. // parse anim_speed
  29027. this.config.anim_speed = PSVUtils.parseSpeed(this.config.anim_speed);
  29028. // reactivate the navbar if the caption is provided
  29029. if (this.config.caption && !this.config.navbar) {
  29030. this.config.navbar = ['caption'];
  29031. }
  29032. // translate boolean fisheye to amount
  29033. if (this.config.fisheye === true) {
  29034. this.config.fisheye = 1;
  29035. }
  29036. else if (this.config.fisheye === false) {
  29037. this.config.fisheye = 0;
  29038. }
  29039. /**
  29040. * @summary Top most parent
  29041. * @member {HTMLElement}
  29042. * @readonly
  29043. */
  29044. this.parent = (typeof options.container === 'string') ? document.getElementById(options.container) : options.container;
  29045. /**
  29046. * @summary Main container
  29047. * @member {HTMLElement}
  29048. * @readonly
  29049. */
  29050. this.container = null;
  29051. /**
  29052. * @member {module:components.PSVLoader}
  29053. * @readonly
  29054. */
  29055. this.loader = null;
  29056. /**
  29057. * @member {module:components.PSVNavBar}
  29058. * @readonly
  29059. */
  29060. this.navbar = null;
  29061. /**
  29062. * @member {module:components.PSVHUD}
  29063. * @readonly
  29064. */
  29065. this.hud = null;
  29066. /**
  29067. * @member {module:components.PSVPanel}
  29068. * @readonly
  29069. */
  29070. this.panel = null;
  29071. /**
  29072. * @member {module:components.PSVTooltip}
  29073. * @readonly
  29074. */
  29075. this.tooltip = null;
  29076. /**
  29077. * @member {HTMLElement}
  29078. * @readonly
  29079. * @private
  29080. */
  29081. this.canvas_container = null;
  29082. /**
  29083. * @member {THREE.WebGLRenderer | THREE.CanvasRenderer}
  29084. * @readonly
  29085. * @private
  29086. */
  29087. this.renderer = null;
  29088. /**
  29089. * @member {THREE.Scene}
  29090. * @readonly
  29091. * @private
  29092. */
  29093. this.scene = null;
  29094. /**
  29095. * @member {THREE.PerspectiveCamera}
  29096. * @readonly
  29097. * @private
  29098. */
  29099. this.camera = null;
  29100. /**
  29101. * @member {THREE.Mesh}
  29102. * @readonly
  29103. * @private
  29104. */
  29105. this.mesh = null;
  29106. /**
  29107. * @member {THREE.Raycaster}
  29108. * @readonly
  29109. * @private
  29110. */
  29111. this.raycaster = null;
  29112. /**
  29113. * @member {THREE.DeviceOrientationControls}
  29114. * @readonly
  29115. * @private
  29116. */
  29117. this.doControls = null;
  29118. /**
  29119. * @summary Internal properties
  29120. * @member {Object}
  29121. * @readonly
  29122. * @property {boolean} isCubemap - if the panorama is a cubemap
  29123. * @property {float} longitude - current longitude of the center
  29124. * @property {float} longitude - current latitude of the center
  29125. * @property {THREE.Vector3} direction - direction of the camera
  29126. * @property {float} anim_speed - parsed animation speed (rad/sec)
  29127. * @property {int} zoom_lvl - current zoom level
  29128. * @property {float} vFov - vertical FOV
  29129. * @property {float} hFov - horizontal FOV
  29130. * @property {float} aspect - viewer aspect ratio
  29131. * @property {float} move_speed - move speed (computed with pixel ratio and configuration move_speed)
  29132. * @property {boolean} moving - is the user moving
  29133. * @property {boolean} zooming - is the user zooming
  29134. * @property {int} start_mouse_x - start x position of the click/touch
  29135. * @property {int} start_mouse_y - start y position of the click/touch
  29136. * @property {int} mouse_x - current x position of the cursor
  29137. * @property {int} mouse_y - current y position of the cursor
  29138. * @property {Array[]} mouse_history - list of latest positions of the cursor, [time, x, y]
  29139. * @property {int} gyro_alpha_offset - current alpha offset for gyroscope controls
  29140. * @property {int} pinch_dist - distance between fingers when zooming
  29141. * @property orientation_reqid - animationRequest id of the device orientation
  29142. * @property autorotate_reqid - animationRequest id of the automatic rotation
  29143. * @property {Promise} animation_promise - promise of the current animation (either go to position or image transition)
  29144. * @property {Promise} loading_promise - promise of the setPanorama method
  29145. * @property start_timeout - timeout id of the automatic rotation delay
  29146. * @property {PhotoSphereViewer.ClickData} dblclick_data - temporary storage of click data between two clicks
  29147. * @property dblclick_timeout - timeout id for double click
  29148. * @property {PhotoSphereViewer.CacheItem[]} cache - cached panoramas
  29149. * @property {Size} size - size of the container
  29150. * @property {PhotoSphereViewer.PanoData} pano_data - panorama metadata
  29151. */
  29152. this.prop = {
  29153. isCubemap: undefined,
  29154. longitude: 0,
  29155. latitude: 0,
  29156. direction: null,
  29157. anim_speed: 0,
  29158. zoom_lvl: 0,
  29159. vFov: 0,
  29160. hFov: 0,
  29161. aspect: 0,
  29162. move_speed: 0.1,
  29163. moving: false,
  29164. zooming: false,
  29165. start_mouse_x: 0,
  29166. start_mouse_y: 0,
  29167. mouse_x: 0,
  29168. mouse_y: 0,
  29169. mouse_history: [],
  29170. gyro_alpha_offset: 0,
  29171. pinch_dist: 0,
  29172. orientation_reqid: null,
  29173. autorotate_reqid: null,
  29174. animation_promise: null,
  29175. loading_promise: null,
  29176. start_timeout: null,
  29177. dblclick_data: null,
  29178. dblclick_timeout: null,
  29179. cache: [],
  29180. size: {
  29181. width: 0,
  29182. height: 0
  29183. },
  29184. pano_data: {
  29185. full_width: 0,
  29186. full_height: 0,
  29187. cropped_width: 0,
  29188. cropped_height: 0,
  29189. cropped_x: 0,
  29190. cropped_y: 0
  29191. }
  29192. };
  29193. // init templates
  29194. Object.keys(PhotoSphereViewer.TEMPLATES).forEach(function(tpl) {
  29195. if (!this.config.templates[tpl]) {
  29196. this.config.templates[tpl] = PhotoSphereViewer.TEMPLATES[tpl];
  29197. }
  29198. if (typeof this.config.templates[tpl] === 'string') {
  29199. this.config.templates[tpl] = doT.template(this.config.templates[tpl]);
  29200. }
  29201. }, this);
  29202. // init
  29203. this.parent.photoSphereViewer = this;
  29204. // create actual container
  29205. this.container = document.createElement('div');
  29206. this.container.classList.add('psv-container');
  29207. this.parent.appendChild(this.container);
  29208. // apply container size
  29209. if (this.config.size !== null) {
  29210. this._setViewerSize(this.config.size);
  29211. }
  29212. this._onResize();
  29213. // apply default zoom level
  29214. var tempZoom = Math.round((this.config.default_fov - this.config.min_fov) / (this.config.max_fov - this.config.min_fov) * 100);
  29215. this.zoom(tempZoom - 2 * (tempZoom - 50), false);
  29216. // actual move speed depends on pixel-ratio
  29217. this.prop.move_speed = THREE.Math.degToRad(this.config.move_speed / PhotoSphereViewer.SYSTEM.pixelRatio);
  29218. // set default position
  29219. this.rotate({
  29220. longitude: this.config.default_long,
  29221. latitude: this.config.default_lat
  29222. }, false);
  29223. // load loader (!!)
  29224. this.loader = new PSVLoader(this);
  29225. this.loader.hide();
  29226. // load navbar
  29227. this.navbar = new PSVNavBar(this);
  29228. this.navbar.hide();
  29229. // load hud
  29230. this.hud = new PSVHUD(this);
  29231. this.hud.hide();
  29232. // load side panel
  29233. this.panel = new PSVPanel(this);
  29234. // load hud tooltip
  29235. this.tooltip = new PSVTooltip(this.hud);
  29236. // attach event handlers
  29237. this._bindEvents();
  29238. // load panorama
  29239. if (this.config.panorama) {
  29240. this.load();
  29241. }
  29242. // enable GUI after first render
  29243. this.once('render', function() {
  29244. if (this.config.navbar) {
  29245. this.container.classList.add('psv-container--has-navbar');
  29246. this.navbar.show();
  29247. }
  29248. this.hud.show();
  29249. if (this.config.markers) {
  29250. this.config.markers.forEach(function(marker) {
  29251. this.hud.addMarker(marker, false);
  29252. }, this);
  29253. this.hud.renderMarkers();
  29254. }
  29255. // Queue animation
  29256. if (this.config.time_anim !== false) {
  29257. this.prop.start_timeout = window.setTimeout(this.startAutorotate.bind(this), this.config.time_anim);
  29258. }
  29259. /**
  29260. * @event ready
  29261. * @memberof PhotoSphereViewer
  29262. * @summary Triggered when the panorama image has been loaded and the viewer is ready to perform the first render
  29263. */
  29264. setTimeout(this.trigger.bind(this, 'ready'), 0);
  29265. }.bind(this));
  29266. }
  29267. /**
  29268. * @summary Triggers an event on the viewer
  29269. * @function trigger
  29270. * @memberof PhotoSphereViewer
  29271. * @instance
  29272. * @param {string} name
  29273. * @param {...*} [arguments]
  29274. * @returns {uEvent.Event}
  29275. */
  29276. /**
  29277. * @summary Triggers an event on the viewer and returns the modified value
  29278. * @function change
  29279. * @memberof PhotoSphereViewer
  29280. * @instance
  29281. * @param {string} name
  29282. * @param {*} value
  29283. * @param {...*} [arguments]
  29284. * @returns {*}
  29285. */
  29286. /**
  29287. * @summary Attaches an event listener on the viewer
  29288. * @function on
  29289. * @memberof PhotoSphereViewer
  29290. * @instance
  29291. * @param {string|Object.<string, function>} name - event name or events map
  29292. * @param {function} [callback]
  29293. * @returns {PhotoSphereViewer}
  29294. */
  29295. /**
  29296. * @summary Removes an event listener from the viewer
  29297. * @function off
  29298. * @memberof PhotoSphereViewer
  29299. * @instance
  29300. * @param {string|Object.<string, function>} name - event name or events map
  29301. * @param {function} [callback]
  29302. * @returns {PhotoSphereViewer}
  29303. */
  29304. /**
  29305. * @summary Attaches an event listener called once on the viewer
  29306. * @function once
  29307. * @memberof PhotoSphereViewer
  29308. * @instance
  29309. * @param {string|Object.<string, function>} name - event name or events map
  29310. * @param {function} [callback]
  29311. * @returns {PhotoSphereViewer}
  29312. */
  29313. uEvent.mixin(PhotoSphereViewer);
  29314. /**
  29315. * @summary Loads the XMP data with AJAX
  29316. * @param {string} panorama
  29317. * @returns {Promise.<PhotoSphereViewer.PanoData>}
  29318. * @throws {PSVError} when the image cannot be loaded
  29319. * @private
  29320. */
  29321. PhotoSphereViewer.prototype._loadXMP = function(panorama) {
  29322. if (!this.config.usexmpdata) {
  29323. return D.resolved(null);
  29324. }
  29325. var defer = D();
  29326. var xhr = new XMLHttpRequest();
  29327. var progress = 0;
  29328. xhr.onreadystatechange = function() {
  29329. if (xhr.readyState === 4) {
  29330. if (xhr.status === 200 || xhr.status === 201 || xhr.status === 202 || xhr.status === 0) {
  29331. this.loader.setProgress(100);
  29332. var binary = xhr.responseText;
  29333. var a = binary.indexOf('<x:xmpmeta'), b = binary.indexOf('</x:xmpmeta>');
  29334. var data = binary.substring(a, b);
  29335. // No data retrieved
  29336. if (a === -1 || b === -1 || data.indexOf('GPano:') === -1) {
  29337. defer.resolve(null);
  29338. }
  29339. else {
  29340. var pano_data = {
  29341. full_width: parseInt(PSVUtils.getXMPValue(data, 'FullPanoWidthPixels')),
  29342. full_height: parseInt(PSVUtils.getXMPValue(data, 'FullPanoHeightPixels')),
  29343. cropped_width: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaImageWidthPixels')),
  29344. cropped_height: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaImageHeightPixels')),
  29345. cropped_x: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaLeftPixels')),
  29346. cropped_y: parseInt(PSVUtils.getXMPValue(data, 'CroppedAreaTopPixels'))
  29347. };
  29348. if (!pano_data.full_width || !pano_data.full_height || !pano_data.cropped_width || !pano_data.cropped_height) {
  29349. console.warn('PhotoSphereViewer: invalid XMP data');
  29350. defer.resolve(null);
  29351. }
  29352. else {
  29353. defer.resolve(pano_data);
  29354. }
  29355. }
  29356. }
  29357. else {
  29358. this.container.textContent = 'Cannot load image';
  29359. throw new PSVError('Cannot load image');
  29360. }
  29361. }
  29362. else if (xhr.readyState === 3) {
  29363. this.loader.setProgress(progress += 10);
  29364. }
  29365. }.bind(this);
  29366. xhr.onprogress = function(e) {
  29367. if (e.lengthComputable) {
  29368. var new_progress = parseInt(e.loaded / e.total * 100);
  29369. if (new_progress > progress) {
  29370. progress = new_progress;
  29371. this.loader.setProgress(progress);
  29372. }
  29373. }
  29374. }.bind(this);
  29375. xhr.onerror = function() {
  29376. this.container.textContent = 'Cannot load image';
  29377. throw new PSVError('Cannot load image');
  29378. }.bind(this);
  29379. xhr.open('GET', panorama, true);
  29380. xhr.send(null);
  29381. return defer.promise;
  29382. };
  29383. /**
  29384. * @summary Loads the panorama texture(s)
  29385. * @param {string|string[]} panorama
  29386. * @returns {Promise.<THREE.Texture|THREE.Texture[]>}
  29387. * @fires PhotoSphereViewer.panorama-load-progress
  29388. * @throws {PSVError} when the image cannot be loaded
  29389. * @private
  29390. */
  29391. PhotoSphereViewer.prototype._loadTexture = function(panorama) {
  29392. var tempPanorama = [];
  29393. if (Array.isArray(panorama)) {
  29394. if (panorama.length !== 6) {
  29395. throw new PSVError('Must provide exactly 6 image paths when using cubemap.');
  29396. }
  29397. // reorder images
  29398. for (var i = 0; i < 6; i++) {
  29399. tempPanorama[i] = panorama[PhotoSphereViewer.CUBE_MAP[i]];
  29400. }
  29401. panorama = tempPanorama;
  29402. }
  29403. else if (typeof panorama === 'object') {
  29404. if (!PhotoSphereViewer.CUBE_HASHMAP.every(function(side) {
  29405. return !!panorama[side];
  29406. })) {
  29407. throw new PSVError('Must provide exactly left, front, right, back, top, bottom when using cubemap.');
  29408. }
  29409. // transform into array
  29410. PhotoSphereViewer.CUBE_HASHMAP.forEach(function(side, i) {
  29411. tempPanorama[i] = panorama[side];
  29412. });
  29413. panorama = tempPanorama;
  29414. }
  29415. if (Array.isArray(panorama)) {
  29416. if (this.prop.isCubemap === false) {
  29417. throw new PSVError('The viewer was initialized with an equirectangular panorama, cannot switch to cubemap.');
  29418. }
  29419. if (this.config.fisheye) {
  29420. console.warn('PhotoSphereViewer: fisheye effect with cubemap texture can generate distorsions.');
  29421. }
  29422. if (this.config.cache_texture === PhotoSphereViewer.DEFAULTS.cache_texture) {
  29423. this.config.cache_texture *= 6;
  29424. }
  29425. this.prop.isCubemap = true;
  29426. return this._loadCubemapTexture(panorama);
  29427. }
  29428. else {
  29429. if (this.prop.isCubemap === true) {
  29430. throw new PSVError('The viewer was initialized with an cubemap, cannot switch to equirectangular panorama.');
  29431. }
  29432. this.prop.isCubemap = false;
  29433. return this._loadEquirectangularTexture(panorama);
  29434. }
  29435. };
  29436. /**
  29437. * @summary Loads the sphere texture
  29438. * @param {string} panorama
  29439. * @returns {Promise.<THREE.Texture>}
  29440. * @fires PhotoSphereViewer.panorama-load-progress
  29441. * @throws {PSVError} when the image cannot be loaded
  29442. * @private
  29443. */
  29444. PhotoSphereViewer.prototype._loadEquirectangularTexture = function(panorama) {
  29445. if (this.config.cache_texture) {
  29446. var cache = this.getPanoramaCache(panorama);
  29447. if (cache) {
  29448. this.prop.pano_data = cache.pano_data;
  29449. return D.resolved(cache.image);
  29450. }
  29451. }
  29452. return this._loadXMP(panorama).then(function(pano_data) {
  29453. var defer = D();
  29454. var loader = new THREE.ImageLoader();
  29455. var progress = pano_data ? 100 : 0;
  29456. loader.setCrossOrigin('anonymous');
  29457. var onload = function(img) {
  29458. progress = 100;
  29459. this.loader.setProgress(progress);
  29460. /**
  29461. * @event panorama-load-progress
  29462. * @memberof PhotoSphereViewer
  29463. * @summary Triggered while a panorama image is loading
  29464. * @param {string} panorama
  29465. * @param {int} progress
  29466. */
  29467. this.trigger('panorama-load-progress', panorama, progress);
  29468. // Config XMP data
  29469. if (!pano_data && this.config.pano_data) {
  29470. pano_data = PSVUtils.clone(this.config.pano_data);
  29471. }
  29472. // Default XMP data
  29473. if (!pano_data) {
  29474. pano_data = {
  29475. full_width: img.width,
  29476. full_height: img.height,
  29477. cropped_width: img.width,
  29478. cropped_height: img.height,
  29479. cropped_x: 0,
  29480. cropped_y: 0
  29481. };
  29482. }
  29483. this.prop.pano_data = pano_data;
  29484. var texture;
  29485. var ratio = Math.min(pano_data.full_width, PhotoSphereViewer.SYSTEM.maxTextureWidth) / pano_data.full_width;
  29486. // resize image / fill cropped parts with black
  29487. if (ratio !== 1 || pano_data.cropped_width !== pano_data.full_width || pano_data.cropped_height !== pano_data.full_height) {
  29488. var resized_pano_data = PSVUtils.clone(pano_data);
  29489. resized_pano_data.full_width *= ratio;
  29490. resized_pano_data.full_height *= ratio;
  29491. resized_pano_data.cropped_width *= ratio;
  29492. resized_pano_data.cropped_height *= ratio;
  29493. resized_pano_data.cropped_x *= ratio;
  29494. resized_pano_data.cropped_y *= ratio;
  29495. img.width = resized_pano_data.cropped_width;
  29496. img.height = resized_pano_data.cropped_height;
  29497. var buffer = document.createElement('canvas');
  29498. buffer.width = resized_pano_data.full_width;
  29499. buffer.height = resized_pano_data.full_height;
  29500. var ctx = buffer.getContext('2d');
  29501. ctx.drawImage(img, resized_pano_data.cropped_x, resized_pano_data.cropped_y, resized_pano_data.cropped_width, resized_pano_data.cropped_height);
  29502. texture = new THREE.Texture(buffer);
  29503. }
  29504. else {
  29505. texture = new THREE.Texture(img);
  29506. }
  29507. texture.needsUpdate = true;
  29508. texture.minFilter = THREE.LinearFilter;
  29509. texture.generateMipmaps = false;
  29510. if (this.config.cache_texture) {
  29511. this._putPanoramaCache({
  29512. panorama: panorama,
  29513. image: texture,
  29514. pano_data: pano_data
  29515. });
  29516. }
  29517. defer.resolve(texture);
  29518. };
  29519. var onprogress = function(e) {
  29520. if (e.lengthComputable) {
  29521. var new_progress = parseInt(e.loaded / e.total * 100);
  29522. if (new_progress > progress) {
  29523. progress = new_progress;
  29524. this.loader.setProgress(progress);
  29525. this.trigger('panorama-load-progress', panorama, progress);
  29526. }
  29527. }
  29528. };
  29529. var onerror = function(e) {
  29530. this.container.textContent = 'Cannot load image';
  29531. defer.reject(e);
  29532. throw new PSVError('Cannot load image');
  29533. };
  29534. loader.load(panorama, onload.bind(this), onprogress.bind(this), onerror.bind(this));
  29535. return defer.promise;
  29536. }.bind(this));
  29537. };
  29538. /**
  29539. * @summary Load the six textures of the cube
  29540. * @param {string[]} panorama
  29541. * @returns {Promise.<THREE.Texture[]>}
  29542. * @fires PhotoSphereViewer.panorama-load-progress
  29543. * @throws {PSVError} when the image cannot be loaded
  29544. * @private
  29545. */
  29546. PhotoSphereViewer.prototype._loadCubemapTexture = function(panorama) {
  29547. var defer = D();
  29548. var loader = new THREE.ImageLoader();
  29549. var progress = [0, 0, 0, 0, 0, 0];
  29550. var loaded = [];
  29551. var done = 0;
  29552. loader.setCrossOrigin('anonymous');
  29553. var onend = function() {
  29554. loaded.forEach(function(img) {
  29555. img.needsUpdate = true;
  29556. img.minFilter = THREE.LinearFilter;
  29557. img.generateMipmaps = false;
  29558. });
  29559. defer.resolve(loaded);
  29560. };
  29561. var onload = function(i, img) {
  29562. done++;
  29563. progress[i] = 100;
  29564. this.loader.setProgress(PSVUtils.sum(progress) / 6);
  29565. this.trigger('panorama-load-progress', panorama[i], progress[i]);
  29566. var ratio = Math.min(img.width, PhotoSphereViewer.SYSTEM.maxTextureWidth / 2) / img.width;
  29567. // resize image
  29568. if (ratio !== 1) {
  29569. var buffer = document.createElement('canvas');
  29570. buffer.width = img.width * ratio;
  29571. buffer.height = img.height * ratio;
  29572. var ctx = buffer.getContext('2d');
  29573. ctx.drawImage(img, 0, 0, buffer.width, buffer.height);
  29574. loaded[i] = new THREE.Texture(buffer);
  29575. }
  29576. else {
  29577. loaded[i] = new THREE.Texture(img);
  29578. }
  29579. if (this.config.cache_texture) {
  29580. this._putPanoramaCache({
  29581. panorama: panorama[i],
  29582. image: loaded[i]
  29583. });
  29584. }
  29585. if (done === 6) {
  29586. onend();
  29587. }
  29588. };
  29589. var onprogress = function(i, e) {
  29590. if (e.lengthComputable) {
  29591. var new_progress = parseInt(e.loaded / e.total * 100);
  29592. if (new_progress > progress[i]) {
  29593. progress[i] = new_progress;
  29594. this.loader.setProgress(PSVUtils.sum(progress) / 6);
  29595. this.trigger('panorama-load-progress', panorama[i], progress[i]);
  29596. }
  29597. }
  29598. };
  29599. var onerror = function(i, e) {
  29600. this.container.textContent = 'Cannot load image';
  29601. defer.reject(e);
  29602. throw new PSVError('Cannot load image ' + i);
  29603. };
  29604. for (var i = 0; i < 6; i++) {
  29605. if (this.config.cache_texture) {
  29606. var cache = this.getPanoramaCache(panorama[i]);
  29607. if (cache) {
  29608. done++;
  29609. progress[i] = 100;
  29610. loaded[i] = cache.image;
  29611. continue;
  29612. }
  29613. }
  29614. loader.load(panorama[i], onload.bind(this, i), onprogress.bind(this, i), onerror.bind(this, i));
  29615. }
  29616. if (done === 6) {
  29617. defer.resolve(loaded);
  29618. }
  29619. return defer.promise;
  29620. };
  29621. /**
  29622. * @summary Applies the texture to the scene, creates the scene if needed
  29623. * @param {THREE.Texture|THREE.Texture[]} texture
  29624. * @fires PhotoSphereViewer.panorama-loaded
  29625. * @private
  29626. */
  29627. PhotoSphereViewer.prototype._setTexture = function(texture) {
  29628. if (!this.scene) {
  29629. this._createScene();
  29630. }
  29631. if (this.prop.isCubemap) {
  29632. for (var i = 0; i < 6; i++) {
  29633. if (this.mesh.material[i].map) {
  29634. this.mesh.material[i].map.dispose();
  29635. }
  29636. this.mesh.material[i].map = texture[i];
  29637. }
  29638. }
  29639. else {
  29640. if (this.mesh.material.map) {
  29641. this.mesh.material.map.dispose();
  29642. }
  29643. this.mesh.material.map = texture;
  29644. }
  29645. /**
  29646. * @event panorama-loaded
  29647. * @memberof PhotoSphereViewer
  29648. * @summary Triggered when a panorama image has been loaded
  29649. */
  29650. this.trigger('panorama-loaded');
  29651. this.render();
  29652. };
  29653. /**
  29654. * @summary Creates the 3D scene and GUI components
  29655. * @private
  29656. */
  29657. PhotoSphereViewer.prototype._createScene = function() {
  29658. this.raycaster = new THREE.Raycaster();
  29659. this.renderer = PhotoSphereViewer.SYSTEM.isWebGLSupported && this.config.webgl ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer();
  29660. this.renderer.setSize(this.prop.size.width, this.prop.size.height);
  29661. this.renderer.setPixelRatio(PhotoSphereViewer.SYSTEM.pixelRatio);
  29662. var cameraDistance = PhotoSphereViewer.SPHERE_RADIUS;
  29663. if (this.prop.isCubemap) {
  29664. cameraDistance *= Math.sqrt(3);
  29665. }
  29666. if (this.config.fisheye) {
  29667. cameraDistance += PhotoSphereViewer.SPHERE_RADIUS;
  29668. }
  29669. this.camera = new THREE.PerspectiveCamera(this.config.default_fov, this.prop.size.width / this.prop.size.height, 1, cameraDistance);
  29670. this.camera.position.set(0, 0, 0);
  29671. if (this.config.gyroscope && PSVUtils.checkTHREE('DeviceOrientationControls')) {
  29672. this.doControls = new THREE.DeviceOrientationControls(this.camera);
  29673. }
  29674. this.scene = new THREE.Scene();
  29675. this.scene.add(this.camera);
  29676. if (this.prop.isCubemap) {
  29677. this._createCubemap();
  29678. }
  29679. else {
  29680. this._createSphere();
  29681. }
  29682. // create canvas container
  29683. this.canvas_container = document.createElement('div');
  29684. this.canvas_container.className = 'psv-canvas-container';
  29685. this.renderer.domElement.className = 'psv-canvas';
  29686. this.container.appendChild(this.canvas_container);
  29687. this.canvas_container.appendChild(this.renderer.domElement);
  29688. };
  29689. /**
  29690. * @summary Creates the sphere mesh
  29691. * @private
  29692. */
  29693. PhotoSphereViewer.prototype._createSphere = function() {
  29694. // The middle of the panorama is placed at longitude=0
  29695. var geometry = new THREE.SphereGeometry(
  29696. PhotoSphereViewer.SPHERE_RADIUS,
  29697. PhotoSphereViewer.SPHERE_VERTICES,
  29698. PhotoSphereViewer.SPHERE_VERTICES,
  29699. -PSVUtils.HalfPI
  29700. );
  29701. var material = new THREE.MeshBasicMaterial({
  29702. side: THREE.DoubleSide, // needs to be DoubleSide for CanvasRenderer
  29703. overdraw: PhotoSphereViewer.SYSTEM.isWebGLSupported && this.config.webgl ? 0 : 1
  29704. });
  29705. this.mesh = new THREE.Mesh(geometry, material);
  29706. this.mesh.scale.x = -1;
  29707. this.mesh.rotation.x = this.config.sphere_correction.tilt;
  29708. this.mesh.rotation.y = this.config.sphere_correction.pan;
  29709. this.mesh.rotation.z = this.config.sphere_correction.roll;
  29710. this.scene.add(this.mesh);
  29711. };
  29712. /**
  29713. * @summary Creates the cube mesh
  29714. * @private
  29715. */
  29716. PhotoSphereViewer.prototype._createCubemap = function() {
  29717. var geometry = new THREE.BoxGeometry(
  29718. PhotoSphereViewer.SPHERE_RADIUS * 2, PhotoSphereViewer.SPHERE_RADIUS * 2, PhotoSphereViewer.SPHERE_RADIUS * 2,
  29719. PhotoSphereViewer.CUBE_VERTICES, PhotoSphereViewer.CUBE_VERTICES, PhotoSphereViewer.CUBE_VERTICES
  29720. );
  29721. var materials = [];
  29722. for (var i = 0; i < 6; i++) {
  29723. materials.push(new THREE.MeshBasicMaterial({
  29724. side: THREE.BackSide,
  29725. overdraw: PhotoSphereViewer.SYSTEM.isWebGLSupported && this.config.webgl ? 0 : 1
  29726. }));
  29727. }
  29728. this.mesh = new THREE.Mesh(geometry, materials);
  29729. this.mesh.position.x -= PhotoSphereViewer.SPHERE_RADIUS;
  29730. this.mesh.position.y -= PhotoSphereViewer.SPHERE_RADIUS;
  29731. this.mesh.position.z -= PhotoSphereViewer.SPHERE_RADIUS;
  29732. this.mesh.applyMatrix(new THREE.Matrix4().makeScale(1, 1, -1));
  29733. this.scene.add(this.mesh);
  29734. };
  29735. /**
  29736. * @summary Performs transition between the current and a new texture
  29737. * @param {THREE.Texture} texture
  29738. * @param {PhotoSphereViewer.Position} [position]
  29739. * @returns {Promise}
  29740. * @private
  29741. * @throws {PSVError} if the panorama is a cubemap
  29742. */
  29743. PhotoSphereViewer.prototype._transition = function(texture, position) {
  29744. if (this.prop.isCubemap) {
  29745. throw new PSVError('Transition is not available with cubemap.');
  29746. }
  29747. // create a new sphere with the new texture
  29748. var geometry = new THREE.SphereGeometry(
  29749. PhotoSphereViewer.SPHERE_RADIUS * 0.9,
  29750. PhotoSphereViewer.SPHERE_VERTICES,
  29751. PhotoSphereViewer.SPHERE_VERTICES,
  29752. -PSVUtils.HalfPI
  29753. );
  29754. var material = new THREE.MeshBasicMaterial({
  29755. side: THREE.DoubleSide,
  29756. overdraw: PhotoSphereViewer.SYSTEM.isWebGLSupported && this.config.webgl ? 0 : 1,
  29757. map: texture,
  29758. transparent: true,
  29759. opacity: 0
  29760. });
  29761. var mesh = new THREE.Mesh(geometry, material);
  29762. mesh.scale.x = -1;
  29763. // rotate the new sphere to make the target position face the camera
  29764. if (position) {
  29765. // Longitude rotation along the vertical axis
  29766. mesh.rotateY(position.longitude - this.prop.longitude);
  29767. // Latitude rotation along the camera horizontal axis
  29768. var axis = new THREE.Vector3(0, 1, 0).cross(this.camera.getWorldDirection()).normalize();
  29769. var q = new THREE.Quaternion().setFromAxisAngle(axis, position.latitude - this.prop.latitude);
  29770. mesh.quaternion.multiplyQuaternions(q, mesh.quaternion);
  29771. }
  29772. this.scene.add(mesh);
  29773. this.render();
  29774. return PSVUtils.animation({
  29775. properties: {
  29776. opacity: { start: 0.0, end: 1.0 }
  29777. },
  29778. duration: this.config.transition.duration,
  29779. easing: 'outCubic',
  29780. onTick: function(properties) {
  29781. material.opacity = properties.opacity;
  29782. this.render();
  29783. }.bind(this)
  29784. })
  29785. .then(function() {
  29786. // remove temp sphere and transfer the texture to the main sphere
  29787. this.mesh.material.map.dispose();
  29788. this.mesh.material.map = texture;
  29789. this.scene.remove(mesh);
  29790. mesh.geometry.dispose();
  29791. mesh.geometry = null;
  29792. mesh.material.dispose();
  29793. mesh.material = null;
  29794. // actually rotate the camera
  29795. if (position) {
  29796. // FIXME: find a better way to handle ranges
  29797. if (this.config.latitude_range || this.config.longitude_range) {
  29798. this.config.longitude_range = this.config.latitude_range = null;
  29799. console.warn('PhotoSphereViewer: trying to perform transition with longitude_range and/or latitude_range, ranges cleared.');
  29800. }
  29801. this.rotate(position);
  29802. }
  29803. else {
  29804. this.render();
  29805. }
  29806. }.bind(this));
  29807. };
  29808. /**
  29809. * @summary Reverses autorotate direction with smooth transition
  29810. * @private
  29811. */
  29812. PhotoSphereViewer.prototype._reverseAutorotate = function() {
  29813. var self = this;
  29814. var newSpeed = -this.config.anim_speed;
  29815. var range = this.config.longitude_range;
  29816. this.config.longitude_range = null;
  29817. PSVUtils.animation({
  29818. properties: {
  29819. speed: { start: this.config.anim_speed, end: 0 }
  29820. },
  29821. duration: 300,
  29822. easing: 'inSine',
  29823. onTick: function(properties) {
  29824. self.config.anim_speed = properties.speed;
  29825. }
  29826. })
  29827. .then(function() {
  29828. return PSVUtils.animation({
  29829. properties: {
  29830. speed: { start: 0, end: newSpeed }
  29831. },
  29832. duration: 300,
  29833. easing: 'outSine',
  29834. onTick: function(properties) {
  29835. self.config.anim_speed = properties.speed;
  29836. }
  29837. });
  29838. })
  29839. .then(function() {
  29840. self.config.longitude_range = range;
  29841. self.config.anim_speed = newSpeed;
  29842. });
  29843. };
  29844. /**
  29845. * @summary Adds a panorama to the cache
  29846. * @param {PhotoSphereViewer.CacheItem} cache
  29847. * @fires PhotoSphereViewer.panorama-cached
  29848. * @throws {PSVError} when the cache is disabled
  29849. * @private
  29850. */
  29851. PhotoSphereViewer.prototype._putPanoramaCache = function(cache) {
  29852. if (!this.config.cache_texture) {
  29853. throw new PSVError('Cannot add panorama to cache, cache_texture is disabled');
  29854. }
  29855. var existingCache = this.getPanoramaCache(cache.panorama);
  29856. if (existingCache) {
  29857. existingCache.image = cache.image;
  29858. existingCache.pano_data = cache.pano_data;
  29859. }
  29860. else {
  29861. this.prop.cache = this.prop.cache.slice(0, this.config.cache_texture - 1); // remove most ancient elements
  29862. this.prop.cache.unshift(cache);
  29863. }
  29864. /**
  29865. * @event panorama-cached
  29866. * @memberof PhotoSphereViewer
  29867. * @summary Triggered when a panorama is stored in the cache
  29868. * @param {string} panorama
  29869. */
  29870. this.trigger('panorama-cached', cache.panorama);
  29871. };
  29872. /**
  29873. * @summary Stops all current animations
  29874. * @private
  29875. */
  29876. PhotoSphereViewer.prototype._stopAll = function() {
  29877. this.stopAutorotate();
  29878. this.stopAnimation();
  29879. this.stopGyroscopeControl();
  29880. };
  29881. /**
  29882. * @summary Number of pixels bellow which a mouse move will be considered as a click
  29883. * @type {int}
  29884. * @readonly
  29885. * @private
  29886. */
  29887. PhotoSphereViewer.MOVE_THRESHOLD = 4;
  29888. /**
  29889. * @summary Angle in radians bellow which two angles are considered identical
  29890. * @type {float}
  29891. * @readonly
  29892. * @private
  29893. */
  29894. PhotoSphereViewer.ANGLE_THRESHOLD = 0.003;
  29895. /**
  29896. * @summary Delay in milliseconds between two clicks to consider a double click
  29897. * @type {int}
  29898. * @readonly
  29899. * @private
  29900. */
  29901. PhotoSphereViewer.DBLCLICK_DELAY = 300;
  29902. /**
  29903. * @summary Time size of the mouse position history used to compute inertia
  29904. * @type {int}
  29905. * @readonly
  29906. * @private
  29907. */
  29908. PhotoSphereViewer.INERTIA_WINDOW = 300;
  29909. /**
  29910. * @summary Radius of the THREE.SphereGeometry
  29911. * Half-length of the THREE.BoxGeometry
  29912. * @type {int}
  29913. * @readonly
  29914. * @private
  29915. */
  29916. PhotoSphereViewer.SPHERE_RADIUS = 100;
  29917. /**
  29918. * @summary Number of vertice of the THREE.SphereGeometry
  29919. * @type {int}
  29920. * @readonly
  29921. * @private
  29922. */
  29923. PhotoSphereViewer.SPHERE_VERTICES = 64;
  29924. /**
  29925. * @summary Number of vertices of each side of the THREE.BoxGeometry
  29926. * @type {int}
  29927. * @readonly
  29928. * @private
  29929. */
  29930. PhotoSphereViewer.CUBE_VERTICES = 8;
  29931. /**
  29932. * @summary Order of cube textures for arrays
  29933. * @type {int[]}
  29934. * @readonly
  29935. * @private
  29936. */
  29937. PhotoSphereViewer.CUBE_MAP = [0, 2, 4, 5, 3, 1];
  29938. /**
  29939. * @summary Order of cube textures for maps
  29940. * @type {string[]}
  29941. * @readonly
  29942. * @private
  29943. */
  29944. PhotoSphereViewer.CUBE_HASHMAP = ['left', 'right', 'top', 'bottom', 'back', 'front'];
  29945. /**
  29946. * @summary Map between keyboard events `keyCode|which` and `key`
  29947. * @type {Object.<int, string>}
  29948. * @readonly
  29949. * @private
  29950. */
  29951. PhotoSphereViewer.KEYMAP = {
  29952. 33: 'PageUp',
  29953. 34: 'PageDown',
  29954. 37: 'ArrowLeft',
  29955. 38: 'ArrowUp',
  29956. 39: 'ArrowRight',
  29957. 40: 'ArrowDown',
  29958. 107: '+',
  29959. 109: '-'
  29960. };
  29961. /**
  29962. * @summary System properties
  29963. * @type {Object}
  29964. * @readonly
  29965. * @private
  29966. */
  29967. PhotoSphereViewer.SYSTEM = {
  29968. loaded: false,
  29969. pixelRatio: 1,
  29970. isWebGLSupported: false,
  29971. isCanvasSupported: false,
  29972. deviceOrientationSupported: null,
  29973. maxTextureWidth: 0,
  29974. mouseWheelEvent: null,
  29975. fullscreenEvent: null
  29976. };
  29977. /**
  29978. * @summary SVG icons sources
  29979. * @type {Object.<string, string>}
  29980. * @readonly
  29981. */
  29982. PhotoSphereViewer.ICONS = {};
  29983. /**
  29984. * @summary Default options, see {@link http://photo-sphere-viewer.js.org/#options}
  29985. * @type {Object}
  29986. * @readonly
  29987. */
  29988. PhotoSphereViewer.DEFAULTS = {
  29989. panorama: null,
  29990. container: null,
  29991. caption: null,
  29992. usexmpdata: true,
  29993. pano_data: null,
  29994. webgl: true,
  29995. min_fov: 30,
  29996. max_fov: 90,
  29997. default_fov: null,
  29998. default_long: 0,
  29999. default_lat: 0,
  30000. sphere_correction: {
  30001. pan: 0,
  30002. tilt: 0,
  30003. roll: 0
  30004. },
  30005. longitude_range: null,
  30006. latitude_range: null,
  30007. move_speed: 1,
  30008. time_anim: 2000,
  30009. anim_speed: '2rpm',
  30010. anim_lat: null,
  30011. fisheye: false,
  30012. navbar: [
  30013. 'autorotate',
  30014. 'zoom',
  30015. 'download',
  30016. 'markers',
  30017. 'caption',
  30018. 'gyroscope',
  30019. 'fullscreen'
  30020. ],
  30021. tooltip: {
  30022. offset: 5,
  30023. arrow_size: 7,
  30024. delay: 100
  30025. },
  30026. lang: {
  30027. autorotate: 'Automatic rotation',
  30028. zoom: 'Zoom',
  30029. zoomOut: 'Zoom out',
  30030. zoomIn: 'Zoom in',
  30031. download: 'Download',
  30032. fullscreen: 'Fullscreen',
  30033. markers: 'Markers',
  30034. gyroscope: 'Gyroscope'
  30035. },
  30036. mousewheel: true,
  30037. mousewheel_factor: 1,
  30038. mousemove: true,
  30039. mousemove_hover: false,
  30040. keyboard: true,
  30041. gyroscope: false,
  30042. move_inertia: true,
  30043. click_event_on_marker: false,
  30044. transition: {
  30045. duration: 1500,
  30046. loader: true
  30047. },
  30048. loading_img: null,
  30049. loading_txt: 'Loading...',
  30050. size: null,
  30051. cache_texture: 0,
  30052. templates: {},
  30053. markers: []
  30054. };
  30055. /**
  30056. * @summary doT.js templates
  30057. * @type {Object.<string, string>}
  30058. * @readonly
  30059. */
  30060. PhotoSphereViewer.TEMPLATES = {
  30061. markersList: '\
  30062. <div class="psv-markers-list-container"> \
  30063. <h1 class="psv-markers-list-title">{{= it.config.lang.markers }}</h1> \
  30064. <ul class="psv-markers-list"> \
  30065. {{~ it.markers: marker }} \
  30066. <li data-psv-marker="{{= marker.id }}" class="psv-markers-list-item {{? marker.className }}{{= marker.className }}{{?}}"> \
  30067. {{? marker.image }}<img class="psv-markers-list-image" src="{{= marker.image }}"/>{{?}} \
  30068. <p class="psv-markers-list-name">{{? marker.tooltip }}{{= marker.tooltip.content }}{{?? marker.html }}{{= marker.html }}{{??}}{{= marker.id }}{{?}}</p> \
  30069. </li> \
  30070. {{~}} \
  30071. </ul> \
  30072. </div>'
  30073. };
  30074. /**
  30075. * @summary Adds all needed event listeners
  30076. * @private
  30077. */
  30078. PhotoSphereViewer.prototype._bindEvents = function() {
  30079. window.addEventListener('resize', this);
  30080. // all interation events are binded to the HUD only
  30081. if (this.config.mousemove) {
  30082. this.hud.container.style.cursor = 'move';
  30083. if (this.config.mousemove_hover) {
  30084. this.hud.container.addEventListener('mouseenter', this);
  30085. this.hud.container.addEventListener('mouseleave', this);
  30086. }
  30087. else {
  30088. this.hud.container.addEventListener('mousedown', this);
  30089. window.addEventListener('mouseup', this);
  30090. }
  30091. this.hud.container.addEventListener('touchstart', this);
  30092. window.addEventListener('touchend', this);
  30093. this.hud.container.addEventListener('mousemove', this);
  30094. this.hud.container.addEventListener('touchmove', this);
  30095. }
  30096. if (PhotoSphereViewer.SYSTEM.fullscreenEvent) {
  30097. document.addEventListener(PhotoSphereViewer.SYSTEM.fullscreenEvent, this);
  30098. }
  30099. if (this.config.mousewheel) {
  30100. this.hud.container.addEventListener(PhotoSphereViewer.SYSTEM.mouseWheelEvent, this);
  30101. }
  30102. this.on('_side-reached', function(side) {
  30103. if (this.isAutorotateEnabled()) {
  30104. if (side === 'left' || side === 'right') {
  30105. this._reverseAutorotate();
  30106. }
  30107. }
  30108. });
  30109. };
  30110. /**
  30111. * @summary Removes all event listeners
  30112. * @private
  30113. */
  30114. PhotoSphereViewer.prototype._unbindEvents = function() {
  30115. window.removeEventListener('resize', this);
  30116. if (this.config.mousemove) {
  30117. this.hud.container.removeEventListener('mousedown', this);
  30118. this.hud.container.removeEventListener('mouseenter', this);
  30119. this.hud.container.removeEventListener('touchstart', this);
  30120. window.removeEventListener('mouseup', this);
  30121. window.removeEventListener('touchend', this);
  30122. this.hud.container.removeEventListener('mouseleave', this);
  30123. this.hud.container.removeEventListener('mousemove', this);
  30124. this.hud.container.removeEventListener('touchmove', this);
  30125. }
  30126. if (PhotoSphereViewer.SYSTEM.fullscreenEvent) {
  30127. document.removeEventListener(PhotoSphereViewer.SYSTEM.fullscreenEvent, this);
  30128. }
  30129. if (this.config.mousewheel) {
  30130. this.hud.container.removeEventListener(PhotoSphereViewer.SYSTEM.mouseWheelEvent, this);
  30131. }
  30132. this.off('_side-reached');
  30133. };
  30134. /**
  30135. * @summary Handles events
  30136. * @param {Event} evt
  30137. * @private
  30138. */
  30139. PhotoSphereViewer.prototype.handleEvent = function(evt) {
  30140. switch (evt.type) {
  30141. // @formatter:off
  30142. case 'resize': PSVUtils.throttle(this._onResize(), 50); break;
  30143. case 'keydown': this._onKeyDown(evt); break;
  30144. case 'mousedown': this._onMouseDown(evt); break;
  30145. case 'mouseenter': this._onMouseDown(evt); break;
  30146. case 'touchstart': this._onTouchStart(evt); break;
  30147. case 'mouseup': this._onMouseUp(evt); break;
  30148. case 'mouseleave': this._onMouseUp(evt); break;
  30149. case 'touchend': this._onTouchEnd(evt); break;
  30150. case 'mousemove': this._onMouseMove(evt); break;
  30151. case 'touchmove': this._onTouchMove(evt); break;
  30152. case PhotoSphereViewer.SYSTEM.fullscreenEvent: this._fullscreenToggled(); break;
  30153. case PhotoSphereViewer.SYSTEM.mouseWheelEvent: this._onMouseWheel(evt); break;
  30154. // @formatter:on
  30155. }
  30156. };
  30157. /**
  30158. * @summary Resizes the canvas when the window is resized
  30159. * @fires PhotoSphereViewer.size-updated
  30160. * @private
  30161. */
  30162. PhotoSphereViewer.prototype._onResize = function() {
  30163. if (this.container.clientWidth !== this.prop.size.width || this.container.clientHeight !== this.prop.size.height) {
  30164. this.prop.size.width = parseInt(this.container.clientWidth);
  30165. this.prop.size.height = parseInt(this.container.clientHeight);
  30166. this.prop.aspect = this.prop.size.width / this.prop.size.height;
  30167. if (this.renderer) {
  30168. this.renderer.setSize(this.prop.size.width, this.prop.size.height);
  30169. this.render();
  30170. }
  30171. /**
  30172. * @event size-updated
  30173. * @memberof PhotoSphereViewer
  30174. * @summary Triggered when the viewer size changes
  30175. * @param {PhotoSphereViewer.Size} size
  30176. */
  30177. this.trigger('size-updated', this.getSize());
  30178. }
  30179. };
  30180. /**
  30181. * @summary Handles keyboard events
  30182. * @param {KeyboardEvent} evt
  30183. * @private
  30184. */
  30185. PhotoSphereViewer.prototype._onKeyDown = function(evt) {
  30186. var dLong = 0;
  30187. var dLat = 0;
  30188. var dZoom = 0;
  30189. var key = evt.key || PhotoSphereViewer.KEYMAP[evt.keyCode || evt.which];
  30190. switch (key) {
  30191. // @formatter:off
  30192. case 'ArrowUp': dLat = 0.01; break;
  30193. case 'ArrowDown': dLat = -0.01; break;
  30194. case 'ArrowRight': dLong = 0.01; break;
  30195. case 'ArrowLeft': dLong = -0.01; break;
  30196. case 'PageUp':case '+': dZoom = 1; break;
  30197. case 'PageDown':case '-': dZoom = -1; break;
  30198. // @formatter:on
  30199. }
  30200. if (dZoom !== 0) {
  30201. this.zoom(this.prop.zoom_lvl + dZoom);
  30202. }
  30203. else if (dLat !== 0 || dLong !== 0) {
  30204. this.rotate({
  30205. longitude: this.prop.longitude + dLong * this.prop.move_speed * this.prop.hFov,
  30206. latitude: this.prop.latitude + dLat * this.prop.move_speed * this.prop.vFov
  30207. });
  30208. }
  30209. };
  30210. /**
  30211. * @summary Handles mouse button events
  30212. * @param {MouseEvent} evt
  30213. * @private
  30214. */
  30215. PhotoSphereViewer.prototype._onMouseDown = function(evt) {
  30216. this._startMove(evt);
  30217. };
  30218. /**
  30219. * @summary Handles mouse buttons events
  30220. * @param {MouseEvent} evt
  30221. * @private
  30222. */
  30223. PhotoSphereViewer.prototype._onMouseUp = function(evt) {
  30224. this._stopMove(evt);
  30225. };
  30226. /**
  30227. * @summary Handles mouse move events
  30228. * @param {MouseEvent} evt
  30229. * @private
  30230. */
  30231. PhotoSphereViewer.prototype._onMouseMove = function(evt) {
  30232. if (evt.buttons !== 0) {
  30233. evt.preventDefault();
  30234. this._move(evt);
  30235. }
  30236. else if (this.config.mousemove_hover) {
  30237. this._moveAbsolute(evt);
  30238. }
  30239. };
  30240. /**
  30241. * @summary Handles touch events
  30242. * @param {TouchEvent} evt
  30243. * @private
  30244. */
  30245. PhotoSphereViewer.prototype._onTouchStart = function(evt) {
  30246. if (evt.touches.length === 1) {
  30247. this._startMove(evt.touches[0]);
  30248. }
  30249. else if (evt.touches.length === 2) {
  30250. this._startZoom(evt);
  30251. }
  30252. };
  30253. /**
  30254. * @summary Handles touch events
  30255. * @param {TouchEvent} evt
  30256. * @private
  30257. */
  30258. PhotoSphereViewer.prototype._onTouchEnd = function(evt) {
  30259. this._stopMove(evt.changedTouches[0]);
  30260. };
  30261. /**
  30262. * @summary Handles touch move events
  30263. * @param {TouchEvent} evt
  30264. * @private
  30265. */
  30266. PhotoSphereViewer.prototype._onTouchMove = function(evt) {
  30267. if (evt.touches.length === 1) {
  30268. evt.preventDefault();
  30269. this._move(evt.touches[0]);
  30270. }
  30271. else if (evt.touches.length === 2) {
  30272. evt.preventDefault();
  30273. this._zoom(evt);
  30274. }
  30275. };
  30276. /**
  30277. * @summary Initializes the movement
  30278. * @param {MouseEvent|Touch} evt
  30279. * @private
  30280. */
  30281. PhotoSphereViewer.prototype._startMove = function(evt) {
  30282. this.stopAutorotate();
  30283. this.stopAnimation();
  30284. this.prop.mouse_x = this.prop.start_mouse_x = parseInt(evt.clientX);
  30285. this.prop.mouse_y = this.prop.start_mouse_y = parseInt(evt.clientY);
  30286. this.prop.moving = true;
  30287. this.prop.zooming = false;
  30288. this.prop.mouse_history.length = 0;
  30289. this._logMouseMove(evt);
  30290. };
  30291. /**
  30292. * @summary Initializes the zoom
  30293. * @param {TouchEvent} evt
  30294. * @private
  30295. */
  30296. PhotoSphereViewer.prototype._startZoom = function(evt) {
  30297. var t = [
  30298. { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) },
  30299. { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) }
  30300. ];
  30301. this.prop.pinch_dist = Math.sqrt(Math.pow(t[0].x - t[1].x, 2) + Math.pow(t[0].y - t[1].y, 2));
  30302. this.prop.moving = false;
  30303. this.prop.zooming = true;
  30304. };
  30305. /**
  30306. * @summary Stops the movement
  30307. * @description If the move threshold was not reached a click event is triggered, otherwise an animation is launched to simulate inertia
  30308. * @param {MouseEvent|Touch} evt
  30309. * @private
  30310. */
  30311. PhotoSphereViewer.prototype._stopMove = function(evt) {
  30312. if (!PSVUtils.getClosest(evt.target, '.psv-hud')) {
  30313. return;
  30314. }
  30315. if (this.prop.moving) {
  30316. // move threshold to trigger a click
  30317. if (Math.abs(evt.clientX - this.prop.start_mouse_x) < PhotoSphereViewer.MOVE_THRESHOLD && Math.abs(evt.clientY - this.prop.start_mouse_y) < PhotoSphereViewer.MOVE_THRESHOLD) {
  30318. this._click(evt);
  30319. this.prop.moving = false;
  30320. }
  30321. // inertia animation
  30322. else if (this.config.move_inertia && !this.isGyroscopeEnabled()) {
  30323. this._logMouseMove(evt);
  30324. this._stopMoveInertia(evt);
  30325. }
  30326. else {
  30327. this.prop.moving = false;
  30328. }
  30329. this.prop.mouse_history.length = 0;
  30330. }
  30331. this.prop.zooming = false;
  30332. };
  30333. /**
  30334. * @summary Performs an animation to simulate inertia when the movement stops
  30335. * @param {MouseEvent|Touch} evt
  30336. * @private
  30337. */
  30338. PhotoSphereViewer.prototype._stopMoveInertia = function(evt) {
  30339. var direction = {
  30340. x: evt.clientX - this.prop.mouse_history[0][1],
  30341. y: evt.clientY - this.prop.mouse_history[0][2]
  30342. };
  30343. var norm = Math.sqrt(direction.x * direction.x + direction.y * direction.y);
  30344. this.prop.animation_promise = PSVUtils.animation({
  30345. properties: {
  30346. clientX: { start: evt.clientX, end: evt.clientX + direction.x },
  30347. clientY: { start: evt.clientY, end: evt.clientY + direction.y }
  30348. },
  30349. duration: norm * PhotoSphereViewer.INERTIA_WINDOW / 100,
  30350. easing: 'outCirc',
  30351. onTick: function(properties) {
  30352. this._move(properties, false);
  30353. }.bind(this)
  30354. })
  30355. .ensure(function() {
  30356. this.prop.moving = false;
  30357. }.bind(this));
  30358. };
  30359. /**
  30360. * @summary Triggers an event with all coordinates when a simple click is performed
  30361. * @param {MouseEvent|Touch} evt
  30362. * @fires PhotoSphereViewer.click
  30363. * @fires PhotoSphereViewer.dblclick
  30364. * @private
  30365. */
  30366. PhotoSphereViewer.prototype._click = function(evt) {
  30367. var boundingRect = this.container.getBoundingClientRect();
  30368. var data = {
  30369. target: evt.target,
  30370. client_x: evt.clientX,
  30371. client_y: evt.clientY,
  30372. viewer_x: parseInt(evt.clientX - boundingRect.left),
  30373. viewer_y: parseInt(evt.clientY - boundingRect.top)
  30374. };
  30375. var intersect = this.viewerCoordsToVector3({ x: data.viewer_x, y: data.viewer_y });
  30376. if (intersect) {
  30377. var sphericalCoords = this.vector3ToSphericalCoords(intersect);
  30378. data.longitude = sphericalCoords.longitude;
  30379. data.latitude = sphericalCoords.latitude;
  30380. // TODO: for cubemap, computes texture's index and coordinates
  30381. if (!this.prop.isCubemap) {
  30382. var textureCoords = this.sphericalCoordsToTextureCoords({ longitude: data.longitude, latitude: data.latitude });
  30383. data.texture_x = textureCoords.x;
  30384. data.texture_y = textureCoords.y;
  30385. }
  30386. if (!this.prop.dblclick_timeout) {
  30387. /**
  30388. * @event click
  30389. * @memberof PhotoSphereViewer
  30390. * @summary Triggered when the user clicks on the viewer (everywhere excluding the navbar and the side panel)
  30391. * @param {PhotoSphereViewer.ClickData} data
  30392. */
  30393. this.trigger('click', data);
  30394. this.prop.dblclick_data = PSVUtils.clone(data);
  30395. this.prop.dblclick_timeout = setTimeout(function() {
  30396. this.prop.dblclick_timeout = null;
  30397. this.prop.dblclick_data = null;
  30398. }.bind(this), PhotoSphereViewer.DBLCLICK_DELAY);
  30399. }
  30400. else {
  30401. if (Math.abs(this.prop.dblclick_data.client_x - data.client_x) < PhotoSphereViewer.MOVE_THRESHOLD &&
  30402. Math.abs(this.prop.dblclick_data.client_y - data.client_y) < PhotoSphereViewer.MOVE_THRESHOLD) {
  30403. /**
  30404. * @event dblclick
  30405. * @memberof PhotoSphereViewer
  30406. * @summary Triggered when the user double clicks on the viewer. The simple `click` event is always fired before `dblclick`
  30407. * @param {PhotoSphereViewer.ClickData} data
  30408. */
  30409. this.trigger('dblclick', this.prop.dblclick_data);
  30410. }
  30411. clearTimeout(this.prop.dblclick_timeout);
  30412. this.prop.dblclick_timeout = null;
  30413. this.prop.dblclick_data = null;
  30414. }
  30415. }
  30416. };
  30417. /**
  30418. * @summary Performs movement
  30419. * @param {MouseEvent|Touch} evt
  30420. * @param {boolean} [log=true]
  30421. * @private
  30422. */
  30423. PhotoSphereViewer.prototype._move = function(evt, log) {
  30424. if (this.prop.moving) {
  30425. var x = parseInt(evt.clientX);
  30426. var y = parseInt(evt.clientY);
  30427. var rotation = {
  30428. longitude: (x - this.prop.mouse_x) / this.prop.size.width * this.prop.move_speed * this.prop.hFov * PhotoSphereViewer.SYSTEM.pixelRatio,
  30429. latitude: (y - this.prop.mouse_y) / this.prop.size.height * this.prop.move_speed * this.prop.vFov * PhotoSphereViewer.SYSTEM.pixelRatio
  30430. };
  30431. if (this.isGyroscopeEnabled()) {
  30432. this.prop.gyro_alpha_offset += rotation.longitude;
  30433. }
  30434. else {
  30435. this.rotate({
  30436. longitude: this.prop.longitude - rotation.longitude,
  30437. latitude: this.prop.latitude + rotation.latitude
  30438. });
  30439. }
  30440. this.prop.mouse_x = x;
  30441. this.prop.mouse_y = y;
  30442. if (log !== false) {
  30443. this._logMouseMove(evt);
  30444. }
  30445. }
  30446. };
  30447. /**
  30448. * @summary Performs movement absolute to cursor position in viewer
  30449. * @param {MouseEvent} evt
  30450. * @private
  30451. */
  30452. PhotoSphereViewer.prototype._moveAbsolute = function(evt) {
  30453. if (this.prop.moving) {
  30454. this.rotate({
  30455. longitude: ((evt.clientX - this.container.offsetLeft) / this.container.offsetWidth - 0.5) * PSVUtils.TwoPI,
  30456. latitude: -((evt.clientY - this.container.offsetTop) / this.container.offsetHeight - 0.5) * Math.PI
  30457. });
  30458. }
  30459. };
  30460. /**
  30461. * @summary Perfoms zoom
  30462. * @param {TouchEvent} evt
  30463. * @private
  30464. */
  30465. PhotoSphereViewer.prototype._zoom = function(evt) {
  30466. if (this.prop.zooming) {
  30467. var t = [
  30468. { x: parseInt(evt.touches[0].clientX), y: parseInt(evt.touches[0].clientY) },
  30469. { x: parseInt(evt.touches[1].clientX), y: parseInt(evt.touches[1].clientY) }
  30470. ];
  30471. var p = Math.sqrt(Math.pow(t[0].x - t[1].x, 2) + Math.pow(t[0].y - t[1].y, 2));
  30472. var delta = 80 * (p - this.prop.pinch_dist) / this.prop.size.width;
  30473. this.zoom(this.prop.zoom_lvl + delta);
  30474. this.prop.pinch_dist = p;
  30475. }
  30476. };
  30477. /**
  30478. * @summary Handles mouse wheel events
  30479. * @param {MouseWheelEvent} evt
  30480. * @private
  30481. */
  30482. PhotoSphereViewer.prototype._onMouseWheel = function(evt) {
  30483. evt.preventDefault();
  30484. evt.stopPropagation();
  30485. var delta = PSVUtils.normalizeWheel(evt).spinY * 5;
  30486. if (delta !== 0) {
  30487. this.zoom(this.prop.zoom_lvl - delta * this.config.mousewheel_factor);
  30488. }
  30489. };
  30490. /**
  30491. * @summary Handles fullscreen events
  30492. * @fires PhotoSphereViewer.fullscreen-updated
  30493. * @private
  30494. */
  30495. PhotoSphereViewer.prototype._fullscreenToggled = function() {
  30496. var enabled = this.isFullscreenEnabled();
  30497. if (this.config.keyboard) {
  30498. if (enabled) {
  30499. this.startKeyboardControl();
  30500. }
  30501. else {
  30502. this.stopKeyboardControl();
  30503. }
  30504. }
  30505. /**
  30506. * @event fullscreen-updated
  30507. * @memberof PhotoSphereViewer
  30508. * @summary Triggered when the fullscreen mode is enabled/disabled
  30509. * @param {boolean} enabled
  30510. */
  30511. this.trigger('fullscreen-updated', enabled);
  30512. };
  30513. /**
  30514. * @summary Stores each mouse position during a mouse move
  30515. * @description Positions older than "INERTIA_WINDOW" are removed<br>
  30516. * Positions before a pause of "INERTIA_WINDOW" / 10 are removed
  30517. * @param {MouseEvent|Touch} evt
  30518. * @private
  30519. */
  30520. PhotoSphereViewer.prototype._logMouseMove = function(evt) {
  30521. var now = Date.now();
  30522. this.prop.mouse_history.push([now, evt.clientX, evt.clientY]);
  30523. var previous = null;
  30524. for (var i = 0; i < this.prop.mouse_history.length;) {
  30525. if (this.prop.mouse_history[0][i] < now - PhotoSphereViewer.INERTIA_WINDOW) {
  30526. this.prop.mouse_history.splice(i, 1);
  30527. }
  30528. else if (previous && this.prop.mouse_history[0][i] - previous > PhotoSphereViewer.INERTIA_WINDOW / 10) {
  30529. this.prop.mouse_history.splice(0, i);
  30530. i = 0;
  30531. previous = this.prop.mouse_history[0][i];
  30532. }
  30533. else {
  30534. i++;
  30535. previous = this.prop.mouse_history[0][i];
  30536. }
  30537. }
  30538. };
  30539. /**
  30540. * @summary Starts to load the panorama
  30541. * @returns {Promise}
  30542. * @throws {PSVError} when the panorama is not configured
  30543. */
  30544. PhotoSphereViewer.prototype.load = function() {
  30545. if (!this.config.panorama) {
  30546. throw new PSVError('No value given for panorama.');
  30547. }
  30548. return this.setPanorama(this.config.panorama, false);
  30549. };
  30550. /**
  30551. * @summary Returns the current position of the camera
  30552. * @returns {PhotoSphereViewer.Position}
  30553. */
  30554. PhotoSphereViewer.prototype.getPosition = function() {
  30555. return {
  30556. longitude: this.prop.longitude,
  30557. latitude: this.prop.latitude
  30558. };
  30559. };
  30560. /**
  30561. * @summary Returns the current zoom level
  30562. * @returns {int}
  30563. */
  30564. PhotoSphereViewer.prototype.getZoomLevel = function() {
  30565. return this.prop.zoom_lvl;
  30566. };
  30567. /**
  30568. * @summary Returns the current viewer size
  30569. * @returns {PhotoSphereViewer.Size}
  30570. */
  30571. PhotoSphereViewer.prototype.getSize = function() {
  30572. return {
  30573. width: this.prop.size.width,
  30574. height: this.prop.size.height
  30575. };
  30576. };
  30577. /**
  30578. * @summary Checks if the automatic rotation is enabled
  30579. * @returns {boolean}
  30580. */
  30581. PhotoSphereViewer.prototype.isAutorotateEnabled = function() {
  30582. return !!this.prop.autorotate_reqid;
  30583. };
  30584. /**
  30585. * @summary Checks if the gyroscope is enabled
  30586. * @returns {boolean}
  30587. */
  30588. PhotoSphereViewer.prototype.isGyroscopeEnabled = function() {
  30589. return !!this.prop.orientation_reqid;
  30590. };
  30591. /**
  30592. * @summary Checks if the viewer is in fullscreen
  30593. * @returns {boolean}
  30594. */
  30595. PhotoSphereViewer.prototype.isFullscreenEnabled = function() {
  30596. return PSVUtils.isFullscreenEnabled(this.container);
  30597. };
  30598. /**
  30599. * @summary Performs a render
  30600. * @param {boolean} [updateDirection=true] - should update camera direction
  30601. * @fires PhotoSphereViewer.render
  30602. */
  30603. PhotoSphereViewer.prototype.render = function(updateDirection) {
  30604. if (updateDirection !== false) {
  30605. this.prop.direction = this.sphericalCoordsToVector3(this.prop);
  30606. }
  30607. this.camera.position.set(0, 0, 0);
  30608. this.camera.lookAt(this.prop.direction);
  30609. if (this.config.fisheye) {
  30610. this.camera.position.copy(this.prop.direction).multiplyScalar(this.config.fisheye / 2).negate();
  30611. }
  30612. this.camera.aspect = this.prop.aspect;
  30613. this.camera.fov = this.prop.vFov;
  30614. this.camera.updateProjectionMatrix();
  30615. this.renderer.render(this.scene, this.camera);
  30616. /**
  30617. * @event render
  30618. * @memberof PhotoSphereViewer
  30619. * @summary Triggered on each viewer render, **this event is triggered very often**
  30620. */
  30621. this.trigger('render');
  30622. };
  30623. /**
  30624. * @summary Destroys the viewer
  30625. * @description The memory used by the ThreeJS context is not totally cleared. This will be fixed as soon as possible.
  30626. */
  30627. PhotoSphereViewer.prototype.destroy = function() {
  30628. this._stopAll();
  30629. this.stopKeyboardControl();
  30630. if (this.isFullscreenEnabled()) {
  30631. PSVUtils.exitFullscreen();
  30632. }
  30633. // remove listeners
  30634. this._unbindEvents();
  30635. // destroy components
  30636. if (this.tooltip) {
  30637. this.tooltip.destroy();
  30638. }
  30639. if (this.hud) {
  30640. this.hud.destroy();
  30641. }
  30642. if (this.loader) {
  30643. this.loader.destroy();
  30644. }
  30645. if (this.navbar) {
  30646. this.navbar.destroy();
  30647. }
  30648. if (this.panel) {
  30649. this.panel.destroy();
  30650. }
  30651. if (this.doControls) {
  30652. this.doControls.disconnect();
  30653. }
  30654. // destroy ThreeJS view
  30655. if (this.scene) {
  30656. PSVUtils.cleanTHREEScene(this.scene);
  30657. }
  30658. // remove container
  30659. if (this.canvas_container) {
  30660. this.container.removeChild(this.canvas_container);
  30661. }
  30662. this.parent.removeChild(this.container);
  30663. delete this.parent.photoSphereViewer;
  30664. // clean references
  30665. delete this.parent;
  30666. delete this.container;
  30667. delete this.loader;
  30668. delete this.navbar;
  30669. delete this.hud;
  30670. delete this.panel;
  30671. delete this.tooltip;
  30672. delete this.canvas_container;
  30673. delete this.renderer;
  30674. delete this.scene;
  30675. delete this.camera;
  30676. delete this.mesh;
  30677. delete this.doControls;
  30678. delete this.raycaster;
  30679. delete this.passes;
  30680. delete this.config;
  30681. this.prop.cache.length = 0;
  30682. };
  30683. /**
  30684. * @summary Loads a new panorama file
  30685. * @description Loads a new panorama file, optionally changing the camera position and activating the transition animation.<br>
  30686. * If the "position" is not defined, the camera will not move and the ongoing animation will continue<br>
  30687. * "config.transition" must be configured for "transition" to be taken in account
  30688. * @param {string|string[]} path - URL of the new panorama file
  30689. * @param {PhotoSphereViewer.ExtendedPosition} [position]
  30690. * @param {boolean} [transition=false]
  30691. * @returns {Promise}
  30692. * @throws {PSVError} when another panorama is already loading
  30693. */
  30694. PhotoSphereViewer.prototype.setPanorama = function(path, position, transition) {
  30695. if (this.prop.loading_promise !== null) {
  30696. throw new PSVError('Loading already in progress');
  30697. }
  30698. if (typeof position === 'boolean') {
  30699. transition = position;
  30700. position = undefined;
  30701. }
  30702. if (transition && this.prop.isCubemap) {
  30703. throw new PSVError('Transition is not available with cubemap.');
  30704. }
  30705. if (position) {
  30706. this.cleanPosition(position);
  30707. this._stopAll();
  30708. }
  30709. this.config.panorama = path;
  30710. if (!transition || !this.config.transition || !this.scene) {
  30711. this.loader.show();
  30712. if (this.canvas_container) {
  30713. this.canvas_container.style.opacity = 0;
  30714. }
  30715. this.prop.loading_promise = this._loadTexture(this.config.panorama)
  30716. .then(function(texture) {
  30717. this._setTexture(texture);
  30718. if (position) {
  30719. this.rotate(position);
  30720. }
  30721. }.bind(this))
  30722. .ensure(function() {
  30723. this.loader.hide();
  30724. this.canvas_container.style.opacity = 1;
  30725. this.prop.loading_promise = null;
  30726. }.bind(this))
  30727. .rethrow();
  30728. }
  30729. else {
  30730. if (this.config.transition.loader) {
  30731. this.loader.show();
  30732. }
  30733. this.prop.loading_promise = this._loadTexture(this.config.panorama)
  30734. .then(function(texture) {
  30735. this.loader.hide();
  30736. return this._transition(texture, position);
  30737. }.bind(this))
  30738. .ensure(function() {
  30739. this.loader.hide();
  30740. this.prop.loading_promise = null;
  30741. }.bind(this))
  30742. .rethrow();
  30743. }
  30744. return this.prop.loading_promise;
  30745. };
  30746. /**
  30747. * @summary Starts the automatic rotation
  30748. * @fires PhotoSphereViewer.autorotate
  30749. */
  30750. PhotoSphereViewer.prototype.startAutorotate = function() {
  30751. this._stopAll();
  30752. var last;
  30753. var elapsed;
  30754. var run = function (timestamp) {
  30755. if (timestamp) {
  30756. elapsed = last === undefined ? 0 : timestamp - last;
  30757. last = timestamp;
  30758. this.rotate({
  30759. longitude: this.prop.longitude + this.config.anim_speed * elapsed / 1000,
  30760. latitude: this.prop.latitude - (this.prop.latitude - this.config.anim_lat) / 200
  30761. });
  30762. }
  30763. this.prop.autorotate_reqid = window.requestAnimationFrame(run);
  30764. }.bind(this);
  30765. run();
  30766. /**
  30767. * @event autorotate
  30768. * @memberof PhotoSphereViewer
  30769. * @summary Triggered when the automatic rotation is enabled/disabled
  30770. * @param {boolean} enabled
  30771. */
  30772. this.trigger('autorotate', true);
  30773. };
  30774. /**
  30775. * @summary Stops the automatic rotation
  30776. * @fires PhotoSphereViewer.autorotate
  30777. */
  30778. PhotoSphereViewer.prototype.stopAutorotate = function() {
  30779. if (this.prop.start_timeout) {
  30780. window.clearTimeout(this.prop.start_timeout);
  30781. this.prop.start_timeout = null;
  30782. }
  30783. if (this.prop.autorotate_reqid) {
  30784. window.cancelAnimationFrame(this.prop.autorotate_reqid);
  30785. this.prop.autorotate_reqid = null;
  30786. this.trigger('autorotate', false);
  30787. }
  30788. };
  30789. /**
  30790. * @summary Starts or stops the automatic rotation
  30791. */
  30792. PhotoSphereViewer.prototype.toggleAutorotate = function() {
  30793. if (this.isAutorotateEnabled()) {
  30794. this.stopAutorotate();
  30795. }
  30796. else {
  30797. this.startAutorotate();
  30798. }
  30799. };
  30800. /**
  30801. * @summary Enables the gyroscope navigation if available
  30802. * @fires PhotoSphereViewer.gyroscope-updated
  30803. */
  30804. PhotoSphereViewer.prototype.startGyroscopeControl = function() {
  30805. if (!this.doControls || !this.doControls.enabled) {
  30806. console.warn('PhotoSphereViewer: gyroscope disabled');
  30807. return;
  30808. }
  30809. PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then(
  30810. PhotoSphereViewer.prototype._startGyroscopeControl.bind(this),
  30811. function() {
  30812. console.warn('PhotoSphereViewer: gyroscope not available');
  30813. }
  30814. );
  30815. };
  30816. /**
  30817. * @summary Immediately enables the gyroscope navigation
  30818. * @description Do not call this method directly, call `startGyroscopeControl` instead
  30819. * @fires PhotoSphereViewer.gyroscope-updated
  30820. * @private
  30821. */
  30822. PhotoSphereViewer.prototype._startGyroscopeControl = function() {
  30823. this._stopAll();
  30824. // compute the alpha offset to keep the current orientation
  30825. this.doControls.alphaOffset = this.prop.longitude;
  30826. this.doControls.update();
  30827. var direction = this.camera.getWorldDirection(new THREE.Vector3());
  30828. var sphericalCoords = this.vector3ToSphericalCoords(direction);
  30829. this.prop.gyro_alpha_offset = sphericalCoords.longitude;
  30830. var run = function() {
  30831. this.doControls.alphaOffset = this.prop.gyro_alpha_offset;
  30832. this.doControls.update();
  30833. this.camera.getWorldDirection(this.prop.direction);
  30834. this.prop.direction.multiplyScalar(PhotoSphereViewer.SPHERE_RADIUS);
  30835. var sphericalCoords = this.vector3ToSphericalCoords(this.prop.direction);
  30836. this.prop.longitude = sphericalCoords.longitude;
  30837. this.prop.latitude = sphericalCoords.latitude;
  30838. this.render(false);
  30839. this.prop.orientation_reqid = window.requestAnimationFrame(run);
  30840. }.bind(this);
  30841. run();
  30842. /**
  30843. * @event gyroscope-updated
  30844. * @memberof PhotoSphereViewer
  30845. * @summary Triggered when the gyroscope mode is enabled/disabled
  30846. * @param {boolean} enabled
  30847. */
  30848. this.trigger('gyroscope-updated', true);
  30849. };
  30850. /**
  30851. * @summary Disables the gyroscope navigation
  30852. * @fires PhotoSphereViewer.gyroscope-updated
  30853. */
  30854. PhotoSphereViewer.prototype.stopGyroscopeControl = function() {
  30855. if (this.prop.orientation_reqid) {
  30856. window.cancelAnimationFrame(this.prop.orientation_reqid);
  30857. this.prop.orientation_reqid = null;
  30858. this.trigger('gyroscope-updated', false);
  30859. this.render();
  30860. }
  30861. };
  30862. /**
  30863. * @summary Enables or disables the gyroscope navigation
  30864. */
  30865. PhotoSphereViewer.prototype.toggleGyroscopeControl = function() {
  30866. if (this.isGyroscopeEnabled()) {
  30867. this.stopGyroscopeControl();
  30868. }
  30869. else {
  30870. this.startGyroscopeControl();
  30871. }
  30872. };
  30873. /**
  30874. * @summary Rotates the view to specific longitude and latitude
  30875. * @param {PhotoSphereViewer.ExtendedPosition} position
  30876. * @param {boolean} [render=true]
  30877. * @fires PhotoSphereViewer._side-reached
  30878. * @fires PhotoSphereViewer.position-updated
  30879. */
  30880. PhotoSphereViewer.prototype.rotate = function(position, render) {
  30881. this.cleanPosition(position);
  30882. /**
  30883. * @event _side-reached
  30884. * @memberof PhotoSphereViewer
  30885. * @param {string} side
  30886. * @private
  30887. */
  30888. this.applyRanges(position).forEach(
  30889. this.trigger.bind(this, '_side-reached')
  30890. );
  30891. this.prop.longitude = position.longitude;
  30892. this.prop.latitude = position.latitude;
  30893. if (render !== false && this.renderer) {
  30894. this.render();
  30895. /**
  30896. * @event position-updated
  30897. * @memberof PhotoSphereViewer
  30898. * @summary Triggered when the view longitude and/or latitude changes
  30899. * @param {PhotoSphereViewer.Position} position
  30900. */
  30901. this.trigger('position-updated', this.getPosition());
  30902. }
  30903. };
  30904. /**
  30905. * @summary Rotates the view to specific longitude and latitude with a smooth animation
  30906. * @param {PhotoSphereViewer.ExtendedPosition} position
  30907. * @param {string|int} duration - animation speed or duration (in milliseconds)
  30908. * @returns {Promise}
  30909. */
  30910. PhotoSphereViewer.prototype.animate = function(position, duration) {
  30911. this._stopAll();
  30912. this.cleanPosition(position);
  30913. if (!duration || Math.abs(position.longitude - this.prop.longitude) < PhotoSphereViewer.ANGLE_THRESHOLD && Math.abs(position.latitude - this.prop.latitude) < PhotoSphereViewer.ANGLE_THRESHOLD) {
  30914. this.rotate(position);
  30915. return D.resolved();
  30916. }
  30917. this.applyRanges(position).forEach(
  30918. this.trigger.bind(this, '_side-reached')
  30919. );
  30920. if (!duration && typeof duration !== 'number') {
  30921. // desired radial speed
  30922. duration = duration ? PSVUtils.parseSpeed(duration) : this.config.anim_speed;
  30923. // get the angle between current position and target
  30924. var angle = Math.acos(
  30925. Math.cos(this.prop.latitude) * Math.cos(position.latitude) * Math.cos(this.prop.longitude - position.longitude) +
  30926. Math.sin(this.prop.latitude) * Math.sin(position.latitude)
  30927. );
  30928. // compute duration
  30929. duration = angle / duration * 1000;
  30930. }
  30931. // longitude offset for shortest arc
  30932. var tOffset = PSVUtils.getShortestArc(this.prop.longitude, position.longitude);
  30933. this.prop.animation_promise = PSVUtils.animation({
  30934. properties: {
  30935. longitude: { start: this.prop.longitude, end: this.prop.longitude + tOffset },
  30936. latitude: { start: this.prop.latitude, end: position.latitude }
  30937. },
  30938. duration: duration,
  30939. easing: 'inOutSine',
  30940. onTick: this.rotate.bind(this)
  30941. });
  30942. return this.prop.animation_promise;
  30943. };
  30944. /**
  30945. * @summary Stops the ongoing animation
  30946. */
  30947. PhotoSphereViewer.prototype.stopAnimation = function() {
  30948. if (this.prop.animation_promise) {
  30949. this.prop.animation_promise.cancel();
  30950. this.prop.animation_promise = null;
  30951. }
  30952. };
  30953. /**
  30954. * @summary Zooms to a specific level between `max_fov` and `min_fov`
  30955. * @param {int} level - new zoom level from 0 to 100
  30956. * @param {boolean} [render=true]
  30957. * @fires PhotoSphereViewer.zoom-updated
  30958. */
  30959. PhotoSphereViewer.prototype.zoom = function(level, render) {
  30960. this.prop.zoom_lvl = PSVUtils.bound(Math.round(level), 0, 100);
  30961. this.prop.vFov = this.config.max_fov + (this.prop.zoom_lvl / 100) * (this.config.min_fov - this.config.max_fov);
  30962. this.prop.hFov = THREE.Math.radToDeg(2 * Math.atan(Math.tan(THREE.Math.degToRad(this.prop.vFov) / 2) * this.prop.aspect));
  30963. if (render !== false && this.renderer) {
  30964. this.render();
  30965. /**
  30966. * @event zoom-updated
  30967. * @memberof PhotoSphereViewer
  30968. * @summary Triggered when the zoom level changes
  30969. * @param {int} zoomLevel
  30970. */
  30971. this.trigger('zoom-updated', this.getZoomLevel());
  30972. }
  30973. };
  30974. /**
  30975. * @summary Increases the zoom level by 1
  30976. */
  30977. PhotoSphereViewer.prototype.zoomIn = function() {
  30978. if (this.prop.zoom_lvl < 100) {
  30979. this.zoom(this.prop.zoom_lvl + 1);
  30980. }
  30981. };
  30982. /**
  30983. * @summary Decreases the zoom level by 1
  30984. */
  30985. PhotoSphereViewer.prototype.zoomOut = function() {
  30986. if (this.prop.zoom_lvl > 0) {
  30987. this.zoom(this.prop.zoom_lvl - 1);
  30988. }
  30989. };
  30990. /**
  30991. * @summary Resizes the viewer
  30992. * @param {PhotoSphereViewer.CssSize} size
  30993. */
  30994. PhotoSphereViewer.prototype.resize = function(size) {
  30995. if (size.width) {
  30996. this.container.style.width = size.width;
  30997. }
  30998. if (size.height) {
  30999. this.container.style.height = size.height;
  31000. }
  31001. this._onResize();
  31002. };
  31003. /**
  31004. * @summary Enters or exits the fullscreen mode
  31005. */
  31006. PhotoSphereViewer.prototype.toggleFullscreen = function() {
  31007. if (!this.isFullscreenEnabled()) {
  31008. PSVUtils.requestFullscreen(this.container);
  31009. }
  31010. else {
  31011. PSVUtils.exitFullscreen();
  31012. }
  31013. };
  31014. /**
  31015. * @summary Enables the keyboard controls (done automatically when entering fullscreen)
  31016. */
  31017. PhotoSphereViewer.prototype.startKeyboardControl = function() {
  31018. window.addEventListener('keydown', this);
  31019. };
  31020. /**
  31021. * @summary Disables the keyboard controls (done automatically when exiting fullscreen)
  31022. */
  31023. PhotoSphereViewer.prototype.stopKeyboardControl = function() {
  31024. window.removeEventListener('keydown', this);
  31025. };
  31026. /**
  31027. * @summary Preload a panorama file without displaying it
  31028. * @param {string} panorama
  31029. * @returns {Promise}
  31030. * @throws {PSVError} when the cache is disabled
  31031. */
  31032. PhotoSphereViewer.prototype.preloadPanorama = function(panorama) {
  31033. if (!this.config.cache_texture) {
  31034. throw new PSVError('Cannot preload panorama, cache_texture is disabled');
  31035. }
  31036. return this._loadTexture(panorama);
  31037. };
  31038. /**
  31039. * @summary Removes a panorama from the cache or clears the entire cache
  31040. * @param {string} [panorama]
  31041. * @throws {PSVError} when the cache is disabled
  31042. */
  31043. PhotoSphereViewer.prototype.clearPanoramaCache = function(panorama) {
  31044. if (!this.config.cache_texture) {
  31045. throw new PSVError('Cannot clear cache, cache_texture is disabled');
  31046. }
  31047. if (panorama) {
  31048. for (var i = 0, l = this.prop.cache.length; i < l; i++) {
  31049. if (this.prop.cache[i].panorama === panorama) {
  31050. this.prop.cache.splice(i, 1);
  31051. break;
  31052. }
  31053. }
  31054. }
  31055. else {
  31056. this.prop.cache.length = 0;
  31057. }
  31058. };
  31059. /**
  31060. * @summary Retrieves the cache for a panorama
  31061. * @param {string} panorama
  31062. * @returns {PhotoSphereViewer.CacheItem}
  31063. * @throws {PSVError} when the cache is disabled
  31064. */
  31065. PhotoSphereViewer.prototype.getPanoramaCache = function(panorama) {
  31066. if (!this.config.cache_texture) {
  31067. throw new PSVError('Cannot query cache, cache_texture is disabled');
  31068. }
  31069. return this.prop.cache.filter(function(cache) {
  31070. return cache.panorama === panorama;
  31071. }).shift();
  31072. };
  31073. /**
  31074. * @summary Inits the global SYSTEM var with generic support information
  31075. * @private
  31076. */
  31077. PhotoSphereViewer._loadSystem = function() {
  31078. var S = PhotoSphereViewer.SYSTEM;
  31079. S.loaded = true;
  31080. S.pixelRatio = window.devicePixelRatio || 1;
  31081. S.isWebGLSupported = PSVUtils.isWebGLSupported();
  31082. S.isCanvasSupported = PSVUtils.isCanvasSupported();
  31083. S.maxTextureWidth = S.isWebGLSupported ? PSVUtils.getMaxTextureWidth() : 4096;
  31084. S.mouseWheelEvent = PSVUtils.mouseWheelEvent();
  31085. S.fullscreenEvent = PSVUtils.fullscreenEvent();
  31086. S.deviceOrientationSupported = PSVUtils.isDeviceOrientationSupported();
  31087. };
  31088. /**
  31089. * @summary Sets the viewer size
  31090. * @param {PhotoSphereViewer.Size} size
  31091. * @private
  31092. */
  31093. PhotoSphereViewer.prototype._setViewerSize = function(size) {
  31094. ['width', 'height'].forEach(function(dim) {
  31095. if (size[dim]) {
  31096. if (/^[0-9.]+$/.test(size[dim])) {
  31097. size[dim] += 'px';
  31098. }
  31099. this.parent.style[dim] = size[dim];
  31100. }
  31101. }, this);
  31102. };
  31103. /**
  31104. * @summary Converts pixel texture coordinates to spherical radians coordinates
  31105. * @param {PhotoSphereViewer.Point} point
  31106. * @returns {PhotoSphereViewer.Position}
  31107. */
  31108. PhotoSphereViewer.prototype.textureCoordsToSphericalCoords = function(point) {
  31109. if (this.prop.isCubemap) {
  31110. throw new PSVError('Unable to use texture coords with cubemap.');
  31111. }
  31112. var relativeX = (point.x + this.prop.pano_data.cropped_x) / this.prop.pano_data.full_width * PSVUtils.TwoPI;
  31113. var relativeY = (point.y + this.prop.pano_data.cropped_y) / this.prop.pano_data.full_height * Math.PI;
  31114. return {
  31115. longitude: relativeX >= Math.PI ? relativeX - Math.PI : relativeX + Math.PI,
  31116. latitude: PSVUtils.HalfPI - relativeY
  31117. };
  31118. };
  31119. /**
  31120. * @summary Converts spherical radians coordinates to pixel texture coordinates
  31121. * @param {PhotoSphereViewer.Position} position
  31122. * @returns {PhotoSphereViewer.Point}
  31123. */
  31124. PhotoSphereViewer.prototype.sphericalCoordsToTextureCoords = function(position) {
  31125. if (this.prop.isCubemap) {
  31126. throw new PSVError('Unable to use texture coords with cubemap.');
  31127. }
  31128. var relativeLong = position.longitude / PSVUtils.TwoPI * this.prop.pano_data.full_width;
  31129. var relativeLat = position.latitude / Math.PI * this.prop.pano_data.full_height;
  31130. return {
  31131. x: parseInt(position.longitude < Math.PI ? relativeLong + this.prop.pano_data.full_width / 2 : relativeLong - this.prop.pano_data.full_width / 2) - this.prop.pano_data.cropped_x,
  31132. y: parseInt(this.prop.pano_data.full_height / 2 - relativeLat) - this.prop.pano_data.cropped_y
  31133. };
  31134. };
  31135. /**
  31136. * @summary Converts spherical radians coordinates to a THREE.Vector3
  31137. * @param {PhotoSphereViewer.Position} position
  31138. * @returns {THREE.Vector3}
  31139. */
  31140. PhotoSphereViewer.prototype.sphericalCoordsToVector3 = function(position) {
  31141. return new THREE.Vector3(
  31142. PhotoSphereViewer.SPHERE_RADIUS * -Math.cos(position.latitude) * Math.sin(position.longitude),
  31143. PhotoSphereViewer.SPHERE_RADIUS * Math.sin(position.latitude),
  31144. PhotoSphereViewer.SPHERE_RADIUS * Math.cos(position.latitude) * Math.cos(position.longitude)
  31145. );
  31146. };
  31147. /**
  31148. * @summary Converts a THREE.Vector3 to spherical radians coordinates
  31149. * @param {THREE.Vector3} vector
  31150. * @returns {PhotoSphereViewer.Position}
  31151. */
  31152. PhotoSphereViewer.prototype.vector3ToSphericalCoords = function(vector) {
  31153. var phi = Math.acos(vector.y / Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z));
  31154. var theta = Math.atan2(vector.x, vector.z);
  31155. return {
  31156. longitude: theta < 0 ? -theta : PSVUtils.TwoPI - theta,
  31157. latitude: PSVUtils.HalfPI - phi
  31158. };
  31159. };
  31160. /**
  31161. * @summary Converts position on the viewer to a THREE.Vector3
  31162. * @param {PhotoSphereViewer.Point} viewerPoint
  31163. * @returns {THREE.Vector3}
  31164. */
  31165. PhotoSphereViewer.prototype.viewerCoordsToVector3 = function(viewerPoint) {
  31166. var screen = new THREE.Vector2(
  31167. 2 * viewerPoint.x / this.prop.size.width - 1,
  31168. -2 * viewerPoint.y / this.prop.size.height + 1
  31169. );
  31170. this.raycaster.setFromCamera(screen, this.camera);
  31171. var intersects = this.raycaster.intersectObjects(this.scene.children);
  31172. if (intersects.length === 1) {
  31173. return intersects[0].point;
  31174. }
  31175. else {
  31176. return null;
  31177. }
  31178. };
  31179. /**
  31180. * @summary Converts a THREE.Vector3 to position on the viewer
  31181. * @param {THREE.Vector3} vector
  31182. * @returns {PhotoSphereViewer.Point}
  31183. */
  31184. PhotoSphereViewer.prototype.vector3ToViewerCoords = function(vector) {
  31185. vector = vector.clone();
  31186. vector.project(this.camera);
  31187. return {
  31188. x: parseInt((vector.x + 1) / 2 * this.prop.size.width),
  31189. y: parseInt((1 - vector.y) / 2 * this.prop.size.height)
  31190. };
  31191. };
  31192. /**
  31193. * @summary Converts x/y to latitude/longitude if present and ensure boundaries
  31194. * @param {PhotoSphereViewer.ExtendedPosition} position - mutated
  31195. * @private
  31196. */
  31197. PhotoSphereViewer.prototype.cleanPosition = function(position) {
  31198. if (position.hasOwnProperty('x') && position.hasOwnProperty('y')) {
  31199. PSVUtils.deepmerge(position, this.textureCoordsToSphericalCoords(position));
  31200. }
  31201. position.longitude = PSVUtils.parseAngle(position.longitude);
  31202. position.latitude = PSVUtils.parseAngle(position.latitude, true);
  31203. };
  31204. /**
  31205. * @summary Apply "longitude_range" and "latitude_range"
  31206. * @param {PhotoSphereViewer.Position} position - mutated
  31207. * @returns {string[]} list of sides that were reached
  31208. * @private
  31209. */
  31210. PhotoSphereViewer.prototype.applyRanges = function(position) {
  31211. var range, offset, sidesReached = [];
  31212. if (this.config.longitude_range) {
  31213. range = PSVUtils.clone(this.config.longitude_range);
  31214. offset = THREE.Math.degToRad(this.prop.hFov) / 2;
  31215. range[0] = PSVUtils.parseAngle(range[0] + offset);
  31216. range[1] = PSVUtils.parseAngle(range[1] - offset);
  31217. if (range[0] > range[1]) { // when the range cross longitude 0
  31218. if (position.longitude > range[1] && position.longitude < range[0]) {
  31219. if (position.longitude > (range[0] / 2 + range[1] / 2)) { // detect which side we are closer too
  31220. position.longitude = range[0];
  31221. sidesReached.push('left');
  31222. }
  31223. else {
  31224. position.longitude = range[1];
  31225. sidesReached.push('right');
  31226. }
  31227. }
  31228. }
  31229. else {
  31230. if (position.longitude < range[0]) {
  31231. position.longitude = range[0];
  31232. sidesReached.push('left');
  31233. }
  31234. else if (position.longitude > range[1]) {
  31235. position.longitude = range[1];
  31236. sidesReached.push('right');
  31237. }
  31238. }
  31239. }
  31240. if (this.config.latitude_range) {
  31241. range = PSVUtils.clone(this.config.latitude_range);
  31242. offset = THREE.Math.degToRad(this.prop.vFov) / 2;
  31243. range[0] = PSVUtils.parseAngle(Math.min(range[0] + offset, range[1]), true);
  31244. range[1] = PSVUtils.parseAngle(Math.max(range[1] - offset, range[0]), true);
  31245. if (position.latitude < range[0]) {
  31246. position.latitude = range[0];
  31247. sidesReached.push('bottom');
  31248. }
  31249. else if (position.latitude > range[1]) {
  31250. position.latitude = range[1];
  31251. sidesReached.push('top');
  31252. }
  31253. }
  31254. return sidesReached;
  31255. };
  31256. /**
  31257. * @module components
  31258. */
  31259. /**
  31260. * Base sub-component class
  31261. * @param {PhotoSphereViewer | module:components.PSVComponent} parent
  31262. * @constructor
  31263. * @memberof module:components
  31264. */
  31265. function PSVComponent(parent) {
  31266. /**
  31267. * @member {PhotoSphereViewer}
  31268. * @readonly
  31269. */
  31270. this.psv = parent instanceof PhotoSphereViewer ? parent : parent.psv;
  31271. /**
  31272. * @member {PhotoSphereViewer|module:components.PSVComponent}
  31273. * @readonly
  31274. */
  31275. this.parent = parent;
  31276. /**
  31277. * @member {HTMLElement}
  31278. * @readonly
  31279. */
  31280. this.container = null;
  31281. // expose some methods to the viewer
  31282. if (this.constructor.publicMethods) {
  31283. this.constructor.publicMethods.forEach(function(method) {
  31284. this.psv[method] = this[method].bind(this);
  31285. }, this);
  31286. }
  31287. }
  31288. /**
  31289. * @summary CSS class added to the component's container
  31290. * @member {string}
  31291. * @readonly
  31292. */
  31293. PSVComponent.className = null;
  31294. /**
  31295. * @summary List of component's methods which are bound the the main viewer
  31296. * @member {string[]}
  31297. * @readonly
  31298. */
  31299. PSVComponent.publicMethods = [];
  31300. /**
  31301. * @summary Creates the component
  31302. * @protected
  31303. */
  31304. PSVComponent.prototype.create = function() {
  31305. this.container = document.createElement('div');
  31306. if (this.constructor.className) {
  31307. this.container.className = this.constructor.className;
  31308. }
  31309. this.parent.container.appendChild(this.container);
  31310. };
  31311. /**
  31312. * @summary Destroys the component
  31313. * @protected
  31314. */
  31315. PSVComponent.prototype.destroy = function() {
  31316. this.parent.container.removeChild(this.container);
  31317. if (this.constructor.publicMethods) {
  31318. this.constructor.publicMethods.forEach(function(method) {
  31319. delete this.psv[method];
  31320. }, this);
  31321. }
  31322. delete this.container;
  31323. delete this.psv;
  31324. delete this.parent;
  31325. };
  31326. /**
  31327. * @summary Hides the component
  31328. * @protected
  31329. */
  31330. PSVComponent.prototype.hide = function() {
  31331. this.container.style.display = 'none';
  31332. };
  31333. /**
  31334. * @summary Displays the component
  31335. * @protected
  31336. */
  31337. PSVComponent.prototype.show = function() {
  31338. this.container.style.display = '';
  31339. };
  31340. /**
  31341. * HUD class
  31342. * @param {PhotoSphereViewer} psv
  31343. * @constructor
  31344. * @extends module:components.PSVComponent
  31345. * @memberof module:components
  31346. */
  31347. function PSVHUD(psv) {
  31348. PSVComponent.call(this, psv);
  31349. /**
  31350. * @member {SVGElement}
  31351. * @readonly
  31352. */
  31353. this.svgContainer = null;
  31354. /**
  31355. * @summary All registered markers
  31356. * @member {Object.<string, PSVMarker>}
  31357. */
  31358. this.markers = {};
  31359. /**
  31360. * @summary Last selected marker
  31361. * @member {PSVMarker}
  31362. * @readonly
  31363. */
  31364. this.currentMarker = null;
  31365. /**
  31366. * @summary Marker under the cursor
  31367. * @member {PSVMarker}
  31368. * @readonly
  31369. */
  31370. this.hoveringMarker = null;
  31371. /**
  31372. * @member {Object}
  31373. * @private
  31374. */
  31375. this.prop = {
  31376. panelOpened: false,
  31377. panelOpening: false,
  31378. markersButton: this.psv.navbar.getNavbarButton('markers', true)
  31379. };
  31380. this.create();
  31381. }
  31382. PSVHUD.prototype = Object.create(PSVComponent.prototype);
  31383. PSVHUD.prototype.constructor = PSVHUD;
  31384. PSVHUD.className = 'psv-hud';
  31385. PSVHUD.publicMethods = [
  31386. 'addMarker',
  31387. 'removeMarker',
  31388. 'updateMarker',
  31389. 'clearMarkers',
  31390. 'getMarker',
  31391. 'getCurrentMarker',
  31392. 'gotoMarker',
  31393. 'hideMarker',
  31394. 'showMarker',
  31395. 'toggleMarker',
  31396. 'toggleMarkersList',
  31397. 'showMarkersList',
  31398. 'hideMarkersList'
  31399. ];
  31400. /**
  31401. * @override
  31402. */
  31403. PSVHUD.prototype.create = function() {
  31404. PSVComponent.prototype.create.call(this);
  31405. this.svgContainer = document.createElementNS(PSVUtils.svgNS, 'svg');
  31406. this.svgContainer.setAttribute('class', 'psv-hud-svg-container');
  31407. this.container.appendChild(this.svgContainer);
  31408. // Markers events via delegation
  31409. this.container.addEventListener('mouseenter', this, true);
  31410. this.container.addEventListener('mouseleave', this, true);
  31411. this.container.addEventListener('mousemove', this, true);
  31412. // Viewer events
  31413. this.psv.on('click', this);
  31414. this.psv.on('dblclick', this);
  31415. this.psv.on('render', this);
  31416. this.psv.on('open-panel', this);
  31417. this.psv.on('close-panel', this);
  31418. };
  31419. /**
  31420. * @override
  31421. */
  31422. PSVHUD.prototype.destroy = function() {
  31423. this.clearMarkers(false);
  31424. this.container.removeEventListener('mouseenter', this);
  31425. this.container.removeEventListener('mouseleave', this);
  31426. this.container.removeEventListener('mousemove', this);
  31427. this.psv.off('click', this);
  31428. this.psv.off('dblclick', this);
  31429. this.psv.off('render', this);
  31430. this.psv.off('open-panel', this);
  31431. this.psv.off('close-panel', this);
  31432. delete this.svgContainer;
  31433. PSVComponent.prototype.destroy.call(this);
  31434. };
  31435. /**
  31436. * @summary Handles events
  31437. * @param {Event} e
  31438. * @private
  31439. */
  31440. PSVHUD.prototype.handleEvent = function(e) {
  31441. switch (e.type) {
  31442. // @formatter:off
  31443. case 'mouseenter': this._onMouseEnter(e); break;
  31444. case 'mouseleave': this._onMouseLeave(e); break;
  31445. case 'mousemove': this._onMouseMove(e); break;
  31446. case 'click': this._onClick(e.args[0], e, false); break;
  31447. case 'dblclick': this._onClick(e.args[0], e, true); break;
  31448. case 'render': this.renderMarkers(); break;
  31449. case 'open-panel': this._onPanelOpened(); break;
  31450. case 'close-panel': this._onPanelClosed(); break;
  31451. // @formatter:on
  31452. }
  31453. };
  31454. /**
  31455. * @summary Adds a new marker to viewer
  31456. * @param {Object} properties - see {@link http://photo-sphere-viewer.js.org/markers.html#config}
  31457. * @param {boolean} [render=true] - renders the marker immediately
  31458. * @returns {PSVMarker}
  31459. * @throws {PSVError} when the marker's id is missing or already exists
  31460. */
  31461. PSVHUD.prototype.addMarker = function(properties, render) {
  31462. if (!properties.id) {
  31463. throw new PSVError('missing marker id');
  31464. }
  31465. if (this.markers[properties.id]) {
  31466. throw new PSVError('marker "' + properties.id + '" already exists');
  31467. }
  31468. var marker = new PSVMarker(properties, this.psv);
  31469. if (marker.isNormal()) {
  31470. this.container.appendChild(marker.$el);
  31471. }
  31472. else {
  31473. this.svgContainer.appendChild(marker.$el);
  31474. }
  31475. this.markers[marker.id] = marker;
  31476. if (render !== false) {
  31477. this.renderMarkers();
  31478. }
  31479. return marker;
  31480. };
  31481. /**
  31482. * @summary Returns the internal marker object for a marker id
  31483. * @param {*} markerId
  31484. * @returns {PSVMarker}
  31485. * @throws {PSVError} when the marker cannot be found
  31486. */
  31487. PSVHUD.prototype.getMarker = function(markerId) {
  31488. var id = typeof markerId === 'object' ? markerId.id : markerId;
  31489. if (!this.markers[id]) {
  31490. throw new PSVError('cannot find marker "' + id + '"');
  31491. }
  31492. return this.markers[id];
  31493. };
  31494. /**
  31495. * @summary Returns the last marker selected by the user
  31496. * @returns {PSVMarker}
  31497. */
  31498. PSVHUD.prototype.getCurrentMarker = function() {
  31499. return this.currentMarker;
  31500. };
  31501. /**
  31502. * @summary Updates the existing marker with the same id
  31503. * @description Every property can be changed but you can't change its type (Eg: `image` to `html`).
  31504. * @param {Object|PSVMarker} properties
  31505. * @param {boolean} [render=true] - renders the marker immediately
  31506. * @returns {PSVMarker}
  31507. */
  31508. PSVHUD.prototype.updateMarker = function(properties, render) {
  31509. var marker = this.getMarker(properties);
  31510. marker.update(properties);
  31511. if (render !== false) {
  31512. this.renderMarkers();
  31513. }
  31514. return marker;
  31515. };
  31516. /**
  31517. * @summary Removes a marker from the viewer
  31518. * @param {*} marker
  31519. * @param {boolean} [render=true] - renders the marker immediately
  31520. */
  31521. PSVHUD.prototype.removeMarker = function(marker, render) {
  31522. marker = this.getMarker(marker);
  31523. if (marker.isNormal()) {
  31524. this.container.removeChild(marker.$el);
  31525. }
  31526. else {
  31527. this.svgContainer.removeChild(marker.$el);
  31528. }
  31529. if (this.hoveringMarker === marker) {
  31530. this.psv.tooltip.hideTooltip();
  31531. }
  31532. marker.destroy();
  31533. delete this.markers[marker.id];
  31534. if (render !== false) {
  31535. this.renderMarkers();
  31536. }
  31537. };
  31538. /**
  31539. * @summary Removes all markers
  31540. * @param {boolean} [render=true] - renders the markers immediately
  31541. */
  31542. PSVHUD.prototype.clearMarkers = function(render) {
  31543. Object.keys(this.markers).forEach(function(marker) {
  31544. this.removeMarker(marker, false);
  31545. }, this);
  31546. if (render !== false) {
  31547. this.renderMarkers();
  31548. }
  31549. };
  31550. /**
  31551. * @summary Rotate the view to face the marker
  31552. * @param {*} marker
  31553. * @param {string|int} [duration] - rotates smoothy, see {@link PhotoSphereViewer#animate}
  31554. * @fires module:components.PSVHUD.goto-marker-done
  31555. * @return {Promise} A promise that will be resolved when the animation finishes
  31556. */
  31557. PSVHUD.prototype.gotoMarker = function(marker, duration) {
  31558. marker = this.getMarker(marker);
  31559. return this.psv.animate(marker, duration)
  31560. .then(function() {
  31561. /**
  31562. * @event goto-marker-done
  31563. * @memberof module:components.PSVHUD
  31564. * @summary Triggered when the animation to a marker is done
  31565. * @param {PSVMarker} marker
  31566. */
  31567. this.psv.trigger('goto-marker-done', marker);
  31568. }.bind(this));
  31569. };
  31570. /**
  31571. * @summary Hides a marker
  31572. * @param {*} marker
  31573. */
  31574. PSVHUD.prototype.hideMarker = function(marker) {
  31575. this.getMarker(marker).visible = false;
  31576. this.renderMarkers();
  31577. };
  31578. /**
  31579. * @summary Shows a marker
  31580. * @param {*} marker
  31581. */
  31582. PSVHUD.prototype.showMarker = function(marker) {
  31583. this.getMarker(marker).visible = true;
  31584. this.renderMarkers();
  31585. };
  31586. /**
  31587. * @summary Toggles a marker
  31588. * @param {*} marker
  31589. */
  31590. PSVHUD.prototype.toggleMarker = function(marker) {
  31591. this.getMarker(marker).visible ^= true;
  31592. this.renderMarkers();
  31593. };
  31594. /**
  31595. * @summary Toggles the visibility of markers list
  31596. */
  31597. PSVHUD.prototype.toggleMarkersList = function() {
  31598. if (this.prop.panelOpened) {
  31599. this.hideMarkersList();
  31600. }
  31601. else {
  31602. this.showMarkersList();
  31603. }
  31604. };
  31605. /**
  31606. * @summary Opens side panel with list of markers
  31607. * @fires module:components.PSVHUD.filter:render-markers-list
  31608. */
  31609. PSVHUD.prototype.showMarkersList = function() {
  31610. var markers = [];
  31611. PSVUtils.forEach(this.markers, function(marker) {
  31612. markers.push(marker);
  31613. });
  31614. /**
  31615. * @event filter:render-markers-list
  31616. * @memberof module:components.PSVHUD
  31617. * @summary Used to alter the list of markers displayed on the side-panel
  31618. * @param {PSVMarker[]} markers
  31619. * @returns {PSVMarker[]}
  31620. */
  31621. var html = this.psv.config.templates.markersList({
  31622. markers: this.psv.change('render-markers-list', markers),
  31623. config: this.psv.config
  31624. });
  31625. this.prop.panelOpening = true;
  31626. this.psv.panel.showPanel(html, true);
  31627. this.psv.panel.container.querySelector('.psv-markers-list').addEventListener('click', this._onClickItem.bind(this));
  31628. };
  31629. /**
  31630. * @summary Closes side panel if it contains the list of markers
  31631. */
  31632. PSVHUD.prototype.hideMarkersList = function() {
  31633. if (this.prop.panelOpened) {
  31634. this.psv.panel.hidePanel();
  31635. }
  31636. };
  31637. /**
  31638. * @summary Updates the visibility and the position of all markers
  31639. */
  31640. PSVHUD.prototype.renderMarkers = function() {
  31641. var rotation = !this.psv.isGyroscopeEnabled() ? 0 : THREE.Math.radToDeg(this.psv.camera.rotation.z);
  31642. PSVUtils.forEach(this.markers, function(marker) {
  31643. var isVisible = marker.visible;
  31644. if (isVisible && marker.isPoly()) {
  31645. var positions = this._getPolyPositions(marker);
  31646. isVisible = positions.length > (marker.isPolygon() ? 2 : 1);
  31647. if (isVisible) {
  31648. marker.position2D = this._getPolyDimensions(marker, positions);
  31649. var points = positions.map(function(pos) {
  31650. return pos.x + ',' + pos.y;
  31651. }).join(' ');
  31652. marker.$el.setAttributeNS(null, 'points', points);
  31653. }
  31654. }
  31655. else if (isVisible) {
  31656. var position = this._getMarkerPosition(marker);
  31657. isVisible = this._isMarkerVisible(marker, position);
  31658. if (isVisible) {
  31659. marker.position2D = position;
  31660. var scale = marker.getScale(this.psv.getZoomLevel());
  31661. if (marker.isSvg()) {
  31662. marker.$el.setAttributeNS(null, 'transform',
  31663. 'translate(' + position.x + ', ' + position.y + ')' +
  31664. (scale !== 1 ? ' scale(' + scale + ', ' + scale + ')' : '') +
  31665. (!marker.lockRotation && rotation ? ' rotate(' + rotation + ')' : '')
  31666. );
  31667. }
  31668. else {
  31669. marker.$el.style.transform = 'translate3D(' + position.x + 'px, ' + position.y + 'px, 0px)' +
  31670. (scale !== 1 ? ' scale(' + scale + ', ' + scale + ')' : '') +
  31671. (!marker.lockRotation && rotation ? ' rotateZ(' + rotation + 'deg)' : '');
  31672. }
  31673. }
  31674. }
  31675. PSVUtils.toggleClass(marker.$el, 'psv-marker--visible', isVisible);
  31676. }.bind(this));
  31677. };
  31678. /**
  31679. * @summary Determines if a point marker is visible<br>
  31680. * It tests if the point is in the general direction of the camera, then check if it's in the viewport
  31681. * @param {PSVMarker} marker
  31682. * @param {PhotoSphereViewer.Point} position
  31683. * @returns {boolean}
  31684. * @private
  31685. */
  31686. PSVHUD.prototype._isMarkerVisible = function(marker, position) {
  31687. return marker.position3D.dot(this.psv.prop.direction) > 0 &&
  31688. position.x + marker.width >= 0 &&
  31689. position.x - marker.width <= this.psv.prop.size.width &&
  31690. position.y + marker.height >= 0 &&
  31691. position.y - marker.height <= this.psv.prop.size.height;
  31692. };
  31693. /**
  31694. * @summary Computes HUD coordinates of a marker
  31695. * @param {PSVMarker} marker
  31696. * @returns {PhotoSphereViewer.Point}
  31697. * @private
  31698. */
  31699. PSVHUD.prototype._getMarkerPosition = function(marker) {
  31700. if (marker._dynamicSize) {
  31701. // make the marker visible to get it's size
  31702. PSVUtils.toggleClass(marker.$el, 'psv-marker--transparent', true);
  31703. var transform = marker.$el.style.transform;
  31704. marker.$el.style.transform = null;
  31705. var rect = marker.$el.getBoundingClientRect();
  31706. marker.$el.style.transform = transform;
  31707. PSVUtils.toggleClass(marker.$el, 'psv-marker--transparent', false);
  31708. marker.width = rect.right - rect.left;
  31709. marker.height = rect.bottom - rect.top;
  31710. }
  31711. var position = this.psv.vector3ToViewerCoords(marker.position3D);
  31712. position.x -= marker.width * marker.anchor.left;
  31713. position.y -= marker.height * marker.anchor.top;
  31714. return position;
  31715. };
  31716. /**
  31717. * @summary Computes HUD coordinates of each point of a polygon/polyline<br>
  31718. * It handles points behind the camera by creating intermediary points suitable for the projector
  31719. * @param {PSVMarker} marker
  31720. * @returns {PhotoSphereViewer.Point[]}
  31721. * @private
  31722. */
  31723. PSVHUD.prototype._getPolyPositions = function(marker) {
  31724. var nbVectors = marker.positions3D.length;
  31725. // compute if each vector is visible
  31726. var positions3D = marker.positions3D.map(function(vector) {
  31727. return {
  31728. vector: vector,
  31729. visible: vector.dot(this.psv.prop.direction) > 0
  31730. };
  31731. }, this);
  31732. // get pairs of visible/invisible vectors for each invisible vector connected to a visible vector
  31733. var toBeComputed = [];
  31734. positions3D.forEach(function(pos, i) {
  31735. if (!pos.visible) {
  31736. var neighbours = [
  31737. i === 0 ? positions3D[nbVectors - 1] : positions3D[i - 1],
  31738. i === nbVectors - 1 ? positions3D[0] : positions3D[i + 1]
  31739. ];
  31740. neighbours.forEach(function(neighbour) {
  31741. if (neighbour.visible) {
  31742. toBeComputed.push({
  31743. visible: neighbour,
  31744. invisible: pos,
  31745. index: i
  31746. });
  31747. }
  31748. });
  31749. }
  31750. });
  31751. // compute intermediary vector for each pair (the loop is reversed for splice to insert at the right place)
  31752. toBeComputed.reverse().forEach(function(pair) {
  31753. positions3D.splice(pair.index, 0, {
  31754. vector: this._getPolyIntermediaryPoint(pair.visible.vector, pair.invisible.vector),
  31755. visible: true
  31756. });
  31757. }, this);
  31758. // translate vectors to screen pos
  31759. return positions3D
  31760. .filter(function(pos) {
  31761. return pos.visible;
  31762. })
  31763. .map(function(pos) {
  31764. return this.psv.vector3ToViewerCoords(pos.vector);
  31765. }, this);
  31766. };
  31767. /**
  31768. * Given one point in the same direction of the camera and one point behind the camera,
  31769. * computes an intermediary point on the great circle delimiting the half sphere visible by the camera.
  31770. * The point is shifted by .01 rad because the projector cannot handle points exactly on this circle.
  31771. * {@link http://math.stackexchange.com/a/1730410/327208}
  31772. * @param P1 {THREE.Vector3}
  31773. * @param P2 {THREE.Vector3}
  31774. * @returns {THREE.Vector3}
  31775. * @private
  31776. */
  31777. PSVHUD.prototype._getPolyIntermediaryPoint = function(P1, P2) {
  31778. var C = this.psv.prop.direction.clone().normalize();
  31779. var N = new THREE.Vector3().crossVectors(P1, P2).normalize();
  31780. var V = new THREE.Vector3().crossVectors(N, P1).normalize();
  31781. var H = new THREE.Vector3().addVectors(P1.clone().multiplyScalar(-C.dot(V)), V.clone().multiplyScalar(C.dot(P1))).normalize();
  31782. var a = new THREE.Vector3().crossVectors(H, C);
  31783. return H.applyAxisAngle(a, 0.01).multiplyScalar(PhotoSphereViewer.SPHERE_RADIUS);
  31784. };
  31785. /**
  31786. * @summary Computes the boundaries positions of a polygon/polyline marker
  31787. * @param {PSVMarker} marker - alters width and height
  31788. * @param {PhotoSphereViewer.Point[]} positions
  31789. * @returns {PhotoSphereViewer.Point}
  31790. * @private
  31791. */
  31792. PSVHUD.prototype._getPolyDimensions = function(marker, positions) {
  31793. var minX = +Infinity;
  31794. var minY = +Infinity;
  31795. var maxX = -Infinity;
  31796. var maxY = -Infinity;
  31797. positions.forEach(function(pos) {
  31798. minX = Math.min(minX, pos.x);
  31799. minY = Math.min(minY, pos.y);
  31800. maxX = Math.max(maxX, pos.x);
  31801. maxY = Math.max(maxY, pos.y);
  31802. });
  31803. marker.width = maxX - minX;
  31804. marker.height = maxY - minY;
  31805. return {
  31806. x: minX,
  31807. y: minY
  31808. };
  31809. };
  31810. /**
  31811. * @summary Handles mouse enter events, show the tooltip for non polygon markers
  31812. * @param {MouseEvent} e
  31813. * @fires module:components.PSVHUD.over-marker
  31814. * @private
  31815. */
  31816. PSVHUD.prototype._onMouseEnter = function(e) {
  31817. var marker;
  31818. if (e.target && (marker = e.target.psvMarker) && !marker.isPoly()) {
  31819. this.hoveringMarker = marker;
  31820. /**
  31821. * @event over-marker
  31822. * @memberof module:components.PSVHUD
  31823. * @summary Triggered when the user puts the cursor hover a marker
  31824. * @param {PSVMarker} marker
  31825. */
  31826. this.psv.trigger('over-marker', marker);
  31827. if (marker.tooltip) {
  31828. this.psv.tooltip.showTooltip({
  31829. content: marker.tooltip.content,
  31830. position: marker.tooltip.position,
  31831. left: marker.position2D.x,
  31832. top: marker.position2D.y,
  31833. box: {
  31834. width: marker.width,
  31835. height: marker.height
  31836. }
  31837. });
  31838. }
  31839. }
  31840. };
  31841. /**
  31842. * @summary Handles mouse leave events, hide the tooltip
  31843. * @param {MouseEvent} e
  31844. * @fires module:components.PSVHUD.leave-marker
  31845. * @private
  31846. */
  31847. PSVHUD.prototype._onMouseLeave = function(e) {
  31848. var marker;
  31849. if (e.target && (marker = e.target.psvMarker)) {
  31850. // do not hide if we enter the tooltip itself while hovering a polygon
  31851. if (marker.isPoly() && e.relatedTarget && PSVUtils.hasParent(e.relatedTarget, this.psv.tooltip.container)) {
  31852. return;
  31853. }
  31854. /**
  31855. * @event leave-marker
  31856. * @memberof module:components.PSVHUD
  31857. * @summary Triggered when the user puts the cursor away from a marker
  31858. * @param {PSVMarker} marker
  31859. */
  31860. this.psv.trigger('leave-marker', marker);
  31861. this.hoveringMarker = null;
  31862. this.psv.tooltip.hideTooltip();
  31863. }
  31864. };
  31865. /**
  31866. * @summary Handles mouse move events, refresh the tooltip for polygon markers
  31867. * @param {MouseEvent} e
  31868. * @fires module:components.PSVHUD.leave-marker
  31869. * @fires module:components.PSVHUD.over-marker
  31870. * @private
  31871. */
  31872. PSVHUD.prototype._onMouseMove = function(e) {
  31873. if (!this.psv.prop.moving) {
  31874. var marker;
  31875. // do not hide if we enter the tooltip itself while hovering a polygon
  31876. if (e.target && (marker = e.target.psvMarker) && marker.isPoly() ||
  31877. e.target && PSVUtils.hasParent(e.target, this.psv.tooltip.container) && (marker = this.hoveringMarker)) {
  31878. if (!this.hoveringMarker) {
  31879. this.psv.trigger('over-marker', marker);
  31880. this.hoveringMarker = marker;
  31881. }
  31882. var boundingRect = this.psv.container.getBoundingClientRect();
  31883. if (marker.tooltip) {
  31884. this.psv.tooltip.showTooltip({
  31885. content: marker.tooltip.content,
  31886. position: marker.tooltip.position,
  31887. top: e.clientY - boundingRect.top - this.psv.config.tooltip.arrow_size / 2,
  31888. left: e.clientX - boundingRect.left - this.psv.config.tooltip.arrow_size,
  31889. box: { // separate the tooltip from the cursor
  31890. width: this.psv.config.tooltip.arrow_size * 2,
  31891. height: this.psv.config.tooltip.arrow_size * 2
  31892. }
  31893. });
  31894. }
  31895. }
  31896. else if (this.hoveringMarker && this.hoveringMarker.isPoly()) {
  31897. this.psv.trigger('leave-marker', this.hoveringMarker);
  31898. this.hoveringMarker = null;
  31899. this.psv.tooltip.hideTooltip();
  31900. }
  31901. }
  31902. };
  31903. /**
  31904. * @summary Handles mouse click events, select the marker and open the panel if necessary
  31905. * @param {Object} data
  31906. * @param {Event} e
  31907. * @param {boolean} dblclick
  31908. * @fires module:components.PSVHUD.select-marker
  31909. * @fires module:components.PSVHUD.unselect-marker
  31910. * @private
  31911. */
  31912. PSVHUD.prototype._onClick = function(data, e, dblclick) {
  31913. var marker;
  31914. if (data.target && (marker = PSVUtils.getClosest(data.target, '.psv-marker')) && marker.psvMarker) {
  31915. this.currentMarker = marker.psvMarker;
  31916. /**
  31917. * @event select-marker
  31918. * @memberof module:components.PSVHUD
  31919. * @summary Triggered when the user clicks on a marker. The marker can be retrieved from outside the event handler
  31920. * with {@link module:components.PSVHUD.getCurrentMarker}
  31921. * @param {PSVMarker} marker
  31922. * @param {boolean} dblclick - the simple click is always fired before the double click
  31923. */
  31924. this.psv.trigger('select-marker', this.currentMarker, dblclick);
  31925. if (this.psv.config.click_event_on_marker) {
  31926. // add the marker to event data
  31927. data.marker = marker.psvMarker;
  31928. }
  31929. else {
  31930. e.stopPropagation();
  31931. }
  31932. }
  31933. else if (this.currentMarker) {
  31934. /**
  31935. * @event unselect-marker
  31936. * @memberof module:components.PSVHUD
  31937. * @summary Triggered when a marker was selected and the user clicks elsewhere
  31938. * @param {PSVMarker} marker
  31939. */
  31940. this.psv.trigger('unselect-marker', this.currentMarker);
  31941. this.currentMarker = null;
  31942. }
  31943. if (marker && marker.psvMarker && marker.psvMarker.content) {
  31944. this.psv.panel.showPanel(marker.psvMarker.content);
  31945. }
  31946. else if (this.psv.panel.prop.opened) {
  31947. e.stopPropagation();
  31948. this.psv.panel.hidePanel();
  31949. }
  31950. };
  31951. /**
  31952. * @summary Clicks on an item
  31953. * @param {MouseEvent} e
  31954. * @fires module:components.PSVHUD.select-marker-list
  31955. * @private
  31956. */
  31957. PSVHUD.prototype._onClickItem = function(e) {
  31958. var li;
  31959. if (e.target && (li = PSVUtils.getClosest(e.target, 'li')) && li.dataset.psvMarker) {
  31960. var marker = this.getMarker(li.dataset.psvMarker);
  31961. /**
  31962. * @event select-marker-list
  31963. * @memberof module:components.PSVHUD
  31964. * @summary Triggered when a marker is selected from the side panel
  31965. * @param {PSVMarker} marker
  31966. */
  31967. this.psv.trigger('select-marker-list', marker);
  31968. this.gotoMarker(marker, 1000);
  31969. this.psv.panel.hidePanel();
  31970. }
  31971. };
  31972. /**
  31973. * @summary Updates status when the panel is updated
  31974. * @private
  31975. */
  31976. PSVHUD.prototype._onPanelOpened = function() {
  31977. if (this.prop.panelOpening) {
  31978. this.prop.panelOpening = false;
  31979. this.prop.panelOpened = true;
  31980. }
  31981. else {
  31982. this.prop.panelOpened = false;
  31983. }
  31984. if (this.prop.markersButton) {
  31985. this.prop.markersButton.toggleActive(this.prop.panelOpened);
  31986. }
  31987. };
  31988. /**
  31989. * @summary Updates status when the panel is updated
  31990. * @private
  31991. */
  31992. PSVHUD.prototype._onPanelClosed = function() {
  31993. this.prop.panelOpened = false;
  31994. this.prop.panelOpening = false;
  31995. if (this.prop.markersButton) {
  31996. this.prop.markersButton.toggleActive(false);
  31997. }
  31998. };
  31999. /**
  32000. * Loader class
  32001. * @param {PhotoSphereViewer} psv
  32002. * @constructor
  32003. * @extends module:components.PSVComponent
  32004. * @memberof module:components
  32005. */
  32006. function PSVLoader(psv) {
  32007. PSVComponent.call(this, psv);
  32008. /**
  32009. * @summary Animation canvas
  32010. * @member {HTMLCanvasElement}
  32011. * @readonly
  32012. * @private
  32013. */
  32014. this.canvas = null;
  32015. /**
  32016. * @summary Inner container for vertical center
  32017. * @member {HTMLElement}
  32018. * @readonly
  32019. * @private
  32020. */
  32021. this.loader = null;
  32022. this.create();
  32023. }
  32024. PSVLoader.prototype = Object.create(PSVComponent.prototype);
  32025. PSVLoader.prototype.constructor = PSVLoader;
  32026. PSVLoader.className = 'psv-loader-container';
  32027. /**
  32028. * @override
  32029. */
  32030. PSVLoader.prototype.create = function() {
  32031. PSVComponent.prototype.create.call(this);
  32032. var pixelRatio = PhotoSphereViewer.SYSTEM.pixelRatio;
  32033. this.loader = document.createElement('div');
  32034. this.loader.className = 'psv-loader';
  32035. this.container.appendChild(this.loader);
  32036. this.canvas = document.createElement('canvas');
  32037. this.canvas.className = 'psv-loader-canvas';
  32038. this.canvas.width = this.loader.clientWidth * pixelRatio;
  32039. this.canvas.height = this.loader.clientWidth * pixelRatio;
  32040. this.loader.appendChild(this.canvas);
  32041. this.tickness = (this.loader.offsetWidth - this.loader.clientWidth) / 2 * pixelRatio;
  32042. var inner;
  32043. if (this.psv.config.loading_img) {
  32044. inner = document.createElement('img');
  32045. inner.className = 'psv-loader-image';
  32046. inner.src = this.psv.config.loading_img;
  32047. }
  32048. else if (this.psv.config.loading_txt) {
  32049. inner = document.createElement('div');
  32050. inner.className = 'psv-loader-text';
  32051. inner.innerHTML = this.psv.config.loading_txt;
  32052. }
  32053. if (inner) {
  32054. var a = Math.round(Math.sqrt(2 * Math.pow((this.canvas.width / 2 - this.tickness / 2) / pixelRatio, 2)));
  32055. inner.style.maxWidth = a + 'px';
  32056. inner.style.maxHeight = a + 'px';
  32057. this.loader.appendChild(inner);
  32058. }
  32059. };
  32060. /**
  32061. * @override
  32062. */
  32063. PSVLoader.prototype.destroy = function() {
  32064. delete this.loader;
  32065. delete this.canvas;
  32066. PSVComponent.prototype.destroy.call(this);
  32067. };
  32068. /**
  32069. * @summary Sets the loader progression
  32070. * @param {int} value - from 0 to 100
  32071. */
  32072. PSVLoader.prototype.setProgress = function(value) {
  32073. var context = this.canvas.getContext('2d');
  32074. context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  32075. context.lineWidth = this.tickness;
  32076. context.strokeStyle = PSVUtils.getStyle(this.loader, 'color');
  32077. context.beginPath();
  32078. context.arc(
  32079. this.canvas.width / 2, this.canvas.height / 2,
  32080. this.canvas.width / 2 - this.tickness / 2,
  32081. -Math.PI / 2, value / 100 * 2 * Math.PI - Math.PI / 2
  32082. );
  32083. context.stroke();
  32084. };
  32085. /**
  32086. * Navigation bar class
  32087. * @param {PhotoSphereViewer} psv
  32088. * @constructor
  32089. * @extends module:components.PSVComponent
  32090. * @memberof module:components
  32091. */
  32092. function PSVNavBar(psv) {
  32093. PSVComponent.call(this, psv);
  32094. /**
  32095. * @member {Object}
  32096. * @readonly
  32097. * @private
  32098. */
  32099. this.config = this.psv.config.navbar;
  32100. /**
  32101. * @summary List of buttons of the navbar
  32102. * @member {Array.<module:components/buttons.PSVNavBarButton>}
  32103. * @readonly
  32104. */
  32105. this.items = [];
  32106. // all buttons
  32107. if (this.config === true) {
  32108. this.config = PSVUtils.clone(PhotoSphereViewer.DEFAULTS.navbar);
  32109. }
  32110. // space separated list
  32111. else if (typeof this.config === 'string') {
  32112. this.config = this.config.split(' ');
  32113. }
  32114. // migration from object
  32115. else if (!Array.isArray(this.config)) {
  32116. console.warn('PhotoSphereViewer: hashmap form of "navbar" is deprecated, use an array instead.');
  32117. var config = this.config;
  32118. this.config = [];
  32119. PSVUtils.forEach(config, function(enabled, key) {
  32120. if (enabled) {
  32121. this.config.push(key);
  32122. }
  32123. }.bind(this));
  32124. this.config.sort(function(a, b) {
  32125. return PhotoSphereViewer.DEFAULTS.navbar.indexOf(a) - PhotoSphereViewer.DEFAULTS.navbar.indexOf(b);
  32126. });
  32127. }
  32128. this.create();
  32129. }
  32130. PSVNavBar.prototype = Object.create(PSVComponent.prototype);
  32131. PSVNavBar.prototype.constructor = PSVNavBar;
  32132. PSVNavBar.className = 'psv-navbar psv-navbar--open';
  32133. PSVNavBar.publicMethods = ['showNavbar', 'hideNavbar', 'toggleNavbar', 'getNavbarButton'];
  32134. /**
  32135. * @override
  32136. * @throws {PSVError} when the configuration is incorrect
  32137. */
  32138. PSVNavBar.prototype.create = function() {
  32139. PSVComponent.prototype.create.call(this);
  32140. this.config.forEach(function(button) {
  32141. if (typeof button === 'object') {
  32142. this.items.push(new PSVNavBarCustomButton(this, button));
  32143. }
  32144. else {
  32145. switch (button) {
  32146. case PSVNavBarAutorotateButton.id:
  32147. this.items.push(new PSVNavBarAutorotateButton(this));
  32148. break;
  32149. case PSVNavBarZoomButton.id:
  32150. this.items.push(new PSVNavBarZoomButton(this));
  32151. break;
  32152. case PSVNavBarDownloadButton.id:
  32153. this.items.push(new PSVNavBarDownloadButton(this));
  32154. break;
  32155. case PSVNavBarMarkersButton.id:
  32156. this.items.push(new PSVNavBarMarkersButton(this));
  32157. break;
  32158. case PSVNavBarFullscreenButton.id:
  32159. this.items.push(new PSVNavBarFullscreenButton(this));
  32160. break;
  32161. case PSVNavBarGyroscopeButton.id:
  32162. if (this.psv.config.gyroscope) {
  32163. this.items.push(new PSVNavBarGyroscopeButton(this));
  32164. }
  32165. break;
  32166. case 'caption':
  32167. this.items.push(new PSVNavBarCaption(this, this.psv.config.caption));
  32168. break;
  32169. case 'spacer':
  32170. button = 'spacer-5';
  32171. /* falls through */
  32172. default:
  32173. var matches = button.match(/^spacer\-([0-9]+)$/);
  32174. if (matches !== null) {
  32175. this.items.push(new PSVNavBarSpacer(this, matches[1]));
  32176. }
  32177. else {
  32178. throw new PSVError('Unknown button ' + button);
  32179. }
  32180. break;
  32181. }
  32182. }
  32183. }, this);
  32184. };
  32185. /**
  32186. * @override
  32187. */
  32188. PSVNavBar.prototype.destroy = function() {
  32189. this.items.forEach(function(item) {
  32190. item.destroy();
  32191. });
  32192. delete this.items;
  32193. delete this.config;
  32194. PSVComponent.prototype.destroy.call(this);
  32195. };
  32196. /**
  32197. * @summary Returns a button by its identifier
  32198. * @param {string} id
  32199. * @param {boolean} [silent=false]
  32200. * @returns {module:components/buttons.PSVNavBarButton}
  32201. */
  32202. PSVNavBar.prototype.getNavbarButton = function(id, silent) {
  32203. var button = null;
  32204. this.items.some(function(item) {
  32205. if (item.id === id) {
  32206. button = item;
  32207. return true;
  32208. }
  32209. else {
  32210. return false;
  32211. }
  32212. });
  32213. if (!button && !silent) {
  32214. console.warn('PhotoSphereViewer: button "' + id + '" not found in the navbar.');
  32215. }
  32216. return button;
  32217. };
  32218. /**
  32219. * @summary Shows the navbar
  32220. */
  32221. PSVNavBar.prototype.showNavbar = function() {
  32222. this.toggleNavbar(true);
  32223. };
  32224. /**
  32225. * @summary Hides the navbar
  32226. */
  32227. PSVNavBar.prototype.hideNavbar = function() {
  32228. this.toggleNavbar(false);
  32229. };
  32230. /**
  32231. * @summary Toggles the navbar
  32232. * @param {boolean} active
  32233. */
  32234. PSVNavBar.prototype.toggleNavbar = function(active) {
  32235. PSVUtils.toggleClass(this.container, 'psv-navbar--open', active);
  32236. };
  32237. /**
  32238. * Navbar caption class
  32239. * @param {PSVNavBar} navbar
  32240. * @param {string} caption
  32241. * @constructor
  32242. * @extends module:components.PSVComponent
  32243. * @memberof module:components
  32244. */
  32245. function PSVNavBarCaption(navbar, caption) {
  32246. PSVComponent.call(this, navbar);
  32247. this.create();
  32248. this.setCaption(caption);
  32249. }
  32250. PSVNavBarCaption.prototype = Object.create(PSVComponent.prototype);
  32251. PSVNavBarCaption.prototype.constructor = PSVNavBarCaption;
  32252. PSVNavBarCaption.className = 'psv-caption';
  32253. PSVNavBarCaption.publicMethods = ['setCaption'];
  32254. /**
  32255. * @summary Sets the bar caption
  32256. * @param {string} html
  32257. */
  32258. PSVNavBarCaption.prototype.setCaption = function(html) {
  32259. if (!html) {
  32260. this.container.innerHTML = '';
  32261. }
  32262. else {
  32263. this.container.innerHTML = html;
  32264. }
  32265. };
  32266. /**
  32267. * Navbar spacer class
  32268. * @param {PSVNavBar} navbar
  32269. * @param {int} [weight=5]
  32270. * @constructor
  32271. * @extends module:components.PSVComponent
  32272. * @memberof module:components
  32273. */
  32274. function PSVNavBarSpacer(navbar, weight) {
  32275. PSVComponent.call(this, navbar);
  32276. /**
  32277. * @member {int}
  32278. * @readonly
  32279. */
  32280. this.weight = weight || 5;
  32281. this.create();
  32282. this.container.classList.add('psv-spacer--weight-' + this.weight);
  32283. }
  32284. PSVNavBarSpacer.prototype = Object.create(PSVComponent.prototype);
  32285. PSVNavBarSpacer.prototype.constructor = PSVNavBarSpacer;
  32286. PSVNavBarSpacer.className = 'psv-spacer';
  32287. /**
  32288. * Panel class
  32289. * @param {PhotoSphereViewer} psv
  32290. * @constructor
  32291. * @extends module:components.PSVComponent
  32292. * @memberof module:components
  32293. */
  32294. function PSVPanel(psv) {
  32295. PSVComponent.call(this, psv);
  32296. /**
  32297. * @summary Content container
  32298. * @member {HTMLElement}
  32299. * @readonly
  32300. * @private
  32301. */
  32302. this.content = null;
  32303. /**
  32304. * @member {Object}
  32305. * @private
  32306. */
  32307. this.prop = {
  32308. mouse_x: 0,
  32309. mouse_y: 0,
  32310. mousedown: false,
  32311. opened: false
  32312. };
  32313. this.create();
  32314. }
  32315. PSVPanel.prototype = Object.create(PSVComponent.prototype);
  32316. PSVPanel.prototype.constructor = PSVPanel;
  32317. PSVPanel.className = 'psv-panel';
  32318. PSVPanel.publicMethods = ['showPanel', 'hidePanel'];
  32319. /**
  32320. * @override
  32321. */
  32322. PSVPanel.prototype.create = function() {
  32323. PSVComponent.prototype.create.call(this);
  32324. this.container.innerHTML =
  32325. '<div class="psv-panel-resizer"></div>' +
  32326. '<div class="psv-panel-close-button"></div>' +
  32327. '<div class="psv-panel-content"></div>';
  32328. this.content = this.container.querySelector('.psv-panel-content');
  32329. var closeBtn = this.container.querySelector('.psv-panel-close-button');
  32330. closeBtn.addEventListener('click', this.hidePanel.bind(this));
  32331. // Stop event bubling from panel
  32332. if (this.psv.config.mousewheel) {
  32333. this.container.addEventListener(PhotoSphereViewer.SYSTEM.mouseWheelEvent, function(e) {
  32334. e.stopPropagation();
  32335. });
  32336. }
  32337. // Event for panel resizing + stop bubling
  32338. var resizer = this.container.querySelector('.psv-panel-resizer');
  32339. resizer.addEventListener('mousedown', this);
  32340. resizer.addEventListener('touchstart', this);
  32341. this.psv.container.addEventListener('mouseup', this);
  32342. this.psv.container.addEventListener('touchend', this);
  32343. this.psv.container.addEventListener('mousemove', this);
  32344. this.psv.container.addEventListener('touchmove', this);
  32345. };
  32346. /**
  32347. * @override
  32348. */
  32349. PSVPanel.prototype.destroy = function() {
  32350. this.psv.container.removeEventListener('mousemove', this);
  32351. this.psv.container.removeEventListener('touchmove', this);
  32352. this.psv.container.removeEventListener('mouseup', this);
  32353. this.psv.container.removeEventListener('touchend', this);
  32354. delete this.prop;
  32355. delete this.content;
  32356. PSVComponent.prototype.destroy.call(this);
  32357. };
  32358. /**
  32359. * @summary Handles events
  32360. * @param {Event} e
  32361. * @private
  32362. */
  32363. PSVPanel.prototype.handleEvent = function(e) {
  32364. switch (e.type) {
  32365. // @formatter:off
  32366. case 'mousedown': this._onMouseDown(e); break;
  32367. case 'touchstart': this._onTouchStart(e); break;
  32368. case 'mousemove': this._onMouseMove(e); break;
  32369. case 'touchmove': this._onTouchMove(e); break;
  32370. case 'mouseup': this._onMouseUp(e); break;
  32371. case 'touchend': this._onMouseUp(e); break;
  32372. // @formatter:on
  32373. }
  32374. };
  32375. /**
  32376. * @summary Shows the panel
  32377. * @param {string} content
  32378. * @param {boolean} [noMargin=false]
  32379. * @fires module:components.PSVPanel.open-panel
  32380. */
  32381. PSVPanel.prototype.showPanel = function(content, noMargin) {
  32382. this.content.innerHTML = content;
  32383. this.content.scrollTop = 0;
  32384. this.container.classList.add('psv-panel--open');
  32385. PSVUtils.toggleClass(this.content, 'psv-panel-content--no-margin', noMargin === true);
  32386. this.prop.opened = true;
  32387. /**
  32388. * @event open-panel
  32389. * @memberof module:components.PSVPanel
  32390. * @summary Triggered when the panel is opened
  32391. */
  32392. this.psv.trigger('open-panel');
  32393. };
  32394. /**
  32395. * @summary Hides the panel
  32396. * @fires module:components.PSVPanel.close-panel
  32397. */
  32398. PSVPanel.prototype.hidePanel = function() {
  32399. this.content.innerHTML = null;
  32400. this.prop.opened = false;
  32401. this.container.classList.remove('psv-panel--open');
  32402. /**
  32403. * @event close-panel
  32404. * @memberof module:components.PSVPanel
  32405. * @summary Trigered when the panel is closed
  32406. */
  32407. this.psv.trigger('close-panel');
  32408. };
  32409. /**
  32410. * @summary Handles mouse down events
  32411. * @param {MouseEvent} evt
  32412. * @private
  32413. */
  32414. PSVPanel.prototype._onMouseDown = function(evt) {
  32415. evt.stopPropagation();
  32416. this._startResize(evt);
  32417. };
  32418. /**
  32419. * @summary Handles touch events
  32420. * @param {TouchEvent} evt
  32421. * @private
  32422. */
  32423. PSVPanel.prototype._onTouchStart = function(evt) {
  32424. evt.stopPropagation();
  32425. this._startResize(evt.changedTouches[0]);
  32426. };
  32427. /**
  32428. * @summary Handles mouse up events
  32429. * @param {MouseEvent} evt
  32430. * @private
  32431. */
  32432. PSVPanel.prototype._onMouseUp = function(evt) {
  32433. if (this.prop.mousedown) {
  32434. evt.stopPropagation();
  32435. this.prop.mousedown = false;
  32436. this.content.classList.remove('psv-panel-content--no-interaction');
  32437. }
  32438. };
  32439. /**
  32440. * @summary Handles mouse move events
  32441. * @param {MouseEvent} evt
  32442. * @private
  32443. */
  32444. PSVPanel.prototype._onMouseMove = function(evt) {
  32445. if (this.prop.mousedown) {
  32446. evt.stopPropagation();
  32447. this._resize(evt);
  32448. }
  32449. };
  32450. /**
  32451. * @summary Handles touch move events
  32452. * @param {TouchEvent} evt
  32453. * @private
  32454. */
  32455. PSVPanel.prototype._onTouchMove = function(evt) {
  32456. if (this.prop.mousedown) {
  32457. this._resize(evt.touches[0]);
  32458. }
  32459. };
  32460. /**
  32461. * @summary Initializes the panel resize
  32462. * @param {MouseEvent|Touch} evt
  32463. * @private
  32464. */
  32465. PSVPanel.prototype._startResize = function(evt) {
  32466. this.prop.mouse_x = parseInt(evt.clientX);
  32467. this.prop.mouse_y = parseInt(evt.clientY);
  32468. this.prop.mousedown = true;
  32469. this.content.classList.add('psv-panel-content--no-interaction');
  32470. };
  32471. /**
  32472. * @summary Resizes the panel
  32473. * @param {MouseEvent|Touch} evt
  32474. * @private
  32475. */
  32476. PSVPanel.prototype._resize = function(evt) {
  32477. var x = parseInt(evt.clientX);
  32478. var y = parseInt(evt.clientY);
  32479. this.container.style.width = (this.container.offsetWidth - (x - this.prop.mouse_x)) + 'px';
  32480. this.prop.mouse_x = x;
  32481. this.prop.mouse_y = y;
  32482. };
  32483. /**
  32484. * Tooltip class
  32485. * @param {module:components.PSVHUD} hud
  32486. * @constructor
  32487. * @extends module:components.PSVComponent
  32488. * @memberof module:components
  32489. */
  32490. function PSVTooltip(hud) {
  32491. PSVComponent.call(this, hud);
  32492. /**
  32493. * @member {Object}
  32494. * @readonly
  32495. * @private
  32496. */
  32497. this.config = this.psv.config.tooltip;
  32498. /**
  32499. * @member {Object}
  32500. * @private
  32501. */
  32502. this.prop = {
  32503. timeout: null
  32504. };
  32505. this.create();
  32506. }
  32507. PSVTooltip.prototype = Object.create(PSVComponent.prototype);
  32508. PSVTooltip.prototype.constructor = PSVTooltip;
  32509. PSVTooltip.className = 'psv-tooltip';
  32510. PSVTooltip.publicMethods = ['showTooltip', 'hideTooltip', 'isTooltipVisible'];
  32511. PSVTooltip.leftMap = { 0: 'left', 0.5: 'center', 1: 'right' };
  32512. PSVTooltip.topMap = { 0: 'top', 0.5: 'center', 1: 'bottom' };
  32513. /**
  32514. * @override
  32515. */
  32516. PSVTooltip.prototype.create = function() {
  32517. PSVComponent.prototype.create.call(this);
  32518. this.container.innerHTML = '<div class="psv-tooltip-arrow"></div><div class="psv-tooltip-content"></div>';
  32519. this.container.style.top = '-1000px';
  32520. this.container.style.left = '-1000px';
  32521. this.content = this.container.querySelector('.psv-tooltip-content');
  32522. this.arrow = this.container.querySelector('.psv-tooltip-arrow');
  32523. this.psv.on('render', this);
  32524. };
  32525. /**
  32526. * @override
  32527. */
  32528. PSVTooltip.prototype.destroy = function() {
  32529. this.psv.off('render', this);
  32530. delete this.config;
  32531. delete this.prop;
  32532. PSVComponent.prototype.destroy.call(this);
  32533. };
  32534. /**
  32535. * @summary Handles events
  32536. * @param {Event} e
  32537. * @private
  32538. */
  32539. PSVTooltip.prototype.handleEvent = function(e) {
  32540. switch (e.type) {
  32541. // @formatter:off
  32542. case 'render': this.hideTooltip(); break;
  32543. // @formatter:on
  32544. }
  32545. };
  32546. /**
  32547. * @summary Checks if the tooltip is visible
  32548. * @returns {boolean}
  32549. */
  32550. PSVTooltip.prototype.isTooltipVisible = function() {
  32551. return this.container.classList.contains('psv-tooltip--visible');
  32552. };
  32553. /**
  32554. * @summary Displays a tooltip on the viewer
  32555. * @param {Object} config
  32556. * @param {string} config.content - HTML content of the tootlip
  32557. * @param {int} config.top - Position of the tip of the arrow of the tooltip, in pixels
  32558. * @param {int} config.left - Position of the tip of the arrow of the tooltip, in pixels
  32559. * @param {string} [config.position='top center'] - Tooltip position toward it's arrow tip.
  32560. * Accepted values are combinations of `top`, `center`, `bottom`
  32561. * and `left`, `center`, `right`
  32562. * @param {string} [config.className] - Additional CSS class added to the tooltip
  32563. * @param {Object} [config.box] - Used when displaying a tooltip on a marker
  32564. * @param {int} [config.box.width=0]
  32565. * @param {int} [config.box.height=0]
  32566. * @fires module:components.PSVTooltip.show-tooltip
  32567. * @throws {PSVError} when the configuration is incorrect
  32568. *
  32569. * @example
  32570. * viewer.showTooltip({ content: 'Hello world', top: 200, left: 450, position: 'center bottom'})
  32571. */
  32572. PSVTooltip.prototype.showTooltip = function(config) {
  32573. if (this.prop.timeout) {
  32574. window.clearTimeout(this.prop.timeout);
  32575. this.prop.timeout = null;
  32576. }
  32577. var isUpdate = this.isTooltipVisible();
  32578. var t = this.container;
  32579. var c = this.content;
  32580. var a = this.arrow;
  32581. if (!config.position) {
  32582. config.position = ['top', 'center'];
  32583. }
  32584. if (!config.box) {
  32585. config.box = {
  32586. width: 0,
  32587. height: 0
  32588. };
  32589. }
  32590. // parse position
  32591. if (typeof config.position === 'string') {
  32592. var tempPos = PSVUtils.parsePosition(config.position);
  32593. if (!(tempPos.left in PSVTooltip.leftMap) || !(tempPos.top in PSVTooltip.topMap)) {
  32594. throw new PSVError('unable to parse tooltip position "' + config.position + '"');
  32595. }
  32596. config.position = [PSVTooltip.topMap[tempPos.top], PSVTooltip.leftMap[tempPos.left]];
  32597. }
  32598. if (config.position[0] === 'center' && config.position[1] === 'center') {
  32599. throw new PSVError('unable to parse tooltip position "center center"');
  32600. }
  32601. if (isUpdate) {
  32602. // Remove every other classes (Firefox does not implements forEach)
  32603. for (var i = t.classList.length - 1; i >= 0; i--) {
  32604. var item = t.classList.item(i);
  32605. if (item !== 'psv-tooltip' && item !== 'psv-tooltip--visible') {
  32606. t.classList.remove(item);
  32607. }
  32608. }
  32609. }
  32610. else {
  32611. t.className = 'psv-tooltip'; // reset the class
  32612. }
  32613. if (config.className) {
  32614. PSVUtils.addClasses(t, config.className);
  32615. }
  32616. c.innerHTML = config.content;
  32617. t.style.top = '0px';
  32618. t.style.left = '0px';
  32619. // compute size
  32620. var rect = t.getBoundingClientRect();
  32621. var style = {
  32622. posClass: config.position.slice(),
  32623. width: rect.right - rect.left,
  32624. height: rect.bottom - rect.top,
  32625. top: 0,
  32626. left: 0,
  32627. arrow_top: 0,
  32628. arrow_left: 0
  32629. };
  32630. // set initial position
  32631. this._computeTooltipPosition(style, config);
  32632. // correct position if overflow
  32633. var refresh = false;
  32634. if (style.top < this.config.offset) {
  32635. style.posClass[0] = 'bottom';
  32636. refresh = true;
  32637. }
  32638. else if (style.top + style.height > this.psv.prop.size.height - this.config.offset) {
  32639. style.posClass[0] = 'top';
  32640. refresh = true;
  32641. }
  32642. if (style.left < this.config.offset) {
  32643. style.posClass[1] = 'right';
  32644. refresh = true;
  32645. }
  32646. else if (style.left + style.width > this.psv.prop.size.width - this.config.offset) {
  32647. style.posClass[1] = 'left';
  32648. refresh = true;
  32649. }
  32650. if (refresh) {
  32651. this._computeTooltipPosition(style, config);
  32652. }
  32653. // apply position
  32654. t.style.top = style.top + 'px';
  32655. t.style.left = style.left + 'px';
  32656. a.style.top = style.arrow_top + 'px';
  32657. a.style.left = style.arrow_left + 'px';
  32658. t.classList.add('psv-tooltip--' + style.posClass.join('-'));
  32659. // delay for correct transition between the two classes
  32660. if (!isUpdate) {
  32661. this.prop.timeout = window.setTimeout(function() {
  32662. t.classList.add('psv-tooltip--visible');
  32663. this.prop.timeout = null;
  32664. /**
  32665. * @event show-tooltip
  32666. * @memberof module:components.PSVTooltip
  32667. * @summary Trigered when the tooltip is shown
  32668. */
  32669. this.psv.trigger('show-tooltip');
  32670. }.bind(this), this.config.delay);
  32671. }
  32672. };
  32673. /**
  32674. * @summary Hides the tooltip
  32675. * @fires module:components.PSVTooltip.hide-tooltip
  32676. */
  32677. PSVTooltip.prototype.hideTooltip = function() {
  32678. if (this.prop.timeout) {
  32679. window.clearTimeout(this.prop.timeout);
  32680. this.prop.timeout = null;
  32681. }
  32682. if (this.isTooltipVisible()) {
  32683. this.container.classList.remove('psv-tooltip--visible');
  32684. this.prop.timeout = window.setTimeout(function() {
  32685. this.content.innerHTML = null;
  32686. this.container.style.top = '-1000px';
  32687. this.container.style.left = '-1000px';
  32688. this.prop.timeout = null;
  32689. }.bind(this), this.config.delay);
  32690. /**
  32691. * @event hide-tooltip
  32692. * @memberof module:components.PSVTooltip
  32693. * @summary Trigered when the tooltip is hidden
  32694. */
  32695. this.psv.trigger('hide-tooltip');
  32696. }
  32697. };
  32698. /**
  32699. * @summary Computes the position of the tooltip and its arrow
  32700. * @param {Object} style
  32701. * @param {Object} config
  32702. * @private
  32703. */
  32704. PSVTooltip.prototype._computeTooltipPosition = function(style, config) {
  32705. var topBottom = false;
  32706. switch (style.posClass[0]) {
  32707. case 'bottom':
  32708. style.top = config.top + config.box.height + this.config.offset + this.config.arrow_size;
  32709. style.arrow_top = -this.config.arrow_size * 2;
  32710. topBottom = true;
  32711. break;
  32712. case 'center':
  32713. style.top = config.top + config.box.height / 2 - style.height / 2;
  32714. style.arrow_top = style.height / 2 - this.config.arrow_size;
  32715. break;
  32716. case 'top':
  32717. style.top = config.top - style.height - this.config.offset - this.config.arrow_size;
  32718. style.arrow_top = style.height;
  32719. topBottom = true;
  32720. break;
  32721. }
  32722. switch (style.posClass[1]) {
  32723. case 'right':
  32724. if (topBottom) {
  32725. style.left = config.left + config.box.width / 2 - this.config.offset - this.config.arrow_size;
  32726. style.arrow_left = this.config.offset;
  32727. }
  32728. else {
  32729. style.left = config.left + config.box.width + this.config.offset + this.config.arrow_size;
  32730. style.arrow_left = -this.config.arrow_size * 2;
  32731. }
  32732. break;
  32733. case 'center':
  32734. style.left = config.left + config.box.width / 2 - style.width / 2;
  32735. style.arrow_left = style.width / 2 - this.config.arrow_size;
  32736. break;
  32737. case 'left':
  32738. if (topBottom) {
  32739. style.left = config.left - style.width + config.box.width / 2 + this.config.offset + this.config.arrow_size;
  32740. style.arrow_left = style.width - this.config.offset - this.config.arrow_size * 2;
  32741. }
  32742. else {
  32743. style.left = config.left - style.width - this.config.offset - this.config.arrow_size;
  32744. style.arrow_left = style.width;
  32745. }
  32746. break;
  32747. }
  32748. };
  32749. /**
  32750. * @module components/buttons
  32751. */
  32752. /**
  32753. * Navigation bar button class
  32754. * @param {module:components.PSVNavBar} navbar
  32755. * @constructor
  32756. * @extends module:components.PSVComponent
  32757. * @memberof module:components/buttons
  32758. */
  32759. function PSVNavBarButton(navbar) {
  32760. PSVComponent.call(this, navbar);
  32761. /**
  32762. * @summary Unique identifier of the button
  32763. * @member {string}
  32764. * @readonly
  32765. */
  32766. this.id = undefined;
  32767. if (this.constructor.id) {
  32768. this.id = this.constructor.id;
  32769. }
  32770. /**
  32771. * @summary State of the button
  32772. * @member {boolean}
  32773. * @readonly
  32774. */
  32775. this.enabled = true;
  32776. }
  32777. PSVNavBarButton.prototype = Object.create(PSVComponent.prototype);
  32778. PSVNavBarButton.prototype.constructor = PSVNavBarButton;
  32779. /**
  32780. * @summary Unique identifier of the button
  32781. * @member {string}
  32782. * @readonly
  32783. */
  32784. PSVNavBarButton.id = null;
  32785. /**
  32786. * @summary SVG icon name injected in the button
  32787. * @member {string}
  32788. * @readonly
  32789. */
  32790. PSVNavBarButton.icon = null;
  32791. /**
  32792. * @summary SVG icon name injected in the button when it is active
  32793. * @member {string}
  32794. * @readonly
  32795. */
  32796. PSVNavBarButton.iconActive = null;
  32797. /**
  32798. * @summary Creates the button
  32799. * @protected
  32800. */
  32801. PSVNavBarButton.prototype.create = function() {
  32802. PSVComponent.prototype.create.call(this);
  32803. if (this.constructor.icon) {
  32804. this._setIcon(this.constructor.icon);
  32805. }
  32806. if (this.id && this.psv.config.lang[this.id]) {
  32807. this.container.title = this.psv.config.lang[this.id];
  32808. }
  32809. this.container.addEventListener('click', function(e) {
  32810. if (this.enabled) {
  32811. this._onClick();
  32812. }
  32813. e.stopPropagation();
  32814. }.bind(this));
  32815. };
  32816. /**
  32817. * @summary Destroys the button
  32818. * @protected
  32819. */
  32820. PSVNavBarButton.prototype.destroy = function() {
  32821. PSVComponent.prototype.destroy.call(this);
  32822. };
  32823. /**
  32824. * @summary Changes the active state of the button
  32825. * @param {boolean} [active] - forced state
  32826. */
  32827. PSVNavBarButton.prototype.toggleActive = function(active) {
  32828. PSVUtils.toggleClass(this.container, 'psv-button--active', active);
  32829. if (this.constructor.iconActive) {
  32830. this._setIcon(active ? this.constructor.iconActive : this.constructor.icon);
  32831. }
  32832. };
  32833. /**
  32834. * @summary Disables the button
  32835. */
  32836. PSVNavBarButton.prototype.disable = function() {
  32837. this.container.classList.add('psv-button--disabled');
  32838. this.enabled = false;
  32839. };
  32840. /**
  32841. * @summary Enables the button
  32842. */
  32843. PSVNavBarButton.prototype.enable = function() {
  32844. this.container.classList.remove('psv-button--disabled');
  32845. this.enabled = true;
  32846. };
  32847. /**
  32848. * @summary Set the button icon from {@link PhotoSphereViewer.ICONS}
  32849. * @param {string} icon
  32850. * @param {HTMLElement} [container] - default is the main button container
  32851. * @private
  32852. */
  32853. PSVNavBarButton.prototype._setIcon = function(icon, container) {
  32854. if (!container) {
  32855. container = this.container;
  32856. }
  32857. if (icon) {
  32858. container.innerHTML = PhotoSphereViewer.ICONS[icon];
  32859. // classList not supported on IE11, className is read-only !!!!
  32860. container.querySelector('svg').setAttribute('class', 'psv-button-svg');
  32861. }
  32862. else {
  32863. container.innerHTML = '';
  32864. }
  32865. };
  32866. /**
  32867. * @summary Action when the button is clicked
  32868. * @private
  32869. * @abstract
  32870. */
  32871. PSVNavBarButton.prototype._onClick = function() {
  32872. };
  32873. /**
  32874. * Navigation bar autorotate button class
  32875. * @param {module:components.PSVNavBar} navbar
  32876. * @constructor
  32877. * @extends module:components/buttons.PSVNavBarButton
  32878. * @memberof module:components/buttons
  32879. */
  32880. function PSVNavBarAutorotateButton(navbar) {
  32881. PSVNavBarButton.call(this, navbar);
  32882. this.create();
  32883. }
  32884. PSVNavBarAutorotateButton.prototype = Object.create(PSVNavBarButton.prototype);
  32885. PSVNavBarAutorotateButton.prototype.constructor = PSVNavBarAutorotateButton;
  32886. PSVNavBarAutorotateButton.id = 'autorotate';
  32887. PSVNavBarAutorotateButton.className = 'psv-button psv-button--hover-scale psv-autorotate-button';
  32888. PSVNavBarAutorotateButton.icon = 'play.svg';
  32889. PSVNavBarAutorotateButton.iconActive = 'play-active.svg';
  32890. /**
  32891. * @override
  32892. */
  32893. PSVNavBarAutorotateButton.prototype.create = function() {
  32894. PSVNavBarButton.prototype.create.call(this);
  32895. this.psv.on('autorotate', this);
  32896. };
  32897. /**
  32898. * @override
  32899. */
  32900. PSVNavBarAutorotateButton.prototype.destroy = function() {
  32901. this.psv.off('autorotate', this);
  32902. PSVNavBarButton.prototype.destroy.call(this);
  32903. };
  32904. /**
  32905. * @summary Handles events
  32906. * @param {Event} e
  32907. * @private
  32908. */
  32909. PSVNavBarAutorotateButton.prototype.handleEvent = function(e) {
  32910. switch (e.type) {
  32911. // @formatter:off
  32912. case 'autorotate': this.toggleActive(e.args[0]); break;
  32913. // @formatter:on
  32914. }
  32915. };
  32916. /**
  32917. * @override
  32918. * @description Toggles autorotate
  32919. */
  32920. PSVNavBarAutorotateButton.prototype._onClick = function() {
  32921. this.psv.toggleAutorotate();
  32922. };
  32923. /**
  32924. * Navigation bar custom button class
  32925. * @param {module:components.PSVNavBar} navbar
  32926. * @param {Object} config
  32927. * @param {string} [config.id]
  32928. * @param {string} [config.className]
  32929. * @param {string} [config.title]
  32930. * @param {string} [config.content]
  32931. * @param {function} [config.onClick]
  32932. * @param {boolean} [config.enabled=true]
  32933. * @param {boolean} [config.visible=true]
  32934. * @constructor
  32935. * @extends module:components/buttons.PSVNavBarButton
  32936. * @memberof module:components/buttons
  32937. */
  32938. function PSVNavBarCustomButton(navbar, config) {
  32939. PSVNavBarButton.call(this, navbar);
  32940. /**
  32941. * @member {Object}
  32942. * @readonly
  32943. * @private
  32944. */
  32945. this.config = config;
  32946. if (this.config.id) {
  32947. this.id = this.config.id;
  32948. }
  32949. this.create();
  32950. }
  32951. PSVNavBarCustomButton.prototype = Object.create(PSVNavBarButton.prototype);
  32952. PSVNavBarCustomButton.prototype.constructor = PSVNavBarCustomButton;
  32953. PSVNavBarCustomButton.className = 'psv-button psv-custom-button';
  32954. /**
  32955. * @override
  32956. */
  32957. PSVNavBarCustomButton.prototype.create = function() {
  32958. PSVNavBarButton.prototype.create.call(this);
  32959. if (this.config.className) {
  32960. PSVUtils.addClasses(this.container, this.config.className);
  32961. }
  32962. if (this.config.title) {
  32963. this.container.title = this.config.title;
  32964. }
  32965. if (this.config.content) {
  32966. this.container.innerHTML = this.config.content;
  32967. }
  32968. if (this.config.enabled === false || this.config.disabled === true) {
  32969. this.disable();
  32970. }
  32971. if (this.config.visible === false || this.config.hidden === true) {
  32972. this.hide();
  32973. }
  32974. };
  32975. /**
  32976. * @override
  32977. */
  32978. PSVNavBarCustomButton.prototype.destroy = function() {
  32979. delete this.config;
  32980. PSVNavBarButton.prototype.destroy.call(this);
  32981. };
  32982. /**
  32983. * @override
  32984. * @description Calls user method
  32985. */
  32986. PSVNavBarCustomButton.prototype._onClick = function() {
  32987. if (this.config.onClick) {
  32988. this.config.onClick.apply(this.psv);
  32989. }
  32990. };
  32991. /**
  32992. * Navigation bar download button class
  32993. * @param {module:components.PSVNavBar} navbar
  32994. * @constructor
  32995. * @extends module:components/buttons.PSVNavBarButton
  32996. * @memberof module:components/buttons
  32997. */
  32998. function PSVNavBarDownloadButton(navbar) {
  32999. PSVNavBarButton.call(this, navbar);
  33000. this.create();
  33001. }
  33002. PSVNavBarDownloadButton.prototype = Object.create(PSVNavBarButton.prototype);
  33003. PSVNavBarDownloadButton.prototype.constructor = PSVNavBarDownloadButton;
  33004. PSVNavBarDownloadButton.id = 'download';
  33005. PSVNavBarDownloadButton.className = 'psv-button psv-button--hover-scale psv-download-button';
  33006. PSVNavBarDownloadButton.icon = 'download.svg';
  33007. /**
  33008. * @override
  33009. * @description Asks the browser to download the panorama source file
  33010. */
  33011. PSVNavBarDownloadButton.prototype._onClick = function() {
  33012. var link = document.createElement('a');
  33013. link.href = this.psv.config.panorama;
  33014. link.download = this.psv.config.panorama;
  33015. this.psv.container.appendChild(link);
  33016. link.click();
  33017. };
  33018. /**
  33019. * Navigation bar fullscreen button class
  33020. * @param {module:components.PSVNavBar} navbar
  33021. * @constructor
  33022. * @extends module:components/buttons.PSVNavBarButton
  33023. * @memberof module:components/buttons
  33024. */
  33025. function PSVNavBarFullscreenButton(navbar) {
  33026. PSVNavBarButton.call(this, navbar);
  33027. this.create();
  33028. }
  33029. PSVNavBarFullscreenButton.prototype = Object.create(PSVNavBarButton.prototype);
  33030. PSVNavBarFullscreenButton.prototype.constructor = PSVNavBarFullscreenButton;
  33031. PSVNavBarFullscreenButton.id = 'fullscreen';
  33032. PSVNavBarFullscreenButton.className = 'psv-button psv-button--hover-scale psv-fullscreen-button';
  33033. PSVNavBarFullscreenButton.icon = 'fullscreen-in.svg';
  33034. PSVNavBarFullscreenButton.iconActive = 'fullscreen-out.svg';
  33035. /**
  33036. * @override
  33037. */
  33038. PSVNavBarFullscreenButton.prototype.create = function() {
  33039. PSVNavBarButton.prototype.create.call(this);
  33040. if (!PhotoSphereViewer.SYSTEM.fullscreenEvent) {
  33041. this.hide();
  33042. console.warn('PhotoSphereViewer: fullscreen not supported.');
  33043. }
  33044. this.psv.on('fullscreen-updated', this);
  33045. };
  33046. /**
  33047. * @override
  33048. */
  33049. PSVNavBarFullscreenButton.prototype.destroy = function() {
  33050. this.psv.off('fullscreen-updated', this);
  33051. PSVNavBarButton.prototype.destroy.call(this);
  33052. };
  33053. /**
  33054. * Handle events
  33055. * @param {Event} e
  33056. * @private
  33057. */
  33058. PSVNavBarFullscreenButton.prototype.handleEvent = function(e) {
  33059. switch (e.type) {
  33060. // @formatter:off
  33061. case 'fullscreen-updated': this.toggleActive(e.args[0]); break;
  33062. // @formatter:on
  33063. }
  33064. };
  33065. /**
  33066. * @override
  33067. * @description Toggles fullscreen
  33068. */
  33069. PSVNavBarFullscreenButton.prototype._onClick = function() {
  33070. this.psv.toggleFullscreen();
  33071. };
  33072. /**
  33073. * Navigation bar gyroscope button class
  33074. * @param {module:components.PSVNavBar} navbar
  33075. * @constructor
  33076. * @extends module:components/buttons.PSVNavBarButton
  33077. * @memberof module:components/buttons
  33078. */
  33079. function PSVNavBarGyroscopeButton(navbar) {
  33080. PSVNavBarButton.call(this, navbar);
  33081. this.create();
  33082. }
  33083. PSVNavBarGyroscopeButton.prototype = Object.create(PSVNavBarButton.prototype);
  33084. PSVNavBarGyroscopeButton.prototype.constructor = PSVNavBarGyroscopeButton;
  33085. PSVNavBarGyroscopeButton.id = 'gyroscope';
  33086. PSVNavBarGyroscopeButton.className = 'psv-button psv-button--hover-scale psv-gyroscope-button';
  33087. PSVNavBarGyroscopeButton.icon = 'compass.svg';
  33088. /**
  33089. * @override
  33090. * @description The button gets visible once the gyroscope API is ready
  33091. */
  33092. PSVNavBarGyroscopeButton.prototype.create = function() {
  33093. PSVNavBarButton.prototype.create.call(this);
  33094. PhotoSphereViewer.SYSTEM.deviceOrientationSupported.then(
  33095. this._onAvailabilityChange.bind(this, true),
  33096. this._onAvailabilityChange.bind(this, false)
  33097. );
  33098. this.hide();
  33099. this.psv.on('gyroscope-updated', this);
  33100. };
  33101. /**
  33102. * @override
  33103. */
  33104. PSVNavBarGyroscopeButton.prototype.destroy = function() {
  33105. this.psv.off('gyroscope-updated', this);
  33106. PSVNavBarButton.prototype.destroy.call(this);
  33107. };
  33108. /**
  33109. * @summary Handles events
  33110. * @param {Event} e
  33111. * @private
  33112. */
  33113. PSVNavBarGyroscopeButton.prototype.handleEvent = function(e) {
  33114. switch (e.type) {
  33115. // @formatter:off
  33116. case 'gyroscope-updated': this.toggleActive(e.args[0]); break;
  33117. // @formatter:on
  33118. }
  33119. };
  33120. /**
  33121. * @override
  33122. * @description Toggles gyroscope control
  33123. */
  33124. PSVNavBarGyroscopeButton.prototype._onClick = function() {
  33125. this.psv.toggleGyroscopeControl();
  33126. };
  33127. /**
  33128. * @summary Updates button display when API is ready
  33129. * @param {boolean} available
  33130. * @private
  33131. * @throws {PSVError} when {@link THREE.DeviceOrientationControls} is not loaded
  33132. */
  33133. PSVNavBarGyroscopeButton.prototype._onAvailabilityChange = function(available) {
  33134. if (available) {
  33135. if (PSVUtils.checkTHREE('DeviceOrientationControls')) {
  33136. this.show();
  33137. }
  33138. else {
  33139. throw new PSVError('Missing Three.js components: DeviceOrientationControls. Get them from three.js-examples package.');
  33140. }
  33141. }
  33142. };
  33143. /**
  33144. * Navigation bar markers button class
  33145. * @param {module:components.PSVNavBar} navbar
  33146. * @constructor
  33147. * @extends module:components/buttons.PSVNavBarButton
  33148. * @memberof module:components/buttons
  33149. */
  33150. function PSVNavBarMarkersButton(navbar) {
  33151. PSVNavBarButton.call(this, navbar);
  33152. this.create();
  33153. }
  33154. PSVNavBarMarkersButton.prototype = Object.create(PSVNavBarButton.prototype);
  33155. PSVNavBarMarkersButton.prototype.constructor = PSVNavBarMarkersButton;
  33156. PSVNavBarMarkersButton.id = 'markers';
  33157. PSVNavBarMarkersButton.className = 'psv-button psv-button--hover-scale psv-markers-button';
  33158. PSVNavBarMarkersButton.icon = 'pin.svg';
  33159. /**
  33160. * @override
  33161. * @description Toggles markers list
  33162. */
  33163. PSVNavBarMarkersButton.prototype._onClick = function() {
  33164. this.psv.hud.toggleMarkersList();
  33165. };
  33166. /**
  33167. * Navigation bar zoom button class
  33168. * @param {module:components.PSVNavBar} navbar
  33169. * @constructor
  33170. * @extends module:components/buttons.PSVNavBarButton
  33171. * @memberof module:components/buttons
  33172. */
  33173. function PSVNavBarZoomButton(navbar) {
  33174. PSVNavBarButton.call(this, navbar);
  33175. /**
  33176. * @member {HTMLElement}
  33177. * @readonly
  33178. * @private
  33179. */
  33180. this.zoom_range = null;
  33181. /**
  33182. * @member {HTMLElement}
  33183. * @readonly
  33184. * @private
  33185. */
  33186. this.zoom_value = null;
  33187. /**
  33188. * @member {Object}
  33189. * @private
  33190. */
  33191. this.prop = {
  33192. mousedown: false,
  33193. buttondown: false,
  33194. longPressInterval: null,
  33195. longPressTimeout: null
  33196. };
  33197. this.create();
  33198. }
  33199. PSVNavBarZoomButton.prototype = Object.create(PSVNavBarButton.prototype);
  33200. PSVNavBarZoomButton.prototype.constructor = PSVNavBarZoomButton;
  33201. PSVNavBarZoomButton.id = 'zoom';
  33202. PSVNavBarZoomButton.className = 'psv-button psv-zoom-button';
  33203. /**
  33204. * @override
  33205. */
  33206. PSVNavBarZoomButton.prototype.create = function() {
  33207. PSVNavBarButton.prototype.create.call(this);
  33208. var zoom_minus = document.createElement('div');
  33209. zoom_minus.className = 'psv-zoom-button-minus';
  33210. zoom_minus.title = this.psv.config.lang.zoomOut;
  33211. this._setIcon('zoom-out.svg', zoom_minus);
  33212. this.container.appendChild(zoom_minus);
  33213. var zoom_range_bg = document.createElement('div');
  33214. zoom_range_bg.className = 'psv-zoom-button-range';
  33215. this.container.appendChild(zoom_range_bg);
  33216. this.zoom_range = document.createElement('div');
  33217. this.zoom_range.className = 'psv-zoom-button-line';
  33218. zoom_range_bg.appendChild(this.zoom_range);
  33219. this.zoom_value = document.createElement('div');
  33220. this.zoom_value.className = 'psv-zoom-button-handle';
  33221. this.zoom_range.appendChild(this.zoom_value);
  33222. var zoom_plus = document.createElement('div');
  33223. zoom_plus.className = 'psv-zoom-button-plus';
  33224. zoom_plus.title = this.psv.config.lang.zoomIn;
  33225. this._setIcon('zoom-in.svg', zoom_plus);
  33226. this.container.appendChild(zoom_plus);
  33227. this.zoom_range.addEventListener('mousedown', this);
  33228. this.zoom_range.addEventListener('touchstart', this);
  33229. this.psv.container.addEventListener('mousemove', this);
  33230. this.psv.container.addEventListener('touchmove', this);
  33231. this.psv.container.addEventListener('mouseup', this);
  33232. this.psv.container.addEventListener('touchend', this);
  33233. zoom_minus.addEventListener('mousedown', this._zoomOut.bind(this));
  33234. zoom_plus.addEventListener('mousedown', this._zoomIn.bind(this));
  33235. this.psv.on('zoom-updated', this);
  33236. this.psv.once('ready', function() {
  33237. this._moveZoomValue(this.psv.prop.zoom_lvl);
  33238. }.bind(this));
  33239. };
  33240. /**
  33241. * @override
  33242. */
  33243. PSVNavBarZoomButton.prototype.destroy = function() {
  33244. this._stopZoomChange();
  33245. this.psv.container.removeEventListener('mousemove', this);
  33246. this.psv.container.removeEventListener('touchmove', this);
  33247. this.psv.container.removeEventListener('mouseup', this);
  33248. this.psv.container.removeEventListener('touchend', this);
  33249. delete this.zoom_range;
  33250. delete this.zoom_value;
  33251. this.psv.off('zoom-updated', this);
  33252. PSVNavBarButton.prototype.destroy.call(this);
  33253. };
  33254. /**
  33255. * @summary Handles events
  33256. * @param {Event} e
  33257. * @private
  33258. */
  33259. PSVNavBarZoomButton.prototype.handleEvent = function(e) {
  33260. switch (e.type) {
  33261. // @formatter:off
  33262. case 'mousedown': this._initZoomChangeWithMouse(e); break;
  33263. case 'touchstart': this._initZoomChangeByTouch(e); break;
  33264. case 'mousemove': this._changeZoomWithMouse(e); break;
  33265. case 'touchmove': this._changeZoomByTouch(e); break;
  33266. case 'mouseup': this._stopZoomChange(e); break;
  33267. case 'touchend': this._stopZoomChange(e); break;
  33268. case 'zoom-updated': this._moveZoomValue(e.args[0]); break;
  33269. // @formatter:on
  33270. }
  33271. };
  33272. /**
  33273. * @summary Moves the zoom cursor
  33274. * @param {int} level
  33275. * @private
  33276. */
  33277. PSVNavBarZoomButton.prototype._moveZoomValue = function(level) {
  33278. this.zoom_value.style.left = (level / 100 * this.zoom_range.offsetWidth - this.zoom_value.offsetWidth / 2) + 'px';
  33279. };
  33280. /**
  33281. * @summary Handles mouse down events
  33282. * @param {MouseEvent} evt
  33283. * @private
  33284. */
  33285. PSVNavBarZoomButton.prototype._initZoomChangeWithMouse = function(evt) {
  33286. if (!this.enabled) {
  33287. return;
  33288. }
  33289. this.prop.mousedown = true;
  33290. this._changeZoom(evt.clientX);
  33291. };
  33292. /**
  33293. * @summary Handles touch events
  33294. * @param {TouchEvent} evt
  33295. * @private
  33296. */
  33297. PSVNavBarZoomButton.prototype._initZoomChangeByTouch = function(evt) {
  33298. if (!this.enabled) {
  33299. return;
  33300. }
  33301. this.prop.mousedown = true;
  33302. this._changeZoom(evt.changedTouches[0].clientX);
  33303. };
  33304. /**
  33305. * @summary Handles click events
  33306. * @description Zooms in and register long press timer
  33307. * @private
  33308. */
  33309. PSVNavBarZoomButton.prototype._zoomIn = function() {
  33310. if (!this.enabled) {
  33311. return;
  33312. }
  33313. this.prop.buttondown = true;
  33314. this.psv.zoomIn();
  33315. this.prop.longPressTimeout = window.setTimeout(this._startLongPressInterval.bind(this, 1), 200);
  33316. };
  33317. /**
  33318. * @summary Handles click events
  33319. * @description Zooms out and register long press timer
  33320. * @private
  33321. */
  33322. PSVNavBarZoomButton.prototype._zoomOut = function() {
  33323. if (!this.enabled) {
  33324. return;
  33325. }
  33326. this.prop.buttondown = true;
  33327. this.psv.zoomOut();
  33328. this.prop.longPressTimeout = window.setTimeout(this._startLongPressInterval.bind(this, -1), 200);
  33329. };
  33330. /**
  33331. * @summary Continues zooming as long as the user presses the button
  33332. * @param value
  33333. * @private
  33334. */
  33335. PSVNavBarZoomButton.prototype._startLongPressInterval = function(value) {
  33336. if (this.prop.buttondown) {
  33337. this.prop.longPressInterval = window.setInterval(function() {
  33338. this.psv.zoom(this.psv.prop.zoom_lvl + value);
  33339. }.bind(this), 50);
  33340. }
  33341. };
  33342. /**
  33343. * @summary Handles mouse up events
  33344. * @private
  33345. */
  33346. PSVNavBarZoomButton.prototype._stopZoomChange = function() {
  33347. if (!this.enabled) {
  33348. return;
  33349. }
  33350. window.clearInterval(this.prop.longPressInterval);
  33351. window.clearTimeout(this.prop.longPressTimeout);
  33352. this.prop.longPressInterval = null;
  33353. this.prop.mousedown = false;
  33354. this.prop.buttondown = false;
  33355. };
  33356. /**
  33357. * @summary Handles mouse move events
  33358. * @param {MouseEvent} evt
  33359. * @private
  33360. */
  33361. PSVNavBarZoomButton.prototype._changeZoomWithMouse = function(evt) {
  33362. if (!this.enabled) {
  33363. return;
  33364. }
  33365. evt.preventDefault();
  33366. this._changeZoom(evt.clientX);
  33367. };
  33368. /**
  33369. * @summary Handles touch move events
  33370. * @param {TouchEvent} evt
  33371. * @private
  33372. */
  33373. PSVNavBarZoomButton.prototype._changeZoomByTouch = function(evt) {
  33374. if (!this.enabled) {
  33375. return;
  33376. }
  33377. this._changeZoom(evt.changedTouches[0].clientX);
  33378. };
  33379. /**
  33380. * @summary Zoom change
  33381. * @param {int} x - mouse/touch position
  33382. * @private
  33383. */
  33384. PSVNavBarZoomButton.prototype._changeZoom = function(x) {
  33385. if (this.prop.mousedown) {
  33386. var user_input = parseInt(x) - this.zoom_range.getBoundingClientRect().left;
  33387. var zoom_level = user_input / this.zoom_range.offsetWidth * 100;
  33388. this.psv.zoom(zoom_level);
  33389. }
  33390. };
  33391. /**
  33392. * Custom error used in the lib
  33393. * @param {string} message
  33394. * @constructor
  33395. */
  33396. function PSVError(message) {
  33397. this.message = message;
  33398. // Use V8's native method if available, otherwise fallback
  33399. if ('captureStackTrace' in Error) {
  33400. Error.captureStackTrace(this, PSVError);
  33401. }
  33402. else {
  33403. this.stack = (new Error()).stack;
  33404. }
  33405. }
  33406. PSVError.prototype = Object.create(Error.prototype);
  33407. PSVError.prototype.name = 'PSVError';
  33408. PSVError.prototype.constructor = PSVError;
  33409. /**
  33410. * @summary exposes {@link PSVError}
  33411. * @memberof PhotoSphereViewer
  33412. * @readonly
  33413. */
  33414. PhotoSphereViewer.Error = PSVError;
  33415. /**
  33416. * Object representing a marker
  33417. * @param {Object} properties - see {@link http://photo-sphere-viewer.js.org/markers.html#config} (merged with the object itself)
  33418. * @param {PhotoSphereViewer} psv
  33419. * @constructor
  33420. * @throws {PSVError} when the configuration is incorrect
  33421. */
  33422. function PSVMarker(properties, psv) {
  33423. if (!properties.id) {
  33424. throw new PSVError('missing marker id');
  33425. }
  33426. if (properties.image && (!properties.width || !properties.height)) {
  33427. throw new PSVError('missing marker width/height');
  33428. }
  33429. if (properties.image || properties.html) {
  33430. if ((!properties.hasOwnProperty('x') || !properties.hasOwnProperty('y')) && (!properties.hasOwnProperty('latitude') || !properties.hasOwnProperty('longitude'))) {
  33431. throw new PSVError('missing marker position, latitude/longitude or x/y');
  33432. }
  33433. }
  33434. /**
  33435. * @member {PhotoSphereViewer}
  33436. * @readonly
  33437. * @protected
  33438. */
  33439. this.psv = psv;
  33440. /**
  33441. * @member {boolean}
  33442. */
  33443. this.visible = true;
  33444. /**
  33445. * @member {boolean}
  33446. * @readonly
  33447. * @private
  33448. */
  33449. this._dynamicSize = false;
  33450. // private properties
  33451. var _id = properties.id;
  33452. var _type = PSVMarker.getType(properties, false);
  33453. var $el;
  33454. // readonly properties
  33455. Object.defineProperties(this, {
  33456. /**
  33457. * @memberof PSVMarker
  33458. * @type {string}
  33459. * @readonly
  33460. */
  33461. id: {
  33462. configurable: false,
  33463. enumerable: true,
  33464. get: function() {
  33465. return _id;
  33466. },
  33467. set: function() {
  33468. }
  33469. },
  33470. /**
  33471. * @memberof PSVMarker
  33472. * @type {string}
  33473. * @see PSVMarker.types
  33474. * @readonly
  33475. */
  33476. type: {
  33477. configurable: false,
  33478. enumerable: true,
  33479. get: function() {
  33480. return _type;
  33481. },
  33482. set: function() {
  33483. }
  33484. },
  33485. /**
  33486. * @memberof PSVMarker
  33487. * @type {HTMLDivElement|SVGElement}
  33488. * @readonly
  33489. */
  33490. $el: {
  33491. configurable: false,
  33492. enumerable: true,
  33493. get: function() {
  33494. return $el;
  33495. },
  33496. set: function() {
  33497. }
  33498. },
  33499. /**
  33500. * @summary Quick access to self value of key `type`
  33501. * @memberof PSVMarker
  33502. * @type {*}
  33503. * @private
  33504. */
  33505. _def: {
  33506. configurable: false,
  33507. enumerable: true,
  33508. get: function() {
  33509. return this[_type];
  33510. },
  33511. set: function(value) {
  33512. this[_type] = value;
  33513. }
  33514. }
  33515. });
  33516. // create element
  33517. if (this.isNormal()) {
  33518. $el = document.createElement('div');
  33519. }
  33520. else if (this.isPolygon()) {
  33521. $el = document.createElementNS(PSVUtils.svgNS, 'polygon');
  33522. }
  33523. else if (this.isPolyline()) {
  33524. $el = document.createElementNS(PSVUtils.svgNS, 'polyline');
  33525. }
  33526. else {
  33527. $el = document.createElementNS(PSVUtils.svgNS, this.type);
  33528. }
  33529. $el.id = 'psv-marker-' + this.id;
  33530. $el.psvMarker = this;
  33531. this.update(properties);
  33532. }
  33533. /**
  33534. * @summary Types of markers
  33535. * @type {string[]}
  33536. * @readonly
  33537. */
  33538. PSVMarker.types = ['image', 'html', 'polygon_px', 'polygon_rad', 'polyline_px', 'polyline_rad', 'rect', 'circle', 'ellipse', 'path'];
  33539. /**
  33540. * @summary Determines the type of a marker by the available properties
  33541. * @param {object} properties
  33542. * @param {boolean} [allowNone=false]
  33543. * @returns {string}
  33544. * @throws {PSVError} when the marker's type cannot be found
  33545. */
  33546. PSVMarker.getType = function(properties, allowNone) {
  33547. var found = [];
  33548. PSVMarker.types.forEach(function(type) {
  33549. if (properties[type]) {
  33550. found.push(type);
  33551. }
  33552. });
  33553. if (found.length === 0 && !allowNone) {
  33554. throw new PSVError('missing marker content, either ' + PSVMarker.types.join(', '));
  33555. }
  33556. else if (found.length > 1) {
  33557. throw new PSVError('multiple marker content, either ' + PSVMarker.types.join(', '));
  33558. }
  33559. return found[0];
  33560. };
  33561. /**
  33562. * @summary Destroys the marker
  33563. */
  33564. PSVMarker.prototype.destroy = function() {
  33565. delete this.$el.psvMarker;
  33566. };
  33567. /**
  33568. * @summary Checks if it is a normal marker (image or html)
  33569. * @returns {boolean}
  33570. */
  33571. PSVMarker.prototype.isNormal = function() {
  33572. return this.type === 'image' || this.type === 'html';
  33573. };
  33574. /**
  33575. * @summary Checks if it is a polygon/polyline marker
  33576. * @returns {boolean}
  33577. */
  33578. PSVMarker.prototype.isPoly = function() {
  33579. return this.isPolygon() || this.isPolyline();
  33580. };
  33581. /**
  33582. * @summary Checks if it is a polygon marker
  33583. * @returns {boolean}
  33584. */
  33585. PSVMarker.prototype.isPolygon = function() {
  33586. return this.type === 'polygon_px' || this.type === 'polygon_rad';
  33587. };
  33588. /**
  33589. * @summary Checks if it is a polyline marker
  33590. * @returns {boolean}
  33591. */
  33592. PSVMarker.prototype.isPolyline = function() {
  33593. return this.type === 'polyline_px' || this.type === 'polyline_rad';
  33594. };
  33595. /**
  33596. * @summary Checks if it is an SVG marker
  33597. * @returns {boolean}
  33598. */
  33599. PSVMarker.prototype.isSvg = function() {
  33600. return this.type === 'rect' || this.type === 'circle' || this.type === 'ellipse' || this.type === 'path';
  33601. };
  33602. /**
  33603. * @summary Computes marker scale from zoom level
  33604. * @param {float} zoomLevel
  33605. * @returns {float}
  33606. */
  33607. PSVMarker.prototype.getScale = function(zoomLevel) {
  33608. if (Array.isArray(this.scale)) {
  33609. return this.scale[0] + (this.scale[1] - this.scale[0]) * PSVUtils.animation.easings.inQuad(zoomLevel / 100);
  33610. }
  33611. else if (typeof this.scale === 'function') {
  33612. return this.scale(zoomLevel);
  33613. }
  33614. else if (typeof this.scale === 'number') {
  33615. return this.scale * PSVUtils.animation.easings.inQuad(zoomLevel / 100);
  33616. }
  33617. else {
  33618. return 1;
  33619. }
  33620. };
  33621. /**
  33622. * @summary Updates the marker with new properties
  33623. * @param {object} [properties]
  33624. * @throws {PSVError} when trying to change the marker's type
  33625. */
  33626. PSVMarker.prototype.update = function(properties) {
  33627. // merge objects
  33628. if (properties && properties !== this) {
  33629. var newType = PSVMarker.getType(properties, true);
  33630. if (newType !== undefined && newType !== this.type) {
  33631. throw new PSVError('cannot change marker type');
  33632. }
  33633. PSVUtils.deepmerge(this, properties);
  33634. }
  33635. // reset CSS class
  33636. if (this.isNormal()) {
  33637. this.$el.setAttribute('class', 'psv-marker psv-marker--normal');
  33638. }
  33639. else {
  33640. this.$el.setAttribute('class', 'psv-marker psv-marker--svg');
  33641. }
  33642. // add CSS classes
  33643. if (this.className) {
  33644. PSVUtils.addClasses(this.$el, this.className);
  33645. }
  33646. if (this.tooltip) {
  33647. PSVUtils.addClasses(this.$el, 'has-tooltip');
  33648. if (typeof this.tooltip === 'string') {
  33649. this.tooltip = { content: this.tooltip };
  33650. }
  33651. }
  33652. // apply style
  33653. if (this.style) {
  33654. PSVUtils.deepmerge(this.$el.style, this.style);
  33655. }
  33656. // parse anchor
  33657. this.anchor = PSVUtils.parsePosition(this.anchor);
  33658. if (this.isNormal()) {
  33659. this._updateNormal();
  33660. }
  33661. else if (this.isPolygon()) {
  33662. this._updatePoly('polygon_rad', 'polygon_px');
  33663. }
  33664. else if (this.isPolyline()) {
  33665. this._updatePoly('polyline_rad', 'polyline_px');
  33666. }
  33667. else {
  33668. this._updateSvg();
  33669. }
  33670. };
  33671. /**
  33672. * @summary Updates a normal marker
  33673. * @private
  33674. */
  33675. PSVMarker.prototype._updateNormal = function() {
  33676. if (this.width && this.height) {
  33677. this.$el.style.width = this.width + 'px';
  33678. this.$el.style.height = this.height + 'px';
  33679. this._dynamicSize = false;
  33680. }
  33681. else {
  33682. this._dynamicSize = true;
  33683. }
  33684. if (this.image) {
  33685. this.$el.style.backgroundImage = 'url(' + this.image + ')';
  33686. }
  33687. else {
  33688. this.$el.innerHTML = this.html;
  33689. }
  33690. // set anchor
  33691. this.$el.style.transformOrigin = this.anchor.left * 100 + '% ' + this.anchor.top * 100 + '%';
  33692. // convert texture coordinates to spherical coordinates
  33693. this.psv.cleanPosition(this);
  33694. // compute x/y/z position
  33695. this.position3D = this.psv.sphericalCoordsToVector3(this);
  33696. };
  33697. /**
  33698. * @summary Updates an SVG marker
  33699. * @private
  33700. */
  33701. PSVMarker.prototype._updateSvg = function() {
  33702. this._dynamicSize = true;
  33703. // set content
  33704. switch (this.type) {
  33705. case 'rect':
  33706. if (typeof this._def === 'number') {
  33707. this._def = {
  33708. x: 0,
  33709. y: 0,
  33710. width: this._def,
  33711. height: this._def
  33712. };
  33713. }
  33714. else if (Array.isArray(this._def)) {
  33715. this._def = {
  33716. x: 0,
  33717. y: 0,
  33718. width: this._def[0],
  33719. height: this._def[1]
  33720. };
  33721. }
  33722. else {
  33723. this._def.x = this._def.y = 0;
  33724. }
  33725. break;
  33726. case 'circle':
  33727. if (typeof this._def === 'number') {
  33728. this._def = {
  33729. cx: this._def,
  33730. cy: this._def,
  33731. r: this._def
  33732. };
  33733. }
  33734. else if (Array.isArray(this._def)) {
  33735. this._def = {
  33736. cx: this._def[0],
  33737. cy: this._def[0],
  33738. r: this._def[0]
  33739. };
  33740. }
  33741. else {
  33742. this._def.cx = this._def.cy = this._def.r;
  33743. }
  33744. break;
  33745. case 'ellipse':
  33746. if (typeof this._def === 'number') {
  33747. this._def = {
  33748. cx: this._def,
  33749. cy: this._def,
  33750. rx: this._def,
  33751. ry: this._def
  33752. };
  33753. }
  33754. else if (Array.isArray(this._def)) {
  33755. this._def = {
  33756. cx: this._def[0],
  33757. cy: this._def[1],
  33758. rx: this._def[0],
  33759. ry: this._def[1]
  33760. };
  33761. }
  33762. else {
  33763. this._def.cx = this._def.rx;
  33764. this._def.cy = this._def.ry;
  33765. }
  33766. break;
  33767. case 'path':
  33768. if (typeof this._def === 'string') {
  33769. this._def = {
  33770. d: this._def
  33771. };
  33772. }
  33773. break;
  33774. }
  33775. Object.getOwnPropertyNames(this._def).forEach(function(prop) {
  33776. this.$el.setAttributeNS(null, prop, this._def[prop]);
  33777. }, this);
  33778. // set style
  33779. if (this.svgStyle) {
  33780. Object.getOwnPropertyNames(this.svgStyle).forEach(function(prop) {
  33781. this.$el.setAttributeNS(null, PSVUtils.dasherize(prop), this.svgStyle[prop]);
  33782. }, this);
  33783. }
  33784. else {
  33785. this.$el.setAttributeNS(null, 'fill', 'rgba(0,0,0,0.5)');
  33786. }
  33787. // convert texture coordinates to spherical coordinates
  33788. this.psv.cleanPosition(this);
  33789. // compute x/y/z position
  33790. this.position3D = this.psv.sphericalCoordsToVector3(this);
  33791. };
  33792. /**
  33793. * @summary Updates a polygon marker
  33794. * @param {'polygon_rad'|'polyline_rad'} key_rad
  33795. * @param {'polygon_px'|'polyline_px'} key_px
  33796. * @private
  33797. */
  33798. PSVMarker.prototype._updatePoly = function(key_rad, key_px) {
  33799. this._dynamicSize = true;
  33800. // set style
  33801. if (this.svgStyle) {
  33802. Object.getOwnPropertyNames(this.svgStyle).forEach(function(prop) {
  33803. this.$el.setAttributeNS(null, PSVUtils.dasherize(prop), this.svgStyle[prop]);
  33804. }, this);
  33805. if (this.isPolyline() && !this.svgStyle.fill) {
  33806. this.$el.setAttributeNS(null, 'fill', 'none');
  33807. }
  33808. }
  33809. else if (this.isPolygon()) {
  33810. this.$el.setAttributeNS(null, 'fill', 'rgba(0,0,0,0.5)');
  33811. }
  33812. else if (this.isPolyline()) {
  33813. this.$el.setAttributeNS(null, 'fill', 'none');
  33814. this.$el.setAttributeNS(null, 'stroke', 'rgb(0,0,0)');
  33815. }
  33816. // fold arrays: [1,2,3,4] => [[1,2],[3,4]]
  33817. [this[key_rad], this[key_px]].forEach(function(polygon) {
  33818. if (polygon && typeof polygon[0] !== 'object') {
  33819. for (var i = 0; i < polygon.length; i++) {
  33820. polygon.splice(i, 2, [polygon[i], polygon[i + 1]]);
  33821. }
  33822. }
  33823. });
  33824. // convert texture coordinates to spherical coordinates
  33825. if (this[key_px]) {
  33826. this[key_rad] = this[key_px].map(function(coord) {
  33827. var sphericalCoords = this.psv.textureCoordsToSphericalCoords({ x: coord[0], y: coord[1] });
  33828. return [sphericalCoords.longitude, sphericalCoords.latitude];
  33829. }, this);
  33830. }
  33831. // clean angles
  33832. else {
  33833. this[key_rad] = this[key_rad].map(function(coord) {
  33834. return [
  33835. PSVUtils.parseAngle(coord[0]),
  33836. PSVUtils.parseAngle(coord[1], true)
  33837. ];
  33838. });
  33839. }
  33840. // TODO : compute the center of the polygon
  33841. this.longitude = this[key_rad][0][0];
  33842. this.latitude = this[key_rad][0][1];
  33843. // compute x/y/z positions
  33844. this.positions3D = this[key_rad].map(function(coord) {
  33845. return this.psv.sphericalCoordsToVector3({ longitude: coord[0], latitude: coord[1] });
  33846. }, this);
  33847. };
  33848. /**
  33849. * Static utilities for PSV
  33850. * @namespace
  33851. */
  33852. var PSVUtils = {};
  33853. /**
  33854. * @summary exposes {@link PSVUtils}
  33855. * @member {object}
  33856. * @memberof PhotoSphereViewer
  33857. * @readonly
  33858. */
  33859. PhotoSphereViewer.Utils = PSVUtils;
  33860. /**
  33861. * @summary Short-Hand for PI*2
  33862. * @type {float}
  33863. * @readonly
  33864. */
  33865. PSVUtils.TwoPI = Math.PI * 2.0;
  33866. /**
  33867. * @summary Short-Hand for PI/2
  33868. * @type {float}
  33869. * @readonly
  33870. */
  33871. PSVUtils.HalfPI = Math.PI / 2.0;
  33872. /**
  33873. * @summary Namespace for SVG creation
  33874. * @type {string}
  33875. * @readonly
  33876. */
  33877. PSVUtils.svgNS = 'http://www.w3.org/2000/svg';
  33878. /**
  33879. * @summary Checks if some three.js components are loaded
  33880. * @param {...string} components
  33881. * @returns {boolean}
  33882. */
  33883. PSVUtils.checkTHREE = function(components) {
  33884. for (var i = 0, l = arguments.length; i < l; i++) {
  33885. if (!(arguments[i] in THREE)) {
  33886. return false;
  33887. }
  33888. }
  33889. return true;
  33890. };
  33891. /**
  33892. * @summary Detects if canvas is supported
  33893. * @returns {boolean}
  33894. */
  33895. PSVUtils.isCanvasSupported = function() {
  33896. var canvas = document.createElement('canvas');
  33897. return !!(canvas.getContext && canvas.getContext('2d'));
  33898. };
  33899. /**
  33900. * @summary Tries to return a canvas webgl context
  33901. * @returns {WebGLRenderingContext}
  33902. */
  33903. PSVUtils.getWebGLCtx = function() {
  33904. var canvas = document.createElement('canvas');
  33905. var names = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'];
  33906. var context = null;
  33907. if (!canvas.getContext) {
  33908. return null;
  33909. }
  33910. if (names.some(function(name) {
  33911. try {
  33912. context = canvas.getContext(name);
  33913. return (context && typeof context.getParameter === 'function');
  33914. } catch (e) {
  33915. return false;
  33916. }
  33917. })) {
  33918. return context;
  33919. }
  33920. else {
  33921. return null;
  33922. }
  33923. };
  33924. /**
  33925. * @summary Detects if WebGL is supported
  33926. * @returns {boolean}
  33927. */
  33928. PSVUtils.isWebGLSupported = function() {
  33929. return !!window.WebGLRenderingContext && PSVUtils.getWebGLCtx() !== null;
  33930. };
  33931. /**
  33932. * @summary Detects if device orientation is supported
  33933. * @description We can only be sure device orientation is supported once received an event with coherent data
  33934. * @returns {Promise}
  33935. */
  33936. PSVUtils.isDeviceOrientationSupported = function() {
  33937. var defer = D();
  33938. if ('DeviceOrientationEvent' in window) {
  33939. var listener = function(event) {
  33940. if (event && event.alpha !== null && !isNaN(event.alpha)) {
  33941. defer.resolve();
  33942. }
  33943. else {
  33944. defer.reject();
  33945. }
  33946. window.removeEventListener('deviceorientation', listener);
  33947. };
  33948. window.addEventListener('deviceorientation', listener, false);
  33949. setTimeout(function() {
  33950. if (defer.promise.isPending()) {
  33951. listener(null);
  33952. }
  33953. }, 2000);
  33954. }
  33955. else {
  33956. defer.reject();
  33957. }
  33958. return defer.promise;
  33959. };
  33960. /**
  33961. * @summary Gets max texture width in WebGL context
  33962. * @returns {int}
  33963. */
  33964. PSVUtils.getMaxTextureWidth = function() {
  33965. var ctx = PSVUtils.getWebGLCtx();
  33966. if (ctx !== null) {
  33967. return ctx.getParameter(ctx.MAX_TEXTURE_SIZE);
  33968. }
  33969. else {
  33970. return 0;
  33971. }
  33972. };
  33973. /**
  33974. * @summary Toggles a CSS class
  33975. * @param {HTMLElement|SVGElement} element
  33976. * @param {string} className
  33977. * @param {boolean} [active] - forced state
  33978. */
  33979. PSVUtils.toggleClass = function(element, className, active) {
  33980. // manual implementation for IE11 and SVGElement
  33981. if (!element.classList) {
  33982. var currentClassName = element.getAttribute('class') || '';
  33983. var currentActive = currentClassName.indexOf(className) !== -1;
  33984. var regex = new RegExp('(?:^|\\s)' + className + '(?:\\s|$)');
  33985. if ((active === undefined || active) && !currentActive) {
  33986. currentClassName += currentClassName.length > 0 ? ' ' + className : className;
  33987. }
  33988. else if (!active) {
  33989. currentClassName = currentClassName.replace(regex, ' ');
  33990. }
  33991. element.setAttribute('class', currentClassName);
  33992. }
  33993. else {
  33994. if (active === undefined) {
  33995. element.classList.toggle(className);
  33996. }
  33997. else if (active && !element.classList.contains(className)) {
  33998. element.classList.add(className);
  33999. }
  34000. else if (!active) {
  34001. element.classList.remove(className);
  34002. }
  34003. }
  34004. };
  34005. /**
  34006. * @summary Adds one or several CSS classes to an element
  34007. * @param {HTMLElement} element
  34008. * @param {string} className
  34009. */
  34010. PSVUtils.addClasses = function(element, className) {
  34011. if (!className) {
  34012. return;
  34013. }
  34014. className.split(' ').forEach(function(name) {
  34015. PSVUtils.toggleClass(element, name, true);
  34016. });
  34017. };
  34018. /**
  34019. * @summary Removes one or several CSS classes to an element
  34020. * @param {HTMLElement} element
  34021. * @param {string} className
  34022. */
  34023. PSVUtils.removeClasses = function(element, className) {
  34024. if (!className) {
  34025. return;
  34026. }
  34027. className.split(' ').forEach(function(name) {
  34028. PSVUtils.toggleClass(element, name, false);
  34029. });
  34030. };
  34031. /**
  34032. * @summary Searches if an element has a particular parent at any level including itself
  34033. * @param {HTMLElement} el
  34034. * @param {HTMLElement} parent
  34035. * @returns {boolean}
  34036. */
  34037. PSVUtils.hasParent = function(el, parent) {
  34038. do {
  34039. if (el === parent) {
  34040. return true;
  34041. }
  34042. } while (!!(el = el.parentNode));
  34043. return false;
  34044. };
  34045. /**
  34046. * @summary Gets the closest parent (can by itself)
  34047. * @param {HTMLElement} el (HTMLElement)
  34048. * @param {string} selector
  34049. * @returns {HTMLElement}
  34050. */
  34051. PSVUtils.getClosest = function(el, selector) {
  34052. var matches = el.matches || el.msMatchesSelector;
  34053. do {
  34054. if (matches.bind(el)(selector)) {
  34055. return el;
  34056. }
  34057. } while (!!(el = el.parentElement));
  34058. return null;
  34059. };
  34060. /**
  34061. * @summary Gets the event name for mouse wheel
  34062. * @returns {string}
  34063. */
  34064. PSVUtils.mouseWheelEvent = function() {
  34065. return 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
  34066. document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
  34067. 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
  34068. };
  34069. /**
  34070. * @summary Gets the event name for fullscreen
  34071. * @returns {string}
  34072. */
  34073. PSVUtils.fullscreenEvent = function() {
  34074. var map = {
  34075. 'exitFullscreen': 'fullscreenchange',
  34076. 'webkitExitFullscreen': 'webkitfullscreenchange',
  34077. 'mozCancelFullScreen': 'mozfullscreenchange',
  34078. 'msExitFullscreen': 'MSFullscreenChange'
  34079. };
  34080. for (var exit in map) {
  34081. if (map.hasOwnProperty(exit) && exit in document) {
  34082. return map[exit];
  34083. }
  34084. }
  34085. return null;
  34086. };
  34087. /**
  34088. * @summary Ensures that a number is in a given interval
  34089. * @param {number} x
  34090. * @param {number} min
  34091. * @param {number} max
  34092. * @returns {number}
  34093. */
  34094. PSVUtils.bound = function(x, min, max) {
  34095. return Math.max(min, Math.min(max, x));
  34096. };
  34097. /**
  34098. * @summary Checks if a value is an integer
  34099. * @function
  34100. * @param {*} value
  34101. * @returns {boolean}
  34102. */
  34103. PSVUtils.isInteger = Number.isInteger || function(value) {
  34104. return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
  34105. };
  34106. /**
  34107. * @summary Computes the sum of an array
  34108. * @param {number[]} array
  34109. * @returns {number}
  34110. */
  34111. PSVUtils.sum = function(array) {
  34112. return array.reduce(function(a, b) {
  34113. return a + b;
  34114. }, 0);
  34115. };
  34116. /**
  34117. * @summary Transforms a string to dash-case
  34118. * {@link https://github.com/shahata/dasherize}
  34119. * @param {string} str
  34120. * @returns {string}
  34121. */
  34122. PSVUtils.dasherize = function(str) {
  34123. return str.replace(/[A-Z](?:(?=[^A-Z])|[A-Z]*(?=[A-Z][^A-Z]|$))/g, function(s, i) {
  34124. return (i > 0 ? '-' : '') + s.toLowerCase();
  34125. });
  34126. };
  34127. /**
  34128. * @summary Returns the value of a given attribute in the panorama metadata
  34129. * @param {string} data
  34130. * @param {string} attr
  34131. * @returns (string)
  34132. */
  34133. PSVUtils.getXMPValue = function(data, attr) {
  34134. var result;
  34135. // XMP data are stored in children
  34136. if ((result = data.match('<GPano:' + attr + '>(.*)</GPano:' + attr + '>')) !== null) {
  34137. return result[1];
  34138. }
  34139. // XMP data are stored in attributes
  34140. else if ((result = data.match('GPano:' + attr + '="(.*?)"')) !== null) {
  34141. return result[1];
  34142. }
  34143. else {
  34144. return null;
  34145. }
  34146. };
  34147. /**
  34148. * @summary Detects if fullscreen is enabled
  34149. * @param {HTMLElement} elt
  34150. * @returns {boolean}
  34151. */
  34152. PSVUtils.isFullscreenEnabled = function(elt) {
  34153. return (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) === elt;
  34154. };
  34155. /**
  34156. * @summary Enters fullscreen mode
  34157. * @param {HTMLElement} elt
  34158. */
  34159. PSVUtils.requestFullscreen = function(elt) {
  34160. (elt.requestFullscreen || elt.mozRequestFullScreen || elt.webkitRequestFullscreen || elt.msRequestFullscreen).call(elt);
  34161. };
  34162. /**
  34163. * @summary Exits fullscreen mode
  34164. */
  34165. PSVUtils.exitFullscreen = function() {
  34166. (document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen || document.msExitFullscreen).call(document);
  34167. };
  34168. /**
  34169. * @summary Gets an element style
  34170. * @param {HTMLElement} elt
  34171. * @param {string} prop
  34172. * @returns {*}
  34173. */
  34174. PSVUtils.getStyle = function(elt, prop) {
  34175. return window.getComputedStyle(elt, null)[prop];
  34176. };
  34177. /**
  34178. * @summary Compute the shortest offset between two longitudes
  34179. * @param {float} from
  34180. * @param {float} to
  34181. * @returns {float}
  34182. */
  34183. PSVUtils.getShortestArc = function(from, to) {
  34184. var tCandidates = [
  34185. 0, // direct
  34186. PSVUtils.TwoPI, // clock-wise cross zero
  34187. -PSVUtils.TwoPI // counter-clock-wise cross zero
  34188. ];
  34189. return tCandidates.reduce(function(value, candidate) {
  34190. candidate = to - from + candidate;
  34191. return Math.abs(candidate) < Math.abs(value) ? candidate : value;
  34192. }, Infinity);
  34193. };
  34194. /**
  34195. * @summary Translate CSS values like "top center" or "10% 50%" as top and left positions
  34196. * @description The implementation is as close as possible to the "background-position" specification
  34197. * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/background-position}
  34198. * @param {string} value
  34199. * @returns {{top: float, left: float}}
  34200. */
  34201. PSVUtils.parsePosition = function(value) {
  34202. if (!value) {
  34203. return { top: 0.5, left: 0.5 };
  34204. }
  34205. if (typeof value === 'object') {
  34206. return value;
  34207. }
  34208. var tokens = value.toLocaleLowerCase().split(' ').slice(0, 2);
  34209. if (tokens.length === 1) {
  34210. if (PSVUtils.parsePosition.positions[tokens[0]] !== undefined) {
  34211. tokens = [tokens[0], 'center'];
  34212. }
  34213. else {
  34214. tokens = [tokens[0], tokens[0]];
  34215. }
  34216. }
  34217. var xFirst = tokens[1] !== 'left' && tokens[1] !== 'right' && tokens[0] !== 'top' && tokens[0] !== 'bottom';
  34218. tokens = tokens.map(function(token) {
  34219. return PSVUtils.parsePosition.positions[token] || token;
  34220. });
  34221. if (!xFirst) {
  34222. tokens.reverse();
  34223. }
  34224. var parsed = tokens.join(' ').match(/^([0-9.]+)% ([0-9.]+)%$/);
  34225. if (parsed) {
  34226. return {
  34227. left: parsed[1] / 100,
  34228. top: parsed[2] / 100
  34229. };
  34230. }
  34231. else {
  34232. return { top: 0.5, left: 0.5 };
  34233. }
  34234. };
  34235. PSVUtils.parsePosition.positions = { 'top': '0%', 'bottom': '100%', 'left': '0%', 'right': '100%', 'center': '50%' };
  34236. /**
  34237. * @summary Parses an speed
  34238. * @param {string} speed - The speed, in radians/degrees/revolutions per second/minute
  34239. * @returns {float} radians per second
  34240. * @throws {PSVError} when the speed cannot be parsed
  34241. */
  34242. PSVUtils.parseSpeed = function(speed) {
  34243. if (typeof speed === 'string') {
  34244. speed = speed.toString().trim();
  34245. // Speed extraction
  34246. var speed_value = parseFloat(speed.replace(/^(-?[0-9]+(?:\.[0-9]*)?).*$/, '$1'));
  34247. var speed_unit = speed.replace(/^-?[0-9]+(?:\.[0-9]*)?(.*)$/, '$1').trim();
  34248. // "per minute" -> "per second"
  34249. if (speed_unit.match(/(pm|per minute)$/)) {
  34250. speed_value /= 60;
  34251. }
  34252. // Which unit?
  34253. switch (speed_unit) {
  34254. // Degrees per minute / second
  34255. case 'dpm':
  34256. case 'degrees per minute':
  34257. case 'dps':
  34258. case 'degrees per second':
  34259. speed = THREE.Math.degToRad(speed_value);
  34260. break;
  34261. // Radians per minute / second
  34262. case 'radians per minute':
  34263. case 'radians per second':
  34264. speed = speed_value;
  34265. break;
  34266. // Revolutions per minute / second
  34267. case 'rpm':
  34268. case 'revolutions per minute':
  34269. case 'rps':
  34270. case 'revolutions per second':
  34271. speed = speed_value * PSVUtils.TwoPI;
  34272. break;
  34273. // Unknown unit
  34274. default:
  34275. throw new PSVError('unknown speed unit "' + speed_unit + '"');
  34276. }
  34277. }
  34278. return speed;
  34279. };
  34280. /**
  34281. * @summary Parses an angle value in radians or degrees and returns a normalized value in radians
  34282. * @param {string|number} angle - eg: 3.14, 3.14rad, 180deg
  34283. * @param {boolean} [zeroCenter=false] - normalize between -Pi/2 - Pi/2 instead of 0 - 2*Pi
  34284. * @returns {float}
  34285. * @throws {PSVError} when the angle cannot be parsed
  34286. */
  34287. PSVUtils.parseAngle = function(angle, zeroCenter) {
  34288. if (typeof angle === 'string') {
  34289. var match = angle.toLowerCase().trim().match(/^(-?[0-9]+(?:\.[0-9]*)?)(.*)$/);
  34290. if (!match) {
  34291. throw new PSVError('unknown angle "' + angle + '"');
  34292. }
  34293. var value = parseFloat(match[1]);
  34294. var unit = match[2];
  34295. if (unit) {
  34296. switch (unit) {
  34297. case 'deg':
  34298. case 'degs':
  34299. angle = THREE.Math.degToRad(value);
  34300. break;
  34301. case 'rad':
  34302. case 'rads':
  34303. angle = value;
  34304. break;
  34305. default:
  34306. throw new PSVError('unknown angle unit "' + unit + '"');
  34307. }
  34308. }
  34309. else {
  34310. angle = value;
  34311. }
  34312. }
  34313. angle = (zeroCenter ? angle + Math.PI : angle) % PSVUtils.TwoPI;
  34314. if (angle < 0) {
  34315. angle = PSVUtils.TwoPI + angle;
  34316. }
  34317. return zeroCenter ? PSVUtils.bound(angle - Math.PI, -PSVUtils.HalfPI, PSVUtils.HalfPI) : angle;
  34318. };
  34319. /**
  34320. * @summary Removes all children of a three.js scene and dispose all textures
  34321. * @param {THREE.Scene} scene
  34322. */
  34323. PSVUtils.cleanTHREEScene = function(scene) {
  34324. scene.children.forEach(function(item) {
  34325. if (item instanceof THREE.Mesh) {
  34326. if (item.geometry) {
  34327. item.geometry.dispose();
  34328. item.geometry = null;
  34329. }
  34330. if (item.material) {
  34331. if (item.material.materials) {
  34332. item.material.materials.forEach(function(material) {
  34333. if (material.map) {
  34334. material.map.dispose();
  34335. material.map = null;
  34336. }
  34337. material.dispose();
  34338. });
  34339. item.material.materials.length = 0;
  34340. }
  34341. else {
  34342. if (item.material.map) {
  34343. item.material.map.dispose();
  34344. item.material.map = null;
  34345. }
  34346. item.material.dispose();
  34347. }
  34348. item.material = null;
  34349. }
  34350. }
  34351. });
  34352. scene.children.length = 0;
  34353. };
  34354. /**
  34355. * @callback AnimationOnTick
  34356. * @param {Object} properties - current values
  34357. * @param {float} progress - 0 to 1
  34358. */
  34359. /**
  34360. * @summary Interpolates each property with an easing and optional delay
  34361. * @param {Object} options
  34362. * @param {Object[]} options.properties
  34363. * @param {number} options.properties[].start
  34364. * @param {number} options.properties[].end
  34365. * @param {int} options.duration
  34366. * @param {int} [options.delay=0]
  34367. * @param {string} [options.easing='linear']
  34368. * @param {AnimationOnTick} options.onTick - called on each frame
  34369. * @returns {Promise} Promise with an additional "cancel" method
  34370. */
  34371. PSVUtils.animation = function(options) {
  34372. var defer = D(false); // alwaysAsync = false to allow immediate resolution of "cancel"
  34373. var start = null;
  34374. if (!options.easing || typeof options.easing === 'string') {
  34375. options.easing = PSVUtils.animation.easings[options.easing || 'linear'];
  34376. }
  34377. function run(timestamp) {
  34378. // the animation has been cancelled
  34379. if (defer.promise.getStatus() === -1) {
  34380. return;
  34381. }
  34382. // first iteration
  34383. if (start === null) {
  34384. start = timestamp;
  34385. }
  34386. // compute progress
  34387. var progress = (timestamp - start) / options.duration;
  34388. var current = {};
  34389. var name;
  34390. if (progress < 1.0) {
  34391. // interpolate properties
  34392. for (name in options.properties) {
  34393. current[name] = options.properties[name].start + (options.properties[name].end - options.properties[name].start) * options.easing(progress);
  34394. }
  34395. options.onTick(current, progress);
  34396. window.requestAnimationFrame(run);
  34397. }
  34398. else {
  34399. // call onTick one last time with final values
  34400. for (name in options.properties) {
  34401. current[name] = options.properties[name].end;
  34402. }
  34403. options.onTick(current, 1.0);
  34404. window.requestAnimationFrame(function() {
  34405. defer.resolve();
  34406. });
  34407. }
  34408. }
  34409. if (options.delay !== undefined) {
  34410. window.setTimeout(function() {
  34411. window.requestAnimationFrame(run);
  34412. }, options.delay);
  34413. }
  34414. else {
  34415. window.requestAnimationFrame(run);
  34416. }
  34417. // add a "cancel" to the promise
  34418. var promise = defer.promise;
  34419. promise.cancel = function() {
  34420. defer.reject();
  34421. };
  34422. return promise;
  34423. };
  34424. /**
  34425. * @summary Collection of easing functions
  34426. * {@link https://gist.github.com/frederickk/6165768}
  34427. * @type {Object.<string, Function>}
  34428. */
  34429. // @formatter:off
  34430. // jscs:disable
  34431. /* jshint ignore:start */
  34432. PSVUtils.animation.easings = {
  34433. linear: function(t) { return t; },
  34434. inQuad: function(t) { return t*t; },
  34435. outQuad: function(t) { return t*(2-t); },
  34436. inOutQuad: function(t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; },
  34437. inCubic: function(t) { return t*t*t; },
  34438. outCubic: function(t) { return (--t)*t*t+1; },
  34439. inOutCubic: function(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; },
  34440. inQuart: function(t) { return t*t*t*t; },
  34441. outQuart: function(t) { return 1-(--t)*t*t*t; },
  34442. inOutQuart: function(t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; },
  34443. inQuint: function(t) { return t*t*t*t*t; },
  34444. outQuint: function(t) { return 1+(--t)*t*t*t*t; },
  34445. inOutQuint: function(t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; },
  34446. inSine: function(t) { return 1-Math.cos(t*(Math.PI/2)); },
  34447. outSine: function(t) { return Math.sin(t*(Math.PI/2)); },
  34448. inOutSine: function(t) { return .5-.5*Math.cos(Math.PI*t); },
  34449. inExpo: function(t) { return Math.pow(2, 10*(t-1)); },
  34450. outExpo: function(t) { return 1-Math.pow(2, -10*t); },
  34451. inOutExpo: function(t) { t=t*2-1; return t<0 ? .5*Math.pow(2, 10*t) : 1-.5*Math.pow(2, -10*t); },
  34452. inCirc: function(t) { return 1-Math.sqrt(1-t*t); },
  34453. outCirc: function(t) { t--; return Math.sqrt(1-t*t); },
  34454. inOutCirc: function(t) { t*=2; return t<1 ? .5-.5*Math.sqrt(1-t*t) : .5+.5*Math.sqrt(1-(t-=2)*t); }
  34455. };
  34456. /* jshint ignore:end */
  34457. // jscs:enable
  34458. // @formatter:off
  34459. /**
  34460. * @summary Returns a function, that, when invoked, will only be triggered at most once during a given window of time.
  34461. * @copyright underscore.js - modified by Clément Prévost {@link http://stackoverflow.com/a/27078401}
  34462. * @param {Function} func
  34463. * @param {int} wait
  34464. * @returns {Function}
  34465. */
  34466. PSVUtils.throttle = function(func, wait) {
  34467. var self, args, result;
  34468. var timeout = null;
  34469. var previous = 0;
  34470. var later = function() {
  34471. previous = Date.now();
  34472. timeout = null;
  34473. result = func.apply(self, args);
  34474. if (!timeout) {
  34475. self = args = null;
  34476. }
  34477. };
  34478. return function() {
  34479. var now = Date.now();
  34480. if (!previous) {
  34481. previous = now;
  34482. }
  34483. var remaining = wait - (now - previous);
  34484. self = this;
  34485. args = arguments;
  34486. if (remaining <= 0 || remaining > wait) {
  34487. if (timeout) {
  34488. clearTimeout(timeout);
  34489. timeout = null;
  34490. }
  34491. previous = now;
  34492. result = func.apply(self, args);
  34493. if (!timeout) {
  34494. self = args = null;
  34495. }
  34496. }
  34497. else if (!timeout) {
  34498. timeout = setTimeout(later, remaining);
  34499. }
  34500. return result;
  34501. };
  34502. };
  34503. /**
  34504. * @summary Test if an object is a plain object
  34505. * @description Test if an object is a plain object, i.e. is constructed
  34506. * by the built-in Object constructor and inherits directly from Object.prototype
  34507. * or null. Some built-in objects pass the test, e.g. Math which is a plain object
  34508. * and some host or exotic objects may pass also.
  34509. * {@link http://stackoverflow.com/a/5878101/1207670}
  34510. * @param {*} obj
  34511. * @returns {boolean}
  34512. */
  34513. PSVUtils.isPlainObject = function(obj) {
  34514. // Basic check for Type object that's not null
  34515. if (typeof obj === 'object' && obj !== null) {
  34516. // If Object.getPrototypeOf supported, use it
  34517. if (typeof Object.getPrototypeOf === 'function') {
  34518. var proto = Object.getPrototypeOf(obj);
  34519. return proto === Object.prototype || proto === null;
  34520. }
  34521. // Otherwise, use internal class
  34522. // This should be reliable as if getPrototypeOf not supported, is pre-ES5
  34523. return Object.prototype.toString.call(obj) === '[object Object]';
  34524. }
  34525. // Not an object
  34526. return false;
  34527. };
  34528. /**
  34529. * @summary Merges the enumerable attributes of two objects
  34530. * @description Replaces arrays and alters the target object.
  34531. * @copyright Nicholas Fisher <nfisher110@gmail.com>
  34532. * @param {Object} target
  34533. * @param {Object} src
  34534. * @returns {Object} target
  34535. */
  34536. PSVUtils.deepmerge = function(target, src) {
  34537. var first = src;
  34538. return (function merge(target, src) {
  34539. if (Array.isArray(src)) {
  34540. if (!target || !Array.isArray(target)) {
  34541. target = [];
  34542. }
  34543. else {
  34544. target.length = 0;
  34545. }
  34546. src.forEach(function(e, i) {
  34547. target[i] = merge(null, e);
  34548. });
  34549. }
  34550. else if (typeof src === 'object') {
  34551. if (!target || Array.isArray(target)) {
  34552. target = {};
  34553. }
  34554. Object.keys(src).forEach(function(key) {
  34555. if (typeof src[key] !== 'object' || !src[key] || !PSVUtils.isPlainObject(src[key])) {
  34556. target[key] = src[key];
  34557. }
  34558. else if (src[key] != first) {
  34559. if (!target[key]) {
  34560. target[key] = merge(null, src[key]);
  34561. }
  34562. else {
  34563. merge(target[key], src[key]);
  34564. }
  34565. }
  34566. });
  34567. }
  34568. else {
  34569. target = src;
  34570. }
  34571. return target;
  34572. }(target, src));
  34573. };
  34574. /**
  34575. * @summary Clones an object
  34576. * @param {Object} src
  34577. * @returns {Object}
  34578. */
  34579. PSVUtils.clone = function(src) {
  34580. return PSVUtils.deepmerge(null, src);
  34581. };
  34582. /**
  34583. * @summary Normalize mousewheel values accross browsers
  34584. * @description From Facebook's Fixed Data Table
  34585. * {@link https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js}
  34586. * @copyright Facebook
  34587. * @param {MouseWheelEvent} event
  34588. * @returns {{spinX: number, spinY: number, pixelX: number, pixelY: number}}
  34589. */
  34590. PSVUtils.normalizeWheel = function(event) {
  34591. var PIXEL_STEP = 10;
  34592. var LINE_HEIGHT = 40;
  34593. var PAGE_HEIGHT = 800;
  34594. var sX = 0, sY = 0; // spinX, spinY
  34595. var pX = 0, pY = 0; // pixelX, pixelY
  34596. // Legacy
  34597. if ('detail' in event) { sY = event.detail; }
  34598. if ('wheelDelta' in event) { sY = -event.wheelDelta / 120; }
  34599. if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120; }
  34600. if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120; }
  34601. // side scrolling on FF with DOMMouseScroll
  34602. if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
  34603. sX = sY;
  34604. sY = 0;
  34605. }
  34606. pX = sX * PIXEL_STEP;
  34607. pY = sY * PIXEL_STEP;
  34608. if ('deltaY' in event) { pY = event.deltaY; }
  34609. if ('deltaX' in event) { pX = event.deltaX; }
  34610. if ((pX || pY) && event.deltaMode) {
  34611. if (event.deltaMode === 1) { // delta in LINE units
  34612. pX *= LINE_HEIGHT;
  34613. pY *= LINE_HEIGHT;
  34614. }
  34615. else { // delta in PAGE units
  34616. pX *= PAGE_HEIGHT;
  34617. pY *= PAGE_HEIGHT;
  34618. }
  34619. }
  34620. // Fall-back if spin cannot be determined
  34621. if (pX && !sX) { sX = (pX < 1) ? -1 : 1; }
  34622. if (pY && !sY) { sY = (pY < 1) ? -1 : 1; }
  34623. return {
  34624. spinX: sX,
  34625. spinY: sY,
  34626. pixelX: pX,
  34627. pixelY: pY
  34628. };
  34629. };
  34630. /**
  34631. * @callback ForEach
  34632. * @param {*} value
  34633. * @param {string} key
  34634. */
  34635. /**
  34636. * Loops over enumerable properties of an object
  34637. * @param {object} object
  34638. * @param {ForEach} callback
  34639. */
  34640. PSVUtils.forEach = function(object, callback) {
  34641. for (var key in object) {
  34642. if (object.hasOwnProperty(key)) {
  34643. callback(object[key], key);
  34644. }
  34645. }
  34646. };
  34647. /**
  34648. * requestAnimationFrame polyfill
  34649. * {@link http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation}
  34650. * @license MIT
  34651. */
  34652. (function(w) {
  34653. "use strict";
  34654. // most browsers have an implementation
  34655. w.requestAnimationFrame = w.requestAnimationFrame ||
  34656. w.mozRequestAnimationFrame || w.webkitRequestAnimationFrame ||
  34657. w.msRequestAnimationFrame;
  34658. w.cancelAnimationFrame = w.cancelAnimationFrame ||
  34659. w.mozCancelAnimationFrame || w.webkitCancelAnimationFrame ||
  34660. w.msCancelAnimationFrame;
  34661. // polyfill, when necessary
  34662. if (!w.requestAnimationFrame) {
  34663. var aAnimQueue = [],
  34664. aProcessing = [],
  34665. iRequestId = 0,
  34666. iIntervalId;
  34667. // create a mock requestAnimationFrame function
  34668. w.requestAnimationFrame = function(callback) {
  34669. aAnimQueue.push([++iRequestId, callback]);
  34670. if (!iIntervalId) {
  34671. iIntervalId = setInterval(function() {
  34672. if (aAnimQueue.length) {
  34673. var time = +new Date();
  34674. // Process all of the currently outstanding frame
  34675. // requests, but none that get added during the
  34676. // processing.
  34677. // Swap the arrays so we don't have to create a new
  34678. // array every frame.
  34679. var temp = aProcessing;
  34680. aProcessing = aAnimQueue;
  34681. aAnimQueue = temp;
  34682. while (aProcessing.length) {
  34683. aProcessing.shift()[1](time);
  34684. }
  34685. } else {
  34686. // don't continue the interval, if unnecessary
  34687. clearInterval(iIntervalId);
  34688. iIntervalId = undefined;
  34689. }
  34690. }, 1000 / 50); // estimating support for 50 frames per second
  34691. }
  34692. return iRequestId;
  34693. };
  34694. // create a mock cancelAnimationFrame function
  34695. w.cancelAnimationFrame = function(requestId) {
  34696. // find the request ID and remove it
  34697. var i, j;
  34698. for (i = 0, j = aAnimQueue.length; i < j; i += 1) {
  34699. if (aAnimQueue[i][0] === requestId) {
  34700. aAnimQueue.splice(i, 1);
  34701. return;
  34702. }
  34703. }
  34704. // If it's not in the queue, it may be in the set we're currently
  34705. // processing (if cancelAnimationFrame is called from within a
  34706. // requestAnimationFrame callback).
  34707. for (i = 0, j = aProcessing.length; i < j; i += 1) {
  34708. if (aProcessing[i][0] === requestId) {
  34709. aProcessing.splice(i, 1);
  34710. return;
  34711. }
  34712. }
  34713. };
  34714. }
  34715. })(window);
  34716. PhotoSphereViewer.ICONS['compass.svg'] = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><path d="M49.997,0C22.38,0.004,0.005,22.383,0,50.002C0.005,77.614,22.38,99.995,49.997,100C77.613,99.995,99.996,77.614,100,50.002C99.996,22.383,77.613,0.004,49.997,0z M49.997,88.81c-21.429-0.04-38.772-17.378-38.809-38.807c0.037-21.437,17.381-38.775,38.809-38.812C71.43,11.227,88.769,28.567,88.81,50.002C88.769,71.432,71.43,88.77,49.997,88.81z"/><path d="M72.073,25.891L40.25,41.071l-0.003-0.004l-0.003,0.009L27.925,74.109l31.82-15.182l0.004,0.004l0.002-0.007l-0.002-0.004L72.073,25.891z M57.837,54.411L44.912,42.579l21.092-10.062L57.837,54.411z"/><!--Created by iconoci from the Noun Project--></svg>';
  34717. PhotoSphereViewer.ICONS['download.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><path d="M83.285,35.575H66.271L66.277,3H32.151v32.575H16.561l33.648,32.701L83.285,35.575z"/><path d="M83.316,64.199v16.32H16.592v-16.32H-0.094v32.639H100V64.199H83.316z"/><!--Created by Michael Zenaty from the Noun Project--></svg>';
  34718. PhotoSphereViewer.ICONS['fullscreen-in.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><polygon points="100,39.925 87.105,39.925 87.105,18.895 66.075,18.895 66.075,6 100,6"/><polygon points="100,93.221 66.075,93.221 66.075,80.326 87.105,80.326 87.105,59.295 100,59.295"/><polygon points="33.925,93.221 0,93.221 0,59.295 12.895,59.295 12.895,80.326 33.925,80.326"/><polygon points="12.895,39.925 0,39.925 0,6 33.925,6 33.925,18.895 12.895,18.895"/><!--Created by Garrett Knoll from the Noun Project--></svg>';
  34719. PhotoSphereViewer.ICONS['fullscreen-out.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><polygon points="66.075,7 78.969,7 78.969,28.031 100,28.031 100,40.925 66.075,40.925"/><polygon points="66.075,60.295 100,60.295 100,73.19 78.969,73.19 78.969,94.221 66.075,94.221"/><polygon points="0,60.295 33.925,60.295 33.925,94.221 21.031,94.221 21.031,73.19 0,73.19"/><polygon points="21.031,7 33.925,7 33.925,40.925 0,40.925 0,28.031 21.031,28.031"/><!--Created by Garrett Knoll from the Noun Project--></svg>';
  34720. PhotoSphereViewer.ICONS['pin.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><path d="M24,0C13.798,0,5.499,8.3,5.499,18.501c0,10.065,17.57,28.635,18.318,29.421C23.865,47.972,23.931,48,24,48s0.135-0.028,0.183-0.078c0.748-0.786,18.318-19.355,18.318-29.421C42.501,8.3,34.202,0,24,0z M24,7.139c5.703,0,10.342,4.64,10.342,10.343c0,5.702-4.639,10.342-10.342,10.342c-5.702,0-10.34-4.64-10.34-10.342C13.66,11.778,18.298,7.139,24,7.139z"/><!--Created by Daniele Marucci from the Noun Project--></svg>';
  34721. PhotoSphereViewer.ICONS['play-active.svg'] = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 41 41" enable-background="new 0 0 41 41" xml:space="preserve"><path d="M40.5,14.1c-0.1-0.1-1.2-0.5-2.898-1C37.5,13.1,37.4,13,37.4,12.9C34.5,6.5,28,2,20.5,2S6.6,6.5,3.7,12.9c0,0.1-0.1,0.1-0.2,0.2c-1.7,0.6-2.8,1-2.9,1L0,14.4v12.1l0.6,0.2c0.1,0,1.1,0.399,2.7,0.899c0.1,0,0.2,0.101,0.2,0.199C6.3,34.4,12.9,39,20.5,39c7.602,0,14.102-4.6,16.9-11.1c0-0.102,0.1-0.102,0.199-0.2c1.699-0.601,2.699-1,2.801-1l0.6-0.3V14.3L40.5,14.1z M6.701,11.5C9.7,7,14.8,4,20.5,4c5.8,0,10.9,3,13.8,7.5c0.2,0.3-0.1,0.6-0.399,0.5c-3.799-1-8.799-2-13.6-2c-4.7,0-9.5,1-13.2,2C6.801,12.1,6.601,11.8,6.701,11.5z M25.1,20.3L18.7,24c-0.3,0.2-0.7,0-0.7-0.5v-7.4c0-0.4,0.4-0.6,0.7-0.4 l6.399,3.8C25.4,19.6,25.4,20.1,25.1,20.3z M34.5,29.201C31.602,33.9,26.4,37,20.5,37c-5.9,0-11.1-3.1-14-7.898c-0.2-0.302,0.1-0.602,0.4-0.5c3.9,1,8.9,2.1,13.6,2.1c5,0,9.9-1,13.602-2C34.4,28.602,34.602,28.9,34.5,29.201z"/><!--Created by Nick Bluth from the Noun Project--></svg>';
  34722. PhotoSphereViewer.ICONS['play.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 41 41" enable-background="new 0 0 41 41" xml:space="preserve"><path d="M40.5,14.1c-0.1-0.1-1.2-0.5-2.899-1c-0.101,0-0.2-0.1-0.2-0.2C34.5,6.5,28,2,20.5,2S6.6,6.5,3.7,12.9c0,0.1-0.1,0.1-0.2,0.2c-1.7,0.6-2.8,1-2.9,1L0,14.4v12.1l0.6,0.2c0.1,0,1.1,0.4,2.7,0.9c0.1,0,0.2,0.1,0.2,0.199C6.3,34.4,12.9,39,20.5,39c7.601,0,14.101-4.6,16.9-11.1c0-0.101,0.1-0.101,0.2-0.2c1.699-0.6,2.699-1,2.8-1l0.6-0.3V14.3L40.5,14.1zM20.5,4c5.8,0,10.9,3,13.8,7.5c0.2,0.3-0.1,0.6-0.399,0.5c-3.8-1-8.8-2-13.6-2c-4.7,0-9.5,1-13.2,2c-0.3,0.1-0.5-0.2-0.4-0.5C9.7,7,14.8,4,20.5,4z M20.5,37c-5.9,0-11.1-3.1-14-7.899c-0.2-0.301,0.1-0.601,0.4-0.5c3.9,1,8.9,2.1,13.6,2.1c5,0,9.9-1,13.601-2c0.3-0.1,0.5,0.2,0.399,0.5C31.601,33.9,26.4,37,20.5,37z M39.101,24.9c0,0.1-0.101,0.3-0.2,0.3c-2.5,0.9-10.4,3.6-18.4,3.6c-7.1,0-15.6-2.699-18.3-3.6C2.1,25.2,2,25,2,24.9V16c0-0.1,0.1-0.3,0.2-0.3c2.6-0.9,10.6-3.6,18.2-3.6c7.5,0,15.899,2.7,18.5,3.6c0.1,0,0.2,0.2,0.2,0.3V24.9z"/><path d="M18.7,24l6.4-3.7c0.3-0.2,0.3-0.7,0-0.8l-6.4-3.8c-0.3-0.2-0.7,0-0.7,0.4v7.4C18,24,18.4,24.2,18.7,24z"/><!--Created by Nick Bluth from the Noun Project--></svg>';
  34723. PhotoSphereViewer.ICONS['zoom-in.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve"><path d="M14.043,12.22c2.476-3.483,1.659-8.313-1.823-10.789C8.736-1.044,3.907-0.228,1.431,3.255c-2.475,3.482-1.66,8.312,1.824,10.787c2.684,1.908,6.281,1.908,8.965,0l4.985,4.985c0.503,0.504,1.32,0.504,1.822,0c0.505-0.503,0.505-1.319,0-1.822L14.043,12.22z M7.738,13.263c-3.053,0-5.527-2.475-5.527-5.525c0-3.053,2.475-5.527,5.527-5.527c3.05,0,5.524,2.474,5.524,5.527C13.262,10.789,10.788,13.263,7.738,13.263z"/><polygon points="8.728,4.009 6.744,4.009 6.744,6.746 4.006,6.746 4.006,8.73 6.744,8.73 6.744,11.466 8.728,11.466 8.728,8.73 11.465,8.73 11.465,6.746 8.728,6.746"/><!--Created by Ryan Canning from the Noun Project--></svg>';
  34724. PhotoSphereViewer.ICONS['zoom-out.svg'] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve"><path d="M14.043,12.22c2.476-3.483,1.659-8.313-1.823-10.789C8.736-1.044,3.907-0.228,1.431,3.255c-2.475,3.482-1.66,8.312,1.824,10.787c2.684,1.908,6.281,1.908,8.965,0l4.985,4.985c0.503,0.504,1.32,0.504,1.822,0c0.505-0.503,0.505-1.319,0-1.822L14.043,12.22z M7.738,13.263c-3.053,0-5.527-2.475-5.527-5.525c0-3.053,2.475-5.527,5.527-5.527c3.05,0,5.524,2.474,5.524,5.527C13.262,10.789,10.788,13.263,7.738,13.263z"/><rect x="4.006" y="6.746" width="7.459" height="1.984"/><!--Created by Ryan Canning from the Noun Project--></svg>';
  34725. return PhotoSphereViewer;
  34726. }));
  34727. },{"three":145,"d.js":144,"uevent":146,"dot/doT":147}],111:[function(require,module,exports) {
  34728. 'use strict';
  34729. Object.defineProperty(exports, "__esModule", {
  34730. value: true
  34731. });
  34732. var userDown = false; //用户鼠标判断
  34733. var bgMove = false;
  34734. var indexPath = $('body').attr('data-path');
  34735. var until = {
  34736. handleModel: function handleModel() {
  34737. // m新增,点击区域隐藏
  34738. $(document).on('click', '.pub-hide-modal', function () {
  34739. $(this).fadeOut();
  34740. });
  34741. $(document).on('click', '.fullscreen-video', function () {
  34742. until.pauseVideo();
  34743. $(this).fadeOut();
  34744. return false;
  34745. });
  34746. $(document).on('click', '.full-pic-modal', function () {
  34747. $(this).fadeOut();
  34748. });
  34749. // 点击背景关闭弹窗
  34750. $(document).on('click', '.pub-modal-mask', function () {
  34751. until.pauseVideo();
  34752. $(this).fadeOut();
  34753. });
  34754. $(document).on('click', '.part-screen', function (e) {
  34755. return false;
  34756. });
  34757. $(document).on('click', '.close-mask-icon', function () {
  34758. until.pauseVideo();
  34759. $(this).parents('.pub-modal-mask').fadeOut();
  34760. });
  34761. $(document).on('click', '.close-full-video', function () {
  34762. until.pauseVideo();
  34763. $(this).parents('.fullscreen-video').fadeOut();
  34764. });
  34765. $(document).on('click', '.close-icon', function () {
  34766. $(this).parents('.pub-modal').fadeOut();
  34767. });
  34768. $(document).on('click', '.go-back', function () {
  34769. $('.mod-full-picture').fadeOut();
  34770. return false;
  34771. });
  34772. },
  34773. // 重力感应
  34774. acceler: function acceler() {
  34775. if (window.DeviceOrientationEvent) {
  34776. var handleOrientation = function handleOrientation(event) {
  34777. var x = event.beta; // 范围是[-180, 180]
  34778. var y = event.gamma; // 范围是[-90, 90]
  34779. // 这里我们把x的数值控制在-90到90,因为我们不需要让设备翻转倒过来。
  34780. if (x > 60) {
  34781. x = 60;
  34782. };
  34783. if (x < -60) {
  34784. x = -60;
  34785. };
  34786. // 设置偏移最大值
  34787. var max = 50;
  34788. var pics = document.getElementsByClassName('bg-move');
  34789. for (var i = 0; i < pics.length; i++) {
  34790. pics[0].style = 'transform: translate3d(' + max * x / 120 + 'px, ' + max * y / 120 + 'px, 0px)';
  34791. }
  34792. };
  34793. window.addEventListener('deviceorientation', handleOrientation, false);
  34794. }
  34795. },
  34796. pauseVideo: function pauseVideo() {
  34797. // video暂停播放
  34798. var videoDom = document.getElementsByTagName('video');
  34799. for (var i = 0; i < videoDom.length; i++) {
  34800. videoDom[i].pause();
  34801. }
  34802. },
  34803. decr: function decr(r) {
  34804. var e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@!~*-_.()'".split("");
  34805. var n = [];
  34806. var a = [];
  34807. r.split("").reverse().forEach(function (r, t) {
  34808. var o = e.indexOf(r);
  34809. if (parseInt((t + 1) % 2) == 1) {
  34810. a.push(o);
  34811. } else {
  34812. var p = parseInt(o - a[(t + 1) / 2 - 1]);
  34813. n.push(e[p]);
  34814. }
  34815. });
  34816. var t = n.join("").replace(/@/g, "%");
  34817. return decodeURIComponent(t);
  34818. },
  34819. /**
  34820. * 解密数据
  34821. */
  34822. deCodeArg: function deCodeArg(target) {
  34823. var srcMap = {};
  34824. if (JSON.parse) {
  34825. srcMap = JSON.parse(until.decr(target));
  34826. } else {
  34827. srcMap = eval('(' + until.decr(target) + ')');
  34828. }
  34829. return srcMap;
  34830. },
  34831. //立即预约
  34832. bookClick: function bookClick() {
  34833. $('.book-icon').click(function () {
  34834. $('.comment-page').fadeIn();
  34835. });
  34836. // 返回
  34837. $('#book-gack-btn').click(function () {
  34838. $('.comment-page').fadeOut();
  34839. });
  34840. // 预约成功
  34841. var successModal = '<div class="progress-modal reset-modal book-success-modal" style="display: block;">\n <p class="tips">\u9884\u7EA6\u6210\u529F\uFF01</p>\n <div class="btn-wrap">\n <div class="btn success-btn book-success-btn">\u662F</div>\n </div>\n </div>';
  34842. $('.book-btn-bottom').click(function () {
  34843. $('.comment-page').append(successModal);
  34844. });
  34845. $('.comment-page').on('click', '.book-success-btn', function () {
  34846. $('.book-success-modal').remove();
  34847. });
  34848. // 视频播放
  34849. $('.poster-lake').click(function () {
  34850. $('.book-video').hide();
  34851. $('#book-video-wrapper').show();
  34852. $('#book-lake-video').show();
  34853. document.getElementById('book-lake-video').play();
  34854. });
  34855. $('.poster-taiga').click(function () {
  34856. $('.book-video').hide();
  34857. $('#book-video-wrapper').show();
  34858. $('#book-taiga-video').show();
  34859. document.getElementById('book-taiga-video').play();
  34860. });
  34861. $('.poster-elden').click(function () {
  34862. $('.book-video').hide();
  34863. $('#book-video-wrapper').show();
  34864. $('#book-elden-video').show();
  34865. document.getElementById('book-elden-video').play();
  34866. });
  34867. },
  34868. // 右上角工具栏
  34869. toolbarClick: function toolbarClick() {
  34870. // 暂停
  34871. $('.toolbar-box').find('.bgm-icon').click(function () {
  34872. var $this = $(this);
  34873. var audio = document.getElementById('bgm-audio');
  34874. if ($this.hasClass('pause')) {
  34875. audio.play();
  34876. $this.removeClass('pause');
  34877. } else {
  34878. audio.pause();
  34879. $this.addClass('pause');
  34880. }
  34881. });
  34882. // 评论
  34883. $('.toolbar-box').find('.comment-icon').click(function () {
  34884. window.open('http://hdzt.duowan.com/1806/m_393864686995.html');
  34885. });
  34886. // 重置进度
  34887. $('.toolbar-box').find('.reset-icon').click(function () {
  34888. $('.reset-modal').fadeIn();
  34889. });
  34890. $('.yes-btn').click(function () {
  34891. localStorage.removeItem('hunter_permision');
  34892. localStorage.removeItem('entry');
  34893. window.location.href = indexPath;
  34894. });
  34895. $('.no-btn').click(function () {
  34896. $('.reset-modal').fadeOut();
  34897. });
  34898. },
  34899. //确认装备
  34900. shooting: function shooting() {
  34901. var huntVideo = document.getElementById('hunt-video');
  34902. var huntVideoB = document.getElementById('hunt-video-b');
  34903. $('.start-equit-btn').click(function () {
  34904. var bag = $('#equit-modal').attr('data-bag');
  34905. $('#equit-video-wrap').find('video').hide();
  34906. if (bag == 'A') {
  34907. $(huntVideo).show();
  34908. huntVideo.play();
  34909. }
  34910. if (bag == 'B') {
  34911. $(huntVideoB).show();
  34912. huntVideoB.play();
  34913. }
  34914. $('#equit-video-wrap').fadeIn();
  34915. });
  34916. huntVideo.addEventListener('ended', function () {
  34917. $('#equit-video-wrap').fadeOut();
  34918. });
  34919. huntVideoB.addEventListener('ended', function () {
  34920. $('#equit-video-wrap').fadeOut();
  34921. });
  34922. // 开始狩猎
  34923. $('.hunt-btn').click(function () {
  34924. $('.fullscreen-modal').hide();
  34925. $('#equit-modal').show();
  34926. });
  34927. $('.nav-item-wrap').click(function () {
  34928. $('.nav-item-wrap').removeClass('active');
  34929. $(this).parents('.container').find('.main').hide();
  34930. $(this).addClass('active');
  34931. var ind = $(this).attr('data-ind');
  34932. var bag = $('#equit-modal').attr('data-bag');
  34933. if (ind == 1 && bag == 'A') {
  34934. $('#weapon-modal').show();
  34935. }
  34936. if (ind == 2 && bag == 'A') {
  34937. $('#fodder-modal').show();
  34938. }
  34939. if (ind == 1 && bag == 'B') {
  34940. $('#weapon-modal-b').show();
  34941. }
  34942. if (ind == 2 && bag == 'B') {
  34943. $('#fodder-modal-b').show();
  34944. }
  34945. });
  34946. $('.bag-a').click(function () {
  34947. var $this = $(this);
  34948. if (!$this.hasClass('bag-a-active')) {
  34949. $this.addClass('bag-a-active');
  34950. $('.bag-b').removeClass('bag-b-active');
  34951. $('#equit-modal').attr('data-bag', 'A');
  34952. $('.nav-item-wrap').eq(0).trigger('click');
  34953. }
  34954. });
  34955. $('.bag-b').click(function () {
  34956. var $this = $(this);
  34957. if (!$this.hasClass('bag-b-active')) {
  34958. $this.addClass('bag-b-active');
  34959. $('.bag-a').removeClass('bag-a-active');
  34960. $('#equit-modal').attr('data-bag', 'B');
  34961. $('.nav-item-wrap').eq(0).trigger('click');
  34962. }
  34963. });
  34964. },
  34965. handleReady: function handleReady(x, y, viewer) {
  34966. var view_lgt = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 6;
  34967. var view_lat = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
  34968. var lakeFlag = false;
  34969. viewer.on('ready', function () {
  34970. $('.loading-bg').hide();
  34971. viewer.rotate({
  34972. x: 0,
  34973. y: 0
  34974. });
  34975. viewer.animate({
  34976. x: x,
  34977. y: y
  34978. }, 2000);
  34979. // 自动旋转
  34980. var container = document.getElementsByClassName('psv-hud-svg-container')[0];
  34981. var $toolbar = $('.toolbar-box');
  34982. var $progress = $('.progress-modal-moblie');
  34983. var $nav = $('.nav');
  34984. var timer = null;
  34985. container.addEventListener('touchstart', function () {
  34986. clearTimeout(timer);
  34987. $toolbar.fadeIn();
  34988. $progress.fadeIn();
  34989. $nav.fadeIn();
  34990. timer = setTimeout(function () {
  34991. $toolbar.fadeOut();
  34992. $progress.fadeOut();
  34993. $nav.fadeOut();
  34994. viewer.startAutorotate();
  34995. }, 5000);
  34996. });
  34997. });
  34998. viewer.on('position-updated', function (position) {
  34999. var lgt = position.longitude;
  35000. var lat = position.latitude;
  35001. if (lgt > view_lgt && lat < view_lat && !lakeFlag) {
  35002. lakeFlag = true;
  35003. $('.progress-modal-moblie').fadeIn();
  35004. $('.suggest-modal').fadeIn();
  35005. $('.nav').fadeIn();
  35006. viewer.startAutorotate();
  35007. }
  35008. });
  35009. }
  35010. };
  35011. exports.default = until;
  35012. },{}],114:[function(require,module,exports) {
  35013. var define;
  35014. ;(function () {
  35015. 'use strict';
  35016. /**
  35017. * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
  35018. *
  35019. * @codingstandard ftlabs-jsv2
  35020. * @copyright The Financial Times Limited [All Rights Reserved]
  35021. * @license MIT License (see LICENSE.txt)
  35022. */
  35023. /*jslint browser:true, node:true*/
  35024. /*global define, Event, Node*/
  35025. /**
  35026. * Instantiate fast-clicking listeners on the specified layer.
  35027. *
  35028. * @constructor
  35029. * @param {Element} layer The layer to listen on
  35030. * @param {Object} [options={}] The options to override the defaults
  35031. */
  35032. function FastClick(layer, options) {
  35033. var oldOnClick;
  35034. options = options || {};
  35035. /**
  35036. * Whether a click is currently being tracked.
  35037. *
  35038. * @type boolean
  35039. */
  35040. this.trackingClick = false;
  35041. /**
  35042. * Timestamp for when click tracking started.
  35043. *
  35044. * @type number
  35045. */
  35046. this.trackingClickStart = 0;
  35047. /**
  35048. * The element being tracked for a click.
  35049. *
  35050. * @type EventTarget
  35051. */
  35052. this.targetElement = null;
  35053. /**
  35054. * X-coordinate of touch start event.
  35055. *
  35056. * @type number
  35057. */
  35058. this.touchStartX = 0;
  35059. /**
  35060. * Y-coordinate of touch start event.
  35061. *
  35062. * @type number
  35063. */
  35064. this.touchStartY = 0;
  35065. /**
  35066. * ID of the last touch, retrieved from Touch.identifier.
  35067. *
  35068. * @type number
  35069. */
  35070. this.lastTouchIdentifier = 0;
  35071. /**
  35072. * Touchmove boundary, beyond which a click will be cancelled.
  35073. *
  35074. * @type number
  35075. */
  35076. this.touchBoundary = options.touchBoundary || 10;
  35077. /**
  35078. * The FastClick layer.
  35079. *
  35080. * @type Element
  35081. */
  35082. this.layer = layer;
  35083. /**
  35084. * The minimum time between tap(touchstart and touchend) events
  35085. *
  35086. * @type number
  35087. */
  35088. this.tapDelay = options.tapDelay || 200;
  35089. /**
  35090. * The maximum time for a tap
  35091. *
  35092. * @type number
  35093. */
  35094. this.tapTimeout = options.tapTimeout || 700;
  35095. if (FastClick.notNeeded(layer)) {
  35096. return;
  35097. }
  35098. // Some old versions of Android don't have Function.prototype.bind
  35099. function bind(method, context) {
  35100. return function() { return method.apply(context, arguments); };
  35101. }
  35102. var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];
  35103. var context = this;
  35104. for (var i = 0, l = methods.length; i < l; i++) {
  35105. context[methods[i]] = bind(context[methods[i]], context);
  35106. }
  35107. // Set up event handlers as required
  35108. if (deviceIsAndroid) {
  35109. layer.addEventListener('mouseover', this.onMouse, true);
  35110. layer.addEventListener('mousedown', this.onMouse, true);
  35111. layer.addEventListener('mouseup', this.onMouse, true);
  35112. }
  35113. layer.addEventListener('click', this.onClick, true);
  35114. layer.addEventListener('touchstart', this.onTouchStart, false);
  35115. layer.addEventListener('touchmove', this.onTouchMove, false);
  35116. layer.addEventListener('touchend', this.onTouchEnd, false);
  35117. layer.addEventListener('touchcancel', this.onTouchCancel, false);
  35118. // Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  35119. // which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
  35120. // layer when they are cancelled.
  35121. if (!Event.prototype.stopImmediatePropagation) {
  35122. layer.removeEventListener = function(type, callback, capture) {
  35123. var rmv = Node.prototype.removeEventListener;
  35124. if (type === 'click') {
  35125. rmv.call(layer, type, callback.hijacked || callback, capture);
  35126. } else {
  35127. rmv.call(layer, type, callback, capture);
  35128. }
  35129. };
  35130. layer.addEventListener = function(type, callback, capture) {
  35131. var adv = Node.prototype.addEventListener;
  35132. if (type === 'click') {
  35133. adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
  35134. if (!event.propagationStopped) {
  35135. callback(event);
  35136. }
  35137. }), capture);
  35138. } else {
  35139. adv.call(layer, type, callback, capture);
  35140. }
  35141. };
  35142. }
  35143. // If a handler is already declared in the element's onclick attribute, it will be fired before
  35144. // FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
  35145. // adding it as listener.
  35146. if (typeof layer.onclick === 'function') {
  35147. // Android browser on at least 3.2 requires a new reference to the function in layer.onclick
  35148. // - the old one won't work if passed to addEventListener directly.
  35149. oldOnClick = layer.onclick;
  35150. layer.addEventListener('click', function(event) {
  35151. oldOnClick(event);
  35152. }, false);
  35153. layer.onclick = null;
  35154. }
  35155. }
  35156. /**
  35157. * Windows Phone 8.1 fakes user agent string to look like Android and iPhone.
  35158. *
  35159. * @type boolean
  35160. */
  35161. var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;
  35162. /**
  35163. * Android requires exceptions.
  35164. *
  35165. * @type boolean
  35166. */
  35167. var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;
  35168. /**
  35169. * iOS requires exceptions.
  35170. *
  35171. * @type boolean
  35172. */
  35173. var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;
  35174. /**
  35175. * iOS 4 requires an exception for select elements.
  35176. *
  35177. * @type boolean
  35178. */
  35179. var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
  35180. /**
  35181. * iOS 6.0-7.* requires the target element to be manually derived
  35182. *
  35183. * @type boolean
  35184. */
  35185. var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);
  35186. /**
  35187. * BlackBerry requires exceptions.
  35188. *
  35189. * @type boolean
  35190. */
  35191. var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
  35192. /**
  35193. * Determine whether a given element requires a native click.
  35194. *
  35195. * @param {EventTarget|Element} target Target DOM element
  35196. * @returns {boolean} Returns true if the element needs a native click
  35197. */
  35198. FastClick.prototype.needsClick = function(target) {
  35199. switch (target.nodeName.toLowerCase()) {
  35200. // Don't send a synthetic click to disabled inputs (issue #62)
  35201. case 'button':
  35202. case 'select':
  35203. case 'textarea':
  35204. if (target.disabled) {
  35205. return true;
  35206. }
  35207. break;
  35208. case 'input':
  35209. // File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
  35210. if ((deviceIsIOS && target.type === 'file') || target.disabled) {
  35211. return true;
  35212. }
  35213. break;
  35214. case 'label':
  35215. case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames
  35216. case 'video':
  35217. return true;
  35218. }
  35219. return (/\bneedsclick\b/).test(target.className);
  35220. };
  35221. /**
  35222. * Determine whether a given element requires a call to focus to simulate click into element.
  35223. *
  35224. * @param {EventTarget|Element} target Target DOM element
  35225. * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
  35226. */
  35227. FastClick.prototype.needsFocus = function(target) {
  35228. switch (target.nodeName.toLowerCase()) {
  35229. case 'textarea':
  35230. return true;
  35231. case 'select':
  35232. return !deviceIsAndroid;
  35233. case 'input':
  35234. switch (target.type) {
  35235. case 'button':
  35236. case 'checkbox':
  35237. case 'file':
  35238. case 'image':
  35239. case 'radio':
  35240. case 'submit':
  35241. return false;
  35242. }
  35243. // No point in attempting to focus disabled inputs
  35244. return !target.disabled && !target.readOnly;
  35245. default:
  35246. return (/\bneedsfocus\b/).test(target.className);
  35247. }
  35248. };
  35249. /**
  35250. * Send a click event to the specified element.
  35251. *
  35252. * @param {EventTarget|Element} targetElement
  35253. * @param {Event} event
  35254. */
  35255. FastClick.prototype.sendClick = function(targetElement, event) {
  35256. var clickEvent, touch;
  35257. // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
  35258. if (document.activeElement && document.activeElement !== targetElement) {
  35259. document.activeElement.blur();
  35260. }
  35261. touch = event.changedTouches[0];
  35262. // Synthesise a click event, with an extra attribute so it can be tracked
  35263. clickEvent = document.createEvent('MouseEvents');
  35264. clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
  35265. clickEvent.forwardedTouchEvent = true;
  35266. targetElement.dispatchEvent(clickEvent);
  35267. };
  35268. FastClick.prototype.determineEventType = function(targetElement) {
  35269. //Issue #159: Android Chrome Select Box does not open with a synthetic click event
  35270. if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
  35271. return 'mousedown';
  35272. }
  35273. return 'click';
  35274. };
  35275. /**
  35276. * @param {EventTarget|Element} targetElement
  35277. */
  35278. FastClick.prototype.focus = function(targetElement) {
  35279. var length;
  35280. // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
  35281. if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {
  35282. length = targetElement.value.length;
  35283. targetElement.setSelectionRange(length, length);
  35284. } else {
  35285. targetElement.focus();
  35286. }
  35287. };
  35288. /**
  35289. * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
  35290. *
  35291. * @param {EventTarget|Element} targetElement
  35292. */
  35293. FastClick.prototype.updateScrollParent = function(targetElement) {
  35294. var scrollParent, parentElement;
  35295. scrollParent = targetElement.fastClickScrollParent;
  35296. // Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
  35297. // target element was moved to another parent.
  35298. if (!scrollParent || !scrollParent.contains(targetElement)) {
  35299. parentElement = targetElement;
  35300. do {
  35301. if (parentElement.scrollHeight > parentElement.offsetHeight) {
  35302. scrollParent = parentElement;
  35303. targetElement.fastClickScrollParent = parentElement;
  35304. break;
  35305. }
  35306. parentElement = parentElement.parentElement;
  35307. } while (parentElement);
  35308. }
  35309. // Always update the scroll top tracker if possible.
  35310. if (scrollParent) {
  35311. scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
  35312. }
  35313. };
  35314. /**
  35315. * @param {EventTarget} targetElement
  35316. * @returns {Element|EventTarget}
  35317. */
  35318. FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
  35319. // On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
  35320. if (eventTarget.nodeType === Node.TEXT_NODE) {
  35321. return eventTarget.parentNode;
  35322. }
  35323. return eventTarget;
  35324. };
  35325. /**
  35326. * On touch start, record the position and scroll offset.
  35327. *
  35328. * @param {Event} event
  35329. * @returns {boolean}
  35330. */
  35331. FastClick.prototype.onTouchStart = function(event) {
  35332. var targetElement, touch, selection;
  35333. // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
  35334. if (event.targetTouches.length > 1) {
  35335. return true;
  35336. }
  35337. targetElement = this.getTargetElementFromEventTarget(event.target);
  35338. touch = event.targetTouches[0];
  35339. if (deviceIsIOS) {
  35340. // Only trusted events will deselect text on iOS (issue #49)
  35341. selection = window.getSelection();
  35342. if (selection.rangeCount && !selection.isCollapsed) {
  35343. return true;
  35344. }
  35345. if (!deviceIsIOS4) {
  35346. // Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
  35347. // when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
  35348. // with the same identifier as the touch event that previously triggered the click that triggered the alert.
  35349. // Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
  35350. // immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
  35351. // Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
  35352. // which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
  35353. // random integers, it's safe to to continue if the identifier is 0 here.
  35354. if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
  35355. event.preventDefault();
  35356. return false;
  35357. }
  35358. this.lastTouchIdentifier = touch.identifier;
  35359. // If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
  35360. // 1) the user does a fling scroll on the scrollable layer
  35361. // 2) the user stops the fling scroll with another tap
  35362. // then the event.target of the last 'touchend' event will be the element that was under the user's finger
  35363. // when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
  35364. // is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
  35365. this.updateScrollParent(targetElement);
  35366. }
  35367. }
  35368. this.trackingClick = true;
  35369. this.trackingClickStart = event.timeStamp;
  35370. this.targetElement = targetElement;
  35371. this.touchStartX = touch.pageX;
  35372. this.touchStartY = touch.pageY;
  35373. // Prevent phantom clicks on fast double-tap (issue #36)
  35374. if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  35375. event.preventDefault();
  35376. }
  35377. return true;
  35378. };
  35379. /**
  35380. * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
  35381. *
  35382. * @param {Event} event
  35383. * @returns {boolean}
  35384. */
  35385. FastClick.prototype.touchHasMoved = function(event) {
  35386. var touch = event.changedTouches[0], boundary = this.touchBoundary;
  35387. if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
  35388. return true;
  35389. }
  35390. return false;
  35391. };
  35392. /**
  35393. * Update the last position.
  35394. *
  35395. * @param {Event} event
  35396. * @returns {boolean}
  35397. */
  35398. FastClick.prototype.onTouchMove = function(event) {
  35399. if (!this.trackingClick) {
  35400. return true;
  35401. }
  35402. // If the touch has moved, cancel the click tracking
  35403. if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
  35404. this.trackingClick = false;
  35405. this.targetElement = null;
  35406. }
  35407. return true;
  35408. };
  35409. /**
  35410. * Attempt to find the labelled control for the given label element.
  35411. *
  35412. * @param {EventTarget|HTMLLabelElement} labelElement
  35413. * @returns {Element|null}
  35414. */
  35415. FastClick.prototype.findControl = function(labelElement) {
  35416. // Fast path for newer browsers supporting the HTML5 control attribute
  35417. if (labelElement.control !== undefined) {
  35418. return labelElement.control;
  35419. }
  35420. // All browsers under test that support touch events also support the HTML5 htmlFor attribute
  35421. if (labelElement.htmlFor) {
  35422. return document.getElementById(labelElement.htmlFor);
  35423. }
  35424. // If no for attribute exists, attempt to retrieve the first labellable descendant element
  35425. // the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
  35426. return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
  35427. };
  35428. /**
  35429. * On touch end, determine whether to send a click event at once.
  35430. *
  35431. * @param {Event} event
  35432. * @returns {boolean}
  35433. */
  35434. FastClick.prototype.onTouchEnd = function(event) {
  35435. var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
  35436. if (!this.trackingClick) {
  35437. return true;
  35438. }
  35439. // Prevent phantom clicks on fast double-tap (issue #36)
  35440. if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  35441. this.cancelNextClick = true;
  35442. return true;
  35443. }
  35444. if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
  35445. return true;
  35446. }
  35447. // Reset to prevent wrong click cancel on input (issue #156).
  35448. this.cancelNextClick = false;
  35449. this.lastClickTime = event.timeStamp;
  35450. trackingClickStart = this.trackingClickStart;
  35451. this.trackingClick = false;
  35452. this.trackingClickStart = 0;
  35453. // On some iOS devices, the targetElement supplied with the event is invalid if the layer
  35454. // is performing a transition or scroll, and has to be re-detected manually. Note that
  35455. // for this to function correctly, it must be called *after* the event target is checked!
  35456. // See issue #57; also filed as rdar://13048589 .
  35457. if (deviceIsIOSWithBadTarget) {
  35458. touch = event.changedTouches[0];
  35459. // In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
  35460. targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
  35461. targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
  35462. }
  35463. targetTagName = targetElement.tagName.toLowerCase();
  35464. if (targetTagName === 'label') {
  35465. forElement = this.findControl(targetElement);
  35466. if (forElement) {
  35467. this.focus(targetElement);
  35468. if (deviceIsAndroid) {
  35469. return false;
  35470. }
  35471. targetElement = forElement;
  35472. }
  35473. } else if (this.needsFocus(targetElement)) {
  35474. // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
  35475. // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
  35476. if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
  35477. this.targetElement = null;
  35478. return false;
  35479. }
  35480. this.focus(targetElement);
  35481. this.sendClick(targetElement, event);
  35482. // Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
  35483. // Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
  35484. if (!deviceIsIOS || targetTagName !== 'select') {
  35485. this.targetElement = null;
  35486. event.preventDefault();
  35487. }
  35488. return false;
  35489. }
  35490. if (deviceIsIOS && !deviceIsIOS4) {
  35491. // Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
  35492. // and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
  35493. scrollParent = targetElement.fastClickScrollParent;
  35494. if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
  35495. return true;
  35496. }
  35497. }
  35498. // Prevent the actual click from going though - unless the target node is marked as requiring
  35499. // real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
  35500. if (!this.needsClick(targetElement)) {
  35501. event.preventDefault();
  35502. this.sendClick(targetElement, event);
  35503. }
  35504. return false;
  35505. };
  35506. /**
  35507. * On touch cancel, stop tracking the click.
  35508. *
  35509. * @returns {void}
  35510. */
  35511. FastClick.prototype.onTouchCancel = function() {
  35512. this.trackingClick = false;
  35513. this.targetElement = null;
  35514. };
  35515. /**
  35516. * Determine mouse events which should be permitted.
  35517. *
  35518. * @param {Event} event
  35519. * @returns {boolean}
  35520. */
  35521. FastClick.prototype.onMouse = function(event) {
  35522. // If a target element was never set (because a touch event was never fired) allow the event
  35523. if (!this.targetElement) {
  35524. return true;
  35525. }
  35526. if (event.forwardedTouchEvent) {
  35527. return true;
  35528. }
  35529. // Programmatically generated events targeting a specific element should be permitted
  35530. if (!event.cancelable) {
  35531. return true;
  35532. }
  35533. // Derive and check the target element to see whether the mouse event needs to be permitted;
  35534. // unless explicitly enabled, prevent non-touch click events from triggering actions,
  35535. // to prevent ghost/doubleclicks.
  35536. if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
  35537. // Prevent any user-added listeners declared on FastClick element from being fired.
  35538. if (event.stopImmediatePropagation) {
  35539. event.stopImmediatePropagation();
  35540. } else {
  35541. // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  35542. event.propagationStopped = true;
  35543. }
  35544. // Cancel the event
  35545. event.stopPropagation();
  35546. event.preventDefault();
  35547. return false;
  35548. }
  35549. // If the mouse event is permitted, return true for the action to go through.
  35550. return true;
  35551. };
  35552. /**
  35553. * On actual clicks, determine whether this is a touch-generated click, a click action occurring
  35554. * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
  35555. * an actual click which should be permitted.
  35556. *
  35557. * @param {Event} event
  35558. * @returns {boolean}
  35559. */
  35560. FastClick.prototype.onClick = function(event) {
  35561. var permitted;
  35562. // It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
  35563. if (this.trackingClick) {
  35564. this.targetElement = null;
  35565. this.trackingClick = false;
  35566. return true;
  35567. }
  35568. // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
  35569. if (event.target.type === 'submit' && event.detail === 0) {
  35570. return true;
  35571. }
  35572. permitted = this.onMouse(event);
  35573. // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
  35574. if (!permitted) {
  35575. this.targetElement = null;
  35576. }
  35577. // If clicks are permitted, return true for the action to go through.
  35578. return permitted;
  35579. };
  35580. /**
  35581. * Remove all FastClick's event listeners.
  35582. *
  35583. * @returns {void}
  35584. */
  35585. FastClick.prototype.destroy = function() {
  35586. var layer = this.layer;
  35587. if (deviceIsAndroid) {
  35588. layer.removeEventListener('mouseover', this.onMouse, true);
  35589. layer.removeEventListener('mousedown', this.onMouse, true);
  35590. layer.removeEventListener('mouseup', this.onMouse, true);
  35591. }
  35592. layer.removeEventListener('click', this.onClick, true);
  35593. layer.removeEventListener('touchstart', this.onTouchStart, false);
  35594. layer.removeEventListener('touchmove', this.onTouchMove, false);
  35595. layer.removeEventListener('touchend', this.onTouchEnd, false);
  35596. layer.removeEventListener('touchcancel', this.onTouchCancel, false);
  35597. };
  35598. /**
  35599. * Check whether FastClick is needed.
  35600. *
  35601. * @param {Element} layer The layer to listen on
  35602. */
  35603. FastClick.notNeeded = function(layer) {
  35604. var metaViewport;
  35605. var chromeVersion;
  35606. var blackberryVersion;
  35607. var firefoxVersion;
  35608. // Devices that don't support touch don't need FastClick
  35609. if (typeof window.ontouchstart === 'undefined') {
  35610. return true;
  35611. }
  35612. // Chrome version - zero for other browsers
  35613. chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
  35614. if (chromeVersion) {
  35615. if (deviceIsAndroid) {
  35616. metaViewport = document.querySelector('meta[name=viewport]');
  35617. if (metaViewport) {
  35618. // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
  35619. if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  35620. return true;
  35621. }
  35622. // Chrome 32 and above with width=device-width or less don't need FastClick
  35623. if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
  35624. return true;
  35625. }
  35626. }
  35627. // Chrome desktop doesn't need FastClick (issue #15)
  35628. } else {
  35629. return true;
  35630. }
  35631. }
  35632. if (deviceIsBlackBerry10) {
  35633. blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);
  35634. // BlackBerry 10.3+ does not require Fastclick library.
  35635. // https://github.com/ftlabs/fastclick/issues/251
  35636. if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
  35637. metaViewport = document.querySelector('meta[name=viewport]');
  35638. if (metaViewport) {
  35639. // user-scalable=no eliminates click delay.
  35640. if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  35641. return true;
  35642. }
  35643. // width=device-width (or less than device-width) eliminates click delay.
  35644. if (document.documentElement.scrollWidth <= window.outerWidth) {
  35645. return true;
  35646. }
  35647. }
  35648. }
  35649. }
  35650. // IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
  35651. if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
  35652. return true;
  35653. }
  35654. // Firefox version - zero for other browsers
  35655. firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
  35656. if (firefoxVersion >= 27) {
  35657. // Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
  35658. metaViewport = document.querySelector('meta[name=viewport]');
  35659. if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
  35660. return true;
  35661. }
  35662. }
  35663. // IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
  35664. // http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
  35665. if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {
  35666. return true;
  35667. }
  35668. return false;
  35669. };
  35670. /**
  35671. * Factory method for creating a FastClick object
  35672. *
  35673. * @param {Element} layer The layer to listen on
  35674. * @param {Object} [options={}] The options to override the defaults
  35675. */
  35676. FastClick.attach = function(layer, options) {
  35677. return new FastClick(layer, options);
  35678. };
  35679. if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
  35680. // AMD. Register as an anonymous module.
  35681. define(function() {
  35682. return FastClick;
  35683. });
  35684. } else if (typeof module !== 'undefined' && module.exports) {
  35685. module.exports = FastClick.attach;
  35686. module.exports.FastClick = FastClick;
  35687. } else {
  35688. window.FastClick = FastClick;
  35689. }
  35690. }());
  35691. },{}],157:[function(require,module,exports) {
  35692. module.exports="/P1-mini.6dc2e6f1.jpg";
  35693. },{}],108:[function(require,module,exports) {
  35694. module.exports="/location.c886854a.png";
  35695. },{}],109:[function(require,module,exports) {
  35696. module.exports="/glass.3b7bb858.png";
  35697. },{}],112:[function(require,module,exports) {
  35698. module.exports="/screen-tap-tips.e5ec73c9.png";
  35699. },{}],30:[function(require,module,exports) {
  35700. 'use strict';
  35701. require('../scss/index.scss');
  35702. require('../scss/page/scene1.scss');
  35703. var _photoSphereViewer = require('photo-sphere-viewer');
  35704. var _photoSphereViewer2 = _interopRequireDefault(_photoSphereViewer);
  35705. var _until = require('./until');
  35706. var _until2 = _interopRequireDefault(_until);
  35707. var _P1Mini = require('../img/P1-mini.jpg');
  35708. var _P1Mini2 = _interopRequireDefault(_P1Mini);
  35709. var _location = require('../img/location.png');
  35710. var _location2 = _interopRequireDefault(_location);
  35711. var _glass = require('../img/glass.png');
  35712. var _glass2 = _interopRequireDefault(_glass);
  35713. var _screenTapTips = require('../img/m/screen-tap-tips.png');
  35714. var _screenTapTips2 = _interopRequireDefault(_screenTapTips);
  35715. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  35716. var attachFastClick = require('fastclick');
  35717. // import '../js/lib/DeviceOrientationControls'
  35718. //望远镜
  35719. var viewer = null;
  35720. var indexPath = $('body').attr('data-path');
  35721. // 进度相关
  35722. var progressNum = 0;
  35723. var progressFlag = {
  35724. 'foot': false,
  35725. 'deer': false,
  35726. 'rabbit': false,
  35727. 'lake': false,
  35728. 'lookout': false
  35729. };
  35730. var videoMap = {
  35731. 'lookup': '8884585',
  35732. 'lake': '8887637',
  35733. 'aim': '8887375',
  35734. 'shoot': '8887379',
  35735. 'open': '8887381'
  35736. };
  35737. var mp4UrlMap = {};
  35738. var lakeV = {
  35739. init: function init() {
  35740. this.initLakeView();
  35741. this.handleNav();
  35742. this.getVideoSource();
  35743. _until2.default.handleReady(1870, 1050, viewer);
  35744. },
  35745. initLakeView: function initLakeView() {
  35746. viewer = new _photoSphereViewer2.default({
  35747. container: 'photosphere',
  35748. // panorama: 'http://hdzt.duowan.com/s/1806hunter/moblie/P1.jpg',
  35749. panorama: _P1Mini2.default,
  35750. min_fov: 50,
  35751. max_fov: 70,
  35752. navbar: false,
  35753. time_anim: false,
  35754. move_speed: 1.7, //m
  35755. anim_speed: '1rpm',
  35756. markers: [
  35757. // 多边形
  35758. {
  35759. id: 'deer-polygon',
  35760. polygon_px: [[1960, 836], [1960, 1048], [2190, 1048], [2190, 836]],
  35761. svgStyle: {
  35762. fill: 'rgba(0, 0, 0, 0)'
  35763. }
  35764. }, {
  35765. id: 'location-deer',
  35766. x: 2060,
  35767. y: 912,
  35768. image: _location2.default,
  35769. width: 35,
  35770. height: 35,
  35771. anchor: 'bottom center'
  35772. },
  35773. // 脚印
  35774. {
  35775. id: 'foot-polygon',
  35776. polygon_px: [[66, 1128], [66, 1276], [260, 1276], [260, 1128]],
  35777. svgStyle: {
  35778. fill: 'rgba(255, 255, 255, 0)'
  35779. }
  35780. }, {
  35781. id: 'location-foot',
  35782. x: 170,
  35783. y: 1218,
  35784. image: _location2.default,
  35785. width: 35,
  35786. height: 35,
  35787. anchor: 'bottom center'
  35788. },
  35789. // 兔子
  35790. {
  35791. id: 'rabit-polygon',
  35792. polygon_px: [[1082, 962], [1082, 1027], [1148, 1028], [1148, 962]],
  35793. svgStyle: {
  35794. fill: 'rgba(255, 255, 255, 0)'
  35795. }
  35796. }, {
  35797. id: 'location-rabit',
  35798. x: 1118,
  35799. y: 996,
  35800. image: _location2.default,
  35801. width: 35,
  35802. height: 35,
  35803. anchor: 'bottom center'
  35804. },
  35805. //望远镜
  35806. {
  35807. id: 'glass',
  35808. x: 1961,
  35809. y: 778,
  35810. image: _glass2.default,
  35811. width: 56,
  35812. height: 59,
  35813. anchor: 'bottom center'
  35814. },
  35815. // 湖
  35816. {
  35817. id: 'location-lake',
  35818. x: 80,
  35819. y: 1055,
  35820. image: _location2.default,
  35821. width: 35,
  35822. height: 35,
  35823. anchor: 'bottom center'
  35824. }]
  35825. });
  35826. },
  35827. getVideoSource: function getVideoSource() {
  35828. var vids = ['8896619', '8896627', '8896635', '8896637', '8896639', '8897789', '8896613', '8897759'];
  35829. // let videoEls = ['lookup', 'lake', 'aim', 'shoot', 'open']
  35830. var videoEls = {
  35831. '8896619': 'lookup',
  35832. '8896627': 'lake',
  35833. '8896635': 'book-lake',
  35834. '8896637': 'book-taiga',
  35835. '8896639': 'book-elden',
  35836. '8897789': 'picVideo',
  35837. '8896613': 'huntVideo',
  35838. '8897759': 'huntVideoB'
  35839. };
  35840. $.ajax({
  35841. type: "GET",
  35842. dataType: "json",
  35843. url: '//video.duowan.com/jsapi/playPageVideoInfo/?vids=' + vids.join(','),
  35844. success: function success(data) {
  35845. for (var i in data) {
  35846. var resouce = _until2.default.deCodeArg(data[i].c).all,
  35847. source = resouce.yuanhua || resouce[1300] || resouce[1000] || resouce[350];
  35848. var name = videoEls[i];
  35849. mp4UrlMap[name] = source.src;
  35850. }
  35851. document.getElementById('hunt-video').src = mp4UrlMap['huntVideo'];
  35852. document.getElementById('hunt-video-b').src = mp4UrlMap['huntVideoB'];
  35853. document.getElementById('book-lake-video').src = mp4UrlMap['book-lake'];
  35854. document.getElementById('book-taiga-video').src = mp4UrlMap['book-taiga'];
  35855. document.getElementById('book-elden-video').src = mp4UrlMap['book-elden'];
  35856. lakeC.lookoutClick();
  35857. lakeC.playVideo();
  35858. }
  35859. });
  35860. },
  35861. // 导航权限处理
  35862. handleNav: function handleNav() {
  35863. // 初始化加载时
  35864. var permision = localStorage.getItem('hunter_permision');
  35865. if (permision) {
  35866. progressFlag = {
  35867. 'foot': true,
  35868. 'deer': true,
  35869. 'rabbit': true,
  35870. 'lake': true,
  35871. 'lookout': true
  35872. };
  35873. $('#cur-progress').html(5);
  35874. if (permision == 2) {
  35875. $('#scene-nav2').removeClass('disable');
  35876. } else if (permision == 3 || permision == 4) {
  35877. $('#scene-nav2').removeClass('disable');
  35878. $('#scene-nav3').removeClass('disable');
  35879. }
  35880. }
  35881. }
  35882. };
  35883. var lakeC = {
  35884. init: function init() {
  35885. this.modalShow();
  35886. _until2.default.shooting();
  35887. _until2.default.bookClick();
  35888. _until2.default.toolbarClick();
  35889. },
  35890. modalShow: function modalShow() {
  35891. // 点击显示介绍弹窗
  35892. $('.nav').find('.current').click(function () {
  35893. $('#lake-suggest-modal').fadeIn();
  35894. });
  35895. // 脚印
  35896. function footModal() {
  35897. if ($('#lake-foot-modal').css('display') == 'none') {
  35898. $('.pub-modal').hide();
  35899. $('#lake-foot-modal').fadeIn();
  35900. viewer.animate({
  35901. longitude: 3.2,
  35902. latitude: -0.27
  35903. }, 600);
  35904. }
  35905. if (!progressFlag['foot']) {
  35906. progressFlag['foot'] = true;
  35907. $('#cur-progress').html(++progressNum);
  35908. progressNum == 5 ? $('#scene-nav2').removeClass('disable') : '';
  35909. progressNum == 5 ? localStorage.setItem('hunter_permision', '2') : '';
  35910. }
  35911. }
  35912. $(document).on('click', '#psv-marker-foot-polygon', function () {
  35913. footModal();
  35914. });
  35915. $(document).on('click', '#psv-marker-location-foot', function () {
  35916. footModal();
  35917. });
  35918. // 鹿
  35919. function deerModal() {
  35920. if ($('#lake-deer-modal').css('display') == 'none') {
  35921. $('.pub-modal').hide();
  35922. $('#lake-deer-modal').fadeIn();
  35923. viewer.animate({
  35924. longitude: 0.1,
  35925. latitude: -0.05
  35926. }, 600);
  35927. }
  35928. if (!progressFlag['deer']) {
  35929. progressFlag['deer'] = true;
  35930. $('#cur-progress').html(++progressNum);
  35931. progressNum == 5 ? $('#scene-nav2').removeClass('disable') : '';
  35932. progressNum == 5 ? localStorage.setItem('hunter_permision', '2') : '';
  35933. }
  35934. }
  35935. $(document).on('click', '#psv-marker-deer-polygon', function (e) {
  35936. deerModal();
  35937. });
  35938. $(document).on('click', '#psv-marker-location-deer', function () {
  35939. deerModal();
  35940. });
  35941. // 野兔
  35942. function rabitModal() {
  35943. if ($('#lake-rabbit-modal').css('display') == 'none') {
  35944. $('.pub-modal').hide();
  35945. $('#lake-rabbit-modal').fadeIn();
  35946. viewer.animate({
  35947. longitude: 4.87,
  35948. latitude: -0.07
  35949. }, 600);
  35950. }
  35951. if (!progressFlag['rabbit']) {
  35952. progressFlag['rabbit'] = true;
  35953. $('#cur-progress').html(++progressNum);
  35954. progressNum == 5 ? $('#scene-nav2').removeClass('disable') : '';
  35955. progressNum == 5 ? localStorage.setItem('hunter_permision', '2') : '';
  35956. }
  35957. }
  35958. $(document).on('click', '#psv-marker-rabit-polygon', function (e) {
  35959. rabitModal();
  35960. });
  35961. $(document).on('click', '#psv-marker-location-rabit', function () {
  35962. rabitModal();
  35963. });
  35964. //湖
  35965. $(document).on('click', '#psv-marker-location-lake', function () {
  35966. if (!$('#lake-pic')[0]) {
  35967. var lakeHtml = ' <div class="mod-full-picture" id="lake-pic" style="display:none">\n <div class="bg-move"></div>\n <div class="eyes-btn" id="open-eyes-modal"></div>\n <div class="pub-btn go-back">\u8FD4\u56DE</div>\n <div class="full-pic-modal small-modal">\n <div class="top-bar">\n \u83B1\u987F\u6E56\n </div>\n <div class="container clearfix">\n <p>\u5730\u7403\u4E0A\u6E56\u6CCA\u603B\u9762\u79EF\u4E3A270\u4E07\u5E73\u65B9\u516C\u91CC\uFF0C\u5360\u9646\u5730\u9762\u79EF\u76841.8%\uFF0C\u9762\u79EF\u5927\u4E8E5000\u5E73\u65B9\u516C\u91CC\u7684\u6E56</p>\n <p>\u9752\u6D77\u6E56\u6CCA\u670935\u4E2A\u3002\u82AC\u5170\u7684\u6E56\u6CCA\u6700\u591A\uFF0C\u88AB\u79F0\u4E3A\u201C\u4E07\u6E56\u4E4B\u56FD\u201D\uFF0C\u62E5\u6709\u5927\u5C0F\u6E56\u6CCA6\u4E07\u591A\u4E2A\u3002</p>\n <p>\u6E56\u6CCA\u4E00\u65E6\u5F62\u6210\uFF0C\u5C31\u53D7\u5230\u5916\u90E8\u81EA\u7136\u56E0\u7D20\u548C\u5185\u90E8\u5404\u79CD\u8FC7\u7A0B\u7684\u6301\u7EED\u4F5C\u7528\u800C\u4E0D\u65AD\u6F14\u53D8\u3002\u5165\u6E56\u6CB3\u6D41\u643A\u5E26\u7684\u5927\u91CF\u6CE5\u6C99\u548C\u751F\u7269\u6B8B\u9AB8\u5E74\u590D\u4E00\u5E74\u5728\u6E56\u5185\u6C89\u79EF\uFF0C\u6E56\u76C6\u9010\u6E10\u6DE4\u6D45\uFF0C\u53D8\u6210\u9646\u5730\uFF0C\u6216\u968F\u7740\u6CBF\u5CB8\u5E26\u6C34\u751F\u690D\u7269\u7684\u53D1\u5C55\uFF0C\u9010\u6E10\u53D8\u6210\u6CBC\u6CFD\u3002</p>\n <div class="eyes-btn" id="screen-open-video"></div>\n </div>\n </div>\n <div class="fullscreen-video fullscreen-video-picture" style="display: none">\n <video x5-playsinline="" webkit-playsinline="true" playsinline="true" controls id="picture-video" preload="metadata">\n <source src="' + mp4UrlMap['picVideo'] + '">\n </video>\n </div>\n </div>';
  35968. $('body').append(lakeHtml);
  35969. }
  35970. _until2.default.acceler();
  35971. $('#lake-pic').fadeIn();
  35972. if (!progressFlag['lake']) {
  35973. progressFlag['lake'] = true;
  35974. $('#cur-progress').html(++progressNum);
  35975. progressNum == 5 ? $('#scene-nav2').removeClass('disable') : '';
  35976. progressNum == 5 ? localStorage.setItem('hunter_permision', '2') : '';
  35977. }
  35978. });
  35979. //moblie 
  35980. $(document).on('click', '#open-eyes-modal', function () {
  35981. var showFlag = $('.full-pic-modal').css('display') == 'none' ? false : true;
  35982. showFlag ? $('.full-pic-modal').fadeOut() : $('.full-pic-modal').fadeIn();
  35983. });
  35984. $(document).on('click', '#screen-open-video', function () {
  35985. $('.fullscreen-video-picture').show();
  35986. var video = document.getElementById('picture-video');
  35987. video.play();
  35988. video.addEventListener("ended", function () {
  35989. video.load();
  35990. $('.fullscreen-video-picture').hide();
  35991. });
  35992. return false;
  35993. });
  35994. },
  35995. playVideo: function playVideo() {
  35996. $('#rabbit-video-play').click(function () {
  35997. if (!$('#lake-video-suggest')[0]) {
  35998. var lakeVideoHtml = '<div class="video-wrapper pub-modal-mask" id="lake-video-suggest">\n <div class="part-screen">\n <video x5-playsinline="" webkit-playsinline="true" playsinline="true" controls autoplay id="lake-video">\n <source src="' + mp4UrlMap['lake'] + '">\n </video>\n </div>\n </div>';
  35999. $('body').append(lakeVideoHtml);
  36000. } else {
  36001. $('#lake-video-suggest').show();
  36002. // document.getElementById('lake-video').play()
  36003. }
  36004. return false;
  36005. });
  36006. },
  36007. // 瞭望台
  36008. lookoutClick: function lookoutClick() {
  36009. var videoHtml = '<div class="fullscreen-video fullscreen-video-lookout">\n <video x5-playsinline="" webkit-playsinline="true" playsinline="true" controls id="lookout-video" width="100%">\n <source src="' + mp4UrlMap['lookup'] + '">\n </video>\n </div>';
  36010. $(document).on('click', '#psv-marker-glass', function () {
  36011. if (!$('#lookout-pic')[0]) {
  36012. var lookOutHtml = ' <div class="mod-full-picture" id="lookout-pic" style="display:none">\n <div class="pub-btn go-back">\u8FD4\u56DE</div>\n <img class="e-tips" src="' + _screenTapTips2.default + '" alt="">\n </div>';
  36013. $('body').append(lookOutHtml);
  36014. }
  36015. $('#lookout-pic').fadeIn();
  36016. if (!progressFlag['lookout']) {
  36017. progressFlag['lookout'] = true;
  36018. $('#cur-progress').html(++progressNum);
  36019. progressNum == 5 ? $('#scene-nav2').removeClass('disable') : '';
  36020. progressNum == 5 ? localStorage.setItem('hunter_permision', '2') : '';
  36021. }
  36022. });
  36023. // 轻触屏幕
  36024. $(document).on('click', '#lookout-pic', function (e) {
  36025. var lookVideo = document.getElementById('lookout-video');
  36026. if (lookVideo) {
  36027. $('#lookout-pic').find('.fullscreen-video').fadeIn();
  36028. lookVideo.play();
  36029. } else {
  36030. $('#lookout-pic').append(videoHtml);
  36031. lookVideo = document.getElementById('lookout-video');
  36032. lookVideo.play();
  36033. }
  36034. lookVideo.addEventListener("ended", function () {
  36035. lookVideo.load();
  36036. lookVideo.pause();
  36037. $('.fullscreen-video-lookout').hide();
  36038. $('#lookout-pic').hide();
  36039. });
  36040. });
  36041. }
  36042. };
  36043. function screenInit() {
  36044. // 竖屏
  36045. if (window.orientation == 180 || window.orientation == 0) {
  36046. $('.across-modal').show();
  36047. }
  36048. // 横屏
  36049. if (window.orientation == 90 || window.orientation == -90) {
  36050. $('.across-modal').hide();
  36051. if (viewer) return;
  36052. var entry = localStorage.getItem('entry');
  36053. if (entry == 'index') {
  36054. _until2.default.handleModel();
  36055. lakeV.init();
  36056. lakeC.init();
  36057. } else {
  36058. window.location.href = indexPath;
  36059. }
  36060. }
  36061. }
  36062. screenInit();
  36063. window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", screenInit, false);
  36064. $(function () {
  36065. attachFastClick(document.body);
  36066. });
  36067. },{"../scss/index.scss":107,"../scss/page/scene1.scss":110,"photo-sphere-viewer":113,"./until":111,"fastclick":114,"../img/P1-mini.jpg":157,"../img/location.png":108,"../img/glass.png":109,"../img/m/screen-tap-tips.png":112}],183:[function(require,module,exports) {
  36068. var global = arguments[3];
  36069. var OVERLAY_ID = '__parcel__error__overlay__';
  36070. var OldModule = module.bundle.Module;
  36071. function Module(moduleName) {
  36072. OldModule.call(this, moduleName);
  36073. this.hot = {
  36074. data: module.bundle.hotData,
  36075. _acceptCallbacks: [],
  36076. _disposeCallbacks: [],
  36077. accept: function (fn) {
  36078. this._acceptCallbacks.push(fn || function () {});
  36079. },
  36080. dispose: function (fn) {
  36081. this._disposeCallbacks.push(fn);
  36082. }
  36083. };
  36084. module.bundle.hotData = null;
  36085. }
  36086. module.bundle.Module = Module;
  36087. var parent = module.bundle.parent;
  36088. if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
  36089. var hostname = '' || location.hostname;
  36090. var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
  36091. var ws = new WebSocket(protocol + '://' + hostname + ':' + '52930' + '/');
  36092. ws.onmessage = function (event) {
  36093. var data = JSON.parse(event.data);
  36094. if (data.type === 'update') {
  36095. data.assets.forEach(function (asset) {
  36096. hmrApply(global.parcelRequire, asset);
  36097. });
  36098. data.assets.forEach(function (asset) {
  36099. if (!asset.isNew) {
  36100. hmrAccept(global.parcelRequire, asset.id);
  36101. }
  36102. });
  36103. // Clear the console after HMR
  36104. console.clear();
  36105. }
  36106. if (data.type === 'reload') {
  36107. ws.close();
  36108. ws.onclose = function () {
  36109. location.reload();
  36110. };
  36111. }
  36112. if (data.type === 'error-resolved') {
  36113. console.log('[parcel] ✨ Error resolved');
  36114. removeErrorOverlay();
  36115. }
  36116. if (data.type === 'error') {
  36117. console.error('[parcel] 🚨 ' + data.error.message + '\n' + data.error.stack);
  36118. removeErrorOverlay();
  36119. var overlay = createErrorOverlay(data);
  36120. document.body.appendChild(overlay);
  36121. }
  36122. };
  36123. }
  36124. function removeErrorOverlay() {
  36125. var overlay = document.getElementById(OVERLAY_ID);
  36126. if (overlay) {
  36127. overlay.remove();
  36128. }
  36129. }
  36130. function createErrorOverlay(data) {
  36131. var overlay = document.createElement('div');
  36132. overlay.id = OVERLAY_ID;
  36133. // html encode message and stack trace
  36134. var message = document.createElement('div');
  36135. var stackTrace = document.createElement('pre');
  36136. message.innerText = data.error.message;
  36137. stackTrace.innerText = data.error.stack;
  36138. overlay.innerHTML = '<div style="background: black; font-size: 16px; color: white; position: fixed; height: 100%; width: 100%; top: 0px; left: 0px; padding: 30px; opacity: 0.85; font-family: Menlo, Consolas, monospace; z-index: 9999;">' + '<span style="background: red; padding: 2px 4px; border-radius: 2px;">ERROR</span>' + '<span style="top: 2px; margin-left: 5px; position: relative;">🚨</span>' + '<div style="font-size: 18px; font-weight: bold; margin-top: 20px;">' + message.innerHTML + '</div>' + '<pre>' + stackTrace.innerHTML + '</pre>' + '</div>';
  36139. return overlay;
  36140. }
  36141. function getParents(bundle, id) {
  36142. var modules = bundle.modules;
  36143. if (!modules) {
  36144. return [];
  36145. }
  36146. var parents = [];
  36147. var k, d, dep;
  36148. for (k in modules) {
  36149. for (d in modules[k][1]) {
  36150. dep = modules[k][1][d];
  36151. if (dep === id || Array.isArray(dep) && dep[dep.length - 1] === id) {
  36152. parents.push(+k);
  36153. }
  36154. }
  36155. }
  36156. if (bundle.parent) {
  36157. parents = parents.concat(getParents(bundle.parent, id));
  36158. }
  36159. return parents;
  36160. }
  36161. function hmrApply(bundle, asset) {
  36162. var modules = bundle.modules;
  36163. if (!modules) {
  36164. return;
  36165. }
  36166. if (modules[asset.id] || !bundle.parent) {
  36167. var fn = new Function('require', 'module', 'exports', asset.generated.js);
  36168. asset.isNew = !modules[asset.id];
  36169. modules[asset.id] = [fn, asset.deps];
  36170. } else if (bundle.parent) {
  36171. hmrApply(bundle.parent, asset);
  36172. }
  36173. }
  36174. function hmrAccept(bundle, id) {
  36175. var modules = bundle.modules;
  36176. if (!modules) {
  36177. return;
  36178. }
  36179. if (!modules[id] && bundle.parent) {
  36180. return hmrAccept(bundle.parent, id);
  36181. }
  36182. var cached = bundle.cache[id];
  36183. bundle.hotData = {};
  36184. if (cached) {
  36185. cached.hot.data = bundle.hotData;
  36186. }
  36187. if (cached && cached.hot && cached.hot._disposeCallbacks.length) {
  36188. cached.hot._disposeCallbacks.forEach(function (cb) {
  36189. cb(bundle.hotData);
  36190. });
  36191. }
  36192. delete bundle.cache[id];
  36193. bundle(id);
  36194. cached = bundle.cache[id];
  36195. if (cached && cached.hot && cached.hot._acceptCallbacks.length) {
  36196. cached.hot._acceptCallbacks.forEach(function (cb) {
  36197. cb();
  36198. });
  36199. return true;
  36200. }
  36201. return getParents(global.parcelRequire, id).some(function (id) {
  36202. return hmrAccept(global.parcelRequire, id);
  36203. });
  36204. }
  36205. },{}],184:[function(require,module,exports) {
  36206. var getBundleURL = require('./bundle-url').getBundleURL;
  36207. function loadBundlesLazy(bundles) {
  36208. if (!Array.isArray(bundles)) {
  36209. bundles = [bundles];
  36210. }
  36211. var id = bundles[bundles.length - 1];
  36212. try {
  36213. return Promise.resolve(require(id));
  36214. } catch (err) {
  36215. if (err.code === 'MODULE_NOT_FOUND') {
  36216. return new LazyPromise(function (resolve, reject) {
  36217. loadBundles(bundles).then(resolve, reject);
  36218. });
  36219. }
  36220. throw err;
  36221. }
  36222. }
  36223. function loadBundles(bundles) {
  36224. var id = bundles[bundles.length - 1];
  36225. return Promise.all(bundles.slice(0, -1).map(loadBundle)).then(function () {
  36226. return require(id);
  36227. });
  36228. }
  36229. var bundleLoaders = {};
  36230. function registerBundleLoader(type, loader) {
  36231. bundleLoaders[type] = loader;
  36232. }
  36233. module.exports = exports = loadBundlesLazy;
  36234. exports.load = loadBundles;
  36235. exports.register = registerBundleLoader;
  36236. var bundles = {};
  36237. function loadBundle(bundle) {
  36238. var id;
  36239. if (Array.isArray(bundle)) {
  36240. id = bundle[1];
  36241. bundle = bundle[0];
  36242. }
  36243. if (bundles[bundle]) {
  36244. return bundles[bundle];
  36245. }
  36246. var type = (bundle.substring(bundle.lastIndexOf('.') + 1, bundle.length) || bundle).toLowerCase();
  36247. var bundleLoader = bundleLoaders[type];
  36248. if (bundleLoader) {
  36249. return bundles[bundle] = bundleLoader(getBundleURL() + bundle).then(function (resolved) {
  36250. if (resolved) {
  36251. module.bundle.modules[id] = [function (require, module) {
  36252. module.exports = resolved;
  36253. }, {}];
  36254. }
  36255. return resolved;
  36256. });
  36257. }
  36258. }
  36259. function LazyPromise(executor) {
  36260. this.executor = executor;
  36261. this.promise = null;
  36262. }
  36263. LazyPromise.prototype.then = function (onSuccess, onError) {
  36264. if (this.promise === null) this.promise = new Promise(this.executor);
  36265. return this.promise.then(onSuccess, onError);
  36266. };
  36267. LazyPromise.prototype.catch = function (onError) {
  36268. if (this.promise === null) this.promise = new Promise(this.executor);
  36269. return this.promise.catch(onError);
  36270. };
  36271. },{"./bundle-url":106}],185:[function(require,module,exports) {
  36272. module.exports = function loadCSSBundle(bundle) {
  36273. return new Promise(function (resolve, reject) {
  36274. var link = document.createElement('link');
  36275. link.rel = 'stylesheet';
  36276. link.href = bundle;
  36277. link.onerror = function (e) {
  36278. link.onerror = link.onload = null;
  36279. reject(e);
  36280. };
  36281. link.onload = function () {
  36282. link.onerror = link.onload = null;
  36283. resolve();
  36284. };
  36285. document.getElementsByTagName('head')[0].appendChild(link);
  36286. });
  36287. };
  36288. },{}],0:[function(require,module,exports) {
  36289. var b=require(184);b.register("css",require(185));b.load([["photo-sphere-viewer.min.bf28a8e3.css",115],["lock.7a624bd5.png",116],["close-icon.b3fd75de.png",117],["lookout-pic.05ca05b8.jpg",118],["P2-lookout.bddb85b2.jpg",119],["P3-lookout.7287f90b.jpg",120],["P1-lake.99042115.jpg",121],["P2-road.81c6be7a.jpg",122],["P3-road.f0075e0c.jpg",123],["P1-loading.217a0e9d.jpg",124],["P2-loading.95e3fd83.jpg",125],["P3-loading.e64cabe9.jpg",126],["euqit-nav-bg.ea6b18b2.png",136],["weapon-icon.f9aad7af.png",127],["fodder-icon.b04fbce3.png",128],["glass-icon.3dc9da25.png",129],["book-icon.b5312cb3.jpg",130],["snow-icon.7cdc2a40.png",131],["bgm-icon.1c104210.png",132],["comment-icon.dd2c03a0.png",133],["reset-btn.fe63d3db.png",134],["eyes-logo.c52ff856.png",135],["orient-lock-pic.94c18e19.png",137],["bag-a.46cecb91.png",138],["bag-a-active.819ecd74.png",139],["bag-b.af62e63b.png",140],["bag-b-active.bc340b72.png",141],["comment-bg.fe2b9b84.jpg",142],["hunter-logo.80ed5834.png",143],30]);
  36290. },{}]},{},[183,0], null)
  36291. //# sourceMappingURL=/scene1.fcb72093.map