aframe-extras.js 761 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402
  1. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. require('./').registerAll();
  3. },{"./":2}],2:[function(require,module,exports){
  4. module.exports = {
  5. controls: require('./src/controls'),
  6. loaders: require('./src/loaders'),
  7. misc: require('./src/misc'),
  8. pathfinding: require('./src/pathfinding'),
  9. physics: require('aframe-physics-system'),
  10. primitives: require('./src/primitives'),
  11. registerAll: function () {
  12. this.controls.registerAll();
  13. this.loaders.registerAll();
  14. this.misc.registerAll();
  15. this.pathfinding.registerAll();
  16. this.physics.registerAll();
  17. this.primitives.registerAll();
  18. }
  19. };
  20. },{"./src/controls":89,"./src/loaders":97,"./src/misc":104,"./src/pathfinding":110,"./src/primitives":118,"aframe-physics-system":11}],3:[function(require,module,exports){
  21. /**
  22. * @author Kyle-Larson https://github.com/Kyle-Larson
  23. * @author Takahiro https://github.com/takahirox
  24. *
  25. * Loader loads FBX file and generates Group representing FBX scene.
  26. * Requires FBX file to be >= 7.0 and in ASCII or to be any version in Binary format.
  27. *
  28. * Supports:
  29. * Mesh Generation (Positional Data)
  30. * Normal Data (Per Vertex Drawing Instance)
  31. * UV Data (Per Vertex Drawing Instance)
  32. * Skinning
  33. * Animation
  34. * - Separated Animations based on stacks.
  35. * - Skeletal & Non-Skeletal Animations
  36. * NURBS (Open, Closed and Periodic forms)
  37. *
  38. * Needs Support:
  39. * Indexed Buffers
  40. * PreRotation support.
  41. */
  42. ( function () {
  43. /**
  44. * Generates a loader for loading FBX files from URL and parsing into
  45. * a THREE.Group.
  46. * @param {THREE.LoadingManager} manager - Loading Manager for loader to use.
  47. */
  48. module.exports = THREE.FBXLoader = function ( manager ) {
  49. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  50. };
  51. Object.assign( THREE.FBXLoader.prototype, {
  52. /**
  53. * Loads an ASCII/Binary FBX file from URL and parses into a THREE.Group.
  54. * THREE.Group will have an animations property of AnimationClips
  55. * of the different animations exported with the FBX.
  56. * @param {string} url - URL of the FBX file.
  57. * @param {function(THREE.Group):void} onLoad - Callback for when FBX file is loaded and parsed.
  58. * @param {function(ProgressEvent):void} onProgress - Callback fired periodically when file is being retrieved from server.
  59. * @param {function(Event):void} onError - Callback fired when error occurs (Currently only with retrieving file, not with parsing errors).
  60. */
  61. load: function ( url, onLoad, onProgress, onError ) {
  62. var self = this;
  63. var resourceDirectory = THREE.Loader.prototype.extractUrlBase( url );
  64. var loader = new THREE.FileLoader( this.manager );
  65. loader.setResponseType( 'arraybuffer' );
  66. loader.load( url, function ( buffer ) {
  67. try {
  68. var scene = self.parse( buffer, resourceDirectory );
  69. onLoad( scene );
  70. } catch ( error ) {
  71. window.setTimeout( function () {
  72. if ( onError ) onError( error );
  73. self.manager.itemError( url );
  74. }, 0 );
  75. }
  76. }, onProgress, onError );
  77. },
  78. /**
  79. * Parses an ASCII/Binary FBX file and returns a THREE.Group.
  80. * THREE.Group will have an animations property of AnimationClips
  81. * of the different animations within the FBX file.
  82. * @param {ArrayBuffer} FBXBuffer - Contents of FBX file to parse.
  83. * @param {string} resourceDirectory - Directory to load external assets (e.g. textures ) from.
  84. * @returns {THREE.Group}
  85. */
  86. parse: function ( FBXBuffer, resourceDirectory ) {
  87. var FBXTree;
  88. if ( isFbxFormatBinary( FBXBuffer ) ) {
  89. FBXTree = new BinaryParser().parse( FBXBuffer );
  90. } else {
  91. var FBXText = convertArrayBufferToString( FBXBuffer );
  92. if ( ! isFbxFormatASCII( FBXText ) ) {
  93. throw new Error( 'THREE.FBXLoader: Unknown format.' );
  94. }
  95. if ( getFbxVersion( FBXText ) < 7000 ) {
  96. throw new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + getFbxVersion( FBXText ) );
  97. }
  98. FBXTree = new TextParser().parse( FBXText );
  99. }
  100. // console.log( FBXTree );
  101. var connections = parseConnections( FBXTree );
  102. var images = parseImages( FBXTree );
  103. var textures = parseTextures( FBXTree, new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ), images, connections );
  104. var materials = parseMaterials( FBXTree, textures, connections );
  105. var deformers = parseDeformers( FBXTree, connections );
  106. var geometryMap = parseGeometries( FBXTree, connections, deformers );
  107. var sceneGraph = parseScene( FBXTree, connections, deformers, geometryMap, materials );
  108. return sceneGraph;
  109. }
  110. } );
  111. /**
  112. * Parses map of relationships between objects.
  113. * @param {{Connections: { properties: { connections: [number, number, string][]}}}} FBXTree
  114. * @returns {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>}
  115. */
  116. function parseConnections( FBXTree ) {
  117. /**
  118. * @type {Map<number, { parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>}
  119. */
  120. var connectionMap = new Map();
  121. if ( 'Connections' in FBXTree ) {
  122. /**
  123. * @type {[number, number, string][]}
  124. */
  125. var connectionArray = FBXTree.Connections.properties.connections;
  126. for ( var connectionArrayIndex = 0, connectionArrayLength = connectionArray.length; connectionArrayIndex < connectionArrayLength; ++ connectionArrayIndex ) {
  127. var connection = connectionArray[ connectionArrayIndex ];
  128. if ( ! connectionMap.has( connection[ 0 ] ) ) {
  129. connectionMap.set( connection[ 0 ], {
  130. parents: [],
  131. children: []
  132. } );
  133. }
  134. var parentRelationship = { ID: connection[ 1 ], relationship: connection[ 2 ] };
  135. connectionMap.get( connection[ 0 ] ).parents.push( parentRelationship );
  136. if ( ! connectionMap.has( connection[ 1 ] ) ) {
  137. connectionMap.set( connection[ 1 ], {
  138. parents: [],
  139. children: []
  140. } );
  141. }
  142. var childRelationship = { ID: connection[ 0 ], relationship: connection[ 2 ] };
  143. connectionMap.get( connection[ 1 ] ).children.push( childRelationship );
  144. }
  145. }
  146. return connectionMap;
  147. }
  148. /**
  149. * Parses map of images referenced in FBXTree.
  150. * @param {{Objects: {subNodes: {Texture: Object.<string, FBXTextureNode>}}}} FBXTree
  151. * @returns {Map<number, string(image blob/data URL)>}
  152. */
  153. function parseImages( FBXTree ) {
  154. /**
  155. * @type {Map<number, string(image blob/data URL)>}
  156. */
  157. var imageMap = new Map();
  158. if ( 'Video' in FBXTree.Objects.subNodes ) {
  159. var videoNodes = FBXTree.Objects.subNodes.Video;
  160. for ( var nodeID in videoNodes ) {
  161. var videoNode = videoNodes[ nodeID ];
  162. // raw image data is in videoNode.properties.Content
  163. if ( 'Content' in videoNode.properties ) {
  164. var image = parseImage( videoNodes[ nodeID ] );
  165. imageMap.set( parseInt( nodeID ), image );
  166. }
  167. }
  168. }
  169. return imageMap;
  170. }
  171. /**
  172. * @param {videoNode} videoNode - Node to get texture image information from.
  173. * @returns {string} - image blob/data URL
  174. */
  175. function parseImage( videoNode ) {
  176. var content = videoNode.properties.Content;
  177. var fileName = videoNode.properties.RelativeFilename || videoNode.properties.Filename;
  178. var extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
  179. var type;
  180. switch ( extension ) {
  181. case 'bmp':
  182. type = 'image/bmp';
  183. break;
  184. case 'jpg':
  185. type = 'image/jpeg';
  186. break;
  187. case 'png':
  188. type = 'image/png';
  189. break;
  190. case 'tif':
  191. type = 'image/tiff';
  192. break;
  193. default:
  194. console.warn( 'FBXLoader: No support image type ' + extension );
  195. return;
  196. }
  197. if ( typeof content === 'string' ) {
  198. return 'data:' + type + ';base64,' + content;
  199. } else {
  200. var array = new Uint8Array( content );
  201. return window.URL.createObjectURL( new Blob( [ array ], { type: type } ) );
  202. }
  203. }
  204. /**
  205. * Parses map of textures referenced in FBXTree.
  206. * @param {{Objects: {subNodes: {Texture: Object.<string, FBXTextureNode>}}}} FBXTree
  207. * @param {THREE.TextureLoader} loader
  208. * @param {Map<number, string(image blob/data URL)>} imageMap
  209. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  210. * @returns {Map<number, THREE.Texture>}
  211. */
  212. function parseTextures( FBXTree, loader, imageMap, connections ) {
  213. /**
  214. * @type {Map<number, THREE.Texture>}
  215. */
  216. var textureMap = new Map();
  217. if ( 'Texture' in FBXTree.Objects.subNodes ) {
  218. var textureNodes = FBXTree.Objects.subNodes.Texture;
  219. for ( var nodeID in textureNodes ) {
  220. var texture = parseTexture( textureNodes[ nodeID ], loader, imageMap, connections );
  221. textureMap.set( parseInt( nodeID ), texture );
  222. }
  223. }
  224. return textureMap;
  225. }
  226. /**
  227. * @param {textureNode} textureNode - Node to get texture information from.
  228. * @param {THREE.TextureLoader} loader
  229. * @param {Map<number, string(image blob/data URL)>} imageMap
  230. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  231. * @returns {THREE.Texture}
  232. */
  233. function parseTexture( textureNode, loader, imageMap, connections ) {
  234. var FBX_ID = textureNode.id;
  235. var name = textureNode.name;
  236. var fileName;
  237. var filePath = textureNode.properties.FileName;
  238. var relativeFilePath = textureNode.properties.RelativeFilename;
  239. var children = connections.get( FBX_ID ).children;
  240. if ( children !== undefined && children.length > 0 && imageMap.has( children[ 0 ].ID ) ) {
  241. fileName = imageMap.get( children[ 0 ].ID );
  242. } else if ( relativeFilePath !== undefined && relativeFilePath[ 0 ] !== '/' &&
  243. relativeFilePath.match( /^[a-zA-Z]:/ ) === null ) {
  244. // use textureNode.properties.RelativeFilename
  245. // if it exists and it doesn't seem an absolute path
  246. fileName = relativeFilePath;
  247. } else {
  248. var split = filePath.split( /[\\\/]/ );
  249. if ( split.length > 0 ) {
  250. fileName = split[ split.length - 1 ];
  251. } else {
  252. fileName = filePath;
  253. }
  254. }
  255. var currentPath = loader.path;
  256. if ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {
  257. loader.setPath( undefined );
  258. }
  259. /**
  260. * @type {THREE.Texture}
  261. */
  262. var texture = loader.load( fileName );
  263. texture.name = name;
  264. texture.FBX_ID = FBX_ID;
  265. var wrapModeU = textureNode.properties.WrapModeU;
  266. var wrapModeV = textureNode.properties.WrapModeV;
  267. var valueU = wrapModeU !== undefined ? wrapModeU.value : 0;
  268. var valueV = wrapModeV !== undefined ? wrapModeV.value : 0;
  269. // http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
  270. // 0: repeat(default), 1: clamp
  271. texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
  272. texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
  273. loader.setPath( currentPath );
  274. return texture;
  275. }
  276. /**
  277. * Parses map of Material information.
  278. * @param {{Objects: {subNodes: {Material: Object.<number, FBXMaterialNode>}}}} FBXTree
  279. * @param {Map<number, THREE.Texture>} textureMap
  280. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  281. * @returns {Map<number, THREE.Material>}
  282. */
  283. function parseMaterials( FBXTree, textureMap, connections ) {
  284. var materialMap = new Map();
  285. if ( 'Material' in FBXTree.Objects.subNodes ) {
  286. var materialNodes = FBXTree.Objects.subNodes.Material;
  287. for ( var nodeID in materialNodes ) {
  288. var material = parseMaterial( materialNodes[ nodeID ], textureMap, connections );
  289. if ( material !== null ) materialMap.set( parseInt( nodeID ), material );
  290. }
  291. }
  292. return materialMap;
  293. }
  294. /**
  295. * Takes information from Material node and returns a generated THREE.Material
  296. * @param {FBXMaterialNode} materialNode
  297. * @param {Map<number, THREE.Texture>} textureMap
  298. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  299. * @returns {THREE.Material}
  300. */
  301. function parseMaterial( materialNode, textureMap, connections ) {
  302. var FBX_ID = materialNode.id;
  303. var name = materialNode.attrName;
  304. var type = materialNode.properties.ShadingModel;
  305. //Case where FBXs wrap shading model in property object.
  306. if ( typeof type === 'object' ) {
  307. type = type.value;
  308. }
  309. // Seems like FBX can include unused materials which don't have any connections.
  310. // Ignores them so far.
  311. if ( ! connections.has( FBX_ID ) ) return null;
  312. var children = connections.get( FBX_ID ).children;
  313. var parameters = parseParameters( materialNode.properties, textureMap, children );
  314. var material;
  315. switch ( type.toLowerCase() ) {
  316. case 'phong':
  317. material = new THREE.MeshPhongMaterial();
  318. break;
  319. case 'lambert':
  320. material = new THREE.MeshLambertMaterial();
  321. break;
  322. default:
  323. console.warn( 'THREE.FBXLoader: No implementation given for material type %s in FBXLoader.js. Defaulting to standard material.', type );
  324. material = new THREE.MeshStandardMaterial( { color: 0x3300ff } );
  325. break;
  326. }
  327. material.setValues( parameters );
  328. material.name = name;
  329. return material;
  330. }
  331. /**
  332. * @typedef {{Diffuse: FBXVector3, Specular: FBXVector3, Shininess: FBXValue, Emissive: FBXVector3, EmissiveFactor: FBXValue, Opacity: FBXValue}} FBXMaterialProperties
  333. */
  334. /**
  335. * @typedef {{color: THREE.Color=, specular: THREE.Color=, shininess: number=, emissive: THREE.Color=, emissiveIntensity: number=, opacity: number=, transparent: boolean=, map: THREE.Texture=}} THREEMaterialParameterPack
  336. */
  337. /**
  338. * @param {FBXMaterialProperties} properties
  339. * @param {Map<number, THREE.Texture>} textureMap
  340. * @param {{ID: number, relationship: string}[]} childrenRelationships
  341. * @returns {THREEMaterialParameterPack}
  342. */
  343. function parseParameters( properties, textureMap, childrenRelationships ) {
  344. var parameters = {};
  345. if ( properties.Diffuse ) {
  346. parameters.color = parseColor( properties.Diffuse );
  347. }
  348. if ( properties.Specular ) {
  349. parameters.specular = parseColor( properties.Specular );
  350. }
  351. if ( properties.Shininess ) {
  352. parameters.shininess = properties.Shininess.value;
  353. }
  354. if ( properties.Emissive ) {
  355. parameters.emissive = parseColor( properties.Emissive );
  356. }
  357. if ( properties.EmissiveFactor ) {
  358. parameters.emissiveIntensity = properties.EmissiveFactor.value;
  359. }
  360. if ( properties.Opacity ) {
  361. parameters.opacity = properties.Opacity.value;
  362. }
  363. if ( parameters.opacity < 1.0 ) {
  364. parameters.transparent = true;
  365. }
  366. for ( var childrenRelationshipsIndex = 0, childrenRelationshipsLength = childrenRelationships.length; childrenRelationshipsIndex < childrenRelationshipsLength; ++ childrenRelationshipsIndex ) {
  367. var relationship = childrenRelationships[ childrenRelationshipsIndex ];
  368. var type = relationship.relationship;
  369. switch ( type ) {
  370. case 'DiffuseColor':
  371. case ' "DiffuseColor':
  372. parameters.map = textureMap.get( relationship.ID );
  373. break;
  374. case 'Bump':
  375. case ' "Bump':
  376. parameters.bumpMap = textureMap.get( relationship.ID );
  377. break;
  378. case 'NormalMap':
  379. case ' "NormalMap':
  380. parameters.normalMap = textureMap.get( relationship.ID );
  381. break;
  382. case 'AmbientColor':
  383. case 'EmissiveColor':
  384. case ' "AmbientColor':
  385. case ' "EmissiveColor':
  386. default:
  387. console.warn( 'THREE.FBXLoader: Unknown texture application of type %s, skipping texture.', type );
  388. break;
  389. }
  390. }
  391. return parameters;
  392. }
  393. /**
  394. * Generates map of Skeleton-like objects for use later when generating and binding skeletons.
  395. * @param {{Objects: {subNodes: {Deformer: Object.<number, FBXSubDeformerNode>}}}} FBXTree
  396. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  397. * @returns {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>}
  398. */
  399. function parseDeformers( FBXTree, connections ) {
  400. var deformers = {};
  401. if ( 'Deformer' in FBXTree.Objects.subNodes ) {
  402. var DeformerNodes = FBXTree.Objects.subNodes.Deformer;
  403. for ( var nodeID in DeformerNodes ) {
  404. var deformerNode = DeformerNodes[ nodeID ];
  405. if ( deformerNode.attrType === 'Skin' ) {
  406. var conns = connections.get( parseInt( nodeID ) );
  407. var skeleton = parseSkeleton( conns, DeformerNodes );
  408. skeleton.FBX_ID = parseInt( nodeID );
  409. deformers[ nodeID ] = skeleton;
  410. }
  411. }
  412. }
  413. return deformers;
  414. }
  415. /**
  416. * Generates a "Skeleton Representation" of FBX nodes based on an FBX Skin Deformer's connections and an object containing SubDeformer nodes.
  417. * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} connections
  418. * @param {Object.<number, FBXSubDeformerNode>} DeformerNodes
  419. * @returns {{map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}}
  420. */
  421. function parseSkeleton( connections, DeformerNodes ) {
  422. var subDeformers = {};
  423. var children = connections.children;
  424. for ( var i = 0, l = children.length; i < l; ++ i ) {
  425. var child = children[ i ];
  426. var subDeformerNode = DeformerNodes[ child.ID ];
  427. var subDeformer = {
  428. FBX_ID: child.ID,
  429. index: i,
  430. indices: [],
  431. weights: [],
  432. transform: parseMatrixArray( subDeformerNode.subNodes.Transform.properties.a ),
  433. transformLink: parseMatrixArray( subDeformerNode.subNodes.TransformLink.properties.a ),
  434. linkMode: subDeformerNode.properties.Mode
  435. };
  436. if ( 'Indexes' in subDeformerNode.subNodes ) {
  437. subDeformer.indices = parseIntArray( subDeformerNode.subNodes.Indexes.properties.a );
  438. subDeformer.weights = parseFloatArray( subDeformerNode.subNodes.Weights.properties.a );
  439. }
  440. subDeformers[ child.ID ] = subDeformer;
  441. }
  442. return {
  443. map: subDeformers,
  444. bones: []
  445. };
  446. }
  447. /**
  448. * Generates Buffer geometries from geometry information in FBXTree, and generates map of THREE.BufferGeometries
  449. * @param {{Objects: {subNodes: {Geometry: Object.<number, FBXGeometryNode}}}} FBXTree
  450. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  451. * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>} deformers
  452. * @returns {Map<number, THREE.BufferGeometry>}
  453. */
  454. function parseGeometries( FBXTree, connections, deformers ) {
  455. var geometryMap = new Map();
  456. if ( 'Geometry' in FBXTree.Objects.subNodes ) {
  457. var geometryNodes = FBXTree.Objects.subNodes.Geometry;
  458. for ( var nodeID in geometryNodes ) {
  459. var relationships = connections.get( parseInt( nodeID ) );
  460. var geo = parseGeometry( geometryNodes[ nodeID ], relationships, deformers );
  461. geometryMap.set( parseInt( nodeID ), geo );
  462. }
  463. }
  464. return geometryMap;
  465. }
  466. /**
  467. * Generates BufferGeometry from FBXGeometryNode.
  468. * @param {FBXGeometryNode} geometryNode
  469. * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
  470. * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformers
  471. * @returns {THREE.BufferGeometry}
  472. */
  473. function parseGeometry( geometryNode, relationships, deformers ) {
  474. switch ( geometryNode.attrType ) {
  475. case 'Mesh':
  476. return parseMeshGeometry( geometryNode, relationships, deformers );
  477. break;
  478. case 'NurbsCurve':
  479. return parseNurbsGeometry( geometryNode );
  480. break;
  481. }
  482. }
  483. /**
  484. * Specialty function for parsing Mesh based Geometry Nodes.
  485. * @param {FBXGeometryNode} geometryNode
  486. * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships - Object representing relationships between specific geometry node and other nodes.
  487. * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformers - Map object of deformers and subDeformers by ID.
  488. * @returns {THREE.BufferGeometry}
  489. */
  490. function parseMeshGeometry( geometryNode, relationships, deformers ) {
  491. for ( var i = 0; i < relationships.children.length; ++ i ) {
  492. var deformer = deformers[ relationships.children[ i ].ID ];
  493. if ( deformer !== undefined ) break;
  494. }
  495. return genGeometry( geometryNode, deformer );
  496. }
  497. /**
  498. * @param {{map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}} deformer - Skeleton representation for geometry instance.
  499. * @returns {THREE.BufferGeometry}
  500. */
  501. function genGeometry( geometryNode, deformer ) {
  502. var geometry = new Geometry();
  503. var subNodes = geometryNode.subNodes;
  504. // First, each index is going to be its own vertex.
  505. var vertexBuffer = parseFloatArray( subNodes.Vertices.properties.a );
  506. var indexBuffer = parseIntArray( subNodes.PolygonVertexIndex.properties.a );
  507. if ( subNodes.LayerElementNormal ) {
  508. var normalInfo = getNormals( subNodes.LayerElementNormal[ 0 ] );
  509. }
  510. if ( subNodes.LayerElementUV ) {
  511. var uvInfo = getUVs( subNodes.LayerElementUV[ 0 ] );
  512. }
  513. if ( subNodes.LayerElementColor ) {
  514. var colorInfo = getColors( subNodes.LayerElementColor[ 0 ] );
  515. }
  516. if ( subNodes.LayerElementMaterial ) {
  517. var materialInfo = getMaterials( subNodes.LayerElementMaterial[ 0 ] );
  518. }
  519. var weightTable = {};
  520. if ( deformer ) {
  521. var subDeformers = deformer.map;
  522. for ( var key in subDeformers ) {
  523. var subDeformer = subDeformers[ key ];
  524. var indices = subDeformer.indices;
  525. for ( var j = 0; j < indices.length; j ++ ) {
  526. var index = indices[ j ];
  527. var weight = subDeformer.weights[ j ];
  528. if ( weightTable[ index ] === undefined ) weightTable[ index ] = [];
  529. weightTable[ index ].push( {
  530. id: subDeformer.index,
  531. weight: weight
  532. } );
  533. }
  534. }
  535. }
  536. var faceVertexBuffer = [];
  537. var polygonIndex = 0;
  538. var displayedWeightsWarning = false;
  539. for ( var polygonVertexIndex = 0; polygonVertexIndex < indexBuffer.length; polygonVertexIndex ++ ) {
  540. var vertexIndex = indexBuffer[ polygonVertexIndex ];
  541. var endOfFace = false;
  542. if ( vertexIndex < 0 ) {
  543. vertexIndex = vertexIndex ^ - 1;
  544. indexBuffer[ polygonVertexIndex ] = vertexIndex;
  545. endOfFace = true;
  546. }
  547. var vertex = new Vertex();
  548. var weightIndices = [];
  549. var weights = [];
  550. vertex.position.fromArray( vertexBuffer, vertexIndex * 3 );
  551. if ( deformer ) {
  552. if ( weightTable[ vertexIndex ] !== undefined ) {
  553. var array = weightTable[ vertexIndex ];
  554. for ( var j = 0, jl = array.length; j < jl; j ++ ) {
  555. weights.push( array[ j ].weight );
  556. weightIndices.push( array[ j ].id );
  557. }
  558. }
  559. if ( weights.length > 4 ) {
  560. if ( ! displayedWeightsWarning ) {
  561. console.warn( 'THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights.' );
  562. displayedWeightsWarning = true;
  563. }
  564. var WIndex = [ 0, 0, 0, 0 ];
  565. var Weight = [ 0, 0, 0, 0 ];
  566. weights.forEach( function ( weight, weightIndex ) {
  567. var currentWeight = weight;
  568. var currentIndex = weightIndices[ weightIndex ];
  569. Weight.forEach( function ( comparedWeight, comparedWeightIndex, comparedWeightArray ) {
  570. if ( currentWeight > comparedWeight ) {
  571. comparedWeightArray[ comparedWeightIndex ] = currentWeight;
  572. currentWeight = comparedWeight;
  573. var tmp = WIndex[ comparedWeightIndex ];
  574. WIndex[ comparedWeightIndex ] = currentIndex;
  575. currentIndex = tmp;
  576. }
  577. } );
  578. } );
  579. weightIndices = WIndex;
  580. weights = Weight;
  581. }
  582. for ( var i = weights.length; i < 4; ++ i ) {
  583. weights[ i ] = 0;
  584. weightIndices[ i ] = 0;
  585. }
  586. vertex.skinWeights.fromArray( weights );
  587. vertex.skinIndices.fromArray( weightIndices );
  588. }
  589. if ( normalInfo ) {
  590. vertex.normal.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, normalInfo ) );
  591. }
  592. if ( uvInfo ) {
  593. vertex.uv.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, uvInfo ) );
  594. }
  595. if ( colorInfo ) {
  596. vertex.color.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, colorInfo ) );
  597. }
  598. faceVertexBuffer.push( vertex );
  599. if ( endOfFace ) {
  600. var face = new Face();
  601. face.genTrianglesFromVertices( faceVertexBuffer );
  602. if ( materialInfo !== undefined ) {
  603. var materials = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo );
  604. face.materialIndex = materials[ 0 ];
  605. } else {
  606. // Seems like some models don't have materialInfo(subNodes.LayerElementMaterial).
  607. // Set 0 in such a case.
  608. face.materialIndex = 0;
  609. }
  610. geometry.faces.push( face );
  611. faceVertexBuffer = [];
  612. polygonIndex ++;
  613. endOfFace = false;
  614. }
  615. }
  616. /**
  617. * @type {{vertexBuffer: number[], normalBuffer: number[], uvBuffer: number[], skinIndexBuffer: number[], skinWeightBuffer: number[], materialIndexBuffer: number[]}}
  618. */
  619. var bufferInfo = geometry.flattenToBuffers();
  620. var geo = new THREE.BufferGeometry();
  621. geo.name = geometryNode.name;
  622. geo.addAttribute( 'position', new THREE.Float32BufferAttribute( bufferInfo.vertexBuffer, 3 ) );
  623. if ( bufferInfo.normalBuffer.length > 0 ) {
  624. geo.addAttribute( 'normal', new THREE.Float32BufferAttribute( bufferInfo.normalBuffer, 3 ) );
  625. }
  626. if ( bufferInfo.uvBuffer.length > 0 ) {
  627. geo.addAttribute( 'uv', new THREE.Float32BufferAttribute( bufferInfo.uvBuffer, 2 ) );
  628. }
  629. if ( subNodes.LayerElementColor ) {
  630. geo.addAttribute( 'color', new THREE.Float32BufferAttribute( bufferInfo.colorBuffer, 3 ) );
  631. }
  632. if ( deformer ) {
  633. geo.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( bufferInfo.skinIndexBuffer, 4 ) );
  634. geo.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( bufferInfo.skinWeightBuffer, 4 ) );
  635. geo.FBX_Deformer = deformer;
  636. }
  637. // Convert the material indices of each vertex into rendering groups on the geometry.
  638. var materialIndexBuffer = bufferInfo.materialIndexBuffer;
  639. var prevMaterialIndex = materialIndexBuffer[ 0 ];
  640. var startIndex = 0;
  641. for ( var i = 0; i < materialIndexBuffer.length; ++ i ) {
  642. if ( materialIndexBuffer[ i ] !== prevMaterialIndex ) {
  643. geo.addGroup( startIndex, i - startIndex, prevMaterialIndex );
  644. prevMaterialIndex = materialIndexBuffer[ i ];
  645. startIndex = i;
  646. }
  647. }
  648. return geo;
  649. }
  650. /**
  651. * Parses normal information for geometry.
  652. * @param {FBXGeometryNode} geometryNode
  653. * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
  654. */
  655. function getNormals( NormalNode ) {
  656. var mappingType = NormalNode.properties.MappingInformationType;
  657. var referenceType = NormalNode.properties.ReferenceInformationType;
  658. var buffer = parseFloatArray( NormalNode.subNodes.Normals.properties.a );
  659. var indexBuffer = [];
  660. if ( referenceType === 'IndexToDirect' ) {
  661. if ( 'NormalIndex' in NormalNode.subNodes ) {
  662. indexBuffer = parseIntArray( NormalNode.subNodes.NormalIndex.properties.a );
  663. } else if ( 'NormalsIndex' in NormalNode.subNodes ) {
  664. indexBuffer = parseIntArray( NormalNode.subNodes.NormalsIndex.properties.a );
  665. }
  666. }
  667. return {
  668. dataSize: 3,
  669. buffer: buffer,
  670. indices: indexBuffer,
  671. mappingType: mappingType,
  672. referenceType: referenceType
  673. };
  674. }
  675. /**
  676. * Parses UV information for geometry.
  677. * @param {FBXGeometryNode} geometryNode
  678. * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
  679. */
  680. function getUVs( UVNode ) {
  681. var mappingType = UVNode.properties.MappingInformationType;
  682. var referenceType = UVNode.properties.ReferenceInformationType;
  683. var buffer = parseFloatArray( UVNode.subNodes.UV.properties.a );
  684. var indexBuffer = [];
  685. if ( referenceType === 'IndexToDirect' ) {
  686. indexBuffer = parseIntArray( UVNode.subNodes.UVIndex.properties.a );
  687. }
  688. return {
  689. dataSize: 2,
  690. buffer: buffer,
  691. indices: indexBuffer,
  692. mappingType: mappingType,
  693. referenceType: referenceType
  694. };
  695. }
  696. /**
  697. * Parses Vertex Color information for geometry.
  698. * @param {FBXGeometryNode} geometryNode
  699. * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
  700. */
  701. function getColors( ColorNode ) {
  702. var mappingType = ColorNode.properties.MappingInformationType;
  703. var referenceType = ColorNode.properties.ReferenceInformationType;
  704. var buffer = parseFloatArray( ColorNode.subNodes.Colors.properties.a );
  705. var indexBuffer = [];
  706. if ( referenceType === 'IndexToDirect' ) {
  707. indexBuffer = parseFloatArray( ColorNode.subNodes.ColorIndex.properties.a );
  708. }
  709. return {
  710. dataSize: 4,
  711. buffer: buffer,
  712. indices: indexBuffer,
  713. mappingType: mappingType,
  714. referenceType: referenceType
  715. };
  716. }
  717. /**
  718. * Parses material application information for geometry.
  719. * @param {FBXGeometryNode}
  720. * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
  721. */
  722. function getMaterials( MaterialNode ) {
  723. var mappingType = MaterialNode.properties.MappingInformationType;
  724. var referenceType = MaterialNode.properties.ReferenceInformationType;
  725. if ( mappingType === 'NoMappingInformation' ) {
  726. return {
  727. dataSize: 1,
  728. buffer: [ 0 ],
  729. indices: [ 0 ],
  730. mappingType: 'AllSame',
  731. referenceType: referenceType
  732. };
  733. }
  734. var materialIndexBuffer = parseIntArray( MaterialNode.subNodes.Materials.properties.a );
  735. // Since materials are stored as indices, there's a bit of a mismatch between FBX and what
  736. // we expect. So we create an intermediate buffer that points to the index in the buffer,
  737. // for conforming with the other functions we've written for other data.
  738. var materialIndices = [];
  739. for ( var materialIndexBufferIndex = 0, materialIndexBufferLength = materialIndexBuffer.length; materialIndexBufferIndex < materialIndexBufferLength; ++ materialIndexBufferIndex ) {
  740. materialIndices.push( materialIndexBufferIndex );
  741. }
  742. return {
  743. dataSize: 1,
  744. buffer: materialIndexBuffer,
  745. indices: materialIndices,
  746. mappingType: mappingType,
  747. referenceType: referenceType
  748. };
  749. }
  750. /**
  751. * Function uses the infoObject and given indices to return value array of object.
  752. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  753. * @param {number} polygonIndex - Index of polygon in geometry.
  754. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  755. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  756. * @returns {number[]}
  757. */
  758. var dataArray = [];
  759. var GetData = {
  760. ByPolygonVertex: {
  761. /**
  762. * Function uses the infoObject and given indices to return value array of object.
  763. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  764. * @param {number} polygonIndex - Index of polygon in geometry.
  765. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  766. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  767. * @returns {number[]}
  768. */
  769. Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  770. var from = ( polygonVertexIndex * infoObject.dataSize );
  771. var to = ( polygonVertexIndex * infoObject.dataSize ) + infoObject.dataSize;
  772. // return infoObject.buffer.slice( from, to );
  773. return slice( dataArray, infoObject.buffer, from, to );
  774. },
  775. /**
  776. * Function uses the infoObject and given indices to return value array of object.
  777. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  778. * @param {number} polygonIndex - Index of polygon in geometry.
  779. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  780. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  781. * @returns {number[]}
  782. */
  783. IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  784. var index = infoObject.indices[ polygonVertexIndex ];
  785. var from = ( index * infoObject.dataSize );
  786. var to = ( index * infoObject.dataSize ) + infoObject.dataSize;
  787. // return infoObject.buffer.slice( from, to );
  788. return slice( dataArray, infoObject.buffer, from, to );
  789. }
  790. },
  791. ByPolygon: {
  792. /**
  793. * Function uses the infoObject and given indices to return value array of object.
  794. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  795. * @param {number} polygonIndex - Index of polygon in geometry.
  796. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  797. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  798. * @returns {number[]}
  799. */
  800. Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  801. var from = polygonIndex * infoObject.dataSize;
  802. var to = polygonIndex * infoObject.dataSize + infoObject.dataSize;
  803. // return infoObject.buffer.slice( from, to );
  804. return slice( dataArray, infoObject.buffer, from, to );
  805. },
  806. /**
  807. * Function uses the infoObject and given indices to return value array of object.
  808. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  809. * @param {number} polygonIndex - Index of polygon in geometry.
  810. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  811. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  812. * @returns {number[]}
  813. */
  814. IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  815. var index = infoObject.indices[ polygonIndex ];
  816. var from = index * infoObject.dataSize;
  817. var to = index * infoObject.dataSize + infoObject.dataSize;
  818. // return infoObject.buffer.slice( from, to );
  819. return slice( dataArray, infoObject.buffer, from, to );
  820. }
  821. },
  822. ByVertice: {
  823. Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  824. var from = ( vertexIndex * infoObject.dataSize );
  825. var to = ( vertexIndex * infoObject.dataSize ) + infoObject.dataSize;
  826. // return infoObject.buffer.slice( from, to );
  827. return slice( dataArray, infoObject.buffer, from, to );
  828. }
  829. },
  830. AllSame: {
  831. /**
  832. * Function uses the infoObject and given indices to return value array of object.
  833. * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
  834. * @param {number} polygonIndex - Index of polygon in geometry.
  835. * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
  836. * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
  837. * @returns {number[]}
  838. */
  839. IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  840. var from = infoObject.indices[ 0 ] * infoObject.dataSize;
  841. var to = infoObject.indices[ 0 ] * infoObject.dataSize + infoObject.dataSize;
  842. // return infoObject.buffer.slice( from, to );
  843. return slice( dataArray, infoObject.buffer, from, to );
  844. }
  845. }
  846. };
  847. function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
  848. return GetData[ infoObject.mappingType ][ infoObject.referenceType ]( polygonVertexIndex, polygonIndex, vertexIndex, infoObject );
  849. }
  850. /**
  851. * Specialty function for parsing NurbsCurve based Geometry Nodes.
  852. * @param {FBXGeometryNode} geometryNode
  853. * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
  854. * @returns {THREE.BufferGeometry}
  855. */
  856. function parseNurbsGeometry( geometryNode ) {
  857. if ( THREE.NURBSCurve === undefined ) {
  858. console.error( 'THREE.FBXLoader: The loader relies on THREE.NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry.' );
  859. return new THREE.BufferGeometry();
  860. }
  861. var order = parseInt( geometryNode.properties.Order );
  862. if ( isNaN( order ) ) {
  863. console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geometryNode.properties.Order, geometryNode.id );
  864. return new THREE.BufferGeometry();
  865. }
  866. var degree = order - 1;
  867. var knots = parseFloatArray( geometryNode.subNodes.KnotVector.properties.a );
  868. var controlPoints = [];
  869. var pointsValues = parseFloatArray( geometryNode.subNodes.Points.properties.a );
  870. for ( var i = 0, l = pointsValues.length; i < l; i += 4 ) {
  871. controlPoints.push( new THREE.Vector4().fromArray( pointsValues, i ) );
  872. }
  873. var startKnot, endKnot;
  874. if ( geometryNode.properties.Form === 'Closed' ) {
  875. controlPoints.push( controlPoints[ 0 ] );
  876. } else if ( geometryNode.properties.Form === 'Periodic' ) {
  877. startKnot = degree;
  878. endKnot = knots.length - 1 - startKnot;
  879. for ( var i = 0; i < degree; ++ i ) {
  880. controlPoints.push( controlPoints[ i ] );
  881. }
  882. }
  883. var curve = new THREE.NURBSCurve( degree, knots, controlPoints, startKnot, endKnot );
  884. var vertices = curve.getPoints( controlPoints.length * 7 );
  885. var positions = new Float32Array( vertices.length * 3 );
  886. for ( var i = 0, l = vertices.length; i < l; ++ i ) {
  887. vertices[ i ].toArray( positions, i * 3 );
  888. }
  889. var geometry = new THREE.BufferGeometry();
  890. geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
  891. return geometry;
  892. }
  893. /**
  894. * Finally generates Scene graph and Scene graph Objects.
  895. * @param {{Objects: {subNodes: {Model: Object.<number, FBXModelNode>}}}} FBXTree
  896. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  897. * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>} deformers
  898. * @param {Map<number, THREE.BufferGeometry>} geometryMap
  899. * @param {Map<number, THREE.Material>} materialMap
  900. * @returns {THREE.Group}
  901. */
  902. function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {
  903. var sceneGraph = new THREE.Group();
  904. var ModelNode = FBXTree.Objects.subNodes.Model;
  905. /**
  906. * @type {Array.<THREE.Object3D>}
  907. */
  908. var modelArray = [];
  909. /**
  910. * @type {Map.<number, THREE.Object3D>}
  911. */
  912. var modelMap = new Map();
  913. for ( var nodeID in ModelNode ) {
  914. var id = parseInt( nodeID );
  915. var node = ModelNode[ nodeID ];
  916. var conns = connections.get( id );
  917. var model = null;
  918. for ( var i = 0; i < conns.parents.length; ++ i ) {
  919. for ( var FBX_ID in deformers ) {
  920. var deformer = deformers[ FBX_ID ];
  921. var subDeformers = deformer.map;
  922. var subDeformer = subDeformers[ conns.parents[ i ].ID ];
  923. if ( subDeformer ) {
  924. var model2 = model;
  925. model = new THREE.Bone();
  926. deformer.bones[ subDeformer.index ] = model;
  927. // seems like we need this not to make non-connected bone, maybe?
  928. // TODO: confirm
  929. if ( model2 !== null ) model.add( model2 );
  930. }
  931. }
  932. }
  933. if ( ! model ) {
  934. switch ( node.attrType ) {
  935. case 'Mesh':
  936. /**
  937. * @type {?THREE.BufferGeometry}
  938. */
  939. var geometry = null;
  940. /**
  941. * @type {THREE.MultiMaterial|THREE.Material}
  942. */
  943. var material = null;
  944. /**
  945. * @type {Array.<THREE.Material>}
  946. */
  947. var materials = [];
  948. for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
  949. var child = conns.children[ childrenIndex ];
  950. if ( geometryMap.has( child.ID ) ) {
  951. geometry = geometryMap.get( child.ID );
  952. }
  953. if ( materialMap.has( child.ID ) ) {
  954. materials.push( materialMap.get( child.ID ) );
  955. }
  956. }
  957. if ( materials.length > 1 ) {
  958. material = materials;
  959. } else if ( materials.length > 0 ) {
  960. material = materials[ 0 ];
  961. } else {
  962. material = new THREE.MeshStandardMaterial( { color: 0x3300ff } );
  963. materials.push( material );
  964. }
  965. if ( 'color' in geometry.attributes ) {
  966. for ( var materialIndex = 0, numMaterials = materials.length; materialIndex < numMaterials; ++materialIndex ) {
  967. materials[ materialIndex ].vertexColors = THREE.VertexColors;
  968. }
  969. }
  970. if ( geometry.FBX_Deformer ) {
  971. for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) {
  972. materials[ materialsIndex ].skinning = true;
  973. }
  974. model = new THREE.SkinnedMesh( geometry, material );
  975. } else {
  976. model = new THREE.Mesh( geometry, material );
  977. }
  978. break;
  979. case 'NurbsCurve':
  980. var geometry = null;
  981. for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
  982. var child = conns.children[ childrenIndex ];
  983. if ( geometryMap.has( child.ID ) ) {
  984. geometry = geometryMap.get( child.ID );
  985. }
  986. }
  987. // FBX does not list materials for Nurbs lines, so we'll just put our own in here.
  988. material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 5 } );
  989. model = new THREE.Line( geometry, material );
  990. break;
  991. default:
  992. model = new THREE.Object3D();
  993. break;
  994. }
  995. }
  996. model.name = node.attrName.replace( /:/, '' ).replace( /_/, '' ).replace( /-/, '' );
  997. model.FBX_ID = id;
  998. modelArray.push( model );
  999. modelMap.set( id, model );
  1000. }
  1001. for ( var modelArrayIndex = 0, modelArrayLength = modelArray.length; modelArrayIndex < modelArrayLength; ++ modelArrayIndex ) {
  1002. var model = modelArray[ modelArrayIndex ];
  1003. var node = ModelNode[ model.FBX_ID ];
  1004. if ( 'Lcl_Translation' in node.properties ) {
  1005. model.position.fromArray( parseFloatArray( node.properties.Lcl_Translation.value ) );
  1006. }
  1007. if ( 'Lcl_Rotation' in node.properties ) {
  1008. var rotation = parseFloatArray( node.properties.Lcl_Rotation.value ).map( degreeToRadian );
  1009. rotation.push( 'ZYX' );
  1010. model.rotation.fromArray( rotation );
  1011. }
  1012. if ( 'Lcl_Scaling' in node.properties ) {
  1013. model.scale.fromArray( parseFloatArray( node.properties.Lcl_Scaling.value ) );
  1014. }
  1015. if ( 'PreRotation' in node.properties ) {
  1016. var preRotations = new THREE.Euler().setFromVector3( parseVector3( node.properties.PreRotation ).multiplyScalar( DEG2RAD ), 'ZYX' );
  1017. preRotations = new THREE.Quaternion().setFromEuler( preRotations );
  1018. var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation );
  1019. preRotations.multiply( currentRotation );
  1020. model.rotation.setFromQuaternion( preRotations, 'ZYX' );
  1021. }
  1022. var conns = connections.get( model.FBX_ID );
  1023. for ( var parentIndex = 0; parentIndex < conns.parents.length; parentIndex ++ ) {
  1024. var pIndex = findIndex( modelArray, function ( mod ) {
  1025. return mod.FBX_ID === conns.parents[ parentIndex ].ID;
  1026. } );
  1027. if ( pIndex > - 1 ) {
  1028. modelArray[ pIndex ].add( model );
  1029. break;
  1030. }
  1031. }
  1032. if ( model.parent === null ) {
  1033. sceneGraph.add( model );
  1034. }
  1035. }
  1036. // Now with the bones created, we can update the skeletons and bind them to the skinned meshes.
  1037. sceneGraph.updateMatrixWorld( true );
  1038. // Put skeleton into bind pose.
  1039. var BindPoseNode = FBXTree.Objects.subNodes.Pose;
  1040. for ( var nodeID in BindPoseNode ) {
  1041. if ( BindPoseNode[ nodeID ].attrType === 'BindPose' ) {
  1042. BindPoseNode = BindPoseNode[ nodeID ];
  1043. break;
  1044. }
  1045. }
  1046. if ( BindPoseNode ) {
  1047. var PoseNode = BindPoseNode.subNodes.PoseNode;
  1048. var worldMatrices = new Map();
  1049. for ( var PoseNodeIndex = 0, PoseNodeLength = PoseNode.length; PoseNodeIndex < PoseNodeLength; ++ PoseNodeIndex ) {
  1050. var node = PoseNode[ PoseNodeIndex ];
  1051. var rawMatWrd = parseMatrixArray( node.subNodes.Matrix.properties.a );
  1052. worldMatrices.set( parseInt( node.id ), rawMatWrd );
  1053. }
  1054. }
  1055. for ( var FBX_ID in deformers ) {
  1056. var deformer = deformers[ FBX_ID ];
  1057. var subDeformers = deformer.map;
  1058. for ( var key in subDeformers ) {
  1059. var subDeformer = subDeformers[ key ];
  1060. var subDeformerIndex = subDeformer.index;
  1061. /**
  1062. * @type {THREE.Bone}
  1063. */
  1064. var bone = deformer.bones[ subDeformerIndex ];
  1065. if ( ! worldMatrices.has( bone.FBX_ID ) ) {
  1066. break;
  1067. }
  1068. var mat = worldMatrices.get( bone.FBX_ID );
  1069. bone.matrixWorld.copy( mat );
  1070. }
  1071. // Now that skeleton is in bind pose, bind to model.
  1072. deformer.skeleton = new THREE.Skeleton( deformer.bones );
  1073. var conns = connections.get( deformer.FBX_ID );
  1074. var parents = conns.parents;
  1075. for ( var parentsIndex = 0, parentsLength = parents.length; parentsIndex < parentsLength; ++ parentsIndex ) {
  1076. var parent = parents[ parentsIndex ];
  1077. if ( geometryMap.has( parent.ID ) ) {
  1078. var geoID = parent.ID;
  1079. var geoConns = connections.get( geoID );
  1080. for ( var i = 0; i < geoConns.parents.length; ++ i ) {
  1081. if ( modelMap.has( geoConns.parents[ i ].ID ) ) {
  1082. var model = modelMap.get( geoConns.parents[ i ].ID );
  1083. //ASSERT model typeof SkinnedMesh
  1084. model.bind( deformer.skeleton, model.matrixWorld );
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. }
  1091. //Skeleton is now bound, return objects to starting
  1092. //world positions.
  1093. sceneGraph.updateMatrixWorld( true );
  1094. // Silly hack with the animation parsing. We're gonna pretend the scene graph has a skeleton
  1095. // to attach animations to, since FBXs treat animations as animations for the entire scene,
  1096. // not just for individual objects.
  1097. sceneGraph.skeleton = {
  1098. bones: modelArray
  1099. };
  1100. var animations = parseAnimations( FBXTree, connections, sceneGraph );
  1101. addAnimations( sceneGraph, animations );
  1102. return sceneGraph;
  1103. }
  1104. /**
  1105. * Parses animation information from FBXTree and generates an AnimationInfoObject.
  1106. * @param {{Objects: {subNodes: {AnimationCurveNode: any, AnimationCurve: any, AnimationLayer: any, AnimationStack: any}}}} FBXTree
  1107. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  1108. */
  1109. function parseAnimations( FBXTree, connections, sceneGraph ) {
  1110. var rawNodes = FBXTree.Objects.subNodes.AnimationCurveNode;
  1111. var rawCurves = FBXTree.Objects.subNodes.AnimationCurve;
  1112. var rawLayers = FBXTree.Objects.subNodes.AnimationLayer;
  1113. var rawStacks = FBXTree.Objects.subNodes.AnimationStack;
  1114. /**
  1115. * @type {{
  1116. curves: Map<number, {
  1117. T: {
  1118. id: number;
  1119. attr: string;
  1120. internalID: number;
  1121. attrX: boolean;
  1122. attrY: boolean;
  1123. attrZ: boolean;
  1124. containerBoneID: number;
  1125. containerID: number;
  1126. curves: {
  1127. x: {
  1128. version: any;
  1129. id: number;
  1130. internalID: number;
  1131. times: number[];
  1132. values: number[];
  1133. attrFlag: number[];
  1134. attrData: number[];
  1135. };
  1136. y: {
  1137. version: any;
  1138. id: number;
  1139. internalID: number;
  1140. times: number[];
  1141. values: number[];
  1142. attrFlag: number[];
  1143. attrData: number[];
  1144. };
  1145. z: {
  1146. version: any;
  1147. id: number;
  1148. internalID: number;
  1149. times: number[];
  1150. values: number[];
  1151. attrFlag: number[];
  1152. attrData: number[];
  1153. };
  1154. };
  1155. },
  1156. R: {
  1157. id: number;
  1158. attr: string;
  1159. internalID: number;
  1160. attrX: boolean;
  1161. attrY: boolean;
  1162. attrZ: boolean;
  1163. containerBoneID: number;
  1164. containerID: number;
  1165. curves: {
  1166. x: {
  1167. version: any;
  1168. id: number;
  1169. internalID: number;
  1170. times: number[];
  1171. values: number[];
  1172. attrFlag: number[];
  1173. attrData: number[];
  1174. };
  1175. y: {
  1176. version: any;
  1177. id: number;
  1178. internalID: number;
  1179. times: number[];
  1180. values: number[];
  1181. attrFlag: number[];
  1182. attrData: number[];
  1183. };
  1184. z: {
  1185. version: any;
  1186. id: number;
  1187. internalID: number;
  1188. times: number[];
  1189. values: number[];
  1190. attrFlag: number[];
  1191. attrData: number[];
  1192. };
  1193. };
  1194. },
  1195. S: {
  1196. id: number;
  1197. attr: string;
  1198. internalID: number;
  1199. attrX: boolean;
  1200. attrY: boolean;
  1201. attrZ: boolean;
  1202. containerBoneID: number;
  1203. containerID: number;
  1204. curves: {
  1205. x: {
  1206. version: any;
  1207. id: number;
  1208. internalID: number;
  1209. times: number[];
  1210. values: number[];
  1211. attrFlag: number[];
  1212. attrData: number[];
  1213. };
  1214. y: {
  1215. version: any;
  1216. id: number;
  1217. internalID: number;
  1218. times: number[];
  1219. values: number[];
  1220. attrFlag: number[];
  1221. attrData: number[];
  1222. };
  1223. z: {
  1224. version: any;
  1225. id: number;
  1226. internalID: number;
  1227. times: number[];
  1228. values: number[];
  1229. attrFlag: number[];
  1230. attrData: number[];
  1231. };
  1232. };
  1233. }
  1234. }>,
  1235. layers: Map<number, {
  1236. T: {
  1237. id: number;
  1238. attr: string;
  1239. internalID: number;
  1240. attrX: boolean;
  1241. attrY: boolean;
  1242. attrZ: boolean;
  1243. containerBoneID: number;
  1244. containerID: number;
  1245. curves: {
  1246. x: {
  1247. version: any;
  1248. id: number;
  1249. internalID: number;
  1250. times: number[];
  1251. values: number[];
  1252. attrFlag: number[];
  1253. attrData: number[];
  1254. };
  1255. y: {
  1256. version: any;
  1257. id: number;
  1258. internalID: number;
  1259. times: number[];
  1260. values: number[];
  1261. attrFlag: number[];
  1262. attrData: number[];
  1263. };
  1264. z: {
  1265. version: any;
  1266. id: number;
  1267. internalID: number;
  1268. times: number[];
  1269. values: number[];
  1270. attrFlag: number[];
  1271. attrData: number[];
  1272. };
  1273. },
  1274. },
  1275. R: {
  1276. id: number;
  1277. attr: string;
  1278. internalID: number;
  1279. attrX: boolean;
  1280. attrY: boolean;
  1281. attrZ: boolean;
  1282. containerBoneID: number;
  1283. containerID: number;
  1284. curves: {
  1285. x: {
  1286. version: any;
  1287. id: number;
  1288. internalID: number;
  1289. times: number[];
  1290. values: number[];
  1291. attrFlag: number[];
  1292. attrData: number[];
  1293. };
  1294. y: {
  1295. version: any;
  1296. id: number;
  1297. internalID: number;
  1298. times: number[];
  1299. values: number[];
  1300. attrFlag: number[];
  1301. attrData: number[];
  1302. };
  1303. z: {
  1304. version: any;
  1305. id: number;
  1306. internalID: number;
  1307. times: number[];
  1308. values: number[];
  1309. attrFlag: number[];
  1310. attrData: number[];
  1311. };
  1312. },
  1313. },
  1314. S: {
  1315. id: number;
  1316. attr: string;
  1317. internalID: number;
  1318. attrX: boolean;
  1319. attrY: boolean;
  1320. attrZ: boolean;
  1321. containerBoneID: number;
  1322. containerID: number;
  1323. curves: {
  1324. x: {
  1325. version: any;
  1326. id: number;
  1327. internalID: number;
  1328. times: number[];
  1329. values: number[];
  1330. attrFlag: number[];
  1331. attrData: number[];
  1332. };
  1333. y: {
  1334. version: any;
  1335. id: number;
  1336. internalID: number;
  1337. times: number[];
  1338. values: number[];
  1339. attrFlag: number[];
  1340. attrData: number[];
  1341. };
  1342. z: {
  1343. version: any;
  1344. id: number;
  1345. internalID: number;
  1346. times: number[];
  1347. values: number[];
  1348. attrFlag: number[];
  1349. attrData: number[];
  1350. };
  1351. },
  1352. }
  1353. }[]>,
  1354. stacks: Map<number, {
  1355. name: string,
  1356. layers: {
  1357. T: {
  1358. id: number;
  1359. attr: string;
  1360. internalID: number;
  1361. attrX: boolean;
  1362. attrY: boolean;
  1363. attrZ: boolean;
  1364. containerBoneID: number;
  1365. containerID: number;
  1366. curves: {
  1367. x: {
  1368. version: any;
  1369. id: number;
  1370. internalID: number;
  1371. times: number[];
  1372. values: number[];
  1373. attrFlag: number[];
  1374. attrData: number[];
  1375. };
  1376. y: {
  1377. version: any;
  1378. id: number;
  1379. internalID: number;
  1380. times: number[];
  1381. values: number[];
  1382. attrFlag: number[];
  1383. attrData: number[];
  1384. };
  1385. z: {
  1386. version: any;
  1387. id: number;
  1388. internalID: number;
  1389. times: number[];
  1390. values: number[];
  1391. attrFlag: number[];
  1392. attrData: number[];
  1393. };
  1394. };
  1395. };
  1396. R: {
  1397. id: number;
  1398. attr: string;
  1399. internalID: number;
  1400. attrX: boolean;
  1401. attrY: boolean;
  1402. attrZ: boolean;
  1403. containerBoneID: number;
  1404. containerID: number;
  1405. curves: {
  1406. x: {
  1407. version: any;
  1408. id: number;
  1409. internalID: number;
  1410. times: number[];
  1411. values: number[];
  1412. attrFlag: number[];
  1413. attrData: number[];
  1414. };
  1415. y: {
  1416. version: any;
  1417. id: number;
  1418. internalID: number;
  1419. times: number[];
  1420. values: number[];
  1421. attrFlag: number[];
  1422. attrData: number[];
  1423. };
  1424. z: {
  1425. version: any;
  1426. id: number;
  1427. internalID: number;
  1428. times: number[];
  1429. values: number[];
  1430. attrFlag: number[];
  1431. attrData: number[];
  1432. };
  1433. };
  1434. };
  1435. S: {
  1436. id: number;
  1437. attr: string;
  1438. internalID: number;
  1439. attrX: boolean;
  1440. attrY: boolean;
  1441. attrZ: boolean;
  1442. containerBoneID: number;
  1443. containerID: number;
  1444. curves: {
  1445. x: {
  1446. version: any;
  1447. id: number;
  1448. internalID: number;
  1449. times: number[];
  1450. values: number[];
  1451. attrFlag: number[];
  1452. attrData: number[];
  1453. };
  1454. y: {
  1455. version: any;
  1456. id: number;
  1457. internalID: number;
  1458. times: number[];
  1459. values: number[];
  1460. attrFlag: number[];
  1461. attrData: number[];
  1462. };
  1463. z: {
  1464. version: any;
  1465. id: number;
  1466. internalID: number;
  1467. times: number[];
  1468. values: number[];
  1469. attrFlag: number[];
  1470. attrData: number[];
  1471. };
  1472. };
  1473. };
  1474. }[][],
  1475. length: number,
  1476. frames: number }>,
  1477. length: number,
  1478. fps: number,
  1479. frames: number
  1480. }}
  1481. */
  1482. var returnObject = {
  1483. curves: new Map(),
  1484. layers: {},
  1485. stacks: {},
  1486. length: 0,
  1487. fps: 30,
  1488. frames: 0
  1489. };
  1490. /**
  1491. * @type {Array.<{
  1492. id: number;
  1493. attr: string;
  1494. internalID: number;
  1495. attrX: boolean;
  1496. attrY: boolean;
  1497. attrZ: boolean;
  1498. containerBoneID: number;
  1499. containerID: number;
  1500. }>}
  1501. */
  1502. var animationCurveNodes = [];
  1503. for ( var nodeID in rawNodes ) {
  1504. if ( nodeID.match( /\d+/ ) ) {
  1505. var animationNode = parseAnimationNode( FBXTree, rawNodes[ nodeID ], connections, sceneGraph );
  1506. animationCurveNodes.push( animationNode );
  1507. }
  1508. }
  1509. /**
  1510. * @type {Map.<number, {
  1511. id: number,
  1512. attr: string,
  1513. internalID: number,
  1514. attrX: boolean,
  1515. attrY: boolean,
  1516. attrZ: boolean,
  1517. containerBoneID: number,
  1518. containerID: number,
  1519. curves: {
  1520. x: {
  1521. version: any,
  1522. id: number,
  1523. internalID: number,
  1524. times: number[],
  1525. values: number[],
  1526. attrFlag: number[],
  1527. attrData: number[],
  1528. },
  1529. y: {
  1530. version: any,
  1531. id: number,
  1532. internalID: number,
  1533. times: number[],
  1534. values: number[],
  1535. attrFlag: number[],
  1536. attrData: number[],
  1537. },
  1538. z: {
  1539. version: any,
  1540. id: number,
  1541. internalID: number,
  1542. times: number[],
  1543. values: number[],
  1544. attrFlag: number[],
  1545. attrData: number[],
  1546. }
  1547. }
  1548. }>}
  1549. */
  1550. var tmpMap = new Map();
  1551. for ( var animationCurveNodeIndex = 0; animationCurveNodeIndex < animationCurveNodes.length; ++ animationCurveNodeIndex ) {
  1552. if ( animationCurveNodes[ animationCurveNodeIndex ] === null ) {
  1553. continue;
  1554. }
  1555. tmpMap.set( animationCurveNodes[ animationCurveNodeIndex ].id, animationCurveNodes[ animationCurveNodeIndex ] );
  1556. }
  1557. /**
  1558. * @type {{
  1559. version: any,
  1560. id: number,
  1561. internalID: number,
  1562. times: number[],
  1563. values: number[],
  1564. attrFlag: number[],
  1565. attrData: number[],
  1566. }[]}
  1567. */
  1568. var animationCurves = [];
  1569. for ( nodeID in rawCurves ) {
  1570. if ( nodeID.match( /\d+/ ) ) {
  1571. var animationCurve = parseAnimationCurve( rawCurves[ nodeID ] );
  1572. // seems like this check would be necessary?
  1573. if ( ! connections.has( animationCurve.id ) ) continue;
  1574. animationCurves.push( animationCurve );
  1575. var firstParentConn = connections.get( animationCurve.id ).parents[ 0 ];
  1576. var firstParentID = firstParentConn.ID;
  1577. var firstParentRelationship = firstParentConn.relationship;
  1578. var axis = '';
  1579. if ( firstParentRelationship.match( /X/ ) ) {
  1580. axis = 'x';
  1581. } else if ( firstParentRelationship.match( /Y/ ) ) {
  1582. axis = 'y';
  1583. } else if ( firstParentRelationship.match( /Z/ ) ) {
  1584. axis = 'z';
  1585. } else {
  1586. continue;
  1587. }
  1588. tmpMap.get( firstParentID ).curves[ axis ] = animationCurve;
  1589. }
  1590. }
  1591. tmpMap.forEach( function ( curveNode ) {
  1592. var id = curveNode.containerBoneID;
  1593. if ( ! returnObject.curves.has( id ) ) {
  1594. returnObject.curves.set( id, { T: null, R: null, S: null } );
  1595. }
  1596. returnObject.curves.get( id )[ curveNode.attr ] = curveNode;
  1597. if ( curveNode.attr === 'R' ) {
  1598. var curves = curveNode.curves;
  1599. // Seems like some FBX files have AnimationCurveNode
  1600. // which doesn't have any connected AnimationCurve.
  1601. // Setting animation parameter for them here.
  1602. if ( curves.x === null ) {
  1603. curves.x = {
  1604. version: null,
  1605. times: [ 0.0 ],
  1606. values: [ 0.0 ]
  1607. };
  1608. }
  1609. if ( curves.y === null ) {
  1610. curves.y = {
  1611. version: null,
  1612. times: [ 0.0 ],
  1613. values: [ 0.0 ]
  1614. };
  1615. }
  1616. if ( curves.z === null ) {
  1617. curves.z = {
  1618. version: null,
  1619. times: [ 0.0 ],
  1620. values: [ 0.0 ]
  1621. };
  1622. }
  1623. curves.x.values = curves.x.values.map( degreeToRadian );
  1624. curves.y.values = curves.y.values.map( degreeToRadian );
  1625. curves.z.values = curves.z.values.map( degreeToRadian );
  1626. if ( curveNode.preRotations !== null ) {
  1627. var preRotations = new THREE.Euler().setFromVector3( curveNode.preRotations, 'ZYX' );
  1628. preRotations = new THREE.Quaternion().setFromEuler( preRotations );
  1629. var frameRotation = new THREE.Euler();
  1630. var frameRotationQuaternion = new THREE.Quaternion();
  1631. for ( var frame = 0; frame < curves.x.times.length; ++ frame ) {
  1632. frameRotation.set( curves.x.values[ frame ], curves.y.values[ frame ], curves.z.values[ frame ], 'ZYX' );
  1633. frameRotationQuaternion.setFromEuler( frameRotation ).premultiply( preRotations );
  1634. frameRotation.setFromQuaternion( frameRotationQuaternion, 'ZYX' );
  1635. curves.x.values[ frame ] = frameRotation.x;
  1636. curves.y.values[ frame ] = frameRotation.y;
  1637. curves.z.values[ frame ] = frameRotation.z;
  1638. }
  1639. }
  1640. }
  1641. } );
  1642. for ( var nodeID in rawLayers ) {
  1643. /**
  1644. * @type {{
  1645. T: {
  1646. id: number;
  1647. attr: string;
  1648. internalID: number;
  1649. attrX: boolean;
  1650. attrY: boolean;
  1651. attrZ: boolean;
  1652. containerBoneID: number;
  1653. containerID: number;
  1654. curves: {
  1655. x: {
  1656. version: any;
  1657. id: number;
  1658. internalID: number;
  1659. times: number[];
  1660. values: number[];
  1661. attrFlag: number[];
  1662. attrData: number[];
  1663. };
  1664. y: {
  1665. version: any;
  1666. id: number;
  1667. internalID: number;
  1668. times: number[];
  1669. values: number[];
  1670. attrFlag: number[];
  1671. attrData: number[];
  1672. };
  1673. z: {
  1674. version: any;
  1675. id: number;
  1676. internalID: number;
  1677. times: number[];
  1678. values: number[];
  1679. attrFlag: number[];
  1680. attrData: number[];
  1681. };
  1682. },
  1683. },
  1684. R: {
  1685. id: number;
  1686. attr: string;
  1687. internalID: number;
  1688. attrX: boolean;
  1689. attrY: boolean;
  1690. attrZ: boolean;
  1691. containerBoneID: number;
  1692. containerID: number;
  1693. curves: {
  1694. x: {
  1695. version: any;
  1696. id: number;
  1697. internalID: number;
  1698. times: number[];
  1699. values: number[];
  1700. attrFlag: number[];
  1701. attrData: number[];
  1702. };
  1703. y: {
  1704. version: any;
  1705. id: number;
  1706. internalID: number;
  1707. times: number[];
  1708. values: number[];
  1709. attrFlag: number[];
  1710. attrData: number[];
  1711. };
  1712. z: {
  1713. version: any;
  1714. id: number;
  1715. internalID: number;
  1716. times: number[];
  1717. values: number[];
  1718. attrFlag: number[];
  1719. attrData: number[];
  1720. };
  1721. },
  1722. },
  1723. S: {
  1724. id: number;
  1725. attr: string;
  1726. internalID: number;
  1727. attrX: boolean;
  1728. attrY: boolean;
  1729. attrZ: boolean;
  1730. containerBoneID: number;
  1731. containerID: number;
  1732. curves: {
  1733. x: {
  1734. version: any;
  1735. id: number;
  1736. internalID: number;
  1737. times: number[];
  1738. values: number[];
  1739. attrFlag: number[];
  1740. attrData: number[];
  1741. };
  1742. y: {
  1743. version: any;
  1744. id: number;
  1745. internalID: number;
  1746. times: number[];
  1747. values: number[];
  1748. attrFlag: number[];
  1749. attrData: number[];
  1750. };
  1751. z: {
  1752. version: any;
  1753. id: number;
  1754. internalID: number;
  1755. times: number[];
  1756. values: number[];
  1757. attrFlag: number[];
  1758. attrData: number[];
  1759. };
  1760. },
  1761. }
  1762. }[]}
  1763. */
  1764. var layer = [];
  1765. var children = connections.get( parseInt( nodeID ) ).children;
  1766. for ( var childIndex = 0; childIndex < children.length; childIndex ++ ) {
  1767. // Skip lockInfluenceWeights
  1768. if ( tmpMap.has( children[ childIndex ].ID ) ) {
  1769. var curveNode = tmpMap.get( children[ childIndex ].ID );
  1770. var boneID = curveNode.containerBoneID;
  1771. if ( layer[ boneID ] === undefined ) {
  1772. layer[ boneID ] = {
  1773. T: null,
  1774. R: null,
  1775. S: null
  1776. };
  1777. }
  1778. layer[ boneID ][ curveNode.attr ] = curveNode;
  1779. }
  1780. }
  1781. returnObject.layers[ nodeID ] = layer;
  1782. }
  1783. for ( var nodeID in rawStacks ) {
  1784. var layers = [];
  1785. var children = connections.get( parseInt( nodeID ) ).children;
  1786. var timestamps = { max: 0, min: Number.MAX_VALUE };
  1787. for ( var childIndex = 0; childIndex < children.length; ++ childIndex ) {
  1788. var currentLayer = returnObject.layers[ children[ childIndex ].ID ];
  1789. if ( currentLayer !== undefined ) {
  1790. layers.push( currentLayer );
  1791. for ( var currentLayerIndex = 0, currentLayerLength = currentLayer.length; currentLayerIndex < currentLayerLength; ++ currentLayerIndex ) {
  1792. var layer = currentLayer[ currentLayerIndex ];
  1793. if ( layer ) {
  1794. getCurveNodeMaxMinTimeStamps( layer, timestamps );
  1795. }
  1796. }
  1797. }
  1798. }
  1799. // Do we have an animation clip with actual length?
  1800. if ( timestamps.max > timestamps.min ) {
  1801. returnObject.stacks[ nodeID ] = {
  1802. name: rawStacks[ nodeID ].attrName,
  1803. layers: layers,
  1804. length: timestamps.max - timestamps.min,
  1805. frames: ( timestamps.max - timestamps.min ) * 30
  1806. };
  1807. }
  1808. }
  1809. return returnObject;
  1810. }
  1811. /**
  1812. * @param {Object} FBXTree
  1813. * @param {{id: number, attrName: string, properties: Object<string, any>}} animationCurveNode
  1814. * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
  1815. * @param {{skeleton: {bones: {FBX_ID: number}[]}}} sceneGraph
  1816. */
  1817. function parseAnimationNode( FBXTree, animationCurveNode, connections, sceneGraph ) {
  1818. var rawModels = FBXTree.Objects.subNodes.Model;
  1819. var returnObject = {
  1820. /**
  1821. * @type {number}
  1822. */
  1823. id: animationCurveNode.id,
  1824. /**
  1825. * @type {string}
  1826. */
  1827. attr: animationCurveNode.attrName,
  1828. /**
  1829. * @type {number}
  1830. */
  1831. internalID: animationCurveNode.id,
  1832. /**
  1833. * @type {boolean}
  1834. */
  1835. attrX: false,
  1836. /**
  1837. * @type {boolean}
  1838. */
  1839. attrY: false,
  1840. /**
  1841. * @type {boolean}
  1842. */
  1843. attrZ: false,
  1844. /**
  1845. * @type {number}
  1846. */
  1847. containerBoneID: - 1,
  1848. /**
  1849. * @type {number}
  1850. */
  1851. containerID: - 1,
  1852. curves: {
  1853. x: null,
  1854. y: null,
  1855. z: null
  1856. },
  1857. /**
  1858. * @type {number[]}
  1859. */
  1860. preRotations: null
  1861. };
  1862. if ( returnObject.attr.match( /S|R|T/ ) ) {
  1863. for ( var attributeKey in animationCurveNode.properties ) {
  1864. if ( attributeKey.match( /X/ ) ) {
  1865. returnObject.attrX = true;
  1866. }
  1867. if ( attributeKey.match( /Y/ ) ) {
  1868. returnObject.attrY = true;
  1869. }
  1870. if ( attributeKey.match( /Z/ ) ) {
  1871. returnObject.attrZ = true;
  1872. }
  1873. }
  1874. } else {
  1875. return null;
  1876. }
  1877. var conns = connections.get( returnObject.id );
  1878. var containerIndices = conns.parents;
  1879. for ( var containerIndicesIndex = containerIndices.length - 1; containerIndicesIndex >= 0; -- containerIndicesIndex ) {
  1880. var boneID = findIndex( sceneGraph.skeleton.bones, function ( bone ) {
  1881. return bone.FBX_ID === containerIndices[ containerIndicesIndex ].ID;
  1882. } );
  1883. if ( boneID > - 1 ) {
  1884. returnObject.containerBoneID = boneID;
  1885. returnObject.containerID = containerIndices[ containerIndicesIndex ].ID;
  1886. var model = rawModels[ returnObject.containerID.toString() ];
  1887. if ( 'PreRotation' in model.properties ) {
  1888. returnObject.preRotations = parseVector3( model.properties.PreRotation ).multiplyScalar( Math.PI / 180 );
  1889. }
  1890. break;
  1891. }
  1892. }
  1893. return returnObject;
  1894. }
  1895. /**
  1896. * @param {{id: number, subNodes: {KeyTime: {properties: {a: string}}, KeyValueFloat: {properties: {a: string}}, KeyAttrFlags: {properties: {a: string}}, KeyAttrDataFloat: {properties: {a: string}}}}} animationCurve
  1897. */
  1898. function parseAnimationCurve( animationCurve ) {
  1899. return {
  1900. version: null,
  1901. id: animationCurve.id,
  1902. internalID: animationCurve.id,
  1903. times: parseFloatArray( animationCurve.subNodes.KeyTime.properties.a ).map( convertFBXTimeToSeconds ),
  1904. values: parseFloatArray( animationCurve.subNodes.KeyValueFloat.properties.a ),
  1905. attrFlag: parseIntArray( animationCurve.subNodes.KeyAttrFlags.properties.a ),
  1906. attrData: parseFloatArray( animationCurve.subNodes.KeyAttrDataFloat.properties.a )
  1907. };
  1908. }
  1909. /**
  1910. * Sets the maxTimeStamp and minTimeStamp variables if it has timeStamps that are either larger or smaller
  1911. * than the max or min respectively.
  1912. * @param {{
  1913. T: {
  1914. id: number,
  1915. attr: string,
  1916. internalID: number,
  1917. attrX: boolean,
  1918. attrY: boolean,
  1919. attrZ: boolean,
  1920. containerBoneID: number,
  1921. containerID: number,
  1922. curves: {
  1923. x: {
  1924. version: any,
  1925. id: number,
  1926. internalID: number,
  1927. times: number[],
  1928. values: number[],
  1929. attrFlag: number[],
  1930. attrData: number[],
  1931. },
  1932. y: {
  1933. version: any,
  1934. id: number,
  1935. internalID: number,
  1936. times: number[],
  1937. values: number[],
  1938. attrFlag: number[],
  1939. attrData: number[],
  1940. },
  1941. z: {
  1942. version: any,
  1943. id: number,
  1944. internalID: number,
  1945. times: number[],
  1946. values: number[],
  1947. attrFlag: number[],
  1948. attrData: number[],
  1949. },
  1950. },
  1951. },
  1952. R: {
  1953. id: number,
  1954. attr: string,
  1955. internalID: number,
  1956. attrX: boolean,
  1957. attrY: boolean,
  1958. attrZ: boolean,
  1959. containerBoneID: number,
  1960. containerID: number,
  1961. curves: {
  1962. x: {
  1963. version: any,
  1964. id: number,
  1965. internalID: number,
  1966. times: number[],
  1967. values: number[],
  1968. attrFlag: number[],
  1969. attrData: number[],
  1970. },
  1971. y: {
  1972. version: any,
  1973. id: number,
  1974. internalID: number,
  1975. times: number[],
  1976. values: number[],
  1977. attrFlag: number[],
  1978. attrData: number[],
  1979. },
  1980. z: {
  1981. version: any,
  1982. id: number,
  1983. internalID: number,
  1984. times: number[],
  1985. values: number[],
  1986. attrFlag: number[],
  1987. attrData: number[],
  1988. },
  1989. },
  1990. },
  1991. S: {
  1992. id: number,
  1993. attr: string,
  1994. internalID: number,
  1995. attrX: boolean,
  1996. attrY: boolean,
  1997. attrZ: boolean,
  1998. containerBoneID: number,
  1999. containerID: number,
  2000. curves: {
  2001. x: {
  2002. version: any,
  2003. id: number,
  2004. internalID: number,
  2005. times: number[],
  2006. values: number[],
  2007. attrFlag: number[],
  2008. attrData: number[],
  2009. },
  2010. y: {
  2011. version: any,
  2012. id: number,
  2013. internalID: number,
  2014. times: number[],
  2015. values: number[],
  2016. attrFlag: number[],
  2017. attrData: number[],
  2018. },
  2019. z: {
  2020. version: any,
  2021. id: number,
  2022. internalID: number,
  2023. times: number[],
  2024. values: number[],
  2025. attrFlag: number[],
  2026. attrData: number[],
  2027. },
  2028. },
  2029. },
  2030. }} layer
  2031. */
  2032. function getCurveNodeMaxMinTimeStamps( layer, timestamps ) {
  2033. if ( layer.R ) {
  2034. getCurveMaxMinTimeStamp( layer.R.curves, timestamps );
  2035. }
  2036. if ( layer.S ) {
  2037. getCurveMaxMinTimeStamp( layer.S.curves, timestamps );
  2038. }
  2039. if ( layer.T ) {
  2040. getCurveMaxMinTimeStamp( layer.T.curves, timestamps );
  2041. }
  2042. }
  2043. /**
  2044. * Sets the maxTimeStamp and minTimeStamp if one of the curve's time stamps
  2045. * exceeds the maximum or minimum.
  2046. * @param {{
  2047. x: {
  2048. version: any,
  2049. id: number,
  2050. internalID: number,
  2051. times: number[],
  2052. values: number[],
  2053. attrFlag: number[],
  2054. attrData: number[],
  2055. },
  2056. y: {
  2057. version: any,
  2058. id: number,
  2059. internalID: number,
  2060. times: number[],
  2061. values: number[],
  2062. attrFlag: number[],
  2063. attrData: number[],
  2064. },
  2065. z: {
  2066. version: any,
  2067. id: number,
  2068. internalID: number,
  2069. times: number[],
  2070. values: number[],
  2071. attrFlag: number[],
  2072. attrData: number[],
  2073. }
  2074. }} curve
  2075. */
  2076. function getCurveMaxMinTimeStamp( curve, timestamps ) {
  2077. if ( curve.x ) {
  2078. getCurveAxisMaxMinTimeStamps( curve.x, timestamps );
  2079. }
  2080. if ( curve.y ) {
  2081. getCurveAxisMaxMinTimeStamps( curve.y, timestamps );
  2082. }
  2083. if ( curve.z ) {
  2084. getCurveAxisMaxMinTimeStamps( curve.z, timestamps );
  2085. }
  2086. }
  2087. /**
  2088. * Sets the maxTimeStamp and minTimeStamp if one of its timestamps exceeds the maximum or minimum.
  2089. * @param {{times: number[]}} axis
  2090. */
  2091. function getCurveAxisMaxMinTimeStamps( axis, timestamps ) {
  2092. timestamps.max = axis.times[ axis.times.length - 1 ] > timestamps.max ? axis.times[ axis.times.length - 1 ] : timestamps.max;
  2093. timestamps.min = axis.times[ 0 ] < timestamps.min ? axis.times[ 0 ] : timestamps.min;
  2094. }
  2095. /**
  2096. * @param {{
  2097. curves: Map<number, {
  2098. T: {
  2099. id: number;
  2100. attr: string;
  2101. internalID: number;
  2102. attrX: boolean;
  2103. attrY: boolean;
  2104. attrZ: boolean;
  2105. containerBoneID: number;
  2106. containerID: number;
  2107. curves: {
  2108. x: {
  2109. version: any;
  2110. id: number;
  2111. internalID: number;
  2112. times: number[];
  2113. values: number[];
  2114. attrFlag: number[];
  2115. attrData: number[];
  2116. };
  2117. y: {
  2118. version: any;
  2119. id: number;
  2120. internalID: number;
  2121. times: number[];
  2122. values: number[];
  2123. attrFlag: number[];
  2124. attrData: number[];
  2125. };
  2126. z: {
  2127. version: any;
  2128. id: number;
  2129. internalID: number;
  2130. times: number[];
  2131. values: number[];
  2132. attrFlag: number[];
  2133. attrData: number[];
  2134. };
  2135. };
  2136. };
  2137. R: {
  2138. id: number;
  2139. attr: string;
  2140. internalID: number;
  2141. attrX: boolean;
  2142. attrY: boolean;
  2143. attrZ: boolean;
  2144. containerBoneID: number;
  2145. containerID: number;
  2146. curves: {
  2147. x: {
  2148. version: any;
  2149. id: number;
  2150. internalID: number;
  2151. times: number[];
  2152. values: number[];
  2153. attrFlag: number[];
  2154. attrData: number[];
  2155. };
  2156. y: {
  2157. version: any;
  2158. id: number;
  2159. internalID: number;
  2160. times: number[];
  2161. values: number[];
  2162. attrFlag: number[];
  2163. attrData: number[];
  2164. };
  2165. z: {
  2166. version: any;
  2167. id: number;
  2168. internalID: number;
  2169. times: number[];
  2170. values: number[];
  2171. attrFlag: number[];
  2172. attrData: number[];
  2173. };
  2174. };
  2175. };
  2176. S: {
  2177. id: number;
  2178. attr: string;
  2179. internalID: number;
  2180. attrX: boolean;
  2181. attrY: boolean;
  2182. attrZ: boolean;
  2183. containerBoneID: number;
  2184. containerID: number;
  2185. curves: {
  2186. x: {
  2187. version: any;
  2188. id: number;
  2189. internalID: number;
  2190. times: number[];
  2191. values: number[];
  2192. attrFlag: number[];
  2193. attrData: number[];
  2194. };
  2195. y: {
  2196. version: any;
  2197. id: number;
  2198. internalID: number;
  2199. times: number[];
  2200. values: number[];
  2201. attrFlag: number[];
  2202. attrData: number[];
  2203. };
  2204. z: {
  2205. version: any;
  2206. id: number;
  2207. internalID: number;
  2208. times: number[];
  2209. values: number[];
  2210. attrFlag: number[];
  2211. attrData: number[];
  2212. };
  2213. };
  2214. };
  2215. }>;
  2216. layers: Map<number, {
  2217. T: {
  2218. id: number;
  2219. attr: string;
  2220. internalID: number;
  2221. attrX: boolean;
  2222. attrY: boolean;
  2223. attrZ: boolean;
  2224. containerBoneID: number;
  2225. containerID: number;
  2226. curves: {
  2227. x: {
  2228. version: any;
  2229. id: number;
  2230. internalID: number;
  2231. times: number[];
  2232. values: number[];
  2233. attrFlag: number[];
  2234. attrData: number[];
  2235. };
  2236. y: {
  2237. version: any;
  2238. id: number;
  2239. internalID: number;
  2240. times: number[];
  2241. values: number[];
  2242. attrFlag: number[];
  2243. attrData: number[];
  2244. };
  2245. z: {
  2246. version: any;
  2247. id: number;
  2248. internalID: number;
  2249. times: number[];
  2250. values: number[];
  2251. attrFlag: number[];
  2252. attrData: number[];
  2253. };
  2254. };
  2255. };
  2256. R: {
  2257. id: number;
  2258. attr: string;
  2259. internalID: number;
  2260. attrX: boolean;
  2261. attrY: boolean;
  2262. attrZ: boolean;
  2263. containerBoneID: number;
  2264. containerID: number;
  2265. curves: {
  2266. x: {
  2267. version: any;
  2268. id: number;
  2269. internalID: number;
  2270. times: number[];
  2271. values: number[];
  2272. attrFlag: number[];
  2273. attrData: number[];
  2274. };
  2275. y: {
  2276. version: any;
  2277. id: number;
  2278. internalID: number;
  2279. times: number[];
  2280. values: number[];
  2281. attrFlag: number[];
  2282. attrData: number[];
  2283. };
  2284. z: {
  2285. version: any;
  2286. id: number;
  2287. internalID: number;
  2288. times: number[];
  2289. values: number[];
  2290. attrFlag: number[];
  2291. attrData: number[];
  2292. };
  2293. };
  2294. };
  2295. S: {
  2296. id: number;
  2297. attr: string;
  2298. internalID: number;
  2299. attrX: boolean;
  2300. attrY: boolean;
  2301. attrZ: boolean;
  2302. containerBoneID: number;
  2303. containerID: number;
  2304. curves: {
  2305. x: {
  2306. version: any;
  2307. id: number;
  2308. internalID: number;
  2309. times: number[];
  2310. values: number[];
  2311. attrFlag: number[];
  2312. attrData: number[];
  2313. };
  2314. y: {
  2315. version: any;
  2316. id: number;
  2317. internalID: number;
  2318. times: number[];
  2319. values: number[];
  2320. attrFlag: number[];
  2321. attrData: number[];
  2322. };
  2323. z: {
  2324. version: any;
  2325. id: number;
  2326. internalID: number;
  2327. times: number[];
  2328. values: number[];
  2329. attrFlag: number[];
  2330. attrData: number[];
  2331. };
  2332. };
  2333. };
  2334. }[]>;
  2335. stacks: Map<number, {
  2336. name: string;
  2337. layers: {
  2338. T: {
  2339. id: number;
  2340. attr: string;
  2341. internalID: number;
  2342. attrX: boolean;
  2343. attrY: boolean;
  2344. attrZ: boolean;
  2345. containerBoneID: number;
  2346. containerID: number;
  2347. curves: {
  2348. x: {
  2349. version: any;
  2350. id: number;
  2351. internalID: number;
  2352. times: number[];
  2353. values: number[];
  2354. attrFlag: number[];
  2355. attrData: number[];
  2356. };
  2357. y: {
  2358. version: any;
  2359. id: number;
  2360. internalID: number;
  2361. times: number[];
  2362. values: number[];
  2363. attrFlag: number[];
  2364. attrData: number[];
  2365. };
  2366. z: {
  2367. version: any;
  2368. id: number;
  2369. internalID: number;
  2370. times: number[];
  2371. values: number[];
  2372. attrFlag: number[];
  2373. attrData: number[];
  2374. };
  2375. };
  2376. };
  2377. R: {
  2378. id: number;
  2379. attr: string;
  2380. internalID: number;
  2381. attrX: boolean;
  2382. attrY: boolean;
  2383. attrZ: boolean;
  2384. containerBoneID: number;
  2385. containerID: number;
  2386. curves: {
  2387. x: {
  2388. version: any;
  2389. id: number;
  2390. internalID: number;
  2391. times: number[];
  2392. values: number[];
  2393. attrFlag: number[];
  2394. attrData: number[];
  2395. };
  2396. y: {
  2397. version: any;
  2398. id: number;
  2399. internalID: number;
  2400. times: number[];
  2401. values: number[];
  2402. attrFlag: number[];
  2403. attrData: number[];
  2404. };
  2405. z: {
  2406. version: any;
  2407. id: number;
  2408. internalID: number;
  2409. times: number[];
  2410. values: number[];
  2411. attrFlag: number[];
  2412. attrData: number[];
  2413. };
  2414. };
  2415. };
  2416. S: {
  2417. id: number;
  2418. attr: string;
  2419. internalID: number;
  2420. attrX: boolean;
  2421. attrY: boolean;
  2422. attrZ: boolean;
  2423. containerBoneID: number;
  2424. containerID: number;
  2425. curves: {
  2426. x: {
  2427. version: any;
  2428. id: number;
  2429. internalID: number;
  2430. times: number[];
  2431. values: number[];
  2432. attrFlag: number[];
  2433. attrData: number[];
  2434. };
  2435. y: {
  2436. version: any;
  2437. id: number;
  2438. internalID: number;
  2439. times: number[];
  2440. values: number[];
  2441. attrFlag: number[];
  2442. attrData: number[];
  2443. };
  2444. z: {
  2445. version: any;
  2446. id: number;
  2447. internalID: number;
  2448. times: number[];
  2449. values: number[];
  2450. attrFlag: number[];
  2451. attrData: number[];
  2452. };
  2453. };
  2454. };
  2455. }[][];
  2456. length: number;
  2457. frames: number;
  2458. }>;
  2459. length: number;
  2460. fps: number;
  2461. frames: number;
  2462. }} animations,
  2463. * @param {{skeleton: { bones: THREE.Bone[]}}} group
  2464. */
  2465. function addAnimations( group, animations ) {
  2466. if ( group.animations === undefined ) {
  2467. group.animations = [];
  2468. }
  2469. var stacks = animations.stacks;
  2470. for ( var key in stacks ) {
  2471. var stack = stacks[ key ];
  2472. /**
  2473. * @type {{
  2474. * name: string,
  2475. * fps: number,
  2476. * length: number,
  2477. * hierarchy: Array.<{
  2478. * parent: number,
  2479. * name: string,
  2480. * keys: Array.<{
  2481. * time: number,
  2482. * pos: Array.<number>,
  2483. * rot: Array.<number>,
  2484. * scl: Array.<number>
  2485. * }>
  2486. * }>
  2487. * }}
  2488. */
  2489. var animationData = {
  2490. name: stack.name,
  2491. fps: 30,
  2492. length: stack.length,
  2493. hierarchy: []
  2494. };
  2495. var bones = group.skeleton.bones;
  2496. for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
  2497. var bone = bones[ bonesIndex ];
  2498. var name = bone.name.replace( /.*:/, '' );
  2499. var parentIndex = findIndex( bones, function ( parentBone ) {
  2500. return bone.parent === parentBone;
  2501. } );
  2502. animationData.hierarchy.push( { parent: parentIndex, name: name, keys: [] } );
  2503. }
  2504. for ( var frame = 0; frame <= stack.frames; frame ++ ) {
  2505. for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
  2506. var bone = bones[ bonesIndex ];
  2507. var boneIndex = bonesIndex;
  2508. var animationNode = stack.layers[ 0 ][ boneIndex ];
  2509. for ( var hierarchyIndex = 0, hierarchyLength = animationData.hierarchy.length; hierarchyIndex < hierarchyLength; ++ hierarchyIndex ) {
  2510. var node = animationData.hierarchy[ hierarchyIndex ];
  2511. if ( node.name === bone.name ) {
  2512. node.keys.push( generateKey( animations, animationNode, bone, frame ) );
  2513. }
  2514. }
  2515. }
  2516. }
  2517. group.animations.push( THREE.AnimationClip.parseAnimation( animationData, bones ) );
  2518. }
  2519. }
  2520. var euler = new THREE.Euler();
  2521. var quaternion = new THREE.Quaternion();
  2522. /**
  2523. * @param {THREE.Bone} bone
  2524. */
  2525. function generateKey( animations, animationNode, bone, frame ) {
  2526. var key = {
  2527. time: frame / animations.fps,
  2528. pos: bone.position.toArray(),
  2529. rot: bone.quaternion.toArray(),
  2530. scl: bone.scale.toArray()
  2531. };
  2532. if ( animationNode === undefined ) return key;
  2533. try {
  2534. if ( hasCurve( animationNode, 'T' ) && hasKeyOnFrame( animationNode.T, frame ) ) {
  2535. key.pos = [ animationNode.T.curves.x.values[ frame ], animationNode.T.curves.y.values[ frame ], animationNode.T.curves.z.values[ frame ] ];
  2536. }
  2537. if ( hasCurve( animationNode, 'R' ) && hasKeyOnFrame( animationNode.R, frame ) ) {
  2538. var rotationX = animationNode.R.curves.x.values[ frame ];
  2539. var rotationY = animationNode.R.curves.y.values[ frame ];
  2540. var rotationZ = animationNode.R.curves.z.values[ frame ];
  2541. quaternion.setFromEuler( euler.set( rotationX, rotationY, rotationZ, 'ZYX' ) );
  2542. key.rot = quaternion.toArray();
  2543. }
  2544. if ( hasCurve( animationNode, 'S' ) && hasKeyOnFrame( animationNode.S, frame ) ) {
  2545. key.scl = [ animationNode.S.curves.x.values[ frame ], animationNode.S.curves.y.values[ frame ], animationNode.S.curves.z.values[ frame ] ];
  2546. }
  2547. } catch ( error ) {
  2548. // Curve is not fully plotted.
  2549. console.log( 'THREE.FBXLoader: ', bone );
  2550. console.log( 'THREE.FBXLoader: ', error );
  2551. }
  2552. return key;
  2553. }
  2554. var AXES = [ 'x', 'y', 'z' ];
  2555. function hasCurve( animationNode, attribute ) {
  2556. if ( animationNode === undefined ) {
  2557. return false;
  2558. }
  2559. var attributeNode = animationNode[ attribute ];
  2560. if ( ! attributeNode ) {
  2561. return false;
  2562. }
  2563. return AXES.every( function ( key ) {
  2564. return attributeNode.curves[ key ] !== null;
  2565. } );
  2566. }
  2567. function hasKeyOnFrame( attributeNode, frame ) {
  2568. return AXES.every( function ( key ) {
  2569. return isKeyExistOnFrame( attributeNode.curves[ key ], frame );
  2570. } );
  2571. }
  2572. function isKeyExistOnFrame( curve, frame ) {
  2573. return curve.values[ frame ] !== undefined;
  2574. }
  2575. /**
  2576. * An instance of a Vertex with data for drawing vertices to the screen.
  2577. * @constructor
  2578. */
  2579. function Vertex() {
  2580. /**
  2581. * Position of the vertex.
  2582. * @type {THREE.Vector3}
  2583. */
  2584. this.position = new THREE.Vector3();
  2585. /**
  2586. * Normal of the vertex
  2587. * @type {THREE.Vector3}
  2588. */
  2589. this.normal = new THREE.Vector3();
  2590. /**
  2591. * UV coordinates of the vertex.
  2592. * @type {THREE.Vector2}
  2593. */
  2594. this.uv = new THREE.Vector2();
  2595. /**
  2596. * Color of the vertex
  2597. * @type {THREE.Vector3}
  2598. */
  2599. this.color = new THREE.Vector3();
  2600. /**
  2601. * Indices of the bones vertex is influenced by.
  2602. * @type {THREE.Vector4}
  2603. */
  2604. this.skinIndices = new THREE.Vector4( 0, 0, 0, 0 );
  2605. /**
  2606. * Weights that each bone influences the vertex.
  2607. * @type {THREE.Vector4}
  2608. */
  2609. this.skinWeights = new THREE.Vector4( 0, 0, 0, 0 );
  2610. }
  2611. Object.assign( Vertex.prototype, {
  2612. copy: function ( target ) {
  2613. var returnVar = target || new Vertex();
  2614. returnVar.position.copy( this.position );
  2615. returnVar.normal.copy( this.normal );
  2616. returnVar.uv.copy( this.uv );
  2617. returnVar.skinIndices.copy( this.skinIndices );
  2618. returnVar.skinWeights.copy( this.skinWeights );
  2619. return returnVar;
  2620. },
  2621. flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer ) {
  2622. this.position.toArray( vertexBuffer, vertexBuffer.length );
  2623. this.normal.toArray( normalBuffer, normalBuffer.length );
  2624. this.uv.toArray( uvBuffer, uvBuffer.length );
  2625. this.color.toArray( colorBuffer, colorBuffer.length );
  2626. this.skinIndices.toArray( skinIndexBuffer, skinIndexBuffer.length );
  2627. this.skinWeights.toArray( skinWeightBuffer, skinWeightBuffer.length );
  2628. }
  2629. } );
  2630. /**
  2631. * @constructor
  2632. */
  2633. function Triangle() {
  2634. /**
  2635. * @type {{position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}
  2636. */
  2637. this.vertices = [];
  2638. }
  2639. Object.assign( Triangle.prototype, {
  2640. copy: function ( target ) {
  2641. var returnVar = target || new Triangle();
  2642. for ( var i = 0; i < this.vertices.length; ++ i ) {
  2643. this.vertices[ i ].copy( returnVar.vertices[ i ] );
  2644. }
  2645. return returnVar;
  2646. },
  2647. flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer ) {
  2648. var vertices = this.vertices;
  2649. for ( var i = 0, l = vertices.length; i < l; ++ i ) {
  2650. vertices[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer );
  2651. }
  2652. }
  2653. } );
  2654. /**
  2655. * @constructor
  2656. */
  2657. function Face() {
  2658. /**
  2659. * @type {{vertices: {position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}[]}
  2660. */
  2661. this.triangles = [];
  2662. this.materialIndex = 0;
  2663. }
  2664. Object.assign( Face.prototype, {
  2665. copy: function ( target ) {
  2666. var returnVar = target || new Face();
  2667. for ( var i = 0; i < this.triangles.length; ++ i ) {
  2668. this.triangles[ i ].copy( returnVar.triangles[ i ] );
  2669. }
  2670. returnVar.materialIndex = this.materialIndex;
  2671. return returnVar;
  2672. },
  2673. genTrianglesFromVertices: function ( vertexArray ) {
  2674. for ( var i = 2; i < vertexArray.length; ++ i ) {
  2675. var triangle = new Triangle();
  2676. triangle.vertices[ 0 ] = vertexArray[ 0 ];
  2677. triangle.vertices[ 1 ] = vertexArray[ i - 1 ];
  2678. triangle.vertices[ 2 ] = vertexArray[ i ];
  2679. this.triangles.push( triangle );
  2680. }
  2681. },
  2682. flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer, materialIndexBuffer ) {
  2683. var triangles = this.triangles;
  2684. var materialIndex = this.materialIndex;
  2685. for ( var i = 0, l = triangles.length; i < l; ++ i ) {
  2686. triangles[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer );
  2687. append( materialIndexBuffer, [ materialIndex, materialIndex, materialIndex ] );
  2688. }
  2689. }
  2690. } );
  2691. /**
  2692. * @constructor
  2693. */
  2694. function Geometry() {
  2695. /**
  2696. * @type {{triangles: {vertices: {position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}[], materialIndex: number}[]}
  2697. */
  2698. this.faces = [];
  2699. /**
  2700. * @type {{}|THREE.Skeleton}
  2701. */
  2702. this.skeleton = null;
  2703. }
  2704. Object.assign( Geometry.prototype, {
  2705. /**
  2706. * @returns {{vertexBuffer: number[], normalBuffer: number[], uvBuffer: number[], skinIndexBuffer: number[], skinWeightBuffer: number[], materialIndexBuffer: number[]}}
  2707. */
  2708. flattenToBuffers: function () {
  2709. var vertexBuffer = [];
  2710. var normalBuffer = [];
  2711. var uvBuffer = [];
  2712. var colorBuffer = [];
  2713. var skinIndexBuffer = [];
  2714. var skinWeightBuffer = [];
  2715. var materialIndexBuffer = [];
  2716. var faces = this.faces;
  2717. for ( var i = 0, l = faces.length; i < l; ++ i ) {
  2718. faces[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer, materialIndexBuffer );
  2719. }
  2720. return {
  2721. vertexBuffer: vertexBuffer,
  2722. normalBuffer: normalBuffer,
  2723. uvBuffer: uvBuffer,
  2724. colorBuffer: colorBuffer,
  2725. skinIndexBuffer: skinIndexBuffer,
  2726. skinWeightBuffer: skinWeightBuffer,
  2727. materialIndexBuffer: materialIndexBuffer
  2728. };
  2729. }
  2730. } );
  2731. function TextParser() {}
  2732. Object.assign( TextParser.prototype, {
  2733. getPrevNode: function () {
  2734. return this.nodeStack[ this.currentIndent - 2 ];
  2735. },
  2736. getCurrentNode: function () {
  2737. return this.nodeStack[ this.currentIndent - 1 ];
  2738. },
  2739. getCurrentProp: function () {
  2740. return this.currentProp;
  2741. },
  2742. pushStack: function ( node ) {
  2743. this.nodeStack.push( node );
  2744. this.currentIndent += 1;
  2745. },
  2746. popStack: function () {
  2747. this.nodeStack.pop();
  2748. this.currentIndent -= 1;
  2749. },
  2750. setCurrentProp: function ( val, name ) {
  2751. this.currentProp = val;
  2752. this.currentPropName = name;
  2753. },
  2754. // ----------parse ---------------------------------------------------
  2755. parse: function ( text ) {
  2756. this.currentIndent = 0;
  2757. this.allNodes = new FBXTree();
  2758. this.nodeStack = [];
  2759. this.currentProp = [];
  2760. this.currentPropName = '';
  2761. var split = text.split( '\n' );
  2762. for ( var lineNum = 0, lineLength = split.length; lineNum < lineLength; lineNum ++ ) {
  2763. var l = split[ lineNum ];
  2764. // skip comment line
  2765. if ( l.match( /^[\s\t]*;/ ) ) {
  2766. continue;
  2767. }
  2768. // skip empty line
  2769. if ( l.match( /^[\s\t]*$/ ) ) {
  2770. continue;
  2771. }
  2772. // beginning of node
  2773. var beginningOfNodeExp = new RegExp( '^\\t{' + this.currentIndent + '}(\\w+):(.*){', '' );
  2774. var match = l.match( beginningOfNodeExp );
  2775. if ( match ) {
  2776. var nodeName = match[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
  2777. var nodeAttrs = match[ 2 ].split( ',' );
  2778. for ( var i = 0, l = nodeAttrs.length; i < l; i ++ ) {
  2779. nodeAttrs[ i ] = nodeAttrs[ i ].trim().replace( /^"/, '' ).replace( /"$/, '' );
  2780. }
  2781. this.parseNodeBegin( l, nodeName, nodeAttrs || null );
  2782. continue;
  2783. }
  2784. // node's property
  2785. var propExp = new RegExp( '^\\t{' + ( this.currentIndent ) + '}(\\w+):[\\s\\t\\r\\n](.*)' );
  2786. var match = l.match( propExp );
  2787. if ( match ) {
  2788. var propName = match[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
  2789. var propValue = match[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
  2790. // for special case: base64 image data follows "Content: ," line
  2791. // Content: ,
  2792. // "iVB..."
  2793. if ( propName === 'Content' && propValue === ',' ) {
  2794. propValue = split[ ++ lineNum ].replace( /"/g, '' ).trim();
  2795. }
  2796. this.parseNodeProperty( l, propName, propValue );
  2797. continue;
  2798. }
  2799. // end of node
  2800. var endOfNodeExp = new RegExp( '^\\t{' + ( this.currentIndent - 1 ) + '}}' );
  2801. if ( l.match( endOfNodeExp ) ) {
  2802. this.nodeEnd();
  2803. continue;
  2804. }
  2805. // for special case,
  2806. //
  2807. // Vertices: *8670 {
  2808. // a: 0.0356229953467846,13.9599733352661,-0.399196773.....(snip)
  2809. // -0.0612030513584614,13.960485458374,-0.409748703241348,-0.10.....
  2810. // 0.12490539252758,13.7450733184814,-0.454119384288788,0.09272.....
  2811. // 0.0836158767342567,13.5432004928589,-0.435397416353226,0.028.....
  2812. //
  2813. // these case the lines must contiue with previous line
  2814. if ( l.match( /^[^\s\t}]/ ) ) {
  2815. this.parseNodePropertyContinued( l );
  2816. }
  2817. }
  2818. return this.allNodes;
  2819. },
  2820. parseNodeBegin: function ( line, nodeName, nodeAttrs ) {
  2821. // var nodeName = match[1];
  2822. var node = { 'name': nodeName, properties: {}, 'subNodes': {} };
  2823. var attrs = this.parseNodeAttr( nodeAttrs );
  2824. var currentNode = this.getCurrentNode();
  2825. // a top node
  2826. if ( this.currentIndent === 0 ) {
  2827. this.allNodes.add( nodeName, node );
  2828. } else {
  2829. // a subnode
  2830. // already exists subnode, then append it
  2831. if ( nodeName in currentNode.subNodes ) {
  2832. var tmp = currentNode.subNodes[ nodeName ];
  2833. // console.log( "duped entry found\nkey: " + nodeName + "\nvalue: " + propValue );
  2834. if ( this.isFlattenNode( currentNode.subNodes[ nodeName ] ) ) {
  2835. if ( attrs.id === '' ) {
  2836. currentNode.subNodes[ nodeName ] = [];
  2837. currentNode.subNodes[ nodeName ].push( tmp );
  2838. } else {
  2839. currentNode.subNodes[ nodeName ] = {};
  2840. currentNode.subNodes[ nodeName ][ tmp.id ] = tmp;
  2841. }
  2842. }
  2843. if ( attrs.id === '' ) {
  2844. currentNode.subNodes[ nodeName ].push( node );
  2845. } else {
  2846. currentNode.subNodes[ nodeName ][ attrs.id ] = node;
  2847. }
  2848. } else if ( typeof attrs.id === 'number' || attrs.id.match( /^\d+$/ ) ) {
  2849. currentNode.subNodes[ nodeName ] = {};
  2850. currentNode.subNodes[ nodeName ][ attrs.id ] = node;
  2851. } else {
  2852. currentNode.subNodes[ nodeName ] = node;
  2853. }
  2854. }
  2855. // for this ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  2856. // NodeAttribute: 1001463072, "NodeAttribute::", "LimbNode" {
  2857. if ( nodeAttrs ) {
  2858. node.id = attrs.id;
  2859. node.attrName = attrs.name;
  2860. node.attrType = attrs.type;
  2861. }
  2862. this.pushStack( node );
  2863. },
  2864. parseNodeAttr: function ( attrs ) {
  2865. var id = attrs[ 0 ];
  2866. if ( attrs[ 0 ] !== '' ) {
  2867. id = parseInt( attrs[ 0 ] );
  2868. if ( isNaN( id ) ) {
  2869. // PolygonVertexIndex: *16380 {
  2870. id = attrs[ 0 ];
  2871. }
  2872. }
  2873. var name = '', type = '';
  2874. if ( attrs.length > 1 ) {
  2875. name = attrs[ 1 ].replace( /^(\w+)::/, '' );
  2876. type = attrs[ 2 ];
  2877. }
  2878. return { id: id, name: name, type: type };
  2879. },
  2880. parseNodeProperty: function ( line, propName, propValue ) {
  2881. var currentNode = this.getCurrentNode();
  2882. var parentName = currentNode.name;
  2883. // special case parent node's is like "Properties70"
  2884. // these children nodes must treat with careful
  2885. if ( parentName !== undefined ) {
  2886. var propMatch = parentName.match( /Properties(\d)+/ );
  2887. if ( propMatch ) {
  2888. this.parseNodeSpecialProperty( line, propName, propValue );
  2889. return;
  2890. }
  2891. }
  2892. // special case Connections
  2893. if ( propName === 'C' ) {
  2894. var connProps = propValue.split( ',' ).slice( 1 );
  2895. var from = parseInt( connProps[ 0 ] );
  2896. var to = parseInt( connProps[ 1 ] );
  2897. var rest = propValue.split( ',' ).slice( 3 );
  2898. propName = 'connections';
  2899. propValue = [ from, to ];
  2900. append( propValue, rest );
  2901. if ( currentNode.properties[ propName ] === undefined ) {
  2902. currentNode.properties[ propName ] = [];
  2903. }
  2904. }
  2905. // special case Connections
  2906. if ( propName === 'Node' ) {
  2907. var id = parseInt( propValue );
  2908. currentNode.properties.id = id;
  2909. currentNode.id = id;
  2910. }
  2911. // already exists in properties, then append this
  2912. if ( propName in currentNode.properties ) {
  2913. // console.log( "duped entry found\nkey: " + propName + "\nvalue: " + propValue );
  2914. if ( Array.isArray( currentNode.properties[ propName ] ) ) {
  2915. currentNode.properties[ propName ].push( propValue );
  2916. } else {
  2917. currentNode.properties[ propName ] += propValue;
  2918. }
  2919. } else {
  2920. // console.log( propName + ": " + propValue );
  2921. if ( Array.isArray( currentNode.properties[ propName ] ) ) {
  2922. currentNode.properties[ propName ].push( propValue );
  2923. } else {
  2924. currentNode.properties[ propName ] = propValue;
  2925. }
  2926. }
  2927. this.setCurrentProp( currentNode.properties, propName );
  2928. },
  2929. // TODO:
  2930. parseNodePropertyContinued: function ( line ) {
  2931. this.currentProp[ this.currentPropName ] += line;
  2932. },
  2933. parseNodeSpecialProperty: function ( line, propName, propValue ) {
  2934. // split this
  2935. // P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1
  2936. // into array like below
  2937. // ["Lcl Scaling", "Lcl Scaling", "", "A", "1,1,1" ]
  2938. var props = propValue.split( '",' );
  2939. for ( var i = 0, l = props.length; i < l; i ++ ) {
  2940. props[ i ] = props[ i ].trim().replace( /^\"/, '' ).replace( /\s/, '_' );
  2941. }
  2942. var innerPropName = props[ 0 ];
  2943. var innerPropType1 = props[ 1 ];
  2944. var innerPropType2 = props[ 2 ];
  2945. var innerPropFlag = props[ 3 ];
  2946. var innerPropValue = props[ 4 ];
  2947. /*
  2948. if ( innerPropValue === undefined ) {
  2949. innerPropValue = props[3];
  2950. }
  2951. */
  2952. // cast value in its type
  2953. switch ( innerPropType1 ) {
  2954. case 'int':
  2955. innerPropValue = parseInt( innerPropValue );
  2956. break;
  2957. case 'double':
  2958. innerPropValue = parseFloat( innerPropValue );
  2959. break;
  2960. case 'ColorRGB':
  2961. case 'Vector3D':
  2962. innerPropValue = parseFloatArray( innerPropValue );
  2963. break;
  2964. }
  2965. // CAUTION: these props must append to parent's parent
  2966. this.getPrevNode().properties[ innerPropName ] = {
  2967. 'type': innerPropType1,
  2968. 'type2': innerPropType2,
  2969. 'flag': innerPropFlag,
  2970. 'value': innerPropValue
  2971. };
  2972. this.setCurrentProp( this.getPrevNode().properties, innerPropName );
  2973. },
  2974. nodeEnd: function () {
  2975. this.popStack();
  2976. },
  2977. /* ---------------------------------------------------------------- */
  2978. /* util */
  2979. isFlattenNode: function ( node ) {
  2980. return ( 'subNodes' in node && 'properties' in node ) ? true : false;
  2981. }
  2982. } );
  2983. // Binary format specification:
  2984. // https://code.blender.org/2013/08/fbx-binary-file-format-specification/
  2985. // https://wiki.rogiken.org/specifications/file-format/fbx/ (more detail but Japanese)
  2986. function BinaryParser() {}
  2987. Object.assign( BinaryParser.prototype, {
  2988. /**
  2989. * Parses binary data and builds FBXTree as much compatible as possible with the one built by TextParser.
  2990. * @param {ArrayBuffer} buffer
  2991. * @returns {THREE.FBXTree}
  2992. */
  2993. parse: function ( buffer ) {
  2994. var reader = new BinaryReader( buffer );
  2995. reader.skip( 23 ); // skip magic 23 bytes
  2996. var version = reader.getUint32();
  2997. console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
  2998. var allNodes = new FBXTree();
  2999. while ( ! this.endOfContent( reader ) ) {
  3000. var node = this.parseNode( reader, version );
  3001. if ( node !== null ) allNodes.add( node.name, node );
  3002. }
  3003. return allNodes;
  3004. },
  3005. /**
  3006. * Checks if reader has reached the end of content.
  3007. * @param {BinaryReader} reader
  3008. * @returns {boolean}
  3009. */
  3010. endOfContent: function( reader ) {
  3011. // footer size: 160bytes + 16-byte alignment padding
  3012. // - 16bytes: magic
  3013. // - padding til 16-byte alignment (at least 1byte?)
  3014. // (seems like some exporters embed fixed 15 or 16bytes?)
  3015. // - 4bytes: magic
  3016. // - 4bytes: version
  3017. // - 120bytes: zero
  3018. // - 16bytes: magic
  3019. if ( reader.size() % 16 === 0 ) {
  3020. return ( ( reader.getOffset() + 160 + 16 ) & ~0xf ) >= reader.size();
  3021. } else {
  3022. return reader.getOffset() + 160 + 16 >= reader.size();
  3023. }
  3024. },
  3025. /**
  3026. * Parses Node as much compatible as possible with the one parsed by TextParser
  3027. * TODO: could be optimized more?
  3028. * @param {BinaryReader} reader
  3029. * @param {number} version
  3030. * @returns {Object} - Returns an Object as node, or null if NULL-record.
  3031. */
  3032. parseNode: function ( reader, version ) {
  3033. // The first three data sizes depends on version.
  3034. var endOffset = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
  3035. var numProperties = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
  3036. var propertyListLen = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
  3037. var nameLen = reader.getUint8();
  3038. var name = reader.getString( nameLen );
  3039. // Regards this node as NULL-record if endOffset is zero
  3040. if ( endOffset === 0 ) return null;
  3041. var propertyList = [];
  3042. for ( var i = 0; i < numProperties; i ++ ) {
  3043. propertyList.push( this.parseProperty( reader ) );
  3044. }
  3045. // Regards the first three elements in propertyList as id, attrName, and attrType
  3046. var id = propertyList.length > 0 ? propertyList[ 0 ] : '';
  3047. var attrName = propertyList.length > 1 ? propertyList[ 1 ] : '';
  3048. var attrType = propertyList.length > 2 ? propertyList[ 2 ] : '';
  3049. var subNodes = {};
  3050. var properties = {};
  3051. var isSingleProperty = false;
  3052. // if this node represents just a single property
  3053. // like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
  3054. if ( numProperties === 1 && reader.getOffset() === endOffset ) {
  3055. isSingleProperty = true;
  3056. }
  3057. while ( endOffset > reader.getOffset() ) {
  3058. var node = this.parseNode( reader, version );
  3059. if ( node === null ) continue;
  3060. // special case: child node is single property
  3061. if ( node.singleProperty === true ) {
  3062. var value = node.propertyList[ 0 ];
  3063. if ( Array.isArray( value ) ) {
  3064. // node represents
  3065. // Vertices: *3 {
  3066. // a: 0.01, 0.02, 0.03
  3067. // }
  3068. // of text format here.
  3069. node.properties[ node.name ] = node.propertyList[ 0 ];
  3070. subNodes[ node.name ] = node;
  3071. // Later phase expects single property array is in node.properties.a as String.
  3072. // TODO: optimize
  3073. node.properties.a = value.toString();
  3074. } else {
  3075. // node represents
  3076. // Version: 100
  3077. // of text format here.
  3078. properties[ node.name ] = value;
  3079. }
  3080. continue;
  3081. }
  3082. // special case: connections
  3083. if ( name === 'Connections' && node.name === 'C' ) {
  3084. var array = [];
  3085. // node.propertyList would be like
  3086. // ["OO", 111264976, 144038752, "d|x"] (?, from, to, additional values)
  3087. for ( var i = 1, il = node.propertyList.length; i < il; i ++ ) {
  3088. array[ i - 1 ] = node.propertyList[ i ];
  3089. }
  3090. if ( properties.connections === undefined ) {
  3091. properties.connections = [];
  3092. }
  3093. properties.connections.push( array );
  3094. continue;
  3095. }
  3096. // special case: child node is Properties\d+
  3097. if ( node.name.match( /^Properties\d+$/ ) ) {
  3098. // move child node's properties to this node.
  3099. var keys = Object.keys( node.properties );
  3100. for ( var i = 0, il = keys.length; i < il; i ++ ) {
  3101. var key = keys[ i ];
  3102. properties[ key ] = node.properties[ key ];
  3103. }
  3104. continue;
  3105. }
  3106. // special case: properties
  3107. if ( name.match( /^Properties\d+$/ ) && node.name === 'P' ) {
  3108. var innerPropName = node.propertyList[ 0 ];
  3109. var innerPropType1 = node.propertyList[ 1 ];
  3110. var innerPropType2 = node.propertyList[ 2 ];
  3111. var innerPropFlag = node.propertyList[ 3 ];
  3112. var innerPropValue;
  3113. if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
  3114. if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
  3115. if ( innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' ||
  3116. innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
  3117. innerPropValue = [
  3118. node.propertyList[ 4 ],
  3119. node.propertyList[ 5 ],
  3120. node.propertyList[ 6 ]
  3121. ];
  3122. } else {
  3123. innerPropValue = node.propertyList[ 4 ];
  3124. }
  3125. if ( innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
  3126. innerPropValue = innerPropValue.toString();
  3127. }
  3128. // this will be copied to parent. see above.
  3129. properties[ innerPropName ] = {
  3130. 'type': innerPropType1,
  3131. 'type2': innerPropType2,
  3132. 'flag': innerPropFlag,
  3133. 'value': innerPropValue
  3134. };
  3135. continue;
  3136. }
  3137. // standard case
  3138. // follows TextParser's manner.
  3139. if ( subNodes[ node.name ] === undefined ) {
  3140. if ( typeof node.id === 'number' ) {
  3141. subNodes[ node.name ] = {};
  3142. subNodes[ node.name ][ node.id ] = node;
  3143. } else {
  3144. subNodes[ node.name ] = node;
  3145. }
  3146. } else {
  3147. if ( node.id === '' ) {
  3148. if ( ! Array.isArray( subNodes[ node.name ] ) ) {
  3149. subNodes[ node.name ] = [ subNodes[ node.name ] ];
  3150. }
  3151. subNodes[ node.name ].push( node );
  3152. } else {
  3153. if ( subNodes[ node.name ][ node.id ] === undefined ) {
  3154. subNodes[ node.name ][ node.id ] = node;
  3155. } else {
  3156. // conflict id. irregular?
  3157. if ( ! Array.isArray( subNodes[ node.name ][ node.id ] ) ) {
  3158. subNodes[ node.name ][ node.id ] = [ subNodes[ node.name ][ node.id ] ];
  3159. }
  3160. subNodes[ node.name ][ node.id ].push( node );
  3161. }
  3162. }
  3163. }
  3164. }
  3165. return {
  3166. singleProperty: isSingleProperty,
  3167. id: id,
  3168. attrName: attrName,
  3169. attrType: attrType,
  3170. name: name,
  3171. properties: properties,
  3172. propertyList: propertyList, // raw property list, would be used by parent
  3173. subNodes: subNodes
  3174. };
  3175. },
  3176. parseProperty: function ( reader ) {
  3177. var type = reader.getChar();
  3178. switch ( type ) {
  3179. case 'F':
  3180. return reader.getFloat32();
  3181. case 'D':
  3182. return reader.getFloat64();
  3183. case 'L':
  3184. return reader.getInt64();
  3185. case 'I':
  3186. return reader.getInt32();
  3187. case 'Y':
  3188. return reader.getInt16();
  3189. case 'C':
  3190. return reader.getBoolean();
  3191. case 'f':
  3192. case 'd':
  3193. case 'l':
  3194. case 'i':
  3195. case 'b':
  3196. var arrayLength = reader.getUint32();
  3197. var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
  3198. var compressedLength = reader.getUint32();
  3199. if ( encoding === 0 ) {
  3200. switch ( type ) {
  3201. case 'f':
  3202. return reader.getFloat32Array( arrayLength );
  3203. case 'd':
  3204. return reader.getFloat64Array( arrayLength );
  3205. case 'l':
  3206. return reader.getInt64Array( arrayLength );
  3207. case 'i':
  3208. return reader.getInt32Array( arrayLength );
  3209. case 'b':
  3210. return reader.getBooleanArray( arrayLength );
  3211. }
  3212. }
  3213. if ( window.Zlib === undefined ) {
  3214. throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
  3215. }
  3216. var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) );
  3217. var reader2 = new BinaryReader( inflate.decompress().buffer );
  3218. switch ( type ) {
  3219. case 'f':
  3220. return reader2.getFloat32Array( arrayLength );
  3221. case 'd':
  3222. return reader2.getFloat64Array( arrayLength );
  3223. case 'l':
  3224. return reader2.getInt64Array( arrayLength );
  3225. case 'i':
  3226. return reader2.getInt32Array( arrayLength );
  3227. case 'b':
  3228. return reader2.getBooleanArray( arrayLength );
  3229. }
  3230. case 'S':
  3231. var length = reader.getUint32();
  3232. return reader.getString( length );
  3233. case 'R':
  3234. var length = reader.getUint32();
  3235. return reader.getArrayBuffer( length );
  3236. default:
  3237. throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
  3238. }
  3239. }
  3240. } );
  3241. function BinaryReader( buffer, littleEndian ) {
  3242. this.dv = new DataView( buffer );
  3243. this.offset = 0;
  3244. this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
  3245. }
  3246. Object.assign( BinaryReader.prototype, {
  3247. getOffset: function () {
  3248. return this.offset;
  3249. },
  3250. size: function () {
  3251. return this.dv.buffer.byteLength;
  3252. },
  3253. skip: function ( length ) {
  3254. this.offset += length;
  3255. },
  3256. // seems like true/false representation depends on exporter.
  3257. // true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
  3258. // then sees LSB.
  3259. getBoolean: function () {
  3260. return ( this.getUint8() & 1 ) === 1;
  3261. },
  3262. getBooleanArray: function ( size ) {
  3263. var a = [];
  3264. for ( var i = 0; i < size; i ++ ) {
  3265. a.push( this.getBoolean() );
  3266. }
  3267. return a;
  3268. },
  3269. getInt8: function () {
  3270. var value = this.dv.getInt8( this.offset );
  3271. this.offset += 1;
  3272. return value;
  3273. },
  3274. getInt8Array: function ( size ) {
  3275. var a = [];
  3276. for ( var i = 0; i < size; i ++ ) {
  3277. a.push( this.getInt8() );
  3278. }
  3279. return a;
  3280. },
  3281. getUint8: function () {
  3282. var value = this.dv.getUint8( this.offset );
  3283. this.offset += 1;
  3284. return value;
  3285. },
  3286. getUint8Array: function ( size ) {
  3287. var a = [];
  3288. for ( var i = 0; i < size; i ++ ) {
  3289. a.push( this.getUint8() );
  3290. }
  3291. return a;
  3292. },
  3293. getInt16: function () {
  3294. var value = this.dv.getInt16( this.offset, this.littleEndian );
  3295. this.offset += 2;
  3296. return value;
  3297. },
  3298. getInt16Array: function ( size ) {
  3299. var a = [];
  3300. for ( var i = 0; i < size; i ++ ) {
  3301. a.push( this.getInt16() );
  3302. }
  3303. return a;
  3304. },
  3305. getUint16: function () {
  3306. var value = this.dv.getUint16( this.offset, this.littleEndian );
  3307. this.offset += 2;
  3308. return value;
  3309. },
  3310. getUint16Array: function ( size ) {
  3311. var a = [];
  3312. for ( var i = 0; i < size; i ++ ) {
  3313. a.push( this.getUint16() );
  3314. }
  3315. return a;
  3316. },
  3317. getInt32: function () {
  3318. var value = this.dv.getInt32( this.offset, this.littleEndian );
  3319. this.offset += 4;
  3320. return value;
  3321. },
  3322. getInt32Array: function ( size ) {
  3323. var a = [];
  3324. for ( var i = 0; i < size; i ++ ) {
  3325. a.push( this.getInt32() );
  3326. }
  3327. return a;
  3328. },
  3329. getUint32: function () {
  3330. var value = this.dv.getUint32( this.offset, this.littleEndian );
  3331. this.offset += 4;
  3332. return value;
  3333. },
  3334. getUint32Array: function ( size ) {
  3335. var a = [];
  3336. for ( var i = 0; i < size; i ++ ) {
  3337. a.push( this.getUint32() );
  3338. }
  3339. return a;
  3340. },
  3341. // JavaScript doesn't support 64-bit integer so attempting to calculate by ourselves.
  3342. // 1 << 32 will return 1 so using multiply operation instead here.
  3343. // There'd be a possibility that this method returns wrong value if the value
  3344. // is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
  3345. // TODO: safely handle 64-bit integer
  3346. getInt64: function () {
  3347. var low, high;
  3348. if ( this.littleEndian ) {
  3349. low = this.getUint32();
  3350. high = this.getUint32();
  3351. } else {
  3352. high = this.getUint32();
  3353. low = this.getUint32();
  3354. }
  3355. // calculate negative value
  3356. if ( high & 0x80000000 ) {
  3357. high = ~high & 0xFFFFFFFF;
  3358. low = ~low & 0xFFFFFFFF;
  3359. if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
  3360. low = ( low + 1 ) & 0xFFFFFFFF;
  3361. return - ( high * 0x100000000 + low );
  3362. }
  3363. return high * 0x100000000 + low;
  3364. },
  3365. getInt64Array: function ( size ) {
  3366. var a = [];
  3367. for ( var i = 0; i < size; i ++ ) {
  3368. a.push( this.getInt64() );
  3369. }
  3370. return a;
  3371. },
  3372. // Note: see getInt64() comment
  3373. getUint64: function () {
  3374. var low, high;
  3375. if ( this.littleEndian ) {
  3376. low = this.getUint32();
  3377. high = this.getUint32();
  3378. } else {
  3379. high = this.getUint32();
  3380. low = this.getUint32();
  3381. }
  3382. return high * 0x100000000 + low;
  3383. },
  3384. getUint64Array: function ( size ) {
  3385. var a = [];
  3386. for ( var i = 0; i < size; i ++ ) {
  3387. a.push( this.getUint64() );
  3388. }
  3389. return a;
  3390. },
  3391. getFloat32: function () {
  3392. var value = this.dv.getFloat32( this.offset, this.littleEndian );
  3393. this.offset += 4;
  3394. return value;
  3395. },
  3396. getFloat32Array: function ( size ) {
  3397. var a = [];
  3398. for ( var i = 0; i < size; i ++ ) {
  3399. a.push( this.getFloat32() );
  3400. }
  3401. return a;
  3402. },
  3403. getFloat64: function () {
  3404. var value = this.dv.getFloat64( this.offset, this.littleEndian );
  3405. this.offset += 8;
  3406. return value;
  3407. },
  3408. getFloat64Array: function ( size ) {
  3409. var a = [];
  3410. for ( var i = 0; i < size; i ++ ) {
  3411. a.push( this.getFloat64() );
  3412. }
  3413. return a;
  3414. },
  3415. getArrayBuffer: function ( size ) {
  3416. var value = this.dv.buffer.slice( this.offset, this.offset + size );
  3417. this.offset += size;
  3418. return value;
  3419. },
  3420. getChar: function () {
  3421. return String.fromCharCode( this.getUint8() );
  3422. },
  3423. getString: function ( size ) {
  3424. var s = '';
  3425. while ( size > 0 ) {
  3426. var value = this.getUint8();
  3427. size--;
  3428. if ( value === 0 ) break;
  3429. s += String.fromCharCode( value );
  3430. }
  3431. this.skip( size );
  3432. return s;
  3433. }
  3434. } );
  3435. function FBXTree() {}
  3436. Object.assign( FBXTree.prototype, {
  3437. add: function ( key, val ) {
  3438. this[ key ] = val;
  3439. },
  3440. searchConnectionParent: function ( id ) {
  3441. if ( this.__cache_search_connection_parent === undefined ) {
  3442. this.__cache_search_connection_parent = [];
  3443. }
  3444. if ( this.__cache_search_connection_parent[ id ] !== undefined ) {
  3445. return this.__cache_search_connection_parent[ id ];
  3446. } else {
  3447. this.__cache_search_connection_parent[ id ] = [];
  3448. }
  3449. var conns = this.Connections.properties.connections;
  3450. var results = [];
  3451. for ( var i = 0; i < conns.length; ++ i ) {
  3452. if ( conns[ i ][ 0 ] == id ) {
  3453. // 0 means scene root
  3454. var res = conns[ i ][ 1 ] === 0 ? - 1 : conns[ i ][ 1 ];
  3455. results.push( res );
  3456. }
  3457. }
  3458. if ( results.length > 0 ) {
  3459. append( this.__cache_search_connection_parent[ id ], results );
  3460. return results;
  3461. } else {
  3462. this.__cache_search_connection_parent[ id ] = [ - 1 ];
  3463. return [ - 1 ];
  3464. }
  3465. },
  3466. searchConnectionChildren: function ( id ) {
  3467. if ( this.__cache_search_connection_children === undefined ) {
  3468. this.__cache_search_connection_children = [];
  3469. }
  3470. if ( this.__cache_search_connection_children[ id ] !== undefined ) {
  3471. return this.__cache_search_connection_children[ id ];
  3472. } else {
  3473. this.__cache_search_connection_children[ id ] = [];
  3474. }
  3475. var conns = this.Connections.properties.connections;
  3476. var res = [];
  3477. for ( var i = 0; i < conns.length; ++ i ) {
  3478. if ( conns[ i ][ 1 ] == id ) {
  3479. // 0 means scene root
  3480. res.push( conns[ i ][ 0 ] === 0 ? - 1 : conns[ i ][ 0 ] );
  3481. // there may more than one kid, then search to the end
  3482. }
  3483. }
  3484. if ( res.length > 0 ) {
  3485. append( this.__cache_search_connection_children[ id ], res );
  3486. return res;
  3487. } else {
  3488. this.__cache_search_connection_children[ id ] = [ ];
  3489. return [ ];
  3490. }
  3491. },
  3492. searchConnectionType: function ( id, to ) {
  3493. var key = id + ',' + to; // TODO: to hash
  3494. if ( this.__cache_search_connection_type === undefined ) {
  3495. this.__cache_search_connection_type = {};
  3496. }
  3497. if ( this.__cache_search_connection_type[ key ] !== undefined ) {
  3498. return this.__cache_search_connection_type[ key ];
  3499. } else {
  3500. this.__cache_search_connection_type[ key ] = '';
  3501. }
  3502. var conns = this.Connections.properties.connections;
  3503. for ( var i = 0; i < conns.length; ++ i ) {
  3504. if ( conns[ i ][ 0 ] == id && conns[ i ][ 1 ] == to ) {
  3505. // 0 means scene root
  3506. this.__cache_search_connection_type[ key ] = conns[ i ][ 2 ];
  3507. return conns[ i ][ 2 ];
  3508. }
  3509. }
  3510. this.__cache_search_connection_type[ id ] = null;
  3511. return null;
  3512. }
  3513. } );
  3514. /**
  3515. * @param {ArrayBuffer} buffer
  3516. * @returns {boolean}
  3517. */
  3518. function isFbxFormatBinary( buffer ) {
  3519. var CORRECT = 'Kaydara FBX Binary \0';
  3520. return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
  3521. }
  3522. /**
  3523. * @returns {boolean}
  3524. */
  3525. function isFbxFormatASCII( text ) {
  3526. var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
  3527. var cursor = 0;
  3528. function read( offset ) {
  3529. var result = text[ offset - 1 ];
  3530. text = text.slice( cursor + offset );
  3531. cursor ++;
  3532. return result;
  3533. }
  3534. for ( var i = 0; i < CORRECT.length; ++ i ) {
  3535. var num = read( 1 );
  3536. if ( num === CORRECT[ i ] ) {
  3537. return false;
  3538. }
  3539. }
  3540. return true;
  3541. }
  3542. /**
  3543. * @returns {number}
  3544. */
  3545. function getFbxVersion( text ) {
  3546. var versionRegExp = /FBXVersion: (\d+)/;
  3547. var match = text.match( versionRegExp );
  3548. if ( match ) {
  3549. var version = parseInt( match[ 1 ] );
  3550. return version;
  3551. }
  3552. throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
  3553. }
  3554. /**
  3555. * Converts FBX ticks into real time seconds.
  3556. * @param {number} time - FBX tick timestamp to convert.
  3557. * @returns {number} - FBX tick in real world time.
  3558. */
  3559. function convertFBXTimeToSeconds( time ) {
  3560. // Constant is FBX ticks per second.
  3561. return time / 46186158000;
  3562. }
  3563. /**
  3564. * Parses comma separated list of float numbers and returns them in an array.
  3565. * @example
  3566. * // Returns [ 5.6, 9.4, 2.5, 1.4 ]
  3567. * parseFloatArray( "5.6,9.4,2.5,1.4" )
  3568. * @returns {number[]}
  3569. */
  3570. function parseFloatArray( string ) {
  3571. var array = string.split( ',' );
  3572. for ( var i = 0, l = array.length; i < l; i ++ ) {
  3573. array[ i ] = parseFloat( array[ i ] );
  3574. }
  3575. return array;
  3576. }
  3577. /**
  3578. * Parses comma separated list of int numbers and returns them in an array.
  3579. * @example
  3580. * // Returns [ 5, 8, 2, 3 ]
  3581. * parseFloatArray( "5,8,2,3" )
  3582. * @returns {number[]}
  3583. */
  3584. function parseIntArray( string ) {
  3585. var array = string.split( ',' );
  3586. for ( var i = 0, l = array.length; i < l; i ++ ) {
  3587. array[ i ] = parseInt( array[ i ] );
  3588. }
  3589. return array;
  3590. }
  3591. /**
  3592. * Parses Vector3 property from FBXTree. Property is given as .value.x, .value.y, etc.
  3593. * @param {FBXVector3} property - Property to parse as Vector3.
  3594. * @returns {THREE.Vector3}
  3595. */
  3596. function parseVector3( property ) {
  3597. return new THREE.Vector3().fromArray( property.value );
  3598. }
  3599. /**
  3600. * Parses Color property from FBXTree. Property is given as .value.x, .value.y, etc.
  3601. * @param {FBXVector3} property - Property to parse as Color.
  3602. * @returns {THREE.Color}
  3603. */
  3604. function parseColor( property ) {
  3605. return new THREE.Color().fromArray( property.value );
  3606. }
  3607. function parseMatrixArray( floatString ) {
  3608. return new THREE.Matrix4().fromArray( parseFloatArray( floatString ) );
  3609. }
  3610. /**
  3611. * Converts ArrayBuffer to String.
  3612. * @param {ArrayBuffer} buffer
  3613. * @param {number} from
  3614. * @param {number} to
  3615. * @returns {String}
  3616. */
  3617. function convertArrayBufferToString( buffer, from, to ) {
  3618. if ( from === undefined ) from = 0;
  3619. if ( to === undefined ) to = buffer.byteLength;
  3620. var array = new Uint8Array( buffer, from, to );
  3621. if ( window.TextDecoder !== undefined ) {
  3622. return new TextDecoder().decode( array );
  3623. }
  3624. var s = '';
  3625. for ( var i = 0, il = array.length; i < il; i ++ ) {
  3626. s += String.fromCharCode( array[ i ] );
  3627. }
  3628. return s;
  3629. }
  3630. /**
  3631. * Converts number from degrees into radians.
  3632. * @param {number} value
  3633. * @returns {number}
  3634. */
  3635. function degreeToRadian( value ) {
  3636. return value * DEG2RAD;
  3637. }
  3638. var DEG2RAD = Math.PI / 180;
  3639. //
  3640. function findIndex( array, func ) {
  3641. for ( var i = 0, l = array.length; i < l; i ++ ) {
  3642. if ( func( array[ i ] ) ) return i;
  3643. }
  3644. return -1;
  3645. }
  3646. function append( a, b ) {
  3647. for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
  3648. a[ j ] = b[ i ];
  3649. }
  3650. }
  3651. function slice( a, b, from, to ) {
  3652. for ( var i = from, j = 0; i < to; i ++, j ++ ) {
  3653. a[ j ] = b[ i ];
  3654. }
  3655. return a;
  3656. }
  3657. } )();
  3658. },{}],4:[function(require,module,exports){
  3659. module.exports = Object.assign(function GamepadButton () {}, {
  3660. FACE_1: 0,
  3661. FACE_2: 1,
  3662. FACE_3: 2,
  3663. FACE_4: 3,
  3664. L_SHOULDER_1: 4,
  3665. R_SHOULDER_1: 5,
  3666. L_SHOULDER_2: 6,
  3667. R_SHOULDER_2: 7,
  3668. SELECT: 8,
  3669. START: 9,
  3670. DPAD_UP: 12,
  3671. DPAD_DOWN: 13,
  3672. DPAD_LEFT: 14,
  3673. DPAD_RIGHT: 15,
  3674. VENDOR: 16,
  3675. });
  3676. },{}],5:[function(require,module,exports){
  3677. function GamepadButtonEvent (type, index, details) {
  3678. this.type = type;
  3679. this.index = index;
  3680. this.pressed = details.pressed;
  3681. this.value = details.value;
  3682. }
  3683. module.exports = GamepadButtonEvent;
  3684. },{}],6:[function(require,module,exports){
  3685. /**
  3686. * @author Wei Meng / http://about.me/menway
  3687. *
  3688. * Description: A THREE loader for PLY ASCII files (known as the Polygon File Format or the Stanford Triangle Format).
  3689. *
  3690. *
  3691. * Limitations: ASCII decoding assumes file is UTF-8.
  3692. *
  3693. * Usage:
  3694. * var loader = new THREE.PLYLoader();
  3695. * loader.load('./models/ply/ascii/dolphins.ply', function (geometry) {
  3696. *
  3697. * scene.add( new THREE.Mesh( geometry ) );
  3698. *
  3699. * } );
  3700. *
  3701. * If the PLY file uses non standard property names, they can be mapped while
  3702. * loading. For example, the following maps the properties
  3703. * “diffuse_(red|green|blue)” in the file to standard color names.
  3704. *
  3705. * loader.setPropertyNameMapping( {
  3706. * diffuse_red: 'red',
  3707. * diffuse_green: 'green',
  3708. * diffuse_blue: 'blue'
  3709. * } );
  3710. *
  3711. */
  3712. module.exports = THREE.PLYLoader = function ( manager ) {
  3713. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  3714. this.propertyNameMapping = {};
  3715. };
  3716. THREE.PLYLoader.prototype = {
  3717. constructor: THREE.PLYLoader,
  3718. load: function ( url, onLoad, onProgress, onError ) {
  3719. var scope = this;
  3720. var loader = new THREE.XHRLoader( this.manager );
  3721. loader.setResponseType( 'arraybuffer' );
  3722. loader.load( url, function ( text ) {
  3723. onLoad( scope.parse( text ) );
  3724. }, onProgress, onError );
  3725. },
  3726. setPropertyNameMapping: function ( mapping ) {
  3727. this.propertyNameMapping = mapping;
  3728. },
  3729. bin2str: function ( buf ) {
  3730. var array_buffer = new Uint8Array( buf );
  3731. var str = '';
  3732. for ( var i = 0; i < buf.byteLength; i ++ ) {
  3733. str += String.fromCharCode( array_buffer[ i ] ); // implicitly assumes little-endian
  3734. }
  3735. return str;
  3736. },
  3737. isASCII: function( data ) {
  3738. var header = this.parseHeader( this.bin2str( data ) );
  3739. return header.format === "ascii";
  3740. },
  3741. parse: function ( data ) {
  3742. if ( data instanceof ArrayBuffer ) {
  3743. return this.isASCII( data )
  3744. ? this.parseASCII( this.bin2str( data ) )
  3745. : this.parseBinary( data );
  3746. } else {
  3747. return this.parseASCII( data );
  3748. }
  3749. },
  3750. parseHeader: function ( data ) {
  3751. var patternHeader = /ply([\s\S]*)end_header\s/;
  3752. var headerText = "";
  3753. var headerLength = 0;
  3754. var result = patternHeader.exec( data );
  3755. if ( result !== null ) {
  3756. headerText = result [ 1 ];
  3757. headerLength = result[ 0 ].length;
  3758. }
  3759. var header = {
  3760. comments: [],
  3761. elements: [],
  3762. headerLength: headerLength
  3763. };
  3764. var lines = headerText.split( '\n' );
  3765. var currentElement = undefined;
  3766. var lineType, lineValues;
  3767. function make_ply_element_property( propertValues, propertyNameMapping ) {
  3768. var property = {
  3769. type: propertValues[ 0 ]
  3770. };
  3771. if ( property.type === 'list' ) {
  3772. property.name = propertValues[ 3 ];
  3773. property.countType = propertValues[ 1 ];
  3774. property.itemType = propertValues[ 2 ];
  3775. } else {
  3776. property.name = propertValues[ 1 ];
  3777. }
  3778. if ( property.name in propertyNameMapping ) {
  3779. property.name = propertyNameMapping[ property.name ];
  3780. }
  3781. return property;
  3782. }
  3783. for ( var i = 0; i < lines.length; i ++ ) {
  3784. var line = lines[ i ];
  3785. line = line.trim();
  3786. if ( line === "" ) {
  3787. continue;
  3788. }
  3789. lineValues = line.split( /\s+/ );
  3790. lineType = lineValues.shift();
  3791. line = lineValues.join( " " );
  3792. switch ( lineType ) {
  3793. case "format":
  3794. header.format = lineValues[ 0 ];
  3795. header.version = lineValues[ 1 ];
  3796. break;
  3797. case "comment":
  3798. header.comments.push( line );
  3799. break;
  3800. case "element":
  3801. if ( ! ( currentElement === undefined ) ) {
  3802. header.elements.push( currentElement );
  3803. }
  3804. currentElement = Object();
  3805. currentElement.name = lineValues[ 0 ];
  3806. currentElement.count = parseInt( lineValues[ 1 ] );
  3807. currentElement.properties = [];
  3808. break;
  3809. case "property":
  3810. currentElement.properties.push( make_ply_element_property( lineValues, this.propertyNameMapping ) );
  3811. break;
  3812. default:
  3813. console.log( "unhandled", lineType, lineValues );
  3814. }
  3815. }
  3816. if ( ! ( currentElement === undefined ) ) {
  3817. header.elements.push( currentElement );
  3818. }
  3819. return header;
  3820. },
  3821. parseASCIINumber: function ( n, type ) {
  3822. switch ( type ) {
  3823. case 'char': case 'uchar': case 'short': case 'ushort': case 'int': case 'uint':
  3824. case 'int8': case 'uint8': case 'int16': case 'uint16': case 'int32': case 'uint32':
  3825. return parseInt( n );
  3826. case 'float': case 'double': case 'float32': case 'float64':
  3827. return parseFloat( n );
  3828. }
  3829. },
  3830. parseASCIIElement: function ( properties, line ) {
  3831. var values = line.split( /\s+/ );
  3832. var element = Object();
  3833. for ( var i = 0; i < properties.length; i ++ ) {
  3834. if ( properties[ i ].type === "list" ) {
  3835. var list = [];
  3836. var n = this.parseASCIINumber( values.shift(), properties[ i ].countType );
  3837. for ( var j = 0; j < n; j ++ ) {
  3838. list.push( this.parseASCIINumber( values.shift(), properties[ i ].itemType ) );
  3839. }
  3840. element[ properties[ i ].name ] = list;
  3841. } else {
  3842. element[ properties[ i ].name ] = this.parseASCIINumber( values.shift(), properties[ i ].type );
  3843. }
  3844. }
  3845. return element;
  3846. },
  3847. parseASCII: function ( data ) {
  3848. // PLY ascii format specification, as per http://en.wikipedia.org/wiki/PLY_(file_format)
  3849. var geometry = new THREE.Geometry();
  3850. var result;
  3851. var header = this.parseHeader( data );
  3852. var patternBody = /end_header\s([\s\S]*)$/;
  3853. var body = "";
  3854. if ( ( result = patternBody.exec( data ) ) !== null ) {
  3855. body = result [ 1 ];
  3856. }
  3857. var lines = body.split( '\n' );
  3858. var currentElement = 0;
  3859. var currentElementCount = 0;
  3860. geometry.useColor = false;
  3861. for ( var i = 0; i < lines.length; i ++ ) {
  3862. var line = lines[ i ];
  3863. line = line.trim();
  3864. if ( line === "" ) {
  3865. continue;
  3866. }
  3867. if ( currentElementCount >= header.elements[ currentElement ].count ) {
  3868. currentElement ++;
  3869. currentElementCount = 0;
  3870. }
  3871. var element = this.parseASCIIElement( header.elements[ currentElement ].properties, line );
  3872. this.handleElement( geometry, header.elements[ currentElement ].name, element );
  3873. currentElementCount ++;
  3874. }
  3875. return this.postProcess( geometry );
  3876. },
  3877. postProcess: function ( geometry ) {
  3878. if ( geometry.useColor ) {
  3879. for ( var i = 0; i < geometry.faces.length; i ++ ) {
  3880. geometry.faces[ i ].vertexColors = [
  3881. geometry.colors[ geometry.faces[ i ].a ],
  3882. geometry.colors[ geometry.faces[ i ].b ],
  3883. geometry.colors[ geometry.faces[ i ].c ]
  3884. ];
  3885. }
  3886. geometry.elementsNeedUpdate = true;
  3887. }
  3888. geometry.computeBoundingSphere();
  3889. return geometry;
  3890. },
  3891. handleElement: function ( geometry, elementName, element ) {
  3892. if ( elementName === "vertex" ) {
  3893. geometry.vertices.push(
  3894. new THREE.Vector3( element.x, element.y, element.z )
  3895. );
  3896. if ( 'red' in element && 'green' in element && 'blue' in element ) {
  3897. geometry.useColor = true;
  3898. var color = new THREE.Color();
  3899. color.setRGB( element.red / 255.0, element.green / 255.0, element.blue / 255.0 );
  3900. geometry.colors.push( color );
  3901. }
  3902. } else if ( elementName === "face" ) {
  3903. // BEGIN: Edits by donmccurdy.
  3904. var vertex_indices = element.vertex_indices || element.vertex_index;
  3905. // END: Edits by donmccurdy.
  3906. if ( vertex_indices.length === 3 ) {
  3907. geometry.faces.push(
  3908. new THREE.Face3( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 2 ] )
  3909. );
  3910. } else if ( vertex_indices.length === 4 ) {
  3911. geometry.faces.push(
  3912. new THREE.Face3( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 3 ] ),
  3913. new THREE.Face3( vertex_indices[ 1 ], vertex_indices[ 2 ], vertex_indices[ 3 ] )
  3914. );
  3915. }
  3916. }
  3917. },
  3918. binaryRead: function ( dataview, at, type, little_endian ) {
  3919. switch ( type ) {
  3920. // corespondences for non-specific length types here match rply:
  3921. case 'int8': case 'char': return [ dataview.getInt8( at ), 1 ];
  3922. case 'uint8': case 'uchar': return [ dataview.getUint8( at ), 1 ];
  3923. case 'int16': case 'short': return [ dataview.getInt16( at, little_endian ), 2 ];
  3924. case 'uint16': case 'ushort': return [ dataview.getUint16( at, little_endian ), 2 ];
  3925. case 'int32': case 'int': return [ dataview.getInt32( at, little_endian ), 4 ];
  3926. case 'uint32': case 'uint': return [ dataview.getUint32( at, little_endian ), 4 ];
  3927. case 'float32': case 'float': return [ dataview.getFloat32( at, little_endian ), 4 ];
  3928. case 'float64': case 'double': return [ dataview.getFloat64( at, little_endian ), 8 ];
  3929. }
  3930. },
  3931. binaryReadElement: function ( dataview, at, properties, little_endian ) {
  3932. var element = Object();
  3933. var result, read = 0;
  3934. for ( var i = 0; i < properties.length; i ++ ) {
  3935. if ( properties[ i ].type === "list" ) {
  3936. var list = [];
  3937. result = this.binaryRead( dataview, at + read, properties[ i ].countType, little_endian );
  3938. var n = result[ 0 ];
  3939. read += result[ 1 ];
  3940. for ( var j = 0; j < n; j ++ ) {
  3941. result = this.binaryRead( dataview, at + read, properties[ i ].itemType, little_endian );
  3942. list.push( result[ 0 ] );
  3943. read += result[ 1 ];
  3944. }
  3945. element[ properties[ i ].name ] = list;
  3946. } else {
  3947. result = this.binaryRead( dataview, at + read, properties[ i ].type, little_endian );
  3948. element[ properties[ i ].name ] = result[ 0 ];
  3949. read += result[ 1 ];
  3950. }
  3951. }
  3952. return [ element, read ];
  3953. },
  3954. parseBinary: function ( data ) {
  3955. var geometry = new THREE.Geometry();
  3956. var header = this.parseHeader( this.bin2str( data ) );
  3957. var little_endian = ( header.format === "binary_little_endian" );
  3958. var body = new DataView( data, header.headerLength );
  3959. var result, loc = 0;
  3960. for ( var currentElement = 0; currentElement < header.elements.length; currentElement ++ ) {
  3961. for ( var currentElementCount = 0; currentElementCount < header.elements[ currentElement ].count; currentElementCount ++ ) {
  3962. result = this.binaryReadElement( body, loc, header.elements[ currentElement ].properties, little_endian );
  3963. loc += result[ 1 ];
  3964. var element = result[ 0 ];
  3965. this.handleElement( geometry, header.elements[ currentElement ].name, element );
  3966. }
  3967. }
  3968. return this.postProcess( geometry );
  3969. }
  3970. };
  3971. },{}],7:[function(require,module,exports){
  3972. module.exports={
  3973. "size": 5,
  3974. "cellSize": 10,
  3975. "extrudeSettings": {
  3976. "amount": 1,
  3977. "bevelEnabled": true,
  3978. "bevelSegments": 1,
  3979. "steps": 1,
  3980. "bevelSize": 0.5,
  3981. "bevelThickness": 0.5
  3982. },
  3983. "autogenerated": true,
  3984. "cells": [
  3985. {
  3986. "q": -1,
  3987. "r": 0,
  3988. "s": 1,
  3989. "h": 1,
  3990. "walkable": true,
  3991. "userData": {}
  3992. },
  3993. {
  3994. "q": 0,
  3995. "r": -1,
  3996. "s": 1,
  3997. "h": 1,
  3998. "walkable": true,
  3999. "userData": {}
  4000. },
  4001. {
  4002. "q": 0,
  4003. "r": 0,
  4004. "s": 0,
  4005. "h": 1,
  4006. "walkable": true,
  4007. "userData": {}
  4008. },
  4009. {
  4010. "q": 1,
  4011. "r": -1,
  4012. "s": 0,
  4013. "h": 1,
  4014. "walkable": true,
  4015. "userData": {}
  4016. },
  4017. {
  4018. "q": -1,
  4019. "r": 1,
  4020. "s": 0,
  4021. "h": 0,
  4022. "walkable": true,
  4023. "userData": {}
  4024. },
  4025. {
  4026. "q": 0,
  4027. "r": 1,
  4028. "s": -1,
  4029. "h": 0,
  4030. "walkable": true,
  4031. "userData": {}
  4032. },
  4033. {
  4034. "q": 1,
  4035. "r": 0,
  4036. "s": -1,
  4037. "h": 0,
  4038. "walkable": true,
  4039. "userData": {}
  4040. }]
  4041. }
  4042. },{}],8:[function(require,module,exports){
  4043. /**
  4044. * Source: https://github.com/Adobe-Marketing-Cloud/fetch-script
  4045. */
  4046. function getScriptId() {
  4047. return 'script_' + Date.now() + '_' + Math.ceil(Math.random() * 100000);
  4048. }
  4049. function createScript(url, id) {
  4050. var script = document.createElement('script');
  4051. script.type = 'text/javascript';
  4052. script.async = true;
  4053. script.id = id;
  4054. script.src = url;
  4055. return script;
  4056. }
  4057. function removeScript(id) {
  4058. const script = document.getElementById(id);
  4059. const parent = script.parentNode;
  4060. try {
  4061. parent && parent.removeChild(script);
  4062. } catch (e) {
  4063. // ignore
  4064. }
  4065. }
  4066. function appendScript(script) {
  4067. const firstScript = document.getElementsByTagName('script')[0];
  4068. firstScript.parentNode.insertBefore(script, firstScript);
  4069. }
  4070. function fetchScriptInternal(url, options, Promise) {
  4071. return new Promise(function(resolve, reject) {
  4072. const timeout = options.timeout || 5000;
  4073. const scriptId = getScriptId();
  4074. const script = createScript(url, scriptId);
  4075. const timeoutId = setTimeout(function() {
  4076. reject(new Error('Script request to ' + url + ' timed out'));
  4077. removeScript(scriptId);
  4078. }, timeout);
  4079. const disableTimeout = function(timeoutId) { clearTimeout(timeoutId); };
  4080. script.addEventListener('load', function(e) {
  4081. resolve({ok: true});
  4082. disableTimeout(timeoutId);
  4083. removeScript(scriptId);
  4084. });
  4085. script.addEventListener('error', function(e) {
  4086. reject(new Error('Script request to ' + url + ' failed ' + e));
  4087. disableTimeout(timeoutId);
  4088. removeScript(scriptId);
  4089. });
  4090. appendScript(script);
  4091. });
  4092. }
  4093. function fetchScript(settings) {
  4094. settings = settings || {};
  4095. return function (url, options) {
  4096. options = options || {};
  4097. return fetchScriptInternal(url, options, settings.Promise || Promise);
  4098. };
  4099. }
  4100. module.exports = fetchScript;
  4101. },{}],9:[function(require,module,exports){
  4102. var vg=module.exports={VERSION:"0.1.1",PI:Math.PI,TAU:2*Math.PI,DEG_TO_RAD:.0174532925,RAD_TO_DEG:57.2957795,SQRT3:Math.sqrt(3),TILE:"tile",ENT:"entity",STR:"structure",HEX:"hex",SQR:"square",ABS:"abstract"};vg.Board=function(e,t){if(!e)throw new Error("You must pass in a grid system for the board to use.");this.tiles=[],this.tileGroup=null,this.group=new THREE.Object3D,this.grid=null,this.overlay=null,this.finder=new vg.AStarFinder(t),vg.Loader.init(),this.setGrid(e)},vg.Board.prototype={setEntityOnTile:function(e,t){var i=this.grid.cellToPixel(t.cell);e.position.copy(i),e.position.y+=e.heightOffset||0,e.tile&&(e.tile.entity=null),e.tile=t,t.entity=e},addTile:function(e){var t=this.tiles.indexOf(e);-1===t&&(this.tiles.push(e),this.snapTileToGrid(e),e.position.y=0,this.tileGroup.add(e.mesh),this.grid.add(e.cell),e.cell.tile=e)},removeTile:function(e){if(e){var t=this.tiles.indexOf(e);this.grid.remove(e.cell),-1!==t&&this.tiles.splice(t,1),e.dispose()}},removeAllTiles:function(){if(this.tileGroup)for(var e=this.tileGroup.children,t=0;t<e.length;t++)this.tileGroup.remove(e[t])},getTileAtCell:function(e){var t=this.grid.cellToHash(e);return e.tile||("undefined"!=typeof this.grid.cells[t]?this.grid.cells[t].tile:null)},snapToGrid:function(e){var t=this.grid.pixelToCell(e);e.copy(this.grid.cellToPixel(t))},snapTileToGrid:function(e){if(e.cell)e.position.copy(this.grid.cellToPixel(e.cell));else{var t=this.grid.pixelToCell(e.position);e.position.copy(this.grid.cellToPixel(t))}return e},getRandomTile:function(){var e=vg.Tools.randomInt(0,this.tiles.length-1);return this.tiles[e]},findPath:function(e,t,i){return this.finder.findPath(e.cell,t.cell,i,this.grid)},setGrid:function(e){this.group.remove(this.tileGroup),this.grid&&e!==this.grid&&(this.removeAllTiles(),this.tiles.forEach(function(e){this.grid.remove(e.cell),e.dispose()}),this.grid.dispose()),this.grid=e,this.tiles=[],this.tileGroup=new THREE.Object3D,this.group.add(this.tileGroup)},generateOverlay:function(e){var t=new THREE.LineBasicMaterial({color:0,opacity:.3});this.overlay&&this.group.remove(this.overlay),this.overlay=new THREE.Object3D,this.grid.generateOverlay(e,this.overlay,t),this.group.add(this.overlay)},generateTilemap:function(e){this.reset();var t=this.grid.generateTiles(e);this.tiles=t,this.tileGroup=new THREE.Object3D;for(var i=0;i<t.length;i++)this.tileGroup.add(t[i].mesh);this.group.add(this.tileGroup)},reset:function(){this.removeAllTiles(),this.tileGroup&&this.group.remove(this.tileGroup)}},vg.Board.prototype.constructor=vg.Board,vg.Cell=function(e,t,i,s){this.q=e||0,this.r=t||0,this.s=i||0,this.h=s||1,this.tile=null,this.userData={},this.walkable=!0,this._calcCost=0,this._priority=0,this._visited=!1,this._parent=null,this.uniqueID=vg.LinkedList.generateID()},vg.Cell.prototype={set:function(e,t,i){return this.q=e,this.r=t,this.s=i,this},copy:function(e){return this.q=e.q,this.r=e.r,this.s=e.s,this.h=e.h,this.tile=e.tile||null,this.userData=e.userData||{},this.walkable=e.walkable,this},add:function(e){return this.q+=e.q,this.r+=e.r,this.s+=e.s,this},equals:function(e){return this.q===e.q&&this.r===e.r&&this.s===e.s}},vg.Cell.prototype.constructor=vg.Cell,vg.HexGrid=function(e){e=e||{},this.type=vg.HEX,this.size=5,this.cellSize="undefined"==typeof e.cellSize?10:e.cellSize,this.cells={},this.numCells=0,this.extrudeSettings=null,this.autogenerated=!1;var t,i=[];for(t=0;6>t;t++)i.push(this._createVertex(t));for(this.cellShape=new THREE.Shape,this.cellShape.moveTo(i[0].x,i[0].y),t=1;6>t;t++)this.cellShape.lineTo(i[t].x,i[t].y);this.cellShape.lineTo(i[0].x,i[0].y),this.cellShape.autoClose=!0,this.cellGeo=new THREE.Geometry,this.cellGeo.vertices=i,this.cellGeo.verticesNeedUpdate=!0,this.cellShapeGeo=new THREE.ShapeGeometry(this.cellShape),this._cellWidth=2*this.cellSize,this._cellLength=.5*vg.SQRT3*this._cellWidth,this._hashDelimeter=".",this._directions=[new vg.Cell(1,-1,0),new vg.Cell(1,0,-1),new vg.Cell(0,1,-1),new vg.Cell(-1,1,0),new vg.Cell(-1,0,1),new vg.Cell(0,-1,1)],this._diagonals=[new vg.Cell(2,-1,-1),new vg.Cell(1,1,-2),new vg.Cell(-1,2,-1),new vg.Cell(-2,1,1),new vg.Cell(-1,-1,2),new vg.Cell(1,-2,1)],this._list=[],this._vec3=new THREE.Vector3,this._cel=new vg.Cell,this._conversionVec=new THREE.Vector3,this._geoCache=[],this._matCache=[]},vg.HexGrid.TWO_THIRDS=2/3,vg.HexGrid.prototype={cellToPixel:function(e){return this._vec3.x=e.q*this._cellWidth*.75,this._vec3.y=e.h,this._vec3.z=-((e.s-e.r)*this._cellLength*.5),this._vec3},pixelToCell:function(e){var t=e.x*(vg.HexGrid.TWO_THIRDS/this.cellSize),i=(-e.x/3+vg.SQRT3/3*e.z)/this.cellSize;return this._cel.set(t,i,-t-i),this._cubeRound(this._cel)},getCellAt:function(e){var t=e.x*(vg.HexGrid.TWO_THIRDS/this.cellSize),i=(-e.x/3+vg.SQRT3/3*e.z)/this.cellSize;return this._cel.set(t,i,-t-i),this._cubeRound(this._cel),this.cells[this.cellToHash(this._cel)]},getNeighbors:function(e,t,i){var s,n,l=this._directions.length;for(this._list.length=0,s=0;l>s;s++)this._cel.copy(e),this._cel.add(this._directions[s]),n=this.cells[this.cellToHash(this._cel)],!n||i&&!i(e,n)||this._list.push(n);if(t)for(s=0;l>s;s++)this._cel.copy(e),this._cel.add(this._diagonals[s]),n=this.cells[this.cellToHash(this._cel)],!n||i&&!i(e,n)||this._list.push(n);return this._list},getRandomCell:function(){var e,t=0,i=vg.Tools.randomInt(0,this.numCells);for(e in this.cells){if(t===i)return this.cells[e];t++}return this.cells[e]},cellToHash:function(e){return e.q+this._hashDelimeter+e.r+this._hashDelimeter+e.s},distance:function(e,t){var i=Math.max(Math.abs(e.q-t.q),Math.abs(e.r-t.r),Math.abs(e.s-t.s));return i+=t.h-e.h},clearPath:function(){var e,t;for(e in this.cells)t=this.cells[e],t._calcCost=0,t._priority=0,t._parent=null,t._visited=!1},traverse:function(e){var t;for(t in this.cells)e(this.cells[t])},generateTile:function(e,t,i){var s=Math.abs(e.h);1>s&&(s=1);var n=this._geoCache[s];n||(this.extrudeSettings.amount=s,n=new THREE.ExtrudeGeometry(this.cellShape,this.extrudeSettings),this._geoCache[s]=n);var l=new vg.Tile({size:this.cellSize,scale:t,cell:e,geometry:n,material:i});return e.tile=l,l},generateTiles:function(e){e=e||{};var t=[],i={tileScale:.95,cellSize:this.cellSize,material:null,extrudeSettings:{amount:1,bevelEnabled:!0,bevelSegments:1,steps:1,bevelSize:.5,bevelThickness:.5}};i=vg.Tools.merge(i,e),this.cellSize=i.cellSize,this._cellWidth=2*this.cellSize,this._cellLength=.5*vg.SQRT3*this._cellWidth,this.autogenerated=!0,this.extrudeSettings=i.extrudeSettings;var s,n,l;for(s in this.cells)l=this.cells[s],n=this.generateTile(l,i.tileScale,i.material),n.position.copy(this.cellToPixel(l)),n.position.y=0,t.push(n);return t},generateTilePoly:function(e){e||(e=new THREE.MeshBasicMaterial({color:2405631}));var t=new THREE.Mesh(this.cellShapeGeo,e);return this._vec3.set(1,0,0),t.rotateOnAxis(this._vec3,vg.PI/2),t},generate:function(e){e=e||{},this.size="undefined"==typeof e.size?this.size:e.size;var t,i,s,n;for(t=-this.size;t<this.size+1;t++)for(i=-this.size;i<this.size+1;i++)s=-t-i,Math.abs(t)<=this.size&&Math.abs(i)<=this.size&&Math.abs(s)<=this.size&&(n=new vg.Cell(t,i,s),this.add(n))},generateOverlay:function(e,t,i){var s,n,l,r=this.cellShape.createPointsGeometry();for(s=-e;e+1>s;s++)for(n=-e;e+1>n;n++)if(l=-s-n,Math.abs(s)<=e&&Math.abs(n)<=e&&Math.abs(l)<=e){this._cel.set(s,n,l);var h=new THREE.Line(r,i);h.position.copy(this.cellToPixel(this._cel)),h.rotation.x=90*vg.DEG_TO_RAD,t.add(h)}},add:function(e){var t=this.cellToHash(e);if(!this.cells[t])return this.cells[t]=e,this.numCells++,e},remove:function(e){var t=this.cellToHash(e);this.cells[t]&&(delete this.cells[t],this.numCells--)},dispose:function(){this.cells=null,this.numCells=0,this.cellShape=null,this.cellGeo.dispose(),this.cellGeo=null,this.cellShapeGeo.dispose(),this.cellShapeGeo=null,this._list=null,this._vec3=null,this._conversionVec=null,this._geoCache=null,this._matCache=null},load:function(e,t,i){var s=this;vg.Tools.getJSON({url:e,callback:function(e){s.fromJSON(e),t.call(i||null,e)},cache:!1,scope:s})},fromJSON:function(e){var t,i,s=e.cells;for(this.cells={},this.numCells=0,this.size=e.size,this.cellSize=e.cellSize,this._cellWidth=2*this.cellSize,this._cellLength=.5*vg.SQRT3*this._cellWidth,this.extrudeSettings=e.extrudeSettings,this.autogenerated=e.autogenerated,t=0;t<s.length;t++)i=new vg.Cell,i.copy(s[t]),this.add(i)},toJSON:function(){var e,t,i={size:this.size,cellSize:this.cellSize,extrudeSettings:this.extrudeSettings,autogenerated:this.autogenerated},s=[];for(t in this.cells)e=this.cells[t],s.push({q:e.q,r:e.r,s:e.s,h:e.h,walkable:e.walkable,userData:e.userData});return i.cells=s,i},_createVertex:function(e){var t=vg.TAU/6*e;return new THREE.Vector3(this.cellSize*Math.cos(t),this.cellSize*Math.sin(t),0)},_cubeRound:function(e){var t=Math.round(e.q),i=Math.round(e.r),s=Math.round(e.s),n=Math.abs(t-e.q),l=Math.abs(i-e.r),r=Math.abs(s-e.s);return n>l&&n>r?t=-i-s:l>r?i=-t-s:s=-t-i,this._cel.set(t,i,s)}},vg.HexGrid.prototype.constructor=vg.HexGrid,vg.SqrGrid=function(e){e=e||{},this.type=vg.SQR,this.size=5,this.cellSize="undefined"==typeof e.cellSize?10:e.cellSize,this.cells={},this.numCells=0,this.extrudeSettings=null,this.autogenerated=!1;var t=[];t.push(new THREE.Vector3),t.push(new THREE.Vector3(-this.cellSize,this.cellSize)),t.push(new THREE.Vector3(this.cellSize,this.cellSize)),t.push(new THREE.Vector3(this.cellSize,-this.cellSize)),this.cellShape=new THREE.Shape,this.cellShape.moveTo(-this.cellSize,-this.cellSize),this.cellShape.lineTo(-this.cellSize,this.cellSize),this.cellShape.lineTo(this.cellSize,this.cellSize),this.cellShape.lineTo(this.cellSize,-this.cellSize),this.cellShape.lineTo(-this.cellSize,-this.cellSize),this.cellGeo=new THREE.Geometry,this.cellGeo.vertices=t,this.cellGeo.verticesNeedUpdate=!0,this.cellShapeGeo=new THREE.ShapeGeometry(this.cellShape),this._fullCellSize=2*this.cellSize,this._hashDelimeter=".",this._directions=[new vg.Cell(1,0,0),new vg.Cell(0,-1,0),new vg.Cell(-1,0,0),new vg.Cell(0,1,0)],this._diagonals=[new vg.Cell(-1,-1,0),new vg.Cell(-1,1,0),new vg.Cell(1,1,0),new vg.Cell(1,-1,0)],this._list=[],this._vec3=new THREE.Vector3,this._cel=new vg.Cell,this._conversionVec=new THREE.Vector3,this._geoCache=[],this._matCache=[]},vg.SqrGrid.prototype={cellToPixel:function(e){return this._vec3.x=e.q*this._fullCellSize,this._vec3.y=e.h,this._vec3.z=e.r*this._fullCellSize,this._vec3},pixelToCell:function(e){var t=Math.round(e.x/this._fullCellSize),i=Math.round(e.z/this._fullCellSize);return this._cel.set(t,i,0)},getCellAt:function(e){var t=Math.round(e.x/this._fullCellSize),i=Math.round(e.z/this._fullCellSize);return this._cel.set(t,i),this.cells[this.cellToHash(this._cel)]},getNeighbors:function(e,t,i){var s,n,l=this._directions.length;for(this._list.length=0,s=0;l>s;s++)this._cel.copy(e),this._cel.add(this._directions[s]),n=this.cells[this.cellToHash(this._cel)],!n||i&&!i(e,n)||this._list.push(n);if(t)for(s=0;l>s;s++)this._cel.copy(e),this._cel.add(this._diagonals[s]),n=this.cells[this.cellToHash(this._cel)],!n||i&&!i(e,n)||this._list.push(n);return this._list},getRandomCell:function(){var e,t=0,i=vg.Tools.randomInt(0,this.numCells);for(e in this.cells){if(t===i)return this.cells[e];t++}return this.cells[e]},cellToHash:function(e){return e.q+this._hashDelimeter+e.r},distance:function(e,t){var i=Math.max(Math.abs(e.q-t.q),Math.abs(e.r-t.r));return i+=t.h-e.h},clearPath:function(){var e,t;for(e in this.cells)t=this.cells[e],t._calcCost=0,t._priority=0,t._parent=null,t._visited=!1},traverse:function(e){var t;for(t in this.cells)e(this.cells[t])},generateTile:function(e,t,i){var s=Math.abs(e.h);1>s&&(s=1);var n=this._geoCache[s];n||(this.extrudeSettings.amount=s,n=new THREE.ExtrudeGeometry(this.cellShape,this.extrudeSettings),this._geoCache[s]=n);var l=new vg.Tile({size:this.cellSize,scale:t,cell:e,geometry:n,material:i});return e.tile=l,l},generateTiles:function(e){e=e||{};var t=[],i={tileScale:.95,cellSize:this.cellSize,material:null,extrudeSettings:{amount:1,bevelEnabled:!0,bevelSegments:1,steps:1,bevelSize:.5,bevelThickness:.5}};i=vg.Tools.merge(i,e),this.cellSize=i.cellSize,this._fullCellSize=2*this.cellSize,this.autogenerated=!0,this.extrudeSettings=i.extrudeSettings;var s,n,l;for(s in this.cells)l=this.cells[s],n=this.generateTile(l,i.tileScale,i.material),n.position.copy(this.cellToPixel(l)),n.position.y=0,t.push(n);return t},generateTilePoly:function(e){e||(e=new THREE.MeshBasicMaterial({color:2405631}));var t=new THREE.Mesh(this.cellShapeGeo,e);return this._vec3.set(1,0,0),t.rotateOnAxis(this._vec3,vg.PI/2),t},generate:function(e){e=e||{},this.size="undefined"==typeof e.size?this.size:e.size;var t,i,s,n=Math.ceil(this.size/2);for(t=-n;n>t;t++)for(i=-n;n>i;i++)s=new vg.Cell(t,i+1),this.add(s)},generateOverlay:function(e,t,i){var s,n,l=Math.ceil(e/2);for(s=-l;l>s;s++)for(n=-l;l>n;n++){this._cel.set(s,n);var r=new THREE.Line(this.cellGeo,i);r.position.copy(this.cellToPixel(this._cel)),r.rotation.x=90*vg.DEG_TO_RAD,t.add(r)}},add:function(e){var t=this.cellToHash(e);if(!this.cells[t])return this.cells[t]=e,this.numCells++,e},remove:function(e){var t=this.cellToHash(e);this.cells[t]&&(delete this.cells[t],this.numCells--)},dispose:function(){this.cells=null,this.numCells=0,this.cellShape=null,this.cellGeo.dispose(),this.cellGeo=null,this.cellShapeGeo.dispose(),this.cellShapeGeo=null,this._list=null,this._vec3=null,this._conversionVec=null,this._geoCache=null,this._matCache=null},load:function(e,t,i){vg.Tools.getJSON({url:e,callback:function(e){this.fromJSON(e),t.call(i||null,e)},cache:!1,scope:this})},fromJSON:function(e){var t,i,s=e.cells;for(this.cells={},this.numCells=0,this.size=e.size,this.cellSize=e.cellSize,this._fullCellSize=2*this.cellSize,this.extrudeSettings=e.extrudeSettings,this.autogenerated=e.autogenerated,t=0;t<s.length;t++)i=new vg.Cell,i.copy(s[t]),this.add(i)},toJSON:function(){var e,t,i={size:this.size,cellSize:this.cellSize,extrudeSettings:this.extrudeSettings,autogenerated:this.autogenerated},s=[];for(t in this.cells)e=this.cells[t],s.push({q:e.q,r:e.r,s:e.s,h:e.h,walkable:e.walkable,userData:e.userData});return i.cells=s,i}},vg.SqrGrid.prototype.constructor=vg.SqrGrid,vg.Tile=function(e){e=e||{};var t={cell:null,geometry:null,material:null};if(t=vg.Tools.merge(t,e),!t.cell||!t.geometry)throw new Error("Missing vg.Tile configuration");this.cell=t.cell,this.cell.tile&&this.cell.tile!==this&&this.cell.tile.dispose(),this.cell.tile=this,this.uniqueID=vg.Tools.generateID(),this.geometry=t.geometry,this.material=t.material,this.material||(this.material=new THREE.MeshPhongMaterial({color:vg.Tools.randomizeRGB("30, 30, 30",13)})),this.objectType=vg.TILE,this.entity=null,this.userData={},this.selected=!1,this.highlight="0x0084cc",this.mesh=new THREE.Mesh(this.geometry,this.material),this.mesh.userData.structure=this,this.position=this.mesh.position,this.rotation=this.mesh.rotation,this.rotation.x=-90*vg.DEG_TO_RAD,this.mesh.scale.set(t.scale,t.scale,1),this.material.emissive?this._emissive=this.material.emissive.getHex():this._emissive=null},vg.Tile.prototype={select:function(){return this.material.emissive&&this.material.emissive.setHex(this.highlight),this.selected=!0,this},deselect:function(){return null!==this._emissive&&this.material.emissive&&this.material.emissive.setHex(this._emissive),this.selected=!1,this},toggle:function(){return this.selected?this.deselect():this.select(),this},dispose:function(){this.cell&&this.cell.tile&&(this.cell.tile=null),this.cell=null,this.position=null,this.rotation=null,this.mesh.parent&&this.mesh.parent.remove(this.mesh),this.mesh.userData.structure=null,this.mesh=null,this.material=null,this.userData=null,this.entity=null,this.geometry=null,this._emissive=null}},vg.Tile.prototype.constructor=vg.Tile,function(){var e=function(){this.obj=null,this.next=null,this.prev=null,this.free=!0},t=function(){this.first=null,this.last=null,this.length=0,this.objToNodeMap={},this.uniqueID=Date.now()+""+Math.floor(1e3*Math.random()),this.sortArray=[]};t.generateID=function(){return Math.random().toString(36).slice(2)+Date.now()},t.prototype={getNode:function(e){return this.objToNodeMap[e.uniqueID]},addNode:function(i){var s=new e;if(!i.uniqueID)try{i.uniqueID=t.generateID()}catch(n){return console.error("[LinkedList.addNode] obj passed is immutable: cannot attach necessary identifier"),null}return s.obj=i,s.free=!1,this.objToNodeMap[i.uniqueID]=s,s},swapObjects:function(e,t){this.objToNodeMap[e.obj.uniqueID]=null,this.objToNodeMap[t.uniqueID]=e,e.obj=t},add:function(e){var t=this.objToNodeMap[e.uniqueID];if(t){if(t.free===!1)return;t.obj=e,t.free=!1,t.next=null,t.prev=null}else t=this.addNode(e);if(this.first){if(!this.last)throw new Error("[LinkedList.add] No last in the list -- that shouldn't happen here");this.last.next=t,t.prev=this.last,this.last=t,t.next=null}else this.first=t,this.last=t,t.next=null,t.prev=null;this.length++,this.showDebug&&this.dump("after add")},has:function(e){return!!this.objToNodeMap[e.uniqueID]},moveUp:function(e){this.dump("before move up");var t=this.getNode(e);if(!t)throw"Oops, trying to move an object that isn't in the list";if(t.prev){var i=t.prev,s=i.prev;t==this.last&&(this.last=i);var n=t.next;s&&(s.next=t),t.next=i,t.prev=i.prev,i.next=n,i.prev=t,this.first==i&&(this.first=t)}},moveDown:function(e){var t=this.getNode(e);if(!t)throw"Oops, trying to move an object that isn't in the list";if(t.next){var i=t.next;this.moveUp(i.obj),this.last==i&&(this.last=t)}},sort:function(e){var t,i,s=this.sortArray,n=this.first;for(s.length=0;n;)s.push(n.obj),n=n.next;for(this.clear(),s.sort(e),i=s.length,t=0;i>t;t++)this.add(s[t])},remove:function(e){var t=this.getNode(e);return!t||t.free?!1:(t.prev&&(t.prev.next=t.next),t.next&&(t.next.prev=t.prev),t.prev||(this.first=t.next),t.next||(this.last=t.prev),t.free=!0,t.prev=null,t.next=null,this.length--,!0)},shift:function(){var e=this.first;return 0===this.length?null:(e.prev&&(e.prev.next=e.next),e.next&&(e.next.prev=e.prev),this.first=e.next,e.next||(this.last=null),e.free=!0,e.prev=null,e.next=null,this.length--,e.obj)},pop:function(){var e=this.last;return 0===this.length?null:(e.prev&&(e.prev.next=e.next),e.next&&(e.next.prev=e.prev),this.last=e.prev,e.prev||(this.first=null),e.free=!0,e.prev=null,e.next=null,this.length--,e.obj)},concat:function(e){for(var t=e.first;t;)this.add(t.obj),t=t.next},clear:function(){for(var e=this.first;e;)e.free=!0,e=e.next;this.first=null,this.length=0},dispose:function(){for(var e=this.first;e;)e.obj=null,e=e.next;this.first=null,this.objToNodeMap=null},dump:function(e){console.log("===================="+e+"=====================");for(var t=this.first;t;)console.log("{"+t.obj.toString()+"} previous="+(t.prev?t.prev.obj:"NULL")),t=t.next();console.log("==================================="),console.log("Last: {"+(this.last?this.last.obj:"NULL")+"} First: {"+(this.first?this.first.obj:"NULL")+"}")}},t.prototype.constructor=t,vg.LinkedList=t}(),function(){var e=function(e,t,i,s,n){this._listener=t,this.isOnce=i,this.context=s,this.signal=e,this._priority=n||0};e.prototype={active:!0,params:null,execute:function(e){var t,i;return this.active&&this._listener&&(i=this.params?this.params.concat(e):e,t=this._listener.apply(this.context,i),this.isOnce&&this.detach()),t},detach:function(){return this.isBound()?this.signal.remove(this._listener,this.context):null},isBound:function(){return!!this.signal&&!!this._listener},_destroy:function(){delete this.signal,delete this._listener,delete this.context},toString:function(){return"[SignalBinding isOnce:"+this.isOnce+", isBound:"+this.isBound()+", active:"+this.active+"]"}},e.prototype.constructor=e;var t=function(){this._bindings=[],this._prevParams=null;var e=this;this.dispatch=function(){t.prototype.dispatch.apply(e,arguments)}};t.prototype={memorize:!1,_shouldPropagate:!0,active:!0,validateListener:function(e,t){if("function"!=typeof e)throw new Error("Signal: listener is a required param of {fn}() and should be a Function.".replace("{fn}",t))},_registerListener:function(t,i,s,n){var l,r=this._indexOfListener(t,s);if(-1!==r){if(l=this._bindings[r],l.isOnce!==i)throw new Error("You cannot add"+(i?"":"Once")+"() then add"+(i?"Once":"")+"() the same listener without removing the relationship first.")}else l=new e(this,t,i,s,n),this._addBinding(l);return this.memorize&&this._prevParams&&l.execute(this._prevParams),l},_addBinding:function(e){var t=this._bindings.length;do t--;while(this._bindings[t]&&e._priority<=this._bindings[t]._priority);this._bindings.splice(t+1,0,e)},_indexOfListener:function(e,t){for(var i,s=this._bindings.length;s--;)if(i=this._bindings[s],i._listener===e&&i.context===t)return s;return-1},has:function(e,t){return-1!==this._indexOfListener(e,t)},add:function(e,t,i){return this.validateListener(e,"add"),this._registerListener(e,!1,t,i)},addOnce:function(e,t,i){return this.validateListener(e,"addOnce"),this._registerListener(e,!0,t,i)},remove:function(e,t){this.validateListener(e,"remove");var i=this._indexOfListener(e,t);return-1!==i&&(this._bindings[i]._destroy(),this._bindings.splice(i,1)),e},removeAll:function(e){"undefined"==typeof e&&(e=null);for(var t=this._bindings.length;t--;)e?this._bindings[t].context===e&&(this._bindings[t]._destroy(),this._bindings.splice(t,1)):this._bindings[t]._destroy();e||(this._bindings.length=0)},getNumListeners:function(){return this._bindings.length},halt:function(){this._shouldPropagate=!1},dispatch:function(){if(this.active){var e,t=Array.prototype.slice.call(arguments),i=this._bindings.length;if(this.memorize&&(this._prevParams=t),i){e=this._bindings.slice(),this._shouldPropagate=!0;do i--;while(e[i]&&this._shouldPropagate&&e[i].execute(t)!==!1)}}},forget:function(){this._prevParams=null},dispose:function(){this.removeAll(),delete this._bindings,delete this._prevParams},toString:function(){return"[Signal active:"+this.active+" numListeners:"+this.getNumListeners()+"]"}},t.prototype.constructor=t,vg.Signal=t}(),vg.AStarFinder=function(e){e=e||{};var t={allowDiagonal:!1,heuristicFilter:null};t=vg.Tools.merge(t,e),this.allowDiagonal=t.allowDiagonal,this.heuristicFilter=t.heuristicFilter,this.list=new vg.LinkedList},vg.AStarFinder.prototype={findPath:function(e,t,i,s){var n,l,r,h,o,a;for(i=i||this.heuristicFilter,s.clearPath(),this.list.clear(),this.list.add(e);this.list.length>0;){if(this.list.sort(this.compare),n=this.list.shift(),n._visited=!0,n===t)return vg.PathUtil.backtrace(t);for(r=s.getNeighbors(n,this.allowDiagonal,i),o=0,a=r.length;a>o;o++)if(h=r[o],h.walkable&&(l=n._calcCost+s.distance(n,h),!h._visited||l<h._calcCost)){if(h._visited=!0,h._parent=n,h._calcCost=l,h._priority=l+s.distance(t,h),h===t)return vg.PathUtil.backtrace(t);this.list.add(h)}}return null},compare:function(e,t){return e._priority-t._priority}},vg.AStarFinder.prototype.constructor=vg.AStarFinder,vg.PathUtil={backtrace:function(e){for(var t=[e];e._parent;)e=e._parent,t.push(e);return t.reverse()},biBacktrace:function(e,t){var i=this.backtrace(e),s=this.backtrace(t);return i.concat(s.reverse())},pathLength:function(e){var t,i,s,n,l,r=0;for(t=1;t<e.length;++t)i=e[t-1],s=e[t],n=i[0]-s[0],l=i[1]-s[1],r+=Math.sqrt(n*n+l*l);return r},interpolate:function(e,t,i,s){var n,l,r,h,o,a,c=Math.abs,u=[];for(r=c(i-e),h=c(s-t),n=i>e?1:-1,l=s>t?1:-1,o=r-h;e!==i||t!==s;)u.push([e,t]),a=2*o,a>-h&&(o-=h,e+=n),r>a&&(o+=r,t+=l);return u},expandPath:function(e){var t,i,s,n,l,r,h=[],o=e.length;if(2>o)return h;for(l=0;o-1>l;++l)for(t=e[l],i=e[l+1],s=this.interpolate(t[0],t[1],i[0],i[1]),n=s.length,r=0;n-1>r;++r)h.push(s[r]);return h.push(e[o-1]),h},smoothenPath:function(e,t){var i,s,n,l,r,h,o,a,c,u,d,g,p=t.length,v=t[0][0],f=t[0][1],m=t[p-1][0],_=t[p-1][1];for(i=v,s=f,r=[[i,s]],o=2;p>o;++o){for(c=t[o],n=c[0],l=c[1],u=this.interpolate(i,s,n,l),g=!1,a=1;a<u.length;++a)if(d=u[a],!e.isWalkableAt(d[0],d[1])){g=!0;break}g&&(h=t[o-1],r.push(h),i=h[0],s=h[1])}return r.push([m,_]),r},compressPath:function(e){if(e.length<3)return e;var t,i,s,n,l,r,h=[],o=e[0][0],a=e[0][1],c=e[1][0],u=e[1][1],d=c-o,g=u-a;for(l=Math.sqrt(d*d+g*g),d/=l,g/=l,h.push([o,a]),r=2;r<e.length;r++)t=c,i=u,s=d,n=g,c=e[r][0],u=e[r][1],d=c-t,g=u-i,l=Math.sqrt(d*d+g*g),d/=l,g/=l,(d!==s||g!==n)&&h.push([t,i]);return h.push([c,u]),h}},vg.Loader={manager:null,imageLoader:null,crossOrigin:!1,init:function(e){this.crossOrigin=e||!1,this.manager=new THREE.LoadingManager(function(){},function(){},function(){console.warn("Error loading images")}),this.imageLoader=new THREE.ImageLoader(this.manager),this.imageLoader.crossOrigin=e},loadTexture:function(e,t,i,s){var n=new THREE.Texture(null,t);return this.imageLoader.load(e,function(e){n.image=e,n.needsUpdate=!0,i&&i(n)},null,function(e){s&&s(e)}),n.sourceFile=e,n}},vg.MouseCaster=function(e,t,i){this.down=!1,this.rightDown=!1,this.pickedObject=null,this.selectedObject=null,this.allHits=null,this.active=!0,this.shift=!1,this.ctrl=!1,this.wheel=0,this.position=new THREE.Vector3,this.screenPosition=new THREE.Vector2,this.signal=new vg.Signal,this.group=e,this._camera=t,this._raycaster=new THREE.Raycaster,this._preventDefault=!1,i=i||document,i.addEventListener("mousemove",this._onDocumentMouseMove.bind(this),!1),i.addEventListener("mousedown",this._onDocumentMouseDown.bind(this),!1),i.addEventListener("mouseup",this._onDocumentMouseUp.bind(this),!1),i.addEventListener("mousewheel",this._onMouseWheel.bind(this),!1),i.addEventListener("DOMMouseScroll",this._onMouseWheel.bind(this),!1)},vg.MouseCaster.OVER="over",vg.MouseCaster.OUT="out",vg.MouseCaster.DOWN="down",vg.MouseCaster.UP="up",vg.MouseCaster.CLICK="click",vg.MouseCaster.WHEEL="wheel",vg.MouseCaster.prototype={update:function(){if(this.active){this._raycaster.setFromCamera(this.screenPosition,this._camera);var e,t,i=this._raycaster.intersectObject(this.group,!0);i.length>0?(e=i[0],t=e.object.userData.structure,this.pickedObject!=t&&(this.pickedObject&&this.signal.dispatch(vg.MouseCaster.OUT,this.pickedObject),this.pickedObject=t,this.selectedObject=null,this.signal.dispatch(vg.MouseCaster.OVER,this.pickedObject)),this.position.copy(e.point),this.screenPosition.z=e.distance):(this.pickedObject&&this.signal.dispatch(vg.MouseCaster.OUT,this.pickedObject),this.pickedObject=null,this.selectedObject=null),this.allHits=i}},preventDefault:function(){this._preventDefault=!0},_onDocumentMouseDown:function(e){return e=e||window.event,e.preventDefault(),this._preventDefault?(this._preventDefault=!1,!1):(this.pickedObject&&(this.selectedObject=this.pickedObject),this.shift=e.shiftKey,this.ctrl=e.ctrlKey,this.down=1===e.which,this.rightDown=3===e.which,void this.signal.dispatch(vg.MouseCaster.DOWN,this.pickedObject))},_onDocumentMouseUp:function(e){return e.preventDefault(),this._preventDefault?(this._preventDefault=!1,!1):(this.shift=e.shiftKey,this.ctrl=e.ctrlKey,this.signal.dispatch(vg.MouseCaster.UP,this.pickedObject),this.selectedObject&&this.pickedObject&&this.selectedObject.uniqueID===this.pickedObject.uniqueID&&this.signal.dispatch(vg.MouseCaster.CLICK,this.pickedObject),this.down=1===e.which?!1:this.down,void(this.rightDown=3===e.which?!1:this.rightDown))},_onDocumentMouseMove:function(e){e.preventDefault(),this.screenPosition.x=e.clientX/window.innerWidth*2-1,this.screenPosition.y=2*-(e.clientY/window.innerHeight)+1},_onMouseWheel:function(e){if(this.active){e.preventDefault(),e.stopPropagation();var t=0;void 0!==e.wheelDelta?t=e.wheelDelta:void 0!==e.detail&&(t=-e.detail),t>0?this.wheel++:this.wheel--,this.signal.dispatch(vg.MouseCaster.WHEEL,this.wheel)}}},vg.MouseCaster.prototype.constructor=vg.MouseCaster,vg.Scene=function(e,t){var i={element:document.body,alpha:!0,antialias:!0,clearColor:"#fff",sortObjects:!1,fog:null,light:new THREE.DirectionalLight(16777215),lightPosition:null,cameraType:"PerspectiveCamera",cameraPosition:null,orthoZoom:4},s={minDistance:100,maxDistance:1e3,zoomSpeed:2,noZoom:!1};if(i=vg.Tools.merge(i,e),"boolean"!=typeof t&&(s=vg.Tools.merge(s,t)),this.renderer=new THREE.WebGLRenderer({alpha:i.alpha,antialias:i.antialias}),this.renderer.setClearColor(i.clearColor,0),this.renderer.sortObjects=i.sortObjects,this.width=window.innerWidth,this.height=window.innerHeight,this.orthoZoom=i.orthoZoom,this.container=new THREE.Scene,this.container.fog=i.fog,this.container.add(new THREE.AmbientLight(14540253)),i.lightPosition||i.light.position.set(-1,1,-1).normalize(),this.container.add(i.light),"OrthographicCamera"===i.cameraType){var n=window.innerWidth/this.orthoZoom,l=window.innerHeight/this.orthoZoom;this.camera=new THREE.OrthographicCamera(n/-2,n/2,l/2,l/-2,1,5e3)}else this.camera=new THREE.PerspectiveCamera(50,this.width/this.height,1,5e3);this.contolled=!!t,this.contolled&&(this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement),this.controls.minDistance=s.minDistance,this.controls.maxDistance=s.maxDistance,this.controls.zoomSpeed=s.zoomSpeed,this.controls.noZoom=s.noZoom),i.cameraPosition&&this.camera.position.copy(i.cameraPosition),window.addEventListener("resize",function(){if(this.width=window.innerWidth,this.height=window.innerHeight,"OrthographicCamera"===this.camera.type){var e=this.width/this.orthoZoom,t=this.height/this.orthoZoom;this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2}else this.camera.aspect=this.width/this.height;this.camera.updateProjectionMatrix(),this.renderer.setSize(this.width,this.height)}.bind(this),!1),this.attachTo(i.element)},vg.Scene.prototype={attachTo:function(e){e.style.width=this.width+"px",e.style.height=this.height+"px",this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(this.width,this.height),e.appendChild(this.renderer.domElement)},add:function(e){this.container.add(e)},remove:function(e){this.container.remove(e)},render:function(){this.contolled&&this.controls.update(),this.renderer.render(this.container,this.camera)},updateOrthoZoom:function(){if(this.orthoZoom<=0)return void(this.orthoZoom=0);var e=this.width/this.orthoZoom,t=this.height/this.orthoZoom;this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2,this.camera.updateProjectionMatrix()},focusOn:function(e){this.camera.lookAt(e.position)}},vg.Scene.prototype.constructor=vg.Scene,vg.SelectionManager=function(e){this.mouse=e,this.onSelect=new vg.Signal,this.onDeselect=new vg.Signal,this.selected=null,this.toggleSelection=!1,this.mouse.signal.add(this.onMouse,this)},vg.SelectionManager.prototype={select:function(e,t){e&&(t=t||!0,this.selected!==e&&this.clearSelection(t),e.selected?this.toggleSelection&&(t&&this.onDeselect.dispatch(e),e.deselect()):e.select(),this.selected=e,t&&this.onSelect.dispatch(e))},clearSelection:function(e){e=e||!0,this.selected&&(e&&this.onDeselect.dispatch(this.selected),this.selected.deselect()),this.selected=null},onMouse:function(e,t){switch(e){case vg.MouseCaster.DOWN:t||this.clearSelection();break;case vg.MouseCaster.CLICK:this.select(t)}}},vg.SelectionManager.prototype.constructor=vg.SelectionManager,vg.Tools={clamp:function(e,t,i){return Math.max(t,Math.min(i,e))},sign:function(e){return e&&e/Math.abs(e)},random:function(e,t){return 1===arguments.length?Math.random()*e-.5*e:Math.random()*(t-e)+e},randomInt:function(e,t){return 1===arguments.length?Math.random()*e-.5*e|0:Math.random()*(t-e+1)+e|0},normalize:function(e,t,i){return(e-t)/(i-t)},getShortRotation:function(e){return e%=this.TAU,e>this.PI?e-=this.TAU:e<-this.PI&&(e+=this.TAU),e},generateID:function(){return Math.random().toString(36).slice(2)+Date.now()},isPlainObject:function(e){if("object"!=typeof e||e.nodeType||e===e.window)return!1;try{if(e.constructor&&!Object.prototype.hasOwnProperty.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},merge:function(e,t){var i=this,s=Array.isArray(t),n=s&&[]||{};return s?(e=e||[],n=n.concat(e),t.forEach(function(t,s){"undefined"==typeof n[s]?n[s]=t:i.isPlainObject(t)?n[s]=i.merge(e[s],t):-1===e.indexOf(t)&&n.push(t)}),n):(e&&i.isPlainObject(e)&&Object.keys(e).forEach(function(t){n[t]=e[t];
  4103. }),Object.keys(t).forEach(function(s){t[s]&&i.isPlainObject(t[s])&&e[s]?n[s]=i.merge(e[s],t[s]):n[s]=t[s]}),n)},now:function(){return window.nwf?window.nwf.system.Performance.elapsedTime:window.performance.now()},empty:function(e){for(;e.lastChild;)e.removeChild(e.lastChild)},radixSort:function(e,t,i,s){if(t=t||0,i=i||e.length,s=s||31,!(t>=i-1||0>s)){for(var n=t,l=i,r=1<<s;l>n;)if(e[n]&r){--l;var h=e[n];e[n]=e[l],e[l]=h}else++n;this.radixSort(e,t,l,s-1),this.radixSort(e,l,i,s-1)}},randomizeRGB:function(e,t){var i,s,n=e.split(","),l="rgb(";for(t=this.randomInt(t),i=0;3>i;i++)s=parseInt(n[i])+t,0>s?s=0:s>255&&(s=255),l+=s+",";return l=l.substring(0,l.length-1),l+=")"},getJSON:function(e){var t=new XMLHttpRequest,i="undefined"==typeof e.cache?!1:e.cache,s=i?e.url:e.url+"?t="+Math.floor(1e4*Math.random())+Date.now();t.onreadystatechange=function(){if(200===this.status){var t=null;try{t=JSON.parse(this.responseText)}catch(i){return}return void e.callback.call(e.scope||null,t)}0!==this.status&&console.warn("[Tools.getJSON] Error: "+this.status+" ("+this.statusText+") :: "+e.url)},t.open("GET",s,!0),t.setRequestHeader("Accept","application/json"),t.setRequestHeader("Content-Type","application/json"),t.send("")}};
  4104. },{}],10:[function(require,module,exports){
  4105. /**
  4106. * Polyfill for the additional KeyboardEvent properties defined in the D3E and
  4107. * D4E draft specifications, by @inexorabletash.
  4108. *
  4109. * See: https://github.com/inexorabletash/polyfill
  4110. */
  4111. (function(global) {
  4112. var nativeKeyboardEvent = ('KeyboardEvent' in global);
  4113. if (!nativeKeyboardEvent)
  4114. global.KeyboardEvent = function KeyboardEvent() { throw TypeError('Illegal constructor'); };
  4115. global.KeyboardEvent.DOM_KEY_LOCATION_STANDARD = 0x00; // Default or unknown location
  4116. global.KeyboardEvent.DOM_KEY_LOCATION_LEFT = 0x01; // e.g. Left Alt key
  4117. global.KeyboardEvent.DOM_KEY_LOCATION_RIGHT = 0x02; // e.g. Right Alt key
  4118. global.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD = 0x03; // e.g. Numpad 0 or +
  4119. var STANDARD = window.KeyboardEvent.DOM_KEY_LOCATION_STANDARD,
  4120. LEFT = window.KeyboardEvent.DOM_KEY_LOCATION_LEFT,
  4121. RIGHT = window.KeyboardEvent.DOM_KEY_LOCATION_RIGHT,
  4122. NUMPAD = window.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD;
  4123. //--------------------------------------------------------------------
  4124. //
  4125. // Utilities
  4126. //
  4127. //--------------------------------------------------------------------
  4128. function contains(s, ss) { return String(s).indexOf(ss) !== -1; }
  4129. var os = (function() {
  4130. if (contains(navigator.platform, 'Win')) { return 'win'; }
  4131. if (contains(navigator.platform, 'Mac')) { return 'mac'; }
  4132. if (contains(navigator.platform, 'CrOS')) { return 'cros'; }
  4133. if (contains(navigator.platform, 'Linux')) { return 'linux'; }
  4134. if (contains(navigator.userAgent, 'iPad') || contains(navigator.platform, 'iPod') || contains(navigator.platform, 'iPhone')) { return 'ios'; }
  4135. return '';
  4136. } ());
  4137. var browser = (function() {
  4138. if (contains(navigator.userAgent, 'Chrome/')) { return 'chrome'; }
  4139. if (contains(navigator.vendor, 'Apple')) { return 'safari'; }
  4140. if (contains(navigator.userAgent, 'MSIE')) { return 'ie'; }
  4141. if (contains(navigator.userAgent, 'Gecko/')) { return 'moz'; }
  4142. if (contains(navigator.userAgent, 'Opera/')) { return 'opera'; }
  4143. return '';
  4144. } ());
  4145. var browser_os = browser + '-' + os;
  4146. function mergeIf(baseTable, select, table) {
  4147. if (browser_os === select || browser === select || os === select) {
  4148. Object.keys(table).forEach(function(keyCode) {
  4149. baseTable[keyCode] = table[keyCode];
  4150. });
  4151. }
  4152. }
  4153. function remap(o, key) {
  4154. var r = {};
  4155. Object.keys(o).forEach(function(k) {
  4156. var item = o[k];
  4157. if (key in item) {
  4158. r[item[key]] = item;
  4159. }
  4160. });
  4161. return r;
  4162. }
  4163. function invert(o) {
  4164. var r = {};
  4165. Object.keys(o).forEach(function(k) {
  4166. r[o[k]] = k;
  4167. });
  4168. return r;
  4169. }
  4170. //--------------------------------------------------------------------
  4171. //
  4172. // Generic Mappings
  4173. //
  4174. //--------------------------------------------------------------------
  4175. // "keyInfo" is a dictionary:
  4176. // code: string - name from DOM Level 3 KeyboardEvent code Values
  4177. // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html
  4178. // location (optional): number - one of the DOM_KEY_LOCATION values
  4179. // keyCap (optional): string - keyboard label in en-US locale
  4180. // USB code Usage ID from page 0x07 unless otherwise noted (Informative)
  4181. // Map of keyCode to keyInfo
  4182. var keyCodeToInfoTable = {
  4183. // 0x01 - VK_LBUTTON
  4184. // 0x02 - VK_RBUTTON
  4185. 0x03: { code: 'Cancel' }, // [USB: 0x9b] char \x0018 ??? (Not in D3E)
  4186. // 0x04 - VK_MBUTTON
  4187. // 0x05 - VK_XBUTTON1
  4188. // 0x06 - VK_XBUTTON2
  4189. 0x06: { code: 'Help' }, // [USB: 0x75] ???
  4190. // 0x07 - undefined
  4191. 0x08: { code: 'Backspace' }, // [USB: 0x2a] Labelled Delete on Macintosh keyboards.
  4192. 0x09: { code: 'Tab' }, // [USB: 0x2b]
  4193. // 0x0A-0x0B - reserved
  4194. 0X0C: { code: 'Clear' }, // [USB: 0x9c] NumPad Center (Not in D3E)
  4195. 0X0D: { code: 'Enter' }, // [USB: 0x28]
  4196. // 0x0E-0x0F - undefined
  4197. 0x10: { code: 'Shift' },
  4198. 0x11: { code: 'Control' },
  4199. 0x12: { code: 'Alt' },
  4200. 0x13: { code: 'Pause' }, // [USB: 0x48]
  4201. 0x14: { code: 'CapsLock' }, // [USB: 0x39]
  4202. 0x15: { code: 'KanaMode' }, // [USB: 0x88] - "HangulMode" for Korean layout
  4203. 0x16: { code: 'HangulMode' }, // [USB: 0x90] 0x15 as well in MSDN VK table ???
  4204. 0x17: { code: 'JunjaMode' }, // (Not in D3E)
  4205. 0x18: { code: 'FinalMode' }, // (Not in D3E)
  4206. 0x19: { code: 'KanjiMode' }, // [USB: 0x91] - "HanjaMode" for Korean layout
  4207. // 0x1A - undefined
  4208. 0x1B: { code: 'Escape' }, // [USB: 0x29]
  4209. 0x1C: { code: 'Convert' }, // [USB: 0x8a]
  4210. 0x1D: { code: 'NonConvert' }, // [USB: 0x8b]
  4211. 0x1E: { code: 'Accept' }, // (Not in D3E)
  4212. 0x1F: { code: 'ModeChange' }, // (Not in D3E)
  4213. 0x20: { code: 'Space' }, // [USB: 0x2c]
  4214. 0x21: { code: 'PageUp' }, // [USB: 0x4b]
  4215. 0x22: { code: 'PageDown' }, // [USB: 0x4e]
  4216. 0x23: { code: 'End' }, // [USB: 0x4d]
  4217. 0x24: { code: 'Home' }, // [USB: 0x4a]
  4218. 0x25: { code: 'ArrowLeft' }, // [USB: 0x50]
  4219. 0x26: { code: 'ArrowUp' }, // [USB: 0x52]
  4220. 0x27: { code: 'ArrowRight' }, // [USB: 0x4f]
  4221. 0x28: { code: 'ArrowDown' }, // [USB: 0x51]
  4222. 0x29: { code: 'Select' }, // (Not in D3E)
  4223. 0x2A: { code: 'Print' }, // (Not in D3E)
  4224. 0x2B: { code: 'Execute' }, // [USB: 0x74] (Not in D3E)
  4225. 0x2C: { code: 'PrintScreen' }, // [USB: 0x46]
  4226. 0x2D: { code: 'Insert' }, // [USB: 0x49]
  4227. 0x2E: { code: 'Delete' }, // [USB: 0x4c]
  4228. 0x2F: { code: 'Help' }, // [USB: 0x75] ???
  4229. 0x30: { code: 'Digit0', keyCap: '0' }, // [USB: 0x27] 0)
  4230. 0x31: { code: 'Digit1', keyCap: '1' }, // [USB: 0x1e] 1!
  4231. 0x32: { code: 'Digit2', keyCap: '2' }, // [USB: 0x1f] 2@
  4232. 0x33: { code: 'Digit3', keyCap: '3' }, // [USB: 0x20] 3#
  4233. 0x34: { code: 'Digit4', keyCap: '4' }, // [USB: 0x21] 4$
  4234. 0x35: { code: 'Digit5', keyCap: '5' }, // [USB: 0x22] 5%
  4235. 0x36: { code: 'Digit6', keyCap: '6' }, // [USB: 0x23] 6^
  4236. 0x37: { code: 'Digit7', keyCap: '7' }, // [USB: 0x24] 7&
  4237. 0x38: { code: 'Digit8', keyCap: '8' }, // [USB: 0x25] 8*
  4238. 0x39: { code: 'Digit9', keyCap: '9' }, // [USB: 0x26] 9(
  4239. // 0x3A-0x40 - undefined
  4240. 0x41: { code: 'KeyA', keyCap: 'a' }, // [USB: 0x04]
  4241. 0x42: { code: 'KeyB', keyCap: 'b' }, // [USB: 0x05]
  4242. 0x43: { code: 'KeyC', keyCap: 'c' }, // [USB: 0x06]
  4243. 0x44: { code: 'KeyD', keyCap: 'd' }, // [USB: 0x07]
  4244. 0x45: { code: 'KeyE', keyCap: 'e' }, // [USB: 0x08]
  4245. 0x46: { code: 'KeyF', keyCap: 'f' }, // [USB: 0x09]
  4246. 0x47: { code: 'KeyG', keyCap: 'g' }, // [USB: 0x0a]
  4247. 0x48: { code: 'KeyH', keyCap: 'h' }, // [USB: 0x0b]
  4248. 0x49: { code: 'KeyI', keyCap: 'i' }, // [USB: 0x0c]
  4249. 0x4A: { code: 'KeyJ', keyCap: 'j' }, // [USB: 0x0d]
  4250. 0x4B: { code: 'KeyK', keyCap: 'k' }, // [USB: 0x0e]
  4251. 0x4C: { code: 'KeyL', keyCap: 'l' }, // [USB: 0x0f]
  4252. 0x4D: { code: 'KeyM', keyCap: 'm' }, // [USB: 0x10]
  4253. 0x4E: { code: 'KeyN', keyCap: 'n' }, // [USB: 0x11]
  4254. 0x4F: { code: 'KeyO', keyCap: 'o' }, // [USB: 0x12]
  4255. 0x50: { code: 'KeyP', keyCap: 'p' }, // [USB: 0x13]
  4256. 0x51: { code: 'KeyQ', keyCap: 'q' }, // [USB: 0x14]
  4257. 0x52: { code: 'KeyR', keyCap: 'r' }, // [USB: 0x15]
  4258. 0x53: { code: 'KeyS', keyCap: 's' }, // [USB: 0x16]
  4259. 0x54: { code: 'KeyT', keyCap: 't' }, // [USB: 0x17]
  4260. 0x55: { code: 'KeyU', keyCap: 'u' }, // [USB: 0x18]
  4261. 0x56: { code: 'KeyV', keyCap: 'v' }, // [USB: 0x19]
  4262. 0x57: { code: 'KeyW', keyCap: 'w' }, // [USB: 0x1a]
  4263. 0x58: { code: 'KeyX', keyCap: 'x' }, // [USB: 0x1b]
  4264. 0x59: { code: 'KeyY', keyCap: 'y' }, // [USB: 0x1c]
  4265. 0x5A: { code: 'KeyZ', keyCap: 'z' }, // [USB: 0x1d]
  4266. 0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]
  4267. 0x5C: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]
  4268. 0x5D: { code: 'ContextMenu' }, // [USB: 0x65] Context Menu
  4269. // 0x5E - reserved
  4270. 0x5F: { code: 'Standby' }, // [USB: 0x82] Sleep
  4271. 0x60: { code: 'Numpad0', keyCap: '0', location: NUMPAD }, // [USB: 0x62]
  4272. 0x61: { code: 'Numpad1', keyCap: '1', location: NUMPAD }, // [USB: 0x59]
  4273. 0x62: { code: 'Numpad2', keyCap: '2', location: NUMPAD }, // [USB: 0x5a]
  4274. 0x63: { code: 'Numpad3', keyCap: '3', location: NUMPAD }, // [USB: 0x5b]
  4275. 0x64: { code: 'Numpad4', keyCap: '4', location: NUMPAD }, // [USB: 0x5c]
  4276. 0x65: { code: 'Numpad5', keyCap: '5', location: NUMPAD }, // [USB: 0x5d]
  4277. 0x66: { code: 'Numpad6', keyCap: '6', location: NUMPAD }, // [USB: 0x5e]
  4278. 0x67: { code: 'Numpad7', keyCap: '7', location: NUMPAD }, // [USB: 0x5f]
  4279. 0x68: { code: 'Numpad8', keyCap: '8', location: NUMPAD }, // [USB: 0x60]
  4280. 0x69: { code: 'Numpad9', keyCap: '9', location: NUMPAD }, // [USB: 0x61]
  4281. 0x6A: { code: 'NumpadMultiply', keyCap: '*', location: NUMPAD }, // [USB: 0x55]
  4282. 0x6B: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]
  4283. 0x6C: { code: 'NumpadComma', keyCap: ',', location: NUMPAD }, // [USB: 0x85]
  4284. 0x6D: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD }, // [USB: 0x56]
  4285. 0x6E: { code: 'NumpadDecimal', keyCap: '.', location: NUMPAD }, // [USB: 0x63]
  4286. 0x6F: { code: 'NumpadDivide', keyCap: '/', location: NUMPAD }, // [USB: 0x54]
  4287. 0x70: { code: 'F1' }, // [USB: 0x3a]
  4288. 0x71: { code: 'F2' }, // [USB: 0x3b]
  4289. 0x72: { code: 'F3' }, // [USB: 0x3c]
  4290. 0x73: { code: 'F4' }, // [USB: 0x3d]
  4291. 0x74: { code: 'F5' }, // [USB: 0x3e]
  4292. 0x75: { code: 'F6' }, // [USB: 0x3f]
  4293. 0x76: { code: 'F7' }, // [USB: 0x40]
  4294. 0x77: { code: 'F8' }, // [USB: 0x41]
  4295. 0x78: { code: 'F9' }, // [USB: 0x42]
  4296. 0x79: { code: 'F10' }, // [USB: 0x43]
  4297. 0x7A: { code: 'F11' }, // [USB: 0x44]
  4298. 0x7B: { code: 'F12' }, // [USB: 0x45]
  4299. 0x7C: { code: 'F13' }, // [USB: 0x68]
  4300. 0x7D: { code: 'F14' }, // [USB: 0x69]
  4301. 0x7E: { code: 'F15' }, // [USB: 0x6a]
  4302. 0x7F: { code: 'F16' }, // [USB: 0x6b]
  4303. 0x80: { code: 'F17' }, // [USB: 0x6c]
  4304. 0x81: { code: 'F18' }, // [USB: 0x6d]
  4305. 0x82: { code: 'F19' }, // [USB: 0x6e]
  4306. 0x83: { code: 'F20' }, // [USB: 0x6f]
  4307. 0x84: { code: 'F21' }, // [USB: 0x70]
  4308. 0x85: { code: 'F22' }, // [USB: 0x71]
  4309. 0x86: { code: 'F23' }, // [USB: 0x72]
  4310. 0x87: { code: 'F24' }, // [USB: 0x73]
  4311. // 0x88-0x8F - unassigned
  4312. 0x90: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  4313. 0x91: { code: 'ScrollLock' }, // [USB: 0x47]
  4314. // 0x92-0x96 - OEM specific
  4315. // 0x97-0x9F - unassigned
  4316. // NOTE: 0xA0-0xA5 usually mapped to 0x10-0x12 in browsers
  4317. 0xA0: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]
  4318. 0xA1: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]
  4319. 0xA2: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]
  4320. 0xA3: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]
  4321. 0xA4: { code: 'AltLeft', location: LEFT }, // [USB: 0xe2]
  4322. 0xA5: { code: 'AltRight', location: RIGHT }, // [USB: 0xe6]
  4323. 0xA6: { code: 'BrowserBack' }, // [USB: 0x0c/0x0224]
  4324. 0xA7: { code: 'BrowserForward' }, // [USB: 0x0c/0x0225]
  4325. 0xA8: { code: 'BrowserRefresh' }, // [USB: 0x0c/0x0227]
  4326. 0xA9: { code: 'BrowserStop' }, // [USB: 0x0c/0x0226]
  4327. 0xAA: { code: 'BrowserSearch' }, // [USB: 0x0c/0x0221]
  4328. 0xAB: { code: 'BrowserFavorites' }, // [USB: 0x0c/0x0228]
  4329. 0xAC: { code: 'BrowserHome' }, // [USB: 0x0c/0x0222]
  4330. 0xAD: { code: 'VolumeMute' }, // [USB: 0x7f]
  4331. 0xAE: { code: 'VolumeDown' }, // [USB: 0x81]
  4332. 0xAF: { code: 'VolumeUp' }, // [USB: 0x80]
  4333. 0xB0: { code: 'MediaTrackNext' }, // [USB: 0x0c/0x00b5]
  4334. 0xB1: { code: 'MediaTrackPrevious' }, // [USB: 0x0c/0x00b6]
  4335. 0xB2: { code: 'MediaStop' }, // [USB: 0x0c/0x00b7]
  4336. 0xB3: { code: 'MediaPlayPause' }, // [USB: 0x0c/0x00cd]
  4337. 0xB4: { code: 'LaunchMail' }, // [USB: 0x0c/0x018a]
  4338. 0xB5: { code: 'MediaSelect' },
  4339. 0xB6: { code: 'LaunchApp1' },
  4340. 0xB7: { code: 'LaunchApp2' },
  4341. // 0xB8-0xB9 - reserved
  4342. 0xBA: { code: 'Semicolon', keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)
  4343. 0xBB: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  4344. 0xBC: { code: 'Comma', keyCap: ',' }, // [USB: 0x36] ,<
  4345. 0xBD: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_
  4346. 0xBE: { code: 'Period', keyCap: '.' }, // [USB: 0x37] .>
  4347. 0xBF: { code: 'Slash', keyCap: '/' }, // [USB: 0x38] /? (US Standard 101)
  4348. 0xC0: { code: 'Backquote', keyCap: '`' }, // [USB: 0x35] `~ (US Standard 101)
  4349. // 0xC1-0xCF - reserved
  4350. // 0xD0-0xD7 - reserved
  4351. // 0xD8-0xDA - unassigned
  4352. 0xDB: { code: 'BracketLeft', keyCap: '[' }, // [USB: 0x2f] [{ (US Standard 101)
  4353. 0xDC: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  4354. 0xDD: { code: 'BracketRight', keyCap: ']' }, // [USB: 0x30] ]} (US Standard 101)
  4355. 0xDE: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  4356. // 0xDF - miscellaneous/varies
  4357. // 0xE0 - reserved
  4358. // 0xE1 - OEM specific
  4359. 0xE2: { code: 'IntlBackslash', keyCap: '\\' }, // [USB: 0x64] \| (UK Standard 102)
  4360. // 0xE3-0xE4 - OEM specific
  4361. 0xE5: { code: 'Process' }, // (Not in D3E)
  4362. // 0xE6 - OEM specific
  4363. // 0xE7 - VK_PACKET
  4364. // 0xE8 - unassigned
  4365. // 0xE9-0xEF - OEM specific
  4366. // 0xF0-0xF5 - OEM specific
  4367. 0xF6: { code: 'Attn' }, // [USB: 0x9a] (Not in D3E)
  4368. 0xF7: { code: 'CrSel' }, // [USB: 0xa3] (Not in D3E)
  4369. 0xF8: { code: 'ExSel' }, // [USB: 0xa4] (Not in D3E)
  4370. 0xF9: { code: 'EraseEof' }, // (Not in D3E)
  4371. 0xFA: { code: 'Play' }, // (Not in D3E)
  4372. 0xFB: { code: 'ZoomToggle' }, // (Not in D3E)
  4373. // 0xFC - VK_NONAME - reserved
  4374. // 0xFD - VK_PA1
  4375. 0xFE: { code: 'Clear' } // [USB: 0x9c] (Not in D3E)
  4376. };
  4377. // No legacy keyCode, but listed in D3E:
  4378. // code: usb
  4379. // 'IntlHash': 0x070032,
  4380. // 'IntlRo': 0x070087,
  4381. // 'IntlYen': 0x070089,
  4382. // 'NumpadBackspace': 0x0700bb,
  4383. // 'NumpadClear': 0x0700d8,
  4384. // 'NumpadClearEntry': 0x0700d9,
  4385. // 'NumpadMemoryAdd': 0x0700d3,
  4386. // 'NumpadMemoryClear': 0x0700d2,
  4387. // 'NumpadMemoryRecall': 0x0700d1,
  4388. // 'NumpadMemoryStore': 0x0700d0,
  4389. // 'NumpadMemorySubtract': 0x0700d4,
  4390. // 'NumpadParenLeft': 0x0700b6,
  4391. // 'NumpadParenRight': 0x0700b7,
  4392. //--------------------------------------------------------------------
  4393. //
  4394. // Browser/OS Specific Mappings
  4395. //
  4396. //--------------------------------------------------------------------
  4397. mergeIf(keyCodeToInfoTable,
  4398. 'moz', {
  4399. 0x3B: { code: 'Semicolon', keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)
  4400. 0x3D: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  4401. 0x6B: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  4402. 0x6D: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_
  4403. 0xBB: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]
  4404. 0xBD: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD } // [USB: 0x56]
  4405. });
  4406. mergeIf(keyCodeToInfoTable,
  4407. 'moz-mac', {
  4408. 0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  4409. 0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_
  4410. });
  4411. mergeIf(keyCodeToInfoTable,
  4412. 'moz-win', {
  4413. 0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_
  4414. });
  4415. mergeIf(keyCodeToInfoTable,
  4416. 'chrome-mac', {
  4417. 0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  4418. });
  4419. // Windows via Bootcamp (!)
  4420. if (0) {
  4421. mergeIf(keyCodeToInfoTable,
  4422. 'chrome-win', {
  4423. 0xC0: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  4424. 0xDE: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  4425. 0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)
  4426. });
  4427. mergeIf(keyCodeToInfoTable,
  4428. 'ie', {
  4429. 0xC0: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  4430. 0xDE: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  4431. 0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)
  4432. });
  4433. }
  4434. mergeIf(keyCodeToInfoTable,
  4435. 'safari', {
  4436. 0x03: { code: 'Enter' }, // [USB: 0x28] old Safari
  4437. 0x19: { code: 'Tab' } // [USB: 0x2b] old Safari for Shift+Tab
  4438. });
  4439. mergeIf(keyCodeToInfoTable,
  4440. 'ios', {
  4441. 0x0A: { code: 'Enter', location: STANDARD } // [USB: 0x28]
  4442. });
  4443. mergeIf(keyCodeToInfoTable,
  4444. 'safari-mac', {
  4445. 0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]
  4446. 0x5D: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]
  4447. 0xE5: { code: 'KeyQ', keyCap: 'Q' } // [USB: 0x14] On alternate presses, Ctrl+Q sends this
  4448. });
  4449. //--------------------------------------------------------------------
  4450. //
  4451. // Identifier Mappings
  4452. //
  4453. //--------------------------------------------------------------------
  4454. // Cases where newer-ish browsers send keyIdentifier which can be
  4455. // used to disambiguate keys.
  4456. // keyIdentifierTable[keyIdentifier] -> keyInfo
  4457. var keyIdentifierTable = {};
  4458. if ('cros' === os) {
  4459. keyIdentifierTable['U+00A0'] = { code: 'ShiftLeft', location: LEFT };
  4460. keyIdentifierTable['U+00A1'] = { code: 'ShiftRight', location: RIGHT };
  4461. keyIdentifierTable['U+00A2'] = { code: 'ControlLeft', location: LEFT };
  4462. keyIdentifierTable['U+00A3'] = { code: 'ControlRight', location: RIGHT };
  4463. keyIdentifierTable['U+00A4'] = { code: 'AltLeft', location: LEFT };
  4464. keyIdentifierTable['U+00A5'] = { code: 'AltRight', location: RIGHT };
  4465. }
  4466. if ('chrome-mac' === browser_os) {
  4467. keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };
  4468. }
  4469. if ('safari-mac' === browser_os) {
  4470. keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };
  4471. }
  4472. if ('ios' === os) {
  4473. // These only generate keyup events
  4474. keyIdentifierTable['U+0010'] = { code: 'Function' };
  4475. keyIdentifierTable['U+001C'] = { code: 'ArrowLeft' };
  4476. keyIdentifierTable['U+001D'] = { code: 'ArrowRight' };
  4477. keyIdentifierTable['U+001E'] = { code: 'ArrowUp' };
  4478. keyIdentifierTable['U+001F'] = { code: 'ArrowDown' };
  4479. keyIdentifierTable['U+0001'] = { code: 'Home' }; // [USB: 0x4a] Fn + ArrowLeft
  4480. keyIdentifierTable['U+0004'] = { code: 'End' }; // [USB: 0x4d] Fn + ArrowRight
  4481. keyIdentifierTable['U+000B'] = { code: 'PageUp' }; // [USB: 0x4b] Fn + ArrowUp
  4482. keyIdentifierTable['U+000C'] = { code: 'PageDown' }; // [USB: 0x4e] Fn + ArrowDown
  4483. }
  4484. //--------------------------------------------------------------------
  4485. //
  4486. // Location Mappings
  4487. //
  4488. //--------------------------------------------------------------------
  4489. // Cases where newer-ish browsers send location/keyLocation which
  4490. // can be used to disambiguate keys.
  4491. // locationTable[location][keyCode] -> keyInfo
  4492. var locationTable = [];
  4493. locationTable[LEFT] = {
  4494. 0x10: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]
  4495. 0x11: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]
  4496. 0x12: { code: 'AltLeft', location: LEFT } // [USB: 0xe2]
  4497. };
  4498. locationTable[RIGHT] = {
  4499. 0x10: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]
  4500. 0x11: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]
  4501. 0x12: { code: 'AltRight', location: RIGHT } // [USB: 0xe6]
  4502. };
  4503. locationTable[NUMPAD] = {
  4504. 0x0D: { code: 'NumpadEnter', location: NUMPAD } // [USB: 0x58]
  4505. };
  4506. mergeIf(locationTable[NUMPAD], 'moz', {
  4507. 0x6D: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]
  4508. 0x6B: { code: 'NumpadAdd', location: NUMPAD } // [USB: 0x57]
  4509. });
  4510. mergeIf(locationTable[LEFT], 'moz-mac', {
  4511. 0xE0: { code: 'OSLeft', location: LEFT } // [USB: 0xe3]
  4512. });
  4513. mergeIf(locationTable[RIGHT], 'moz-mac', {
  4514. 0xE0: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  4515. });
  4516. mergeIf(locationTable[RIGHT], 'moz-win', {
  4517. 0x5B: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  4518. });
  4519. mergeIf(locationTable[RIGHT], 'mac', {
  4520. 0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  4521. });
  4522. mergeIf(locationTable[NUMPAD], 'chrome-mac', {
  4523. 0x0C: { code: 'NumLock', location: NUMPAD } // [USB: 0x53]
  4524. });
  4525. mergeIf(locationTable[NUMPAD], 'safari-mac', {
  4526. 0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  4527. 0xBB: { code: 'NumpadAdd', location: NUMPAD }, // [USB: 0x57]
  4528. 0xBD: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]
  4529. 0xBE: { code: 'NumpadDecimal', location: NUMPAD }, // [USB: 0x63]
  4530. 0xBF: { code: 'NumpadDivide', location: NUMPAD } // [USB: 0x54]
  4531. });
  4532. //--------------------------------------------------------------------
  4533. //
  4534. // Key Values
  4535. //
  4536. //--------------------------------------------------------------------
  4537. // Mapping from `code` values to `key` values. Values defined at:
  4538. // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html
  4539. // Entries are only provided when `key` differs from `code`. If
  4540. // printable, `shiftKey` has the shifted printable character. This
  4541. // assumes US Standard 101 layout
  4542. var codeToKeyTable = {
  4543. // Modifier Keys
  4544. ShiftLeft: { key: 'Shift' },
  4545. ShiftRight: { key: 'Shift' },
  4546. ControlLeft: { key: 'Control' },
  4547. ControlRight: { key: 'Control' },
  4548. AltLeft: { key: 'Alt' },
  4549. AltRight: { key: 'Alt' },
  4550. OSLeft: { key: 'OS' },
  4551. OSRight: { key: 'OS' },
  4552. // Whitespace Keys
  4553. NumpadEnter: { key: 'Enter' },
  4554. Space: { key: ' ' },
  4555. // Printable Keys
  4556. Digit0: { key: '0', shiftKey: ')' },
  4557. Digit1: { key: '1', shiftKey: '!' },
  4558. Digit2: { key: '2', shiftKey: '@' },
  4559. Digit3: { key: '3', shiftKey: '#' },
  4560. Digit4: { key: '4', shiftKey: '$' },
  4561. Digit5: { key: '5', shiftKey: '%' },
  4562. Digit6: { key: '6', shiftKey: '^' },
  4563. Digit7: { key: '7', shiftKey: '&' },
  4564. Digit8: { key: '8', shiftKey: '*' },
  4565. Digit9: { key: '9', shiftKey: '(' },
  4566. KeyA: { key: 'a', shiftKey: 'A' },
  4567. KeyB: { key: 'b', shiftKey: 'B' },
  4568. KeyC: { key: 'c', shiftKey: 'C' },
  4569. KeyD: { key: 'd', shiftKey: 'D' },
  4570. KeyE: { key: 'e', shiftKey: 'E' },
  4571. KeyF: { key: 'f', shiftKey: 'F' },
  4572. KeyG: { key: 'g', shiftKey: 'G' },
  4573. KeyH: { key: 'h', shiftKey: 'H' },
  4574. KeyI: { key: 'i', shiftKey: 'I' },
  4575. KeyJ: { key: 'j', shiftKey: 'J' },
  4576. KeyK: { key: 'k', shiftKey: 'K' },
  4577. KeyL: { key: 'l', shiftKey: 'L' },
  4578. KeyM: { key: 'm', shiftKey: 'M' },
  4579. KeyN: { key: 'n', shiftKey: 'N' },
  4580. KeyO: { key: 'o', shiftKey: 'O' },
  4581. KeyP: { key: 'p', shiftKey: 'P' },
  4582. KeyQ: { key: 'q', shiftKey: 'Q' },
  4583. KeyR: { key: 'r', shiftKey: 'R' },
  4584. KeyS: { key: 's', shiftKey: 'S' },
  4585. KeyT: { key: 't', shiftKey: 'T' },
  4586. KeyU: { key: 'u', shiftKey: 'U' },
  4587. KeyV: { key: 'v', shiftKey: 'V' },
  4588. KeyW: { key: 'w', shiftKey: 'W' },
  4589. KeyX: { key: 'x', shiftKey: 'X' },
  4590. KeyY: { key: 'y', shiftKey: 'Y' },
  4591. KeyZ: { key: 'z', shiftKey: 'Z' },
  4592. Numpad0: { key: '0' },
  4593. Numpad1: { key: '1' },
  4594. Numpad2: { key: '2' },
  4595. Numpad3: { key: '3' },
  4596. Numpad4: { key: '4' },
  4597. Numpad5: { key: '5' },
  4598. Numpad6: { key: '6' },
  4599. Numpad7: { key: '7' },
  4600. Numpad8: { key: '8' },
  4601. Numpad9: { key: '9' },
  4602. NumpadMultiply: { key: '*' },
  4603. NumpadAdd: { key: '+' },
  4604. NumpadComma: { key: ',' },
  4605. NumpadSubtract: { key: '-' },
  4606. NumpadDecimal: { key: '.' },
  4607. NumpadDivide: { key: '/' },
  4608. Semicolon: { key: ';', shiftKey: ':' },
  4609. Equal: { key: '=', shiftKey: '+' },
  4610. Comma: { key: ',', shiftKey: '<' },
  4611. Minus: { key: '-', shiftKey: '_' },
  4612. Period: { key: '.', shiftKey: '>' },
  4613. Slash: { key: '/', shiftKey: '?' },
  4614. Backquote: { key: '`', shiftKey: '~' },
  4615. BracketLeft: { key: '[', shiftKey: '{' },
  4616. Backslash: { key: '\\', shiftKey: '|' },
  4617. BracketRight: { key: ']', shiftKey: '}' },
  4618. Quote: { key: '\'', shiftKey: '"' },
  4619. IntlBackslash: { key: '\\', shiftKey: '|' }
  4620. };
  4621. mergeIf(codeToKeyTable, 'mac', {
  4622. OSLeft: { key: 'Meta' },
  4623. OSRight: { key: 'Meta' }
  4624. });
  4625. // Corrections for 'key' names in older browsers (e.g. FF36-)
  4626. // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key#Key_values
  4627. var keyFixTable = {
  4628. Esc: 'Escape',
  4629. Nonconvert: 'NonConvert',
  4630. Left: 'ArrowLeft',
  4631. Up: 'ArrowUp',
  4632. Right: 'ArrowRight',
  4633. Down: 'ArrowDown',
  4634. Del: 'Delete',
  4635. Menu: 'ContextMenu',
  4636. MediaNextTrack: 'MediaTrackNext',
  4637. MediaPreviousTrack: 'MediaTrackPrevious',
  4638. SelectMedia: 'MediaSelect',
  4639. HalfWidth: 'Hankaku',
  4640. FullWidth: 'Zenkaku',
  4641. RomanCharacters: 'Romaji',
  4642. Crsel: 'CrSel',
  4643. Exsel: 'ExSel',
  4644. Zoom: 'ZoomToggle'
  4645. };
  4646. //--------------------------------------------------------------------
  4647. //
  4648. // Exported Functions
  4649. //
  4650. //--------------------------------------------------------------------
  4651. var codeTable = remap(keyCodeToInfoTable, 'code');
  4652. try {
  4653. var nativeLocation = nativeKeyboardEvent && ('location' in new KeyboardEvent(''));
  4654. } catch (_) {}
  4655. function keyInfoForEvent(event) {
  4656. var keyCode = 'keyCode' in event ? event.keyCode : 'which' in event ? event.which : 0;
  4657. var keyInfo = (function(){
  4658. if (nativeLocation || 'keyLocation' in event) {
  4659. var location = nativeLocation ? event.location : event.keyLocation;
  4660. if (location && keyCode in locationTable[location]) {
  4661. return locationTable[location][keyCode];
  4662. }
  4663. }
  4664. if ('keyIdentifier' in event && event.keyIdentifier in keyIdentifierTable) {
  4665. return keyIdentifierTable[event.keyIdentifier];
  4666. }
  4667. if (keyCode in keyCodeToInfoTable) {
  4668. return keyCodeToInfoTable[keyCode];
  4669. }
  4670. return null;
  4671. }());
  4672. // TODO: Track these down and move to general tables
  4673. if (0) {
  4674. // TODO: Map these for newerish browsers?
  4675. // TODO: iOS only?
  4676. // TODO: Override with more common keyIdentifier name?
  4677. switch (event.keyIdentifier) {
  4678. case 'U+0010': keyInfo = { code: 'Function' }; break;
  4679. case 'U+001C': keyInfo = { code: 'ArrowLeft' }; break;
  4680. case 'U+001D': keyInfo = { code: 'ArrowRight' }; break;
  4681. case 'U+001E': keyInfo = { code: 'ArrowUp' }; break;
  4682. case 'U+001F': keyInfo = { code: 'ArrowDown' }; break;
  4683. }
  4684. }
  4685. if (!keyInfo)
  4686. return null;
  4687. var key = (function() {
  4688. var entry = codeToKeyTable[keyInfo.code];
  4689. if (!entry) return keyInfo.code;
  4690. return (event.shiftKey && 'shiftKey' in entry) ? entry.shiftKey : entry.key;
  4691. }());
  4692. return {
  4693. code: keyInfo.code,
  4694. key: key,
  4695. location: keyInfo.location,
  4696. keyCap: keyInfo.keyCap
  4697. };
  4698. }
  4699. function queryKeyCap(code, locale) {
  4700. code = String(code);
  4701. if (!codeTable.hasOwnProperty(code)) return 'Undefined';
  4702. if (locale && String(locale).toLowerCase() !== 'en-us') throw Error('Unsupported locale');
  4703. var keyInfo = codeTable[code];
  4704. return keyInfo.keyCap || keyInfo.code || 'Undefined';
  4705. }
  4706. if ('KeyboardEvent' in global && 'defineProperty' in Object) {
  4707. (function() {
  4708. function define(o, p, v) {
  4709. if (p in o) return;
  4710. Object.defineProperty(o, p, v);
  4711. }
  4712. define(KeyboardEvent.prototype, 'code', { get: function() {
  4713. var keyInfo = keyInfoForEvent(this);
  4714. return keyInfo ? keyInfo.code : '';
  4715. }});
  4716. // Fix for nonstandard `key` values (FF36-)
  4717. if ('key' in KeyboardEvent.prototype) {
  4718. var desc = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, 'key');
  4719. Object.defineProperty(KeyboardEvent.prototype, 'key', { get: function() {
  4720. var key = desc.get.call(this);
  4721. return keyFixTable.hasOwnProperty(key) ? keyFixTable[key] : key;
  4722. }});
  4723. }
  4724. define(KeyboardEvent.prototype, 'key', { get: function() {
  4725. var keyInfo = keyInfoForEvent(this);
  4726. return (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';
  4727. }});
  4728. define(KeyboardEvent.prototype, 'location', { get: function() {
  4729. var keyInfo = keyInfoForEvent(this);
  4730. return (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;
  4731. }});
  4732. define(KeyboardEvent.prototype, 'locale', { get: function() {
  4733. return '';
  4734. }});
  4735. }());
  4736. }
  4737. if (!('queryKeyCap' in global.KeyboardEvent))
  4738. global.KeyboardEvent.queryKeyCap = queryKeyCap;
  4739. // Helper for IE8-
  4740. global.identifyKey = function(event) {
  4741. if ('code' in event)
  4742. return;
  4743. var keyInfo = keyInfoForEvent(event);
  4744. event.code = keyInfo ? keyInfo.code : '';
  4745. event.key = (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';
  4746. event.location = ('location' in event) ? event.location :
  4747. ('keyLocation' in event) ? event.keyLocation :
  4748. (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;
  4749. event.locale = '';
  4750. };
  4751. } (window));
  4752. },{}],11:[function(require,module,exports){
  4753. var CANNON = require('cannon'),
  4754. math = require('./src/components/math');
  4755. module.exports = {
  4756. 'dynamic-body': require('./src/components/body/dynamic-body'),
  4757. 'static-body': require('./src/components/body/static-body'),
  4758. 'constraint': require('./src/components/constraint'),
  4759. 'system': require('./src/system/physics'),
  4760. registerAll: function (AFRAME) {
  4761. if (this._registered) return;
  4762. AFRAME = AFRAME || window.AFRAME;
  4763. math.registerAll();
  4764. if (!AFRAME.systems.physics) AFRAME.registerSystem('physics', this.system);
  4765. if (!AFRAME.components['dynamic-body']) AFRAME.registerComponent('dynamic-body', this['dynamic-body']);
  4766. if (!AFRAME.components['static-body']) AFRAME.registerComponent('static-body', this['static-body']);
  4767. if (!AFRAME.components['constraint']) AFRAME.registerComponent('constraint', this['constraint']);
  4768. this._registered = true;
  4769. }
  4770. };
  4771. // Export CANNON.js.
  4772. window.CANNON = window.CANNON || CANNON;
  4773. },{"./src/components/body/dynamic-body":14,"./src/components/body/static-body":15,"./src/components/constraint":16,"./src/components/math":17,"./src/system/physics":21,"cannon":23}],12:[function(require,module,exports){
  4774. /**
  4775. * CANNON.shape2mesh
  4776. *
  4777. * Source: http://schteppe.github.io/cannon.js/build/cannon.demo.js
  4778. * Author: @schteppe
  4779. */
  4780. var CANNON = require('cannon');
  4781. CANNON.shape2mesh = function(body){
  4782. var obj = new THREE.Object3D();
  4783. for (var l = 0; l < body.shapes.length; l++) {
  4784. var shape = body.shapes[l];
  4785. var mesh;
  4786. switch(shape.type){
  4787. case CANNON.Shape.types.SPHERE:
  4788. var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8);
  4789. mesh = new THREE.Mesh( sphere_geometry, this.currentMaterial );
  4790. break;
  4791. case CANNON.Shape.types.PARTICLE:
  4792. mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial );
  4793. var s = this.settings;
  4794. mesh.scale.set(s.particleSize,s.particleSize,s.particleSize);
  4795. break;
  4796. case CANNON.Shape.types.PLANE:
  4797. var geometry = new THREE.PlaneGeometry(10, 10, 4, 4);
  4798. mesh = new THREE.Object3D();
  4799. var submesh = new THREE.Object3D();
  4800. var ground = new THREE.Mesh( geometry, this.currentMaterial );
  4801. ground.scale.set(100, 100, 100);
  4802. submesh.add(ground);
  4803. ground.castShadow = true;
  4804. ground.receiveShadow = true;
  4805. mesh.add(submesh);
  4806. break;
  4807. case CANNON.Shape.types.BOX:
  4808. var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2,
  4809. shape.halfExtents.y*2,
  4810. shape.halfExtents.z*2 );
  4811. mesh = new THREE.Mesh( box_geometry, this.currentMaterial );
  4812. break;
  4813. case CANNON.Shape.types.CONVEXPOLYHEDRON:
  4814. var geo = new THREE.Geometry();
  4815. // Add vertices
  4816. for (var i = 0; i < shape.vertices.length; i++) {
  4817. var v = shape.vertices[i];
  4818. geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z));
  4819. }
  4820. for(var i=0; i < shape.faces.length; i++){
  4821. var face = shape.faces[i];
  4822. // add triangles
  4823. var a = face[0];
  4824. for (var j = 1; j < face.length - 1; j++) {
  4825. var b = face[j];
  4826. var c = face[j + 1];
  4827. geo.faces.push(new THREE.Face3(a, b, c));
  4828. }
  4829. }
  4830. geo.computeBoundingSphere();
  4831. geo.computeFaceNormals();
  4832. mesh = new THREE.Mesh( geo, this.currentMaterial );
  4833. break;
  4834. case CANNON.Shape.types.HEIGHTFIELD:
  4835. var geometry = new THREE.Geometry();
  4836. var v0 = new CANNON.Vec3();
  4837. var v1 = new CANNON.Vec3();
  4838. var v2 = new CANNON.Vec3();
  4839. for (var xi = 0; xi < shape.data.length - 1; xi++) {
  4840. for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
  4841. for (var k = 0; k < 2; k++) {
  4842. shape.getConvexTrianglePillar(xi, yi, k===0);
  4843. v0.copy(shape.pillarConvex.vertices[0]);
  4844. v1.copy(shape.pillarConvex.vertices[1]);
  4845. v2.copy(shape.pillarConvex.vertices[2]);
  4846. v0.vadd(shape.pillarOffset, v0);
  4847. v1.vadd(shape.pillarOffset, v1);
  4848. v2.vadd(shape.pillarOffset, v2);
  4849. geometry.vertices.push(
  4850. new THREE.Vector3(v0.x, v0.y, v0.z),
  4851. new THREE.Vector3(v1.x, v1.y, v1.z),
  4852. new THREE.Vector3(v2.x, v2.y, v2.z)
  4853. );
  4854. var i = geometry.vertices.length - 3;
  4855. geometry.faces.push(new THREE.Face3(i, i+1, i+2));
  4856. }
  4857. }
  4858. }
  4859. geometry.computeBoundingSphere();
  4860. geometry.computeFaceNormals();
  4861. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  4862. break;
  4863. case CANNON.Shape.types.TRIMESH:
  4864. var geometry = new THREE.Geometry();
  4865. var v0 = new CANNON.Vec3();
  4866. var v1 = new CANNON.Vec3();
  4867. var v2 = new CANNON.Vec3();
  4868. for (var i = 0; i < shape.indices.length / 3; i++) {
  4869. shape.getTriangleVertices(i, v0, v1, v2);
  4870. geometry.vertices.push(
  4871. new THREE.Vector3(v0.x, v0.y, v0.z),
  4872. new THREE.Vector3(v1.x, v1.y, v1.z),
  4873. new THREE.Vector3(v2.x, v2.y, v2.z)
  4874. );
  4875. var j = geometry.vertices.length - 3;
  4876. geometry.faces.push(new THREE.Face3(j, j+1, j+2));
  4877. }
  4878. geometry.computeBoundingSphere();
  4879. geometry.computeFaceNormals();
  4880. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  4881. break;
  4882. default:
  4883. throw "Visual type not recognized: "+shape.type;
  4884. }
  4885. mesh.receiveShadow = true;
  4886. mesh.castShadow = true;
  4887. if(mesh.children){
  4888. for(var i=0; i<mesh.children.length; i++){
  4889. mesh.children[i].castShadow = true;
  4890. mesh.children[i].receiveShadow = true;
  4891. if(mesh.children[i]){
  4892. for(var j=0; j<mesh.children[i].length; j++){
  4893. mesh.children[i].children[j].castShadow = true;
  4894. mesh.children[i].children[j].receiveShadow = true;
  4895. }
  4896. }
  4897. }
  4898. }
  4899. var o = body.shapeOffsets[l];
  4900. var q = body.shapeOrientations[l];
  4901. mesh.position.set(o.x, o.y, o.z);
  4902. mesh.quaternion.set(q.x, q.y, q.z, q.w);
  4903. obj.add(mesh);
  4904. }
  4905. return obj;
  4906. };
  4907. module.exports = CANNON.shape2mesh;
  4908. },{"cannon":23}],13:[function(require,module,exports){
  4909. var CANNON = require('cannon'),
  4910. mesh2shape = require('three-to-cannon');
  4911. require('../../../lib/CANNON-shape2mesh');
  4912. module.exports = {
  4913. schema: {
  4914. shape: {default: 'auto', oneOf: ['auto', 'box', 'cylinder', 'sphere', 'hull', 'none']},
  4915. cylinderAxis: {default: 'y', oneOf: ['x', 'y', 'z']},
  4916. sphereRadius: {default: NaN}
  4917. },
  4918. /**
  4919. * Initializes a body component, assigning it to the physics system and binding listeners for
  4920. * parsing the elements geometry.
  4921. */
  4922. init: function () {
  4923. this.system = this.el.sceneEl.systems.physics;
  4924. if (this.el.sceneEl.hasLoaded) {
  4925. this.initBody();
  4926. } else {
  4927. this.el.sceneEl.addEventListener('loaded', this.initBody.bind(this));
  4928. }
  4929. },
  4930. /**
  4931. * Parses an element's geometry and component metadata to create a CANNON.Body instance for the
  4932. * component.
  4933. */
  4934. initBody: function () {
  4935. var shape,
  4936. el = this.el,
  4937. data = this.data,
  4938. pos = el.getAttribute('position');
  4939. this.body = new CANNON.Body({
  4940. mass: data.mass || 0,
  4941. material: this.system.material,
  4942. position: new CANNON.Vec3(pos.x, pos.y, pos.z),
  4943. linearDamping: data.linearDamping,
  4944. angularDamping: data.angularDamping
  4945. });
  4946. // Matrix World must be updated at root level, if scale is to be applied – updateMatrixWorld()
  4947. // only checks an object's parent, not the rest of the ancestors. Hence, a wrapping entity with
  4948. // scale="0.5 0.5 0.5" will be ignored.
  4949. // Reference: https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L511-L541
  4950. // Potential fix: https://github.com/mrdoob/three.js/pull/7019
  4951. this.el.object3D.updateMatrixWorld(true);
  4952. if(data.shape !== 'none') {
  4953. var options = data.shape === 'auto' ? undefined : AFRAME.utils.extend({}, this.data, {
  4954. type: mesh2shape.Type[data.shape.toUpperCase()]
  4955. });
  4956. shape = mesh2shape(this.el.object3D, options);
  4957. if (!shape) {
  4958. this.el.addEventListener('model-loaded', this.initBody.bind(this));
  4959. return;
  4960. }
  4961. this.body.addShape(shape, shape.offset, shape.orientation);
  4962. // Show wireframe
  4963. if (this.system.debug) {
  4964. this.createWireframe(this.body, shape);
  4965. }
  4966. }
  4967. // Apply rotation
  4968. var rot = el.getAttribute('rotation');
  4969. this.body.quaternion.setFromEuler(
  4970. THREE.Math.degToRad(rot.x),
  4971. THREE.Math.degToRad(rot.y),
  4972. THREE.Math.degToRad(rot.z),
  4973. 'XYZ'
  4974. ).normalize();
  4975. this.el.body = this.body;
  4976. this.body.el = this.el;
  4977. this.isLoaded = true;
  4978. // If component wasn't initialized when play() was called, finish up.
  4979. if (this.isPlaying) {
  4980. this._play();
  4981. }
  4982. this.el.emit('body-loaded', {body: this.el.body});
  4983. },
  4984. /**
  4985. * Registers the component with the physics system, if ready.
  4986. */
  4987. play: function () {
  4988. if (this.isLoaded) this._play();
  4989. },
  4990. /**
  4991. * Internal helper to register component with physics system.
  4992. */
  4993. _play: function () {
  4994. this.system.addBehavior(this, this.system.Phase.SIMULATE);
  4995. this.system.addBody(this.body);
  4996. if (this.wireframe) this.el.sceneEl.object3D.add(this.wireframe);
  4997. this.syncToPhysics();
  4998. },
  4999. /**
  5000. * Unregisters the component with the physics system.
  5001. */
  5002. pause: function () {
  5003. if (!this.isLoaded) return;
  5004. this.system.removeBehavior(this, this.system.Phase.SIMULATE);
  5005. this.system.removeBody(this.body);
  5006. if (this.wireframe) this.el.sceneEl.object3D.remove(this.wireframe);
  5007. },
  5008. /**
  5009. * Removes the component and all physics and scene side effects.
  5010. */
  5011. remove: function () {
  5012. this.pause();
  5013. delete this.body.el;
  5014. delete this.body;
  5015. delete this.el.body;
  5016. delete this.wireframe;
  5017. },
  5018. /**
  5019. * Creates a wireframe for the body, for debugging.
  5020. * TODO(donmccurdy) – Refactor this into a standalone utility or component.
  5021. * @param {CANNON.Body} body
  5022. * @param {CANNON.Shape} shape
  5023. */
  5024. createWireframe: function (body, shape) {
  5025. var offset = shape.offset,
  5026. orientation = shape.orientation,
  5027. mesh = CANNON.shape2mesh(body).children[0];
  5028. this.wireframe = new THREE.LineSegments(
  5029. new THREE.EdgesGeometry(mesh.geometry),
  5030. new THREE.LineBasicMaterial({color: 0xff0000})
  5031. );
  5032. if (offset) {
  5033. this.wireframe.offset = offset.clone();
  5034. }
  5035. if (orientation) {
  5036. orientation.inverse(orientation);
  5037. this.wireframe.orientation = new THREE.Quaternion(
  5038. orientation.x,
  5039. orientation.y,
  5040. orientation.z,
  5041. orientation.w
  5042. );
  5043. }
  5044. this.syncWireframe();
  5045. },
  5046. /**
  5047. * Updates the debugging wireframe's position and rotation.
  5048. */
  5049. syncWireframe: function () {
  5050. var offset,
  5051. wireframe = this.wireframe;
  5052. if (!this.wireframe) return;
  5053. // Apply rotation. If the shape required custom orientation, also apply
  5054. // that on the wireframe.
  5055. wireframe.quaternion.copy(this.body.quaternion);
  5056. if (wireframe.orientation) {
  5057. wireframe.quaternion.multiply(wireframe.orientation);
  5058. }
  5059. // Apply position. If the shape required custom offset, also apply that on
  5060. // the wireframe.
  5061. wireframe.position.copy(this.body.position);
  5062. if (wireframe.offset) {
  5063. offset = wireframe.offset.clone().applyQuaternion(wireframe.quaternion);
  5064. wireframe.position.add(offset);
  5065. }
  5066. wireframe.updateMatrix();
  5067. },
  5068. /**
  5069. * Updates the CANNON.Body instance's position, velocity, and rotation, based on the scene.
  5070. */
  5071. syncToPhysics: (function () {
  5072. var q = new THREE.Quaternion(),
  5073. v = new THREE.Vector3();
  5074. return function () {
  5075. var el = this.el,
  5076. parentEl = el.parentEl,
  5077. body = this.body;
  5078. if (!body) return;
  5079. if (el.components.velocity) body.velocity.copy(el.getAttribute('velocity'));
  5080. if (parentEl.isScene) {
  5081. body.quaternion.copy(el.object3D.quaternion);
  5082. body.position.copy(el.object3D.position);
  5083. } else {
  5084. el.object3D.getWorldQuaternion(q);
  5085. body.quaternion.copy(q);
  5086. el.object3D.getWorldPosition(v);
  5087. body.position.copy(v);
  5088. }
  5089. if (this.wireframe) this.syncWireframe();
  5090. };
  5091. }()),
  5092. /**
  5093. * Updates the scene object's position and rotation, based on the physics simulation.
  5094. */
  5095. syncFromPhysics: (function () {
  5096. var v = new THREE.Vector3(),
  5097. q1 = new THREE.Quaternion(),
  5098. q2 = new THREE.Quaternion();
  5099. return function () {
  5100. var el = this.el,
  5101. parentEl = el.parentEl,
  5102. body = this.body;
  5103. if (!body) return;
  5104. if (parentEl.isScene) {
  5105. el.setAttribute('quaternion', body.quaternion);
  5106. el.setAttribute('position', body.position);
  5107. } else {
  5108. // TODO - Nested rotation doesn't seem to be working as expected.
  5109. q1.copy(body.quaternion);
  5110. parentEl.object3D.getWorldQuaternion(q2);
  5111. q1.multiply(q2.inverse());
  5112. el.setAttribute('quaternion', {x: q1.x, y: q1.y, z: q1.z, w: q1.w});
  5113. v.copy(body.position);
  5114. parentEl.object3D.worldToLocal(v);
  5115. el.setAttribute('position', {x: v.x, y: v.y, z: v.z});
  5116. }
  5117. if (this.wireframe) this.syncWireframe();
  5118. };
  5119. }())
  5120. };
  5121. },{"../../../lib/CANNON-shape2mesh":12,"cannon":23,"three-to-cannon":84}],14:[function(require,module,exports){
  5122. var Body = require('./body');
  5123. /**
  5124. * Dynamic body.
  5125. *
  5126. * Moves according to physics simulation, and may collide with other objects.
  5127. */
  5128. module.exports = AFRAME.utils.extend({}, Body, {
  5129. dependencies: ['quaternion', 'velocity'],
  5130. schema: AFRAME.utils.extend({}, Body.schema, {
  5131. mass: { default: 5 },
  5132. linearDamping: { default: 0.01 },
  5133. angularDamping: { default: 0.01 }
  5134. }),
  5135. step: function () {
  5136. this.syncFromPhysics();
  5137. }
  5138. });
  5139. },{"./body":13}],15:[function(require,module,exports){
  5140. var Body = require('./body');
  5141. /**
  5142. * Static body.
  5143. *
  5144. * Solid body with a fixed position. Unaffected by gravity and collisions, but
  5145. * other objects may collide with it.
  5146. */
  5147. module.exports = AFRAME.utils.extend({}, Body, {
  5148. step: function () {
  5149. this.syncToPhysics();
  5150. }
  5151. });
  5152. },{"./body":13}],16:[function(require,module,exports){
  5153. var CANNON = require('cannon');
  5154. module.exports = {
  5155. dependencies: ['dynamic-body'],
  5156. multiple: true,
  5157. schema: {
  5158. // Type of constraint.
  5159. type: {default: 'lock', oneOf: ['coneTwist', 'distance', 'hinge', 'lock', 'pointToPoint']},
  5160. // Target (other) body for the constraint.
  5161. target: {type: 'selector'},
  5162. // Maximum force that should be applied to constraint the bodies.
  5163. maxForce: {default: 1e6, min: 0},
  5164. // If true, bodies can collide when they are connected.
  5165. collideConnected: {default: true},
  5166. // Wake up bodies when connected.
  5167. wakeUpBodies: {default: true},
  5168. // The distance to be kept between the bodies. If 0, will be set to current distance.
  5169. distance: {default: 0, min: 0},
  5170. // Offset of the hinge or point-to-point constraint, defined locally in the body.
  5171. pivot: {type: 'vec3'},
  5172. targetPivot: {type: 'vec3'},
  5173. // An axis that each body can rotate around, defined locally to that body.
  5174. axis: {type: 'vec3', default: { x: 0, y: 0, z: 1 }},
  5175. targetAxis: {type: 'vec3', default: { x: 0, y: 0, z: 1}}
  5176. },
  5177. init: function () {
  5178. this.system = this.el.sceneEl.systems.physics;
  5179. this.constraint = /* {CANNON.Constraint} */ null;
  5180. },
  5181. remove: function () {
  5182. if (!this.constraint) return;
  5183. this.system.world.removeConstraint(this.constraint);
  5184. this.constraint = null;
  5185. },
  5186. update: function () {
  5187. var el = this.el,
  5188. data = this.data;
  5189. this.remove();
  5190. if (!el.body || !data.target.body) {
  5191. (el.body ? data.target : el).addEventListener('body-loaded', this.update.bind(this, {}));
  5192. return;
  5193. }
  5194. this.constraint = this.createConstraint();
  5195. this.system.world.addConstraint(this.constraint);
  5196. },
  5197. /**
  5198. * Creates a new constraint, given current component data. The CANNON.js constructors are a bit
  5199. * different for each constraint type.
  5200. * @return {CANNON.Constraint}
  5201. */
  5202. createConstraint: function () {
  5203. var data = this.data,
  5204. pivot = new CANNON.Vec3(data.pivot.x, data.pivot.y, data.pivot.z),
  5205. targetPivot = new CANNON.Vec3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z),
  5206. axis = new CANNON.Vec3(data.axis.x, data.axis.y, data.axis.z),
  5207. targetAxis= new CANNON.Vec3(data.targetAxis.x, data.targetAxis.y, data.targetAxis.z);
  5208. var constraint;
  5209. switch (data.type) {
  5210. case 'lock':
  5211. constraint = new CANNON.LockConstraint(
  5212. this.el.body,
  5213. data.target.body,
  5214. {maxForce: data.maxForce}
  5215. );
  5216. break;
  5217. case 'distance':
  5218. constraint = new CANNON.DistanceConstraint(
  5219. this.el.body,
  5220. data.target.body,
  5221. data.distance,
  5222. data.maxForce
  5223. );
  5224. break;
  5225. case 'hinge':
  5226. constraint = new CANNON.HingeConstraint(
  5227. this.el.body,
  5228. data.target.body, {
  5229. pivotA: pivot,
  5230. pivotB: targetPivot,
  5231. axisA: axis,
  5232. axisB: targetAxis,
  5233. maxForce: data.maxForce
  5234. });
  5235. break;
  5236. case 'coneTwist':
  5237. constraint = new CANNON.ConeTwistConstraint(
  5238. this.el.body,
  5239. data.target.body, {
  5240. pivotA: pivot,
  5241. pivotB: targetPivot,
  5242. axisA: axis,
  5243. axisB: targetAxis,
  5244. maxForce: data.maxForce
  5245. });
  5246. break;
  5247. case 'pointToPoint':
  5248. constraint = new CANNON.PointToPointConstraint(
  5249. this.el.body,
  5250. pivot,
  5251. data.target.body,
  5252. targetPivot,
  5253. data.maxForce);
  5254. break;
  5255. default:
  5256. throw new Error('[constraint] Unexpected type: ' + data.type);
  5257. }
  5258. constraint.collideConnected = data.collideConnected;
  5259. return constraint;
  5260. }
  5261. };
  5262. },{"cannon":23}],17:[function(require,module,exports){
  5263. module.exports = {
  5264. 'velocity': require('./velocity'),
  5265. 'quaternion': require('./quaternion'),
  5266. registerAll: function (AFRAME) {
  5267. if (this._registered) return;
  5268. AFRAME = AFRAME || window.AFRAME;
  5269. if (!AFRAME.components['velocity']) AFRAME.registerComponent('velocity', this.velocity);
  5270. if (!AFRAME.components['quaternion']) AFRAME.registerComponent('quaternion', this.quaternion);
  5271. this._registered = true;
  5272. }
  5273. };
  5274. },{"./quaternion":18,"./velocity":19}],18:[function(require,module,exports){
  5275. /**
  5276. * Quaternion.
  5277. *
  5278. * Represents orientation of object in three dimensions. Similar to `rotation`
  5279. * component, but avoids problems of gimbal lock.
  5280. *
  5281. * See: https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
  5282. */
  5283. module.exports = {
  5284. schema: {type: 'vec4'},
  5285. play: function () {
  5286. var el = this.el,
  5287. q = el.object3D.quaternion;
  5288. if (el.hasAttribute('rotation')) {
  5289. el.components.rotation.update();
  5290. el.setAttribute('quaternion', {x: q.x, y: q.y, z: q.z, w: q.w});
  5291. el.removeAttribute('rotation');
  5292. this.update();
  5293. }
  5294. },
  5295. update: function () {
  5296. var data = this.data;
  5297. this.el.object3D.quaternion.set(data.x, data.y, data.z, data.w);
  5298. }
  5299. };
  5300. },{}],19:[function(require,module,exports){
  5301. /**
  5302. * Velocity, in m/s.
  5303. */
  5304. module.exports = {
  5305. schema: {type: 'vec3'},
  5306. init: function () {
  5307. this.system = this.el.sceneEl.systems.physics;
  5308. if (this.system) {
  5309. this.system.addBehavior(this, this.system.Phase.RENDER);
  5310. }
  5311. },
  5312. remove: function () {
  5313. if (this.system) {
  5314. this.system.removeBehavior(this, this.system.Phase.RENDER);
  5315. }
  5316. },
  5317. tick: function (t, dt) {
  5318. if (!dt) return;
  5319. if (this.system) return;
  5320. this.step(t, dt);
  5321. },
  5322. step: function (t, dt) {
  5323. if (!dt) return;
  5324. var physics = this.el.sceneEl.systems.physics || {data: {maxInterval: 1 / 60}},
  5325. // TODO - There's definitely a bug with getComputedAttribute and el.data.
  5326. velocity = this.el.getAttribute('velocity') || {x: 0, y: 0, z: 0},
  5327. position = this.el.getAttribute('position') || {x: 0, y: 0, z: 0};
  5328. dt = Math.min(dt, physics.data.maxInterval * 1000);
  5329. this.el.setAttribute('position', {
  5330. x: position.x + velocity.x * dt / 1000,
  5331. y: position.y + velocity.y * dt / 1000,
  5332. z: position.z + velocity.z * dt / 1000
  5333. });
  5334. }
  5335. };
  5336. },{}],20:[function(require,module,exports){
  5337. module.exports = {
  5338. GRAVITY: -9.8,
  5339. MAX_INTERVAL: 4 / 60,
  5340. ITERATIONS: 10,
  5341. CONTACT_MATERIAL: {
  5342. friction: 0.01,
  5343. restitution: 0.3,
  5344. contactEquationStiffness: 1e8,
  5345. contactEquationRelaxation: 3,
  5346. frictionEquationStiffness: 1e8,
  5347. frictionEquationRegularization: 3
  5348. }
  5349. };
  5350. },{}],21:[function(require,module,exports){
  5351. var CANNON = require('cannon'),
  5352. CONSTANTS = require('../constants'),
  5353. C_GRAV = CONSTANTS.GRAVITY,
  5354. C_MAT = CONSTANTS.CONTACT_MATERIAL;
  5355. /**
  5356. * Physics system.
  5357. */
  5358. module.exports = {
  5359. schema: {
  5360. gravity: { default: C_GRAV },
  5361. iterations: { default: CONSTANTS.ITERATIONS },
  5362. friction: { default: C_MAT.friction },
  5363. restitution: { default: C_MAT.restitution },
  5364. contactEquationStiffness: { default: C_MAT.contactEquationStiffness },
  5365. contactEquationRelaxation: { default: C_MAT.contactEquationRelaxation },
  5366. frictionEquationStiffness: { default: C_MAT.frictionEquationStiffness },
  5367. frictionEquationRegularization: { default: C_MAT.frictionEquationRegularization },
  5368. // Never step more than four frames at once. Effectively pauses the scene
  5369. // when out of focus, and prevents weird "jumps" when focus returns.
  5370. maxInterval: { default: 4 / 60 },
  5371. // If true, show wireframes around physics bodies.
  5372. debug: { default: false },
  5373. },
  5374. /**
  5375. * Update phases, used to separate physics simulation from updates to A-Frame scene.
  5376. * @enum {string}
  5377. */
  5378. Phase: {
  5379. SIMULATE: 'sim',
  5380. RENDER: 'render'
  5381. },
  5382. /**
  5383. * Initializes the physics system.
  5384. */
  5385. init: function () {
  5386. var data = this.data;
  5387. // If true, show wireframes around physics bodies.
  5388. this.debug = data.debug;
  5389. this.children = {};
  5390. this.children[this.Phase.SIMULATE] = [];
  5391. this.children[this.Phase.RENDER] = [];
  5392. this.listeners = {};
  5393. this.world = new CANNON.World();
  5394. this.world.quatNormalizeSkip = 0;
  5395. this.world.quatNormalizeFast = false;
  5396. // this.world.solver.setSpookParams(300,10);
  5397. this.world.solver.iterations = data.iterations;
  5398. this.world.gravity.set(0, data.gravity, 0);
  5399. this.world.broadphase = new CANNON.NaiveBroadphase();
  5400. this.material = new CANNON.Material({name: 'defaultMaterial'});
  5401. this.contactMaterial = new CANNON.ContactMaterial(this.material, this.material, {
  5402. friction: data.friction,
  5403. restitution: data.restitution,
  5404. contactEquationStiffness: data.contactEquationStiffness,
  5405. contactEquationRelaxation: data.contactEquationRelaxation,
  5406. frictionEquationStiffness: data.frictionEquationStiffness,
  5407. frictionEquationRegularization: data.frictionEquationRegularization
  5408. });
  5409. this.world.addContactMaterial(this.contactMaterial);
  5410. },
  5411. /**
  5412. * Updates the physics world on each tick of the A-Frame scene. It would be
  5413. * entirely possible to separate the two – updating physics more or less
  5414. * frequently than the scene – if greater precision or performance were
  5415. * necessary.
  5416. * @param {number} t
  5417. * @param {number} dt
  5418. */
  5419. tick: function (t, dt) {
  5420. if (!dt) return;
  5421. this.world.step(Math.min(dt / 1000, this.data.maxInterval));
  5422. var i;
  5423. for (i = 0; i < this.children[this.Phase.SIMULATE].length; i++) {
  5424. this.children[this.Phase.SIMULATE][i].step(t, dt);
  5425. }
  5426. for (i = 0; i < this.children[this.Phase.RENDER].length; i++) {
  5427. this.children[this.Phase.RENDER][i].step(t, dt);
  5428. }
  5429. },
  5430. /**
  5431. * Adds a body to the scene, and binds collision events to the element.
  5432. * @param {CANNON.Body} body
  5433. */
  5434. addBody: function (body) {
  5435. this.listeners[body.id] = function (e) { body.el.emit('collide', e); };
  5436. body.addEventListener('collide', this.listeners[body.id]);
  5437. this.world.addBody(body);
  5438. },
  5439. /**
  5440. * Removes a body, and its listeners, from the scene.
  5441. * @param {CANNON.Body} body
  5442. */
  5443. removeBody: function (body) {
  5444. body.removeEventListener('collide', this.listeners[body.id]);
  5445. delete this.listeners[body.id];
  5446. this.world.removeBody(body);
  5447. },
  5448. /**
  5449. * Adds a component instance to the system, to be invoked on each tick during
  5450. * the given phase.
  5451. * @param {Component} component
  5452. * @param {string} phase
  5453. */
  5454. addBehavior: function (component, phase) {
  5455. this.children[phase].push(component);
  5456. },
  5457. /**
  5458. * Removes a component instance from the system.
  5459. * @param {Component} component
  5460. * @param {string} phase
  5461. */
  5462. removeBehavior: function (component, phase) {
  5463. this.children[phase].splice(this.children[phase].indexOf(component), 1);
  5464. },
  5465. /**
  5466. * Sets an option on the physics system, affecting future simulation steps.
  5467. * @param {string} opt
  5468. * @param {mixed} value
  5469. */
  5470. update: function (previousData) {
  5471. var data = this.data;
  5472. if (data.debug !== previousData.debug) {
  5473. console.warn('[physics] `debug` cannot be changed dynamically.');
  5474. }
  5475. if (data.maxInterval !== previousData.maxInterval); // noop;
  5476. if (data.gravity !== previousData.gravity) this.world.gravity.set(0, data.gravity, 0);
  5477. this.contactMaterial.friction = data.friction;
  5478. this.contactMaterial.restitution = data.restitution;
  5479. this.contactMaterial.contactEquationStiffness = data.contactEquationStiffness;
  5480. this.contactMaterial.contactEquationRelaxation = data.contactEquationRelaxation;
  5481. this.contactMaterial.frictionEquationStiffness = data.frictionEquationStiffness;
  5482. this.contactMaterial.frictionEquationRegularization = data.frictionEquationRegularization;
  5483. }
  5484. };
  5485. },{"../constants":20,"cannon":23}],22:[function(require,module,exports){
  5486. module.exports={
  5487. "_from": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  5488. "_id": "cannon@0.6.2",
  5489. "_inBundle": false,
  5490. "_integrity": "sha1-kuhwtr7Hd8jqU3mcndOx2tmf0RU=",
  5491. "_location": "/cannon",
  5492. "_phantomChildren": {},
  5493. "_requested": {
  5494. "type": "git",
  5495. "raw": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  5496. "name": "cannon",
  5497. "escapedName": "cannon",
  5498. "rawSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  5499. "saveSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  5500. "fetchSpec": null,
  5501. "gitCommittish": "v0.6.2-dev1"
  5502. },
  5503. "_requiredBy": [
  5504. "/aframe-physics-system"
  5505. ],
  5506. "_resolved": "github:donmccurdy/cannon.js#022e8ba53fa83abf0ad8a0e4fd08623123838a17",
  5507. "_spec": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  5508. "_where": "/Users/donmccurdy/Documents/Projects/aframe-extras/node_modules/aframe-physics-system",
  5509. "author": {
  5510. "name": "Stefan Hedman",
  5511. "email": "schteppe@gmail.com",
  5512. "url": "http://steffe.se"
  5513. },
  5514. "bugs": {
  5515. "url": "https://github.com/schteppe/cannon.js/issues"
  5516. },
  5517. "bundleDependencies": false,
  5518. "dependencies": {},
  5519. "deprecated": false,
  5520. "description": "A lightweight 3D physics engine written in JavaScript.",
  5521. "devDependencies": {
  5522. "browserify": "*",
  5523. "grunt": "~0.4.0",
  5524. "grunt-browserify": "^2.1.4",
  5525. "grunt-contrib-concat": "~0.1.3",
  5526. "grunt-contrib-jshint": "~0.1.1",
  5527. "grunt-contrib-nodeunit": "^0.4.1",
  5528. "grunt-contrib-uglify": "^0.5.1",
  5529. "grunt-contrib-yuidoc": "^0.5.2",
  5530. "jshint": "latest",
  5531. "nodeunit": "^0.9.0",
  5532. "uglify-js": "latest"
  5533. },
  5534. "engines": {
  5535. "node": "*"
  5536. },
  5537. "homepage": "https://github.com/schteppe/cannon.js",
  5538. "keywords": [
  5539. "cannon.js",
  5540. "cannon",
  5541. "physics",
  5542. "engine",
  5543. "3d"
  5544. ],
  5545. "licenses": [
  5546. {
  5547. "type": "MIT"
  5548. }
  5549. ],
  5550. "main": "./src/Cannon.js",
  5551. "name": "cannon",
  5552. "repository": {
  5553. "type": "git",
  5554. "url": "git+https://github.com/schteppe/cannon.js.git"
  5555. },
  5556. "version": "0.6.2"
  5557. }
  5558. },{}],23:[function(require,module,exports){
  5559. // Export classes
  5560. module.exports = {
  5561. version : require('../package.json').version,
  5562. AABB : require('./collision/AABB'),
  5563. ArrayCollisionMatrix : require('./collision/ArrayCollisionMatrix'),
  5564. Body : require('./objects/Body'),
  5565. Box : require('./shapes/Box'),
  5566. Broadphase : require('./collision/Broadphase'),
  5567. Constraint : require('./constraints/Constraint'),
  5568. ContactEquation : require('./equations/ContactEquation'),
  5569. Narrowphase : require('./world/Narrowphase'),
  5570. ConeTwistConstraint : require('./constraints/ConeTwistConstraint'),
  5571. ContactMaterial : require('./material/ContactMaterial'),
  5572. ConvexPolyhedron : require('./shapes/ConvexPolyhedron'),
  5573. Cylinder : require('./shapes/Cylinder'),
  5574. DistanceConstraint : require('./constraints/DistanceConstraint'),
  5575. Equation : require('./equations/Equation'),
  5576. EventTarget : require('./utils/EventTarget'),
  5577. FrictionEquation : require('./equations/FrictionEquation'),
  5578. GSSolver : require('./solver/GSSolver'),
  5579. GridBroadphase : require('./collision/GridBroadphase'),
  5580. Heightfield : require('./shapes/Heightfield'),
  5581. HingeConstraint : require('./constraints/HingeConstraint'),
  5582. LockConstraint : require('./constraints/LockConstraint'),
  5583. Mat3 : require('./math/Mat3'),
  5584. Material : require('./material/Material'),
  5585. NaiveBroadphase : require('./collision/NaiveBroadphase'),
  5586. ObjectCollisionMatrix : require('./collision/ObjectCollisionMatrix'),
  5587. Pool : require('./utils/Pool'),
  5588. Particle : require('./shapes/Particle'),
  5589. Plane : require('./shapes/Plane'),
  5590. PointToPointConstraint : require('./constraints/PointToPointConstraint'),
  5591. Quaternion : require('./math/Quaternion'),
  5592. Ray : require('./collision/Ray'),
  5593. RaycastVehicle : require('./objects/RaycastVehicle'),
  5594. RaycastResult : require('./collision/RaycastResult'),
  5595. RigidVehicle : require('./objects/RigidVehicle'),
  5596. RotationalEquation : require('./equations/RotationalEquation'),
  5597. RotationalMotorEquation : require('./equations/RotationalMotorEquation'),
  5598. SAPBroadphase : require('./collision/SAPBroadphase'),
  5599. SPHSystem : require('./objects/SPHSystem'),
  5600. Shape : require('./shapes/Shape'),
  5601. Solver : require('./solver/Solver'),
  5602. Sphere : require('./shapes/Sphere'),
  5603. SplitSolver : require('./solver/SplitSolver'),
  5604. Spring : require('./objects/Spring'),
  5605. Transform : require('./math/Transform'),
  5606. Trimesh : require('./shapes/Trimesh'),
  5607. Vec3 : require('./math/Vec3'),
  5608. Vec3Pool : require('./utils/Vec3Pool'),
  5609. World : require('./world/World'),
  5610. };
  5611. },{"../package.json":22,"./collision/AABB":24,"./collision/ArrayCollisionMatrix":25,"./collision/Broadphase":26,"./collision/GridBroadphase":27,"./collision/NaiveBroadphase":28,"./collision/ObjectCollisionMatrix":29,"./collision/Ray":31,"./collision/RaycastResult":32,"./collision/SAPBroadphase":33,"./constraints/ConeTwistConstraint":34,"./constraints/Constraint":35,"./constraints/DistanceConstraint":36,"./constraints/HingeConstraint":37,"./constraints/LockConstraint":38,"./constraints/PointToPointConstraint":39,"./equations/ContactEquation":41,"./equations/Equation":42,"./equations/FrictionEquation":43,"./equations/RotationalEquation":44,"./equations/RotationalMotorEquation":45,"./material/ContactMaterial":46,"./material/Material":47,"./math/Mat3":49,"./math/Quaternion":50,"./math/Transform":51,"./math/Vec3":52,"./objects/Body":53,"./objects/RaycastVehicle":54,"./objects/RigidVehicle":55,"./objects/SPHSystem":56,"./objects/Spring":57,"./shapes/Box":59,"./shapes/ConvexPolyhedron":60,"./shapes/Cylinder":61,"./shapes/Heightfield":62,"./shapes/Particle":63,"./shapes/Plane":64,"./shapes/Shape":65,"./shapes/Sphere":66,"./shapes/Trimesh":67,"./solver/GSSolver":68,"./solver/Solver":69,"./solver/SplitSolver":70,"./utils/EventTarget":71,"./utils/Pool":73,"./utils/Vec3Pool":76,"./world/Narrowphase":77,"./world/World":78}],24:[function(require,module,exports){
  5612. var Vec3 = require('../math/Vec3');
  5613. var Utils = require('../utils/Utils');
  5614. module.exports = AABB;
  5615. /**
  5616. * Axis aligned bounding box class.
  5617. * @class AABB
  5618. * @constructor
  5619. * @param {Object} [options]
  5620. * @param {Vec3} [options.upperBound]
  5621. * @param {Vec3} [options.lowerBound]
  5622. */
  5623. function AABB(options){
  5624. options = options || {};
  5625. /**
  5626. * The lower bound of the bounding box.
  5627. * @property lowerBound
  5628. * @type {Vec3}
  5629. */
  5630. this.lowerBound = new Vec3();
  5631. if(options.lowerBound){
  5632. this.lowerBound.copy(options.lowerBound);
  5633. }
  5634. /**
  5635. * The upper bound of the bounding box.
  5636. * @property upperBound
  5637. * @type {Vec3}
  5638. */
  5639. this.upperBound = new Vec3();
  5640. if(options.upperBound){
  5641. this.upperBound.copy(options.upperBound);
  5642. }
  5643. }
  5644. var tmp = new Vec3();
  5645. /**
  5646. * Set the AABB bounds from a set of points.
  5647. * @method setFromPoints
  5648. * @param {Array} points An array of Vec3's.
  5649. * @param {Vec3} position
  5650. * @param {Quaternion} quaternion
  5651. * @param {number} skinSize
  5652. * @return {AABB} The self object
  5653. */
  5654. AABB.prototype.setFromPoints = function(points, position, quaternion, skinSize){
  5655. var l = this.lowerBound,
  5656. u = this.upperBound,
  5657. q = quaternion;
  5658. // Set to the first point
  5659. l.copy(points[0]);
  5660. if(q){
  5661. q.vmult(l, l);
  5662. }
  5663. u.copy(l);
  5664. for(var i = 1; i<points.length; i++){
  5665. var p = points[i];
  5666. if(q){
  5667. q.vmult(p, tmp);
  5668. p = tmp;
  5669. }
  5670. if(p.x > u.x){ u.x = p.x; }
  5671. if(p.x < l.x){ l.x = p.x; }
  5672. if(p.y > u.y){ u.y = p.y; }
  5673. if(p.y < l.y){ l.y = p.y; }
  5674. if(p.z > u.z){ u.z = p.z; }
  5675. if(p.z < l.z){ l.z = p.z; }
  5676. }
  5677. // Add offset
  5678. if (position) {
  5679. position.vadd(l, l);
  5680. position.vadd(u, u);
  5681. }
  5682. if(skinSize){
  5683. l.x -= skinSize;
  5684. l.y -= skinSize;
  5685. l.z -= skinSize;
  5686. u.x += skinSize;
  5687. u.y += skinSize;
  5688. u.z += skinSize;
  5689. }
  5690. return this;
  5691. };
  5692. /**
  5693. * Copy bounds from an AABB to this AABB
  5694. * @method copy
  5695. * @param {AABB} aabb Source to copy from
  5696. * @return {AABB} The this object, for chainability
  5697. */
  5698. AABB.prototype.copy = function(aabb){
  5699. this.lowerBound.copy(aabb.lowerBound);
  5700. this.upperBound.copy(aabb.upperBound);
  5701. return this;
  5702. };
  5703. /**
  5704. * Clone an AABB
  5705. * @method clone
  5706. */
  5707. AABB.prototype.clone = function(){
  5708. return new AABB().copy(this);
  5709. };
  5710. /**
  5711. * Extend this AABB so that it covers the given AABB too.
  5712. * @method extend
  5713. * @param {AABB} aabb
  5714. */
  5715. AABB.prototype.extend = function(aabb){
  5716. this.lowerBound.x = Math.min(this.lowerBound.x, aabb.lowerBound.x);
  5717. this.upperBound.x = Math.max(this.upperBound.x, aabb.upperBound.x);
  5718. this.lowerBound.y = Math.min(this.lowerBound.y, aabb.lowerBound.y);
  5719. this.upperBound.y = Math.max(this.upperBound.y, aabb.upperBound.y);
  5720. this.lowerBound.z = Math.min(this.lowerBound.z, aabb.lowerBound.z);
  5721. this.upperBound.z = Math.max(this.upperBound.z, aabb.upperBound.z);
  5722. };
  5723. /**
  5724. * Returns true if the given AABB overlaps this AABB.
  5725. * @method overlaps
  5726. * @param {AABB} aabb
  5727. * @return {Boolean}
  5728. */
  5729. AABB.prototype.overlaps = function(aabb){
  5730. var l1 = this.lowerBound,
  5731. u1 = this.upperBound,
  5732. l2 = aabb.lowerBound,
  5733. u2 = aabb.upperBound;
  5734. // l2 u2
  5735. // |---------|
  5736. // |--------|
  5737. // l1 u1
  5738. var overlapsX = ((l2.x <= u1.x && u1.x <= u2.x) || (l1.x <= u2.x && u2.x <= u1.x));
  5739. var overlapsY = ((l2.y <= u1.y && u1.y <= u2.y) || (l1.y <= u2.y && u2.y <= u1.y));
  5740. var overlapsZ = ((l2.z <= u1.z && u1.z <= u2.z) || (l1.z <= u2.z && u2.z <= u1.z));
  5741. return overlapsX && overlapsY && overlapsZ;
  5742. };
  5743. // Mostly for debugging
  5744. AABB.prototype.volume = function(){
  5745. var l = this.lowerBound,
  5746. u = this.upperBound;
  5747. return (u.x - l.x) * (u.y - l.y) * (u.z - l.z);
  5748. };
  5749. /**
  5750. * Returns true if the given AABB is fully contained in this AABB.
  5751. * @method contains
  5752. * @param {AABB} aabb
  5753. * @return {Boolean}
  5754. */
  5755. AABB.prototype.contains = function(aabb){
  5756. var l1 = this.lowerBound,
  5757. u1 = this.upperBound,
  5758. l2 = aabb.lowerBound,
  5759. u2 = aabb.upperBound;
  5760. // l2 u2
  5761. // |---------|
  5762. // |---------------|
  5763. // l1 u1
  5764. return (
  5765. (l1.x <= l2.x && u1.x >= u2.x) &&
  5766. (l1.y <= l2.y && u1.y >= u2.y) &&
  5767. (l1.z <= l2.z && u1.z >= u2.z)
  5768. );
  5769. };
  5770. /**
  5771. * @method getCorners
  5772. * @param {Vec3} a
  5773. * @param {Vec3} b
  5774. * @param {Vec3} c
  5775. * @param {Vec3} d
  5776. * @param {Vec3} e
  5777. * @param {Vec3} f
  5778. * @param {Vec3} g
  5779. * @param {Vec3} h
  5780. */
  5781. AABB.prototype.getCorners = function(a, b, c, d, e, f, g, h){
  5782. var l = this.lowerBound,
  5783. u = this.upperBound;
  5784. a.copy(l);
  5785. b.set( u.x, l.y, l.z );
  5786. c.set( u.x, u.y, l.z );
  5787. d.set( l.x, u.y, u.z );
  5788. e.set( u.x, l.y, l.z );
  5789. f.set( l.x, u.y, l.z );
  5790. g.set( l.x, l.y, u.z );
  5791. h.copy(u);
  5792. };
  5793. var transformIntoFrame_corners = [
  5794. new Vec3(),
  5795. new Vec3(),
  5796. new Vec3(),
  5797. new Vec3(),
  5798. new Vec3(),
  5799. new Vec3(),
  5800. new Vec3(),
  5801. new Vec3()
  5802. ];
  5803. /**
  5804. * Get the representation of an AABB in another frame.
  5805. * @method toLocalFrame
  5806. * @param {Transform} frame
  5807. * @param {AABB} target
  5808. * @return {AABB} The "target" AABB object.
  5809. */
  5810. AABB.prototype.toLocalFrame = function(frame, target){
  5811. var corners = transformIntoFrame_corners;
  5812. var a = corners[0];
  5813. var b = corners[1];
  5814. var c = corners[2];
  5815. var d = corners[3];
  5816. var e = corners[4];
  5817. var f = corners[5];
  5818. var g = corners[6];
  5819. var h = corners[7];
  5820. // Get corners in current frame
  5821. this.getCorners(a, b, c, d, e, f, g, h);
  5822. // Transform them to new local frame
  5823. for(var i=0; i !== 8; i++){
  5824. var corner = corners[i];
  5825. frame.pointToLocal(corner, corner);
  5826. }
  5827. return target.setFromPoints(corners);
  5828. };
  5829. /**
  5830. * Get the representation of an AABB in the global frame.
  5831. * @method toWorldFrame
  5832. * @param {Transform} frame
  5833. * @param {AABB} target
  5834. * @return {AABB} The "target" AABB object.
  5835. */
  5836. AABB.prototype.toWorldFrame = function(frame, target){
  5837. var corners = transformIntoFrame_corners;
  5838. var a = corners[0];
  5839. var b = corners[1];
  5840. var c = corners[2];
  5841. var d = corners[3];
  5842. var e = corners[4];
  5843. var f = corners[5];
  5844. var g = corners[6];
  5845. var h = corners[7];
  5846. // Get corners in current frame
  5847. this.getCorners(a, b, c, d, e, f, g, h);
  5848. // Transform them to new local frame
  5849. for(var i=0; i !== 8; i++){
  5850. var corner = corners[i];
  5851. frame.pointToWorld(corner, corner);
  5852. }
  5853. return target.setFromPoints(corners);
  5854. };
  5855. /**
  5856. * Check if the AABB is hit by a ray.
  5857. * @param {Ray} ray
  5858. * @return {number}
  5859. */
  5860. AABB.prototype.overlapsRay = function(ray){
  5861. var t = 0;
  5862. // ray.direction is unit direction vector of ray
  5863. var dirFracX = 1 / ray._direction.x;
  5864. var dirFracY = 1 / ray._direction.y;
  5865. var dirFracZ = 1 / ray._direction.z;
  5866. // this.lowerBound is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
  5867. var t1 = (this.lowerBound.x - ray.from.x) * dirFracX;
  5868. var t2 = (this.upperBound.x - ray.from.x) * dirFracX;
  5869. var t3 = (this.lowerBound.y - ray.from.y) * dirFracY;
  5870. var t4 = (this.upperBound.y - ray.from.y) * dirFracY;
  5871. var t5 = (this.lowerBound.z - ray.from.z) * dirFracZ;
  5872. var t6 = (this.upperBound.z - ray.from.z) * dirFracZ;
  5873. // var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)));
  5874. // var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)));
  5875. var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
  5876. var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
  5877. // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
  5878. if (tmax < 0){
  5879. //t = tmax;
  5880. return false;
  5881. }
  5882. // if tmin > tmax, ray doesn't intersect AABB
  5883. if (tmin > tmax){
  5884. //t = tmax;
  5885. return false;
  5886. }
  5887. return true;
  5888. };
  5889. },{"../math/Vec3":52,"../utils/Utils":75}],25:[function(require,module,exports){
  5890. module.exports = ArrayCollisionMatrix;
  5891. /**
  5892. * Collision "matrix". It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step
  5893. * @class ArrayCollisionMatrix
  5894. * @constructor
  5895. */
  5896. function ArrayCollisionMatrix() {
  5897. /**
  5898. * The matrix storage
  5899. * @property matrix
  5900. * @type {Array}
  5901. */
  5902. this.matrix = [];
  5903. }
  5904. /**
  5905. * Get an element
  5906. * @method get
  5907. * @param {Number} i
  5908. * @param {Number} j
  5909. * @return {Number}
  5910. */
  5911. ArrayCollisionMatrix.prototype.get = function(i, j) {
  5912. i = i.index;
  5913. j = j.index;
  5914. if (j > i) {
  5915. var temp = j;
  5916. j = i;
  5917. i = temp;
  5918. }
  5919. return this.matrix[(i*(i + 1)>>1) + j-1];
  5920. };
  5921. /**
  5922. * Set an element
  5923. * @method set
  5924. * @param {Number} i
  5925. * @param {Number} j
  5926. * @param {Number} value
  5927. */
  5928. ArrayCollisionMatrix.prototype.set = function(i, j, value) {
  5929. i = i.index;
  5930. j = j.index;
  5931. if (j > i) {
  5932. var temp = j;
  5933. j = i;
  5934. i = temp;
  5935. }
  5936. this.matrix[(i*(i + 1)>>1) + j-1] = value ? 1 : 0;
  5937. };
  5938. /**
  5939. * Sets all elements to zero
  5940. * @method reset
  5941. */
  5942. ArrayCollisionMatrix.prototype.reset = function() {
  5943. for (var i=0, l=this.matrix.length; i!==l; i++) {
  5944. this.matrix[i]=0;
  5945. }
  5946. };
  5947. /**
  5948. * Sets the max number of objects
  5949. * @method setNumObjects
  5950. * @param {Number} n
  5951. */
  5952. ArrayCollisionMatrix.prototype.setNumObjects = function(n) {
  5953. this.matrix.length = n*(n-1)>>1;
  5954. };
  5955. },{}],26:[function(require,module,exports){
  5956. var Body = require('../objects/Body');
  5957. var Vec3 = require('../math/Vec3');
  5958. var Quaternion = require('../math/Quaternion');
  5959. var Shape = require('../shapes/Shape');
  5960. var Plane = require('../shapes/Plane');
  5961. module.exports = Broadphase;
  5962. /**
  5963. * Base class for broadphase implementations
  5964. * @class Broadphase
  5965. * @constructor
  5966. * @author schteppe
  5967. */
  5968. function Broadphase(){
  5969. /**
  5970. * The world to search for collisions in.
  5971. * @property world
  5972. * @type {World}
  5973. */
  5974. this.world = null;
  5975. /**
  5976. * If set to true, the broadphase uses bounding boxes for intersection test, else it uses bounding spheres.
  5977. * @property useBoundingBoxes
  5978. * @type {Boolean}
  5979. */
  5980. this.useBoundingBoxes = false;
  5981. /**
  5982. * Set to true if the objects in the world moved.
  5983. * @property {Boolean} dirty
  5984. */
  5985. this.dirty = true;
  5986. }
  5987. /**
  5988. * Get the collision pairs from the world
  5989. * @method collisionPairs
  5990. * @param {World} world The world to search in
  5991. * @param {Array} p1 Empty array to be filled with body objects
  5992. * @param {Array} p2 Empty array to be filled with body objects
  5993. */
  5994. Broadphase.prototype.collisionPairs = function(world,p1,p2){
  5995. throw new Error("collisionPairs not implemented for this BroadPhase class!");
  5996. };
  5997. /**
  5998. * Check if a body pair needs to be intersection tested at all.
  5999. * @method needBroadphaseCollision
  6000. * @param {Body} bodyA
  6001. * @param {Body} bodyB
  6002. * @return {bool}
  6003. */
  6004. Broadphase.prototype.needBroadphaseCollision = function(bodyA,bodyB){
  6005. // Check collision filter masks
  6006. if( (bodyA.collisionFilterGroup & bodyB.collisionFilterMask)===0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask)===0){
  6007. return false;
  6008. }
  6009. // Check types
  6010. if(((bodyA.type & Body.STATIC)!==0 || bodyA.sleepState === Body.SLEEPING) &&
  6011. ((bodyB.type & Body.STATIC)!==0 || bodyB.sleepState === Body.SLEEPING)) {
  6012. // Both bodies are static or sleeping. Skip.
  6013. return false;
  6014. }
  6015. return true;
  6016. };
  6017. /**
  6018. * Check if the bounding volumes of two bodies intersect.
  6019. * @method intersectionTest
  6020. * @param {Body} bodyA
  6021. * @param {Body} bodyB
  6022. * @param {array} pairs1
  6023. * @param {array} pairs2
  6024. */
  6025. Broadphase.prototype.intersectionTest = function(bodyA, bodyB, pairs1, pairs2){
  6026. if(this.useBoundingBoxes){
  6027. this.doBoundingBoxBroadphase(bodyA,bodyB,pairs1,pairs2);
  6028. } else {
  6029. this.doBoundingSphereBroadphase(bodyA,bodyB,pairs1,pairs2);
  6030. }
  6031. };
  6032. /**
  6033. * Check if the bounding spheres of two bodies are intersecting.
  6034. * @method doBoundingSphereBroadphase
  6035. * @param {Body} bodyA
  6036. * @param {Body} bodyB
  6037. * @param {Array} pairs1 bodyA is appended to this array if intersection
  6038. * @param {Array} pairs2 bodyB is appended to this array if intersection
  6039. */
  6040. var Broadphase_collisionPairs_r = new Vec3(), // Temp objects
  6041. Broadphase_collisionPairs_normal = new Vec3(),
  6042. Broadphase_collisionPairs_quat = new Quaternion(),
  6043. Broadphase_collisionPairs_relpos = new Vec3();
  6044. Broadphase.prototype.doBoundingSphereBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  6045. var r = Broadphase_collisionPairs_r;
  6046. bodyB.position.vsub(bodyA.position,r);
  6047. var boundingRadiusSum2 = Math.pow(bodyA.boundingRadius + bodyB.boundingRadius, 2);
  6048. var norm2 = r.norm2();
  6049. if(norm2 < boundingRadiusSum2){
  6050. pairs1.push(bodyA);
  6051. pairs2.push(bodyB);
  6052. }
  6053. };
  6054. /**
  6055. * Check if the bounding boxes of two bodies are intersecting.
  6056. * @method doBoundingBoxBroadphase
  6057. * @param {Body} bodyA
  6058. * @param {Body} bodyB
  6059. * @param {Array} pairs1
  6060. * @param {Array} pairs2
  6061. */
  6062. Broadphase.prototype.doBoundingBoxBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  6063. if(bodyA.aabbNeedsUpdate){
  6064. bodyA.computeAABB();
  6065. }
  6066. if(bodyB.aabbNeedsUpdate){
  6067. bodyB.computeAABB();
  6068. }
  6069. // Check AABB / AABB
  6070. if(bodyA.aabb.overlaps(bodyB.aabb)){
  6071. pairs1.push(bodyA);
  6072. pairs2.push(bodyB);
  6073. }
  6074. };
  6075. /**
  6076. * Removes duplicate pairs from the pair arrays.
  6077. * @method makePairsUnique
  6078. * @param {Array} pairs1
  6079. * @param {Array} pairs2
  6080. */
  6081. var Broadphase_makePairsUnique_temp = { keys:[] },
  6082. Broadphase_makePairsUnique_p1 = [],
  6083. Broadphase_makePairsUnique_p2 = [];
  6084. Broadphase.prototype.makePairsUnique = function(pairs1,pairs2){
  6085. var t = Broadphase_makePairsUnique_temp,
  6086. p1 = Broadphase_makePairsUnique_p1,
  6087. p2 = Broadphase_makePairsUnique_p2,
  6088. N = pairs1.length;
  6089. for(var i=0; i!==N; i++){
  6090. p1[i] = pairs1[i];
  6091. p2[i] = pairs2[i];
  6092. }
  6093. pairs1.length = 0;
  6094. pairs2.length = 0;
  6095. for(var i=0; i!==N; i++){
  6096. var id1 = p1[i].id,
  6097. id2 = p2[i].id;
  6098. var key = id1 < id2 ? id1+","+id2 : id2+","+id1;
  6099. t[key] = i;
  6100. t.keys.push(key);
  6101. }
  6102. for(var i=0; i!==t.keys.length; i++){
  6103. var key = t.keys.pop(),
  6104. pairIndex = t[key];
  6105. pairs1.push(p1[pairIndex]);
  6106. pairs2.push(p2[pairIndex]);
  6107. delete t[key];
  6108. }
  6109. };
  6110. /**
  6111. * To be implemented by subcasses
  6112. * @method setWorld
  6113. * @param {World} world
  6114. */
  6115. Broadphase.prototype.setWorld = function(world){
  6116. };
  6117. /**
  6118. * Check if the bounding spheres of two bodies overlap.
  6119. * @method boundingSphereCheck
  6120. * @param {Body} bodyA
  6121. * @param {Body} bodyB
  6122. * @return {boolean}
  6123. */
  6124. var bsc_dist = new Vec3();
  6125. Broadphase.boundingSphereCheck = function(bodyA,bodyB){
  6126. var dist = bsc_dist;
  6127. bodyA.position.vsub(bodyB.position,dist);
  6128. return Math.pow(bodyA.shape.boundingSphereRadius + bodyB.shape.boundingSphereRadius,2) > dist.norm2();
  6129. };
  6130. /**
  6131. * Returns all the bodies within the AABB.
  6132. * @method aabbQuery
  6133. * @param {World} world
  6134. * @param {AABB} aabb
  6135. * @param {array} result An array to store resulting bodies in.
  6136. * @return {array}
  6137. */
  6138. Broadphase.prototype.aabbQuery = function(world, aabb, result){
  6139. console.warn('.aabbQuery is not implemented in this Broadphase subclass.');
  6140. return [];
  6141. };
  6142. },{"../math/Quaternion":50,"../math/Vec3":52,"../objects/Body":53,"../shapes/Plane":64,"../shapes/Shape":65}],27:[function(require,module,exports){
  6143. module.exports = GridBroadphase;
  6144. var Broadphase = require('./Broadphase');
  6145. var Vec3 = require('../math/Vec3');
  6146. var Shape = require('../shapes/Shape');
  6147. /**
  6148. * Axis aligned uniform grid broadphase.
  6149. * @class GridBroadphase
  6150. * @constructor
  6151. * @extends Broadphase
  6152. * @todo Needs support for more than just planes and spheres.
  6153. * @param {Vec3} aabbMin
  6154. * @param {Vec3} aabbMax
  6155. * @param {Number} nx Number of boxes along x
  6156. * @param {Number} ny Number of boxes along y
  6157. * @param {Number} nz Number of boxes along z
  6158. */
  6159. function GridBroadphase(aabbMin,aabbMax,nx,ny,nz){
  6160. Broadphase.apply(this);
  6161. this.nx = nx || 10;
  6162. this.ny = ny || 10;
  6163. this.nz = nz || 10;
  6164. this.aabbMin = aabbMin || new Vec3(100,100,100);
  6165. this.aabbMax = aabbMax || new Vec3(-100,-100,-100);
  6166. var nbins = this.nx * this.ny * this.nz;
  6167. if (nbins <= 0) {
  6168. throw "GridBroadphase: Each dimension's n must be >0";
  6169. }
  6170. this.bins = [];
  6171. this.binLengths = []; //Rather than continually resizing arrays (thrashing the memory), just record length and allow them to grow
  6172. this.bins.length = nbins;
  6173. this.binLengths.length = nbins;
  6174. for (var i=0;i<nbins;i++) {
  6175. this.bins[i]=[];
  6176. this.binLengths[i]=0;
  6177. }
  6178. }
  6179. GridBroadphase.prototype = new Broadphase();
  6180. GridBroadphase.prototype.constructor = GridBroadphase;
  6181. /**
  6182. * Get all the collision pairs in the physics world
  6183. * @method collisionPairs
  6184. * @param {World} world
  6185. * @param {Array} pairs1
  6186. * @param {Array} pairs2
  6187. */
  6188. var GridBroadphase_collisionPairs_d = new Vec3();
  6189. var GridBroadphase_collisionPairs_binPos = new Vec3();
  6190. GridBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  6191. var N = world.numObjects(),
  6192. bodies = world.bodies;
  6193. var max = this.aabbMax,
  6194. min = this.aabbMin,
  6195. nx = this.nx,
  6196. ny = this.ny,
  6197. nz = this.nz;
  6198. var xstep = ny*nz;
  6199. var ystep = nz;
  6200. var zstep = 1;
  6201. var xmax = max.x,
  6202. ymax = max.y,
  6203. zmax = max.z,
  6204. xmin = min.x,
  6205. ymin = min.y,
  6206. zmin = min.z;
  6207. var xmult = nx / (xmax-xmin),
  6208. ymult = ny / (ymax-ymin),
  6209. zmult = nz / (zmax-zmin);
  6210. var binsizeX = (xmax - xmin) / nx,
  6211. binsizeY = (ymax - ymin) / ny,
  6212. binsizeZ = (zmax - zmin) / nz;
  6213. var binRadius = Math.sqrt(binsizeX*binsizeX + binsizeY*binsizeY + binsizeZ*binsizeZ) * 0.5;
  6214. var types = Shape.types;
  6215. var SPHERE = types.SPHERE,
  6216. PLANE = types.PLANE,
  6217. BOX = types.BOX,
  6218. COMPOUND = types.COMPOUND,
  6219. CONVEXPOLYHEDRON = types.CONVEXPOLYHEDRON;
  6220. var bins=this.bins,
  6221. binLengths=this.binLengths,
  6222. Nbins=this.bins.length;
  6223. // Reset bins
  6224. for(var i=0; i!==Nbins; i++){
  6225. binLengths[i] = 0;
  6226. }
  6227. var ceil = Math.ceil;
  6228. var min = Math.min;
  6229. var max = Math.max;
  6230. function addBoxToBins(x0,y0,z0,x1,y1,z1,bi) {
  6231. var xoff0 = ((x0 - xmin) * xmult)|0,
  6232. yoff0 = ((y0 - ymin) * ymult)|0,
  6233. zoff0 = ((z0 - zmin) * zmult)|0,
  6234. xoff1 = ceil((x1 - xmin) * xmult),
  6235. yoff1 = ceil((y1 - ymin) * ymult),
  6236. zoff1 = ceil((z1 - zmin) * zmult);
  6237. if (xoff0 < 0) { xoff0 = 0; } else if (xoff0 >= nx) { xoff0 = nx - 1; }
  6238. if (yoff0 < 0) { yoff0 = 0; } else if (yoff0 >= ny) { yoff0 = ny - 1; }
  6239. if (zoff0 < 0) { zoff0 = 0; } else if (zoff0 >= nz) { zoff0 = nz - 1; }
  6240. if (xoff1 < 0) { xoff1 = 0; } else if (xoff1 >= nx) { xoff1 = nx - 1; }
  6241. if (yoff1 < 0) { yoff1 = 0; } else if (yoff1 >= ny) { yoff1 = ny - 1; }
  6242. if (zoff1 < 0) { zoff1 = 0; } else if (zoff1 >= nz) { zoff1 = nz - 1; }
  6243. xoff0 *= xstep;
  6244. yoff0 *= ystep;
  6245. zoff0 *= zstep;
  6246. xoff1 *= xstep;
  6247. yoff1 *= ystep;
  6248. zoff1 *= zstep;
  6249. for (var xoff = xoff0; xoff <= xoff1; xoff += xstep) {
  6250. for (var yoff = yoff0; yoff <= yoff1; yoff += ystep) {
  6251. for (var zoff = zoff0; zoff <= zoff1; zoff += zstep) {
  6252. var idx = xoff+yoff+zoff;
  6253. bins[idx][binLengths[idx]++] = bi;
  6254. }
  6255. }
  6256. }
  6257. }
  6258. // Put all bodies into the bins
  6259. for(var i=0; i!==N; i++){
  6260. var bi = bodies[i];
  6261. var si = bi.shape;
  6262. switch(si.type){
  6263. case SPHERE:
  6264. // Put in bin
  6265. // check if overlap with other bins
  6266. var x = bi.position.x,
  6267. y = bi.position.y,
  6268. z = bi.position.z;
  6269. var r = si.radius;
  6270. addBoxToBins(x-r, y-r, z-r, x+r, y+r, z+r, bi);
  6271. break;
  6272. case PLANE:
  6273. if(si.worldNormalNeedsUpdate){
  6274. si.computeWorldNormal(bi.quaternion);
  6275. }
  6276. var planeNormal = si.worldNormal;
  6277. //Relative position from origin of plane object to the first bin
  6278. //Incremented as we iterate through the bins
  6279. var xreset = xmin + binsizeX*0.5 - bi.position.x,
  6280. yreset = ymin + binsizeY*0.5 - bi.position.y,
  6281. zreset = zmin + binsizeZ*0.5 - bi.position.z;
  6282. var d = GridBroadphase_collisionPairs_d;
  6283. d.set(xreset, yreset, zreset);
  6284. for (var xi = 0, xoff = 0; xi !== nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
  6285. for (var yi = 0, yoff = 0; yi !== ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
  6286. for (var zi = 0, zoff = 0; zi !== nz; zi++, zoff += zstep, d.z += binsizeZ) {
  6287. if (d.dot(planeNormal) < binRadius) {
  6288. var idx = xoff + yoff + zoff;
  6289. bins[idx][binLengths[idx]++] = bi;
  6290. }
  6291. }
  6292. }
  6293. }
  6294. break;
  6295. default:
  6296. if (bi.aabbNeedsUpdate) {
  6297. bi.computeAABB();
  6298. }
  6299. addBoxToBins(
  6300. bi.aabb.lowerBound.x,
  6301. bi.aabb.lowerBound.y,
  6302. bi.aabb.lowerBound.z,
  6303. bi.aabb.upperBound.x,
  6304. bi.aabb.upperBound.y,
  6305. bi.aabb.upperBound.z,
  6306. bi);
  6307. break;
  6308. }
  6309. }
  6310. // Check each bin
  6311. for(var i=0; i!==Nbins; i++){
  6312. var binLength = binLengths[i];
  6313. //Skip bins with no potential collisions
  6314. if (binLength > 1) {
  6315. var bin = bins[i];
  6316. // Do N^2 broadphase inside
  6317. for(var xi=0; xi!==binLength; xi++){
  6318. var bi = bin[xi];
  6319. for(var yi=0; yi!==xi; yi++){
  6320. var bj = bin[yi];
  6321. if(this.needBroadphaseCollision(bi,bj)){
  6322. this.intersectionTest(bi,bj,pairs1,pairs2);
  6323. }
  6324. }
  6325. }
  6326. }
  6327. }
  6328. // for (var zi = 0, zoff=0; zi < nz; zi++, zoff+= zstep) {
  6329. // console.log("layer "+zi);
  6330. // for (var yi = 0, yoff=0; yi < ny; yi++, yoff += ystep) {
  6331. // var row = '';
  6332. // for (var xi = 0, xoff=0; xi < nx; xi++, xoff += xstep) {
  6333. // var idx = xoff + yoff + zoff;
  6334. // row += ' ' + binLengths[idx];
  6335. // }
  6336. // console.log(row);
  6337. // }
  6338. // }
  6339. this.makePairsUnique(pairs1,pairs2);
  6340. };
  6341. },{"../math/Vec3":52,"../shapes/Shape":65,"./Broadphase":26}],28:[function(require,module,exports){
  6342. module.exports = NaiveBroadphase;
  6343. var Broadphase = require('./Broadphase');
  6344. var AABB = require('./AABB');
  6345. /**
  6346. * Naive broadphase implementation, used in lack of better ones.
  6347. * @class NaiveBroadphase
  6348. * @constructor
  6349. * @description The naive broadphase looks at all possible pairs without restriction, therefore it has complexity N^2 (which is bad)
  6350. * @extends Broadphase
  6351. */
  6352. function NaiveBroadphase(){
  6353. Broadphase.apply(this);
  6354. }
  6355. NaiveBroadphase.prototype = new Broadphase();
  6356. NaiveBroadphase.prototype.constructor = NaiveBroadphase;
  6357. /**
  6358. * Get all the collision pairs in the physics world
  6359. * @method collisionPairs
  6360. * @param {World} world
  6361. * @param {Array} pairs1
  6362. * @param {Array} pairs2
  6363. */
  6364. NaiveBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  6365. var bodies = world.bodies,
  6366. n = bodies.length,
  6367. i,j,bi,bj;
  6368. // Naive N^2 ftw!
  6369. for(i=0; i!==n; i++){
  6370. for(j=0; j!==i; j++){
  6371. bi = bodies[i];
  6372. bj = bodies[j];
  6373. if(!this.needBroadphaseCollision(bi,bj)){
  6374. continue;
  6375. }
  6376. this.intersectionTest(bi,bj,pairs1,pairs2);
  6377. }
  6378. }
  6379. };
  6380. var tmpAABB = new AABB();
  6381. /**
  6382. * Returns all the bodies within an AABB.
  6383. * @method aabbQuery
  6384. * @param {World} world
  6385. * @param {AABB} aabb
  6386. * @param {array} result An array to store resulting bodies in.
  6387. * @return {array}
  6388. */
  6389. NaiveBroadphase.prototype.aabbQuery = function(world, aabb, result){
  6390. result = result || [];
  6391. for(var i = 0; i < world.bodies.length; i++){
  6392. var b = world.bodies[i];
  6393. if(b.aabbNeedsUpdate){
  6394. b.computeAABB();
  6395. }
  6396. // Ugly hack until Body gets aabb
  6397. if(b.aabb.overlaps(aabb)){
  6398. result.push(b);
  6399. }
  6400. }
  6401. return result;
  6402. };
  6403. },{"./AABB":24,"./Broadphase":26}],29:[function(require,module,exports){
  6404. module.exports = ObjectCollisionMatrix;
  6405. /**
  6406. * Records what objects are colliding with each other
  6407. * @class ObjectCollisionMatrix
  6408. * @constructor
  6409. */
  6410. function ObjectCollisionMatrix() {
  6411. /**
  6412. * The matrix storage
  6413. * @property matrix
  6414. * @type {Object}
  6415. */
  6416. this.matrix = {};
  6417. }
  6418. /**
  6419. * @method get
  6420. * @param {Number} i
  6421. * @param {Number} j
  6422. * @return {Number}
  6423. */
  6424. ObjectCollisionMatrix.prototype.get = function(i, j) {
  6425. i = i.id;
  6426. j = j.id;
  6427. if (j > i) {
  6428. var temp = j;
  6429. j = i;
  6430. i = temp;
  6431. }
  6432. return i+'-'+j in this.matrix;
  6433. };
  6434. /**
  6435. * @method set
  6436. * @param {Number} i
  6437. * @param {Number} j
  6438. * @param {Number} value
  6439. */
  6440. ObjectCollisionMatrix.prototype.set = function(i, j, value) {
  6441. i = i.id;
  6442. j = j.id;
  6443. if (j > i) {
  6444. var temp = j;
  6445. j = i;
  6446. i = temp;
  6447. }
  6448. if (value) {
  6449. this.matrix[i+'-'+j] = true;
  6450. }
  6451. else {
  6452. delete this.matrix[i+'-'+j];
  6453. }
  6454. };
  6455. /**
  6456. * Empty the matrix
  6457. * @method reset
  6458. */
  6459. ObjectCollisionMatrix.prototype.reset = function() {
  6460. this.matrix = {};
  6461. };
  6462. /**
  6463. * Set max number of objects
  6464. * @method setNumObjects
  6465. * @param {Number} n
  6466. */
  6467. ObjectCollisionMatrix.prototype.setNumObjects = function(n) {
  6468. };
  6469. },{}],30:[function(require,module,exports){
  6470. module.exports = OverlapKeeper;
  6471. /**
  6472. * @class OverlapKeeper
  6473. * @constructor
  6474. */
  6475. function OverlapKeeper() {
  6476. this.current = [];
  6477. this.previous = [];
  6478. }
  6479. OverlapKeeper.prototype.getKey = function(i, j) {
  6480. if (j < i) {
  6481. var temp = j;
  6482. j = i;
  6483. i = temp;
  6484. }
  6485. return (i << 16) | j;
  6486. };
  6487. /**
  6488. * @method set
  6489. * @param {Number} i
  6490. * @param {Number} j
  6491. */
  6492. OverlapKeeper.prototype.set = function(i, j) {
  6493. // Insertion sort. This way the diff will have linear complexity.
  6494. var key = this.getKey(i, j);
  6495. var current = this.current;
  6496. var index = 0;
  6497. while(key > current[index]){
  6498. index++;
  6499. }
  6500. if(key === current[index]){
  6501. return; // Pair was already added
  6502. }
  6503. for(var j=current.length-1; j>=index; j--){
  6504. current[j + 1] = current[j];
  6505. }
  6506. current[index] = key;
  6507. };
  6508. /**
  6509. * @method tick
  6510. */
  6511. OverlapKeeper.prototype.tick = function() {
  6512. var tmp = this.current;
  6513. this.current = this.previous;
  6514. this.previous = tmp;
  6515. this.current.length = 0;
  6516. };
  6517. function unpackAndPush(array, key){
  6518. array.push((key & 0xFFFF0000) >> 16, key & 0x0000FFFF);
  6519. }
  6520. /**
  6521. * @method getDiff
  6522. * @param {array} additions
  6523. * @param {array} removals
  6524. */
  6525. OverlapKeeper.prototype.getDiff = function(additions, removals) {
  6526. var a = this.current;
  6527. var b = this.previous;
  6528. var al = a.length;
  6529. var bl = b.length;
  6530. var j=0;
  6531. for (var i = 0; i < al; i++) {
  6532. var found = false;
  6533. var keyA = a[i];
  6534. while(keyA > b[j]){
  6535. j++;
  6536. }
  6537. found = keyA === b[j];
  6538. if(!found){
  6539. unpackAndPush(additions, keyA);
  6540. }
  6541. }
  6542. j = 0;
  6543. for (var i = 0; i < bl; i++) {
  6544. var found = false;
  6545. var keyB = b[i];
  6546. while(keyB > a[j]){
  6547. j++;
  6548. }
  6549. found = a[j] === keyB;
  6550. if(!found){
  6551. unpackAndPush(removals, keyB);
  6552. }
  6553. }
  6554. };
  6555. },{}],31:[function(require,module,exports){
  6556. module.exports = Ray;
  6557. var Vec3 = require('../math/Vec3');
  6558. var Quaternion = require('../math/Quaternion');
  6559. var Transform = require('../math/Transform');
  6560. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  6561. var Box = require('../shapes/Box');
  6562. var RaycastResult = require('../collision/RaycastResult');
  6563. var Shape = require('../shapes/Shape');
  6564. var AABB = require('../collision/AABB');
  6565. /**
  6566. * A line in 3D space that intersects bodies and return points.
  6567. * @class Ray
  6568. * @constructor
  6569. * @param {Vec3} from
  6570. * @param {Vec3} to
  6571. */
  6572. function Ray(from, to){
  6573. /**
  6574. * @property {Vec3} from
  6575. */
  6576. this.from = from ? from.clone() : new Vec3();
  6577. /**
  6578. * @property {Vec3} to
  6579. */
  6580. this.to = to ? to.clone() : new Vec3();
  6581. /**
  6582. * @private
  6583. * @property {Vec3} _direction
  6584. */
  6585. this._direction = new Vec3();
  6586. /**
  6587. * The precision of the ray. Used when checking parallelity etc.
  6588. * @property {Number} precision
  6589. */
  6590. this.precision = 0.0001;
  6591. /**
  6592. * Set to true if you want the Ray to take .collisionResponse flags into account on bodies and shapes.
  6593. * @property {Boolean} checkCollisionResponse
  6594. */
  6595. this.checkCollisionResponse = true;
  6596. /**
  6597. * If set to true, the ray skips any hits with normal.dot(rayDirection) < 0.
  6598. * @property {Boolean} skipBackfaces
  6599. */
  6600. this.skipBackfaces = false;
  6601. /**
  6602. * @property {number} collisionFilterMask
  6603. * @default -1
  6604. */
  6605. this.collisionFilterMask = -1;
  6606. /**
  6607. * @property {number} collisionFilterGroup
  6608. * @default -1
  6609. */
  6610. this.collisionFilterGroup = -1;
  6611. /**
  6612. * The intersection mode. Should be Ray.ANY, Ray.ALL or Ray.CLOSEST.
  6613. * @property {number} mode
  6614. */
  6615. this.mode = Ray.ANY;
  6616. /**
  6617. * Current result object.
  6618. * @property {RaycastResult} result
  6619. */
  6620. this.result = new RaycastResult();
  6621. /**
  6622. * Will be set to true during intersectWorld() if the ray hit anything.
  6623. * @property {Boolean} hasHit
  6624. */
  6625. this.hasHit = false;
  6626. /**
  6627. * Current, user-provided result callback. Will be used if mode is Ray.ALL.
  6628. * @property {Function} callback
  6629. */
  6630. this.callback = function(result){};
  6631. }
  6632. Ray.prototype.constructor = Ray;
  6633. Ray.CLOSEST = 1;
  6634. Ray.ANY = 2;
  6635. Ray.ALL = 4;
  6636. var tmpAABB = new AABB();
  6637. var tmpArray = [];
  6638. /**
  6639. * Do itersection against all bodies in the given World.
  6640. * @method intersectWorld
  6641. * @param {World} world
  6642. * @param {object} options
  6643. * @return {Boolean} True if the ray hit anything, otherwise false.
  6644. */
  6645. Ray.prototype.intersectWorld = function (world, options) {
  6646. this.mode = options.mode || Ray.ANY;
  6647. this.result = options.result || new RaycastResult();
  6648. this.skipBackfaces = !!options.skipBackfaces;
  6649. this.collisionFilterMask = typeof(options.collisionFilterMask) !== 'undefined' ? options.collisionFilterMask : -1;
  6650. this.collisionFilterGroup = typeof(options.collisionFilterGroup) !== 'undefined' ? options.collisionFilterGroup : -1;
  6651. if(options.from){
  6652. this.from.copy(options.from);
  6653. }
  6654. if(options.to){
  6655. this.to.copy(options.to);
  6656. }
  6657. this.callback = options.callback || function(){};
  6658. this.hasHit = false;
  6659. this.result.reset();
  6660. this._updateDirection();
  6661. this.getAABB(tmpAABB);
  6662. tmpArray.length = 0;
  6663. world.broadphase.aabbQuery(world, tmpAABB, tmpArray);
  6664. this.intersectBodies(tmpArray);
  6665. return this.hasHit;
  6666. };
  6667. var v1 = new Vec3(),
  6668. v2 = new Vec3();
  6669. /*
  6670. * As per "Barycentric Technique" as named here http://www.blackpawn.com/texts/pointinpoly/default.html But without the division
  6671. */
  6672. Ray.pointInTriangle = pointInTriangle;
  6673. function pointInTriangle(p, a, b, c) {
  6674. c.vsub(a,v0);
  6675. b.vsub(a,v1);
  6676. p.vsub(a,v2);
  6677. var dot00 = v0.dot( v0 );
  6678. var dot01 = v0.dot( v1 );
  6679. var dot02 = v0.dot( v2 );
  6680. var dot11 = v1.dot( v1 );
  6681. var dot12 = v1.dot( v2 );
  6682. var u,v;
  6683. return ( (u = dot11 * dot02 - dot01 * dot12) >= 0 ) &&
  6684. ( (v = dot00 * dot12 - dot01 * dot02) >= 0 ) &&
  6685. ( u + v < ( dot00 * dot11 - dot01 * dot01 ) );
  6686. }
  6687. /**
  6688. * Shoot a ray at a body, get back information about the hit.
  6689. * @method intersectBody
  6690. * @private
  6691. * @param {Body} body
  6692. * @param {RaycastResult} [result] Deprecated - set the result property of the Ray instead.
  6693. */
  6694. var intersectBody_xi = new Vec3();
  6695. var intersectBody_qi = new Quaternion();
  6696. Ray.prototype.intersectBody = function (body, result) {
  6697. if(result){
  6698. this.result = result;
  6699. this._updateDirection();
  6700. }
  6701. var checkCollisionResponse = this.checkCollisionResponse;
  6702. if(checkCollisionResponse && !body.collisionResponse){
  6703. return;
  6704. }
  6705. if((this.collisionFilterGroup & body.collisionFilterMask)===0 || (body.collisionFilterGroup & this.collisionFilterMask)===0){
  6706. return;
  6707. }
  6708. var xi = intersectBody_xi;
  6709. var qi = intersectBody_qi;
  6710. for (var i = 0, N = body.shapes.length; i < N; i++) {
  6711. var shape = body.shapes[i];
  6712. if(checkCollisionResponse && !shape.collisionResponse){
  6713. continue; // Skip
  6714. }
  6715. body.quaternion.mult(body.shapeOrientations[i], qi);
  6716. body.quaternion.vmult(body.shapeOffsets[i], xi);
  6717. xi.vadd(body.position, xi);
  6718. this.intersectShape(
  6719. shape,
  6720. qi,
  6721. xi,
  6722. body
  6723. );
  6724. if(this.result._shouldStop){
  6725. break;
  6726. }
  6727. }
  6728. };
  6729. /**
  6730. * @method intersectBodies
  6731. * @param {Array} bodies An array of Body objects.
  6732. * @param {RaycastResult} [result] Deprecated
  6733. */
  6734. Ray.prototype.intersectBodies = function (bodies, result) {
  6735. if(result){
  6736. this.result = result;
  6737. this._updateDirection();
  6738. }
  6739. for ( var i = 0, l = bodies.length; !this.result._shouldStop && i < l; i ++ ) {
  6740. this.intersectBody(bodies[i]);
  6741. }
  6742. };
  6743. /**
  6744. * Updates the _direction vector.
  6745. * @private
  6746. * @method _updateDirection
  6747. */
  6748. Ray.prototype._updateDirection = function(){
  6749. this.to.vsub(this.from, this._direction);
  6750. this._direction.normalize();
  6751. };
  6752. /**
  6753. * @method intersectShape
  6754. * @private
  6755. * @param {Shape} shape
  6756. * @param {Quaternion} quat
  6757. * @param {Vec3} position
  6758. * @param {Body} body
  6759. */
  6760. Ray.prototype.intersectShape = function(shape, quat, position, body){
  6761. var from = this.from;
  6762. // Checking boundingSphere
  6763. var distance = distanceFromIntersection(from, this._direction, position);
  6764. if ( distance > shape.boundingSphereRadius ) {
  6765. return;
  6766. }
  6767. var intersectMethod = this[shape.type];
  6768. if(intersectMethod){
  6769. intersectMethod.call(this, shape, quat, position, body, shape);
  6770. }
  6771. };
  6772. var vector = new Vec3();
  6773. var normal = new Vec3();
  6774. var intersectPoint = new Vec3();
  6775. var a = new Vec3();
  6776. var b = new Vec3();
  6777. var c = new Vec3();
  6778. var d = new Vec3();
  6779. var tmpRaycastResult = new RaycastResult();
  6780. /**
  6781. * @method intersectBox
  6782. * @private
  6783. * @param {Shape} shape
  6784. * @param {Quaternion} quat
  6785. * @param {Vec3} position
  6786. * @param {Body} body
  6787. */
  6788. Ray.prototype.intersectBox = function(shape, quat, position, body, reportedShape){
  6789. return this.intersectConvex(shape.convexPolyhedronRepresentation, quat, position, body, reportedShape);
  6790. };
  6791. Ray.prototype[Shape.types.BOX] = Ray.prototype.intersectBox;
  6792. /**
  6793. * @method intersectPlane
  6794. * @private
  6795. * @param {Shape} shape
  6796. * @param {Quaternion} quat
  6797. * @param {Vec3} position
  6798. * @param {Body} body
  6799. */
  6800. Ray.prototype.intersectPlane = function(shape, quat, position, body, reportedShape){
  6801. var from = this.from;
  6802. var to = this.to;
  6803. var direction = this._direction;
  6804. // Get plane normal
  6805. var worldNormal = new Vec3(0, 0, 1);
  6806. quat.vmult(worldNormal, worldNormal);
  6807. var len = new Vec3();
  6808. from.vsub(position, len);
  6809. var planeToFrom = len.dot(worldNormal);
  6810. to.vsub(position, len);
  6811. var planeToTo = len.dot(worldNormal);
  6812. if(planeToFrom * planeToTo > 0){
  6813. // "from" and "to" are on the same side of the plane... bail out
  6814. return;
  6815. }
  6816. if(from.distanceTo(to) < planeToFrom){
  6817. return;
  6818. }
  6819. var n_dot_dir = worldNormal.dot(direction);
  6820. if (Math.abs(n_dot_dir) < this.precision) {
  6821. // No intersection
  6822. return;
  6823. }
  6824. var planePointToFrom = new Vec3();
  6825. var dir_scaled_with_t = new Vec3();
  6826. var hitPointWorld = new Vec3();
  6827. from.vsub(position, planePointToFrom);
  6828. var t = -worldNormal.dot(planePointToFrom) / n_dot_dir;
  6829. direction.scale(t, dir_scaled_with_t);
  6830. from.vadd(dir_scaled_with_t, hitPointWorld);
  6831. this.reportIntersection(worldNormal, hitPointWorld, reportedShape, body, -1);
  6832. };
  6833. Ray.prototype[Shape.types.PLANE] = Ray.prototype.intersectPlane;
  6834. /**
  6835. * Get the world AABB of the ray.
  6836. * @method getAABB
  6837. * @param {AABB} aabb
  6838. */
  6839. Ray.prototype.getAABB = function(result){
  6840. var to = this.to;
  6841. var from = this.from;
  6842. result.lowerBound.x = Math.min(to.x, from.x);
  6843. result.lowerBound.y = Math.min(to.y, from.y);
  6844. result.lowerBound.z = Math.min(to.z, from.z);
  6845. result.upperBound.x = Math.max(to.x, from.x);
  6846. result.upperBound.y = Math.max(to.y, from.y);
  6847. result.upperBound.z = Math.max(to.z, from.z);
  6848. };
  6849. var intersectConvexOptions = {
  6850. faceList: [0]
  6851. };
  6852. var worldPillarOffset = new Vec3();
  6853. var intersectHeightfield_localRay = new Ray();
  6854. var intersectHeightfield_index = [];
  6855. var intersectHeightfield_minMax = [];
  6856. /**
  6857. * @method intersectHeightfield
  6858. * @private
  6859. * @param {Shape} shape
  6860. * @param {Quaternion} quat
  6861. * @param {Vec3} position
  6862. * @param {Body} body
  6863. */
  6864. Ray.prototype.intersectHeightfield = function(shape, quat, position, body, reportedShape){
  6865. var data = shape.data,
  6866. w = shape.elementSize;
  6867. // Convert the ray to local heightfield coordinates
  6868. var localRay = intersectHeightfield_localRay; //new Ray(this.from, this.to);
  6869. localRay.from.copy(this.from);
  6870. localRay.to.copy(this.to);
  6871. Transform.pointToLocalFrame(position, quat, localRay.from, localRay.from);
  6872. Transform.pointToLocalFrame(position, quat, localRay.to, localRay.to);
  6873. localRay._updateDirection();
  6874. // Get the index of the data points to test against
  6875. var index = intersectHeightfield_index;
  6876. var iMinX, iMinY, iMaxX, iMaxY;
  6877. // Set to max
  6878. iMinX = iMinY = 0;
  6879. iMaxX = iMaxY = shape.data.length - 1;
  6880. var aabb = new AABB();
  6881. localRay.getAABB(aabb);
  6882. shape.getIndexOfPosition(aabb.lowerBound.x, aabb.lowerBound.y, index, true);
  6883. iMinX = Math.max(iMinX, index[0]);
  6884. iMinY = Math.max(iMinY, index[1]);
  6885. shape.getIndexOfPosition(aabb.upperBound.x, aabb.upperBound.y, index, true);
  6886. iMaxX = Math.min(iMaxX, index[0] + 1);
  6887. iMaxY = Math.min(iMaxY, index[1] + 1);
  6888. for(var i = iMinX; i < iMaxX; i++){
  6889. for(var j = iMinY; j < iMaxY; j++){
  6890. if(this.result._shouldStop){
  6891. return;
  6892. }
  6893. shape.getAabbAtIndex(i, j, aabb);
  6894. if(!aabb.overlapsRay(localRay)){
  6895. continue;
  6896. }
  6897. // Lower triangle
  6898. shape.getConvexTrianglePillar(i, j, false);
  6899. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  6900. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  6901. if(this.result._shouldStop){
  6902. return;
  6903. }
  6904. // Upper triangle
  6905. shape.getConvexTrianglePillar(i, j, true);
  6906. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  6907. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  6908. }
  6909. }
  6910. };
  6911. Ray.prototype[Shape.types.HEIGHTFIELD] = Ray.prototype.intersectHeightfield;
  6912. var Ray_intersectSphere_intersectionPoint = new Vec3();
  6913. var Ray_intersectSphere_normal = new Vec3();
  6914. /**
  6915. * @method intersectSphere
  6916. * @private
  6917. * @param {Shape} shape
  6918. * @param {Quaternion} quat
  6919. * @param {Vec3} position
  6920. * @param {Body} body
  6921. */
  6922. Ray.prototype.intersectSphere = function(shape, quat, position, body, reportedShape){
  6923. var from = this.from,
  6924. to = this.to,
  6925. r = shape.radius;
  6926. var a = Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2) + Math.pow(to.z - from.z, 2);
  6927. var b = 2 * ((to.x - from.x) * (from.x - position.x) + (to.y - from.y) * (from.y - position.y) + (to.z - from.z) * (from.z - position.z));
  6928. var c = Math.pow(from.x - position.x, 2) + Math.pow(from.y - position.y, 2) + Math.pow(from.z - position.z, 2) - Math.pow(r, 2);
  6929. var delta = Math.pow(b, 2) - 4 * a * c;
  6930. var intersectionPoint = Ray_intersectSphere_intersectionPoint;
  6931. var normal = Ray_intersectSphere_normal;
  6932. if(delta < 0){
  6933. // No intersection
  6934. return;
  6935. } else if(delta === 0){
  6936. // single intersection point
  6937. from.lerp(to, delta, intersectionPoint);
  6938. intersectionPoint.vsub(position, normal);
  6939. normal.normalize();
  6940. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  6941. } else {
  6942. var d1 = (- b - Math.sqrt(delta)) / (2 * a);
  6943. var d2 = (- b + Math.sqrt(delta)) / (2 * a);
  6944. if(d1 >= 0 && d1 <= 1){
  6945. from.lerp(to, d1, intersectionPoint);
  6946. intersectionPoint.vsub(position, normal);
  6947. normal.normalize();
  6948. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  6949. }
  6950. if(this.result._shouldStop){
  6951. return;
  6952. }
  6953. if(d2 >= 0 && d2 <= 1){
  6954. from.lerp(to, d2, intersectionPoint);
  6955. intersectionPoint.vsub(position, normal);
  6956. normal.normalize();
  6957. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  6958. }
  6959. }
  6960. };
  6961. Ray.prototype[Shape.types.SPHERE] = Ray.prototype.intersectSphere;
  6962. var intersectConvex_normal = new Vec3();
  6963. var intersectConvex_minDistNormal = new Vec3();
  6964. var intersectConvex_minDistIntersect = new Vec3();
  6965. var intersectConvex_vector = new Vec3();
  6966. /**
  6967. * @method intersectConvex
  6968. * @private
  6969. * @param {Shape} shape
  6970. * @param {Quaternion} quat
  6971. * @param {Vec3} position
  6972. * @param {Body} body
  6973. * @param {object} [options]
  6974. * @param {array} [options.faceList]
  6975. */
  6976. Ray.prototype.intersectConvex = function intersectConvex(
  6977. shape,
  6978. quat,
  6979. position,
  6980. body,
  6981. reportedShape,
  6982. options
  6983. ){
  6984. var minDistNormal = intersectConvex_minDistNormal;
  6985. var normal = intersectConvex_normal;
  6986. var vector = intersectConvex_vector;
  6987. var minDistIntersect = intersectConvex_minDistIntersect;
  6988. var faceList = (options && options.faceList) || null;
  6989. // Checking faces
  6990. var faces = shape.faces,
  6991. vertices = shape.vertices,
  6992. normals = shape.faceNormals;
  6993. var direction = this._direction;
  6994. var from = this.from;
  6995. var to = this.to;
  6996. var fromToDistance = from.distanceTo(to);
  6997. var minDist = -1;
  6998. var Nfaces = faceList ? faceList.length : faces.length;
  6999. var result = this.result;
  7000. for (var j = 0; !result._shouldStop && j < Nfaces; j++) {
  7001. var fi = faceList ? faceList[j] : j;
  7002. var face = faces[fi];
  7003. var faceNormal = normals[fi];
  7004. var q = quat;
  7005. var x = position;
  7006. // determine if ray intersects the plane of the face
  7007. // note: this works regardless of the direction of the face normal
  7008. // Get plane point in world coordinates...
  7009. vector.copy(vertices[face[0]]);
  7010. q.vmult(vector,vector);
  7011. vector.vadd(x,vector);
  7012. // ...but make it relative to the ray from. We'll fix this later.
  7013. vector.vsub(from,vector);
  7014. // Get plane normal
  7015. q.vmult(faceNormal,normal);
  7016. // If this dot product is negative, we have something interesting
  7017. var dot = direction.dot(normal);
  7018. // Bail out if ray and plane are parallel
  7019. if ( Math.abs( dot ) < this.precision ){
  7020. continue;
  7021. }
  7022. // calc distance to plane
  7023. var scalar = normal.dot(vector) / dot;
  7024. // if negative distance, then plane is behind ray
  7025. if (scalar < 0){
  7026. continue;
  7027. }
  7028. // if (dot < 0) {
  7029. // Intersection point is from + direction * scalar
  7030. direction.mult(scalar,intersectPoint);
  7031. intersectPoint.vadd(from,intersectPoint);
  7032. // a is the point we compare points b and c with.
  7033. a.copy(vertices[face[0]]);
  7034. q.vmult(a,a);
  7035. x.vadd(a,a);
  7036. for(var i = 1; !result._shouldStop && i < face.length - 1; i++){
  7037. // Transform 3 vertices to world coords
  7038. b.copy(vertices[face[i]]);
  7039. c.copy(vertices[face[i+1]]);
  7040. q.vmult(b,b);
  7041. q.vmult(c,c);
  7042. x.vadd(b,b);
  7043. x.vadd(c,c);
  7044. var distance = intersectPoint.distanceTo(from);
  7045. if(!(pointInTriangle(intersectPoint, a, b, c) || pointInTriangle(intersectPoint, b, a, c)) || distance > fromToDistance){
  7046. continue;
  7047. }
  7048. this.reportIntersection(normal, intersectPoint, reportedShape, body, fi);
  7049. }
  7050. // }
  7051. }
  7052. };
  7053. Ray.prototype[Shape.types.CONVEXPOLYHEDRON] = Ray.prototype.intersectConvex;
  7054. var intersectTrimesh_normal = new Vec3();
  7055. var intersectTrimesh_localDirection = new Vec3();
  7056. var intersectTrimesh_localFrom = new Vec3();
  7057. var intersectTrimesh_localTo = new Vec3();
  7058. var intersectTrimesh_worldNormal = new Vec3();
  7059. var intersectTrimesh_worldIntersectPoint = new Vec3();
  7060. var intersectTrimesh_localAABB = new AABB();
  7061. var intersectTrimesh_triangles = [];
  7062. var intersectTrimesh_treeTransform = new Transform();
  7063. /**
  7064. * @method intersectTrimesh
  7065. * @private
  7066. * @param {Shape} shape
  7067. * @param {Quaternion} quat
  7068. * @param {Vec3} position
  7069. * @param {Body} body
  7070. * @param {object} [options]
  7071. * @todo Optimize by transforming the world to local space first.
  7072. * @todo Use Octree lookup
  7073. */
  7074. Ray.prototype.intersectTrimesh = function intersectTrimesh(
  7075. mesh,
  7076. quat,
  7077. position,
  7078. body,
  7079. reportedShape,
  7080. options
  7081. ){
  7082. var normal = intersectTrimesh_normal;
  7083. var triangles = intersectTrimesh_triangles;
  7084. var treeTransform = intersectTrimesh_treeTransform;
  7085. var minDistNormal = intersectConvex_minDistNormal;
  7086. var vector = intersectConvex_vector;
  7087. var minDistIntersect = intersectConvex_minDistIntersect;
  7088. var localAABB = intersectTrimesh_localAABB;
  7089. var localDirection = intersectTrimesh_localDirection;
  7090. var localFrom = intersectTrimesh_localFrom;
  7091. var localTo = intersectTrimesh_localTo;
  7092. var worldIntersectPoint = intersectTrimesh_worldIntersectPoint;
  7093. var worldNormal = intersectTrimesh_worldNormal;
  7094. var faceList = (options && options.faceList) || null;
  7095. // Checking faces
  7096. var indices = mesh.indices,
  7097. vertices = mesh.vertices,
  7098. normals = mesh.faceNormals;
  7099. var from = this.from;
  7100. var to = this.to;
  7101. var direction = this._direction;
  7102. var minDist = -1;
  7103. treeTransform.position.copy(position);
  7104. treeTransform.quaternion.copy(quat);
  7105. // Transform ray to local space!
  7106. Transform.vectorToLocalFrame(position, quat, direction, localDirection);
  7107. Transform.pointToLocalFrame(position, quat, from, localFrom);
  7108. Transform.pointToLocalFrame(position, quat, to, localTo);
  7109. localTo.x *= mesh.scale.x;
  7110. localTo.y *= mesh.scale.y;
  7111. localTo.z *= mesh.scale.z;
  7112. localFrom.x *= mesh.scale.x;
  7113. localFrom.y *= mesh.scale.y;
  7114. localFrom.z *= mesh.scale.z;
  7115. localTo.vsub(localFrom, localDirection);
  7116. localDirection.normalize();
  7117. var fromToDistanceSquared = localFrom.distanceSquared(localTo);
  7118. mesh.tree.rayQuery(this, treeTransform, triangles);
  7119. for (var i = 0, N = triangles.length; !this.result._shouldStop && i !== N; i++) {
  7120. var trianglesIndex = triangles[i];
  7121. mesh.getNormal(trianglesIndex, normal);
  7122. // determine if ray intersects the plane of the face
  7123. // note: this works regardless of the direction of the face normal
  7124. // Get plane point in world coordinates...
  7125. mesh.getVertex(indices[trianglesIndex * 3], a);
  7126. // ...but make it relative to the ray from. We'll fix this later.
  7127. a.vsub(localFrom,vector);
  7128. // If this dot product is negative, we have something interesting
  7129. var dot = localDirection.dot(normal);
  7130. // Bail out if ray and plane are parallel
  7131. // if (Math.abs( dot ) < this.precision){
  7132. // continue;
  7133. // }
  7134. // calc distance to plane
  7135. var scalar = normal.dot(vector) / dot;
  7136. // if negative distance, then plane is behind ray
  7137. if (scalar < 0){
  7138. continue;
  7139. }
  7140. // Intersection point is from + direction * scalar
  7141. localDirection.scale(scalar,intersectPoint);
  7142. intersectPoint.vadd(localFrom,intersectPoint);
  7143. // Get triangle vertices
  7144. mesh.getVertex(indices[trianglesIndex * 3 + 1], b);
  7145. mesh.getVertex(indices[trianglesIndex * 3 + 2], c);
  7146. var squaredDistance = intersectPoint.distanceSquared(localFrom);
  7147. if(!(pointInTriangle(intersectPoint, b, a, c) || pointInTriangle(intersectPoint, a, b, c)) || squaredDistance > fromToDistanceSquared){
  7148. continue;
  7149. }
  7150. // transform intersectpoint and normal to world
  7151. Transform.vectorToWorldFrame(quat, normal, worldNormal);
  7152. Transform.pointToWorldFrame(position, quat, intersectPoint, worldIntersectPoint);
  7153. this.reportIntersection(worldNormal, worldIntersectPoint, reportedShape, body, trianglesIndex);
  7154. }
  7155. triangles.length = 0;
  7156. };
  7157. Ray.prototype[Shape.types.TRIMESH] = Ray.prototype.intersectTrimesh;
  7158. /**
  7159. * @method reportIntersection
  7160. * @private
  7161. * @param {Vec3} normal
  7162. * @param {Vec3} hitPointWorld
  7163. * @param {Shape} shape
  7164. * @param {Body} body
  7165. * @return {boolean} True if the intersections should continue
  7166. */
  7167. Ray.prototype.reportIntersection = function(normal, hitPointWorld, shape, body, hitFaceIndex){
  7168. var from = this.from;
  7169. var to = this.to;
  7170. var distance = from.distanceTo(hitPointWorld);
  7171. var result = this.result;
  7172. // Skip back faces?
  7173. if(this.skipBackfaces && normal.dot(this._direction) > 0){
  7174. return;
  7175. }
  7176. result.hitFaceIndex = typeof(hitFaceIndex) !== 'undefined' ? hitFaceIndex : -1;
  7177. switch(this.mode){
  7178. case Ray.ALL:
  7179. this.hasHit = true;
  7180. result.set(
  7181. from,
  7182. to,
  7183. normal,
  7184. hitPointWorld,
  7185. shape,
  7186. body,
  7187. distance
  7188. );
  7189. result.hasHit = true;
  7190. this.callback(result);
  7191. break;
  7192. case Ray.CLOSEST:
  7193. // Store if closer than current closest
  7194. if(distance < result.distance || !result.hasHit){
  7195. this.hasHit = true;
  7196. result.hasHit = true;
  7197. result.set(
  7198. from,
  7199. to,
  7200. normal,
  7201. hitPointWorld,
  7202. shape,
  7203. body,
  7204. distance
  7205. );
  7206. }
  7207. break;
  7208. case Ray.ANY:
  7209. // Report and stop.
  7210. this.hasHit = true;
  7211. result.hasHit = true;
  7212. result.set(
  7213. from,
  7214. to,
  7215. normal,
  7216. hitPointWorld,
  7217. shape,
  7218. body,
  7219. distance
  7220. );
  7221. result._shouldStop = true;
  7222. break;
  7223. }
  7224. };
  7225. var v0 = new Vec3(),
  7226. intersect = new Vec3();
  7227. function distanceFromIntersection(from, direction, position) {
  7228. // v0 is vector from from to position
  7229. position.vsub(from,v0);
  7230. var dot = v0.dot(direction);
  7231. // intersect = direction*dot + from
  7232. direction.mult(dot,intersect);
  7233. intersect.vadd(from,intersect);
  7234. var distance = position.distanceTo(intersect);
  7235. return distance;
  7236. }
  7237. },{"../collision/AABB":24,"../collision/RaycastResult":32,"../math/Quaternion":50,"../math/Transform":51,"../math/Vec3":52,"../shapes/Box":59,"../shapes/ConvexPolyhedron":60,"../shapes/Shape":65}],32:[function(require,module,exports){
  7238. var Vec3 = require('../math/Vec3');
  7239. module.exports = RaycastResult;
  7240. /**
  7241. * Storage for Ray casting data.
  7242. * @class RaycastResult
  7243. * @constructor
  7244. */
  7245. function RaycastResult(){
  7246. /**
  7247. * @property {Vec3} rayFromWorld
  7248. */
  7249. this.rayFromWorld = new Vec3();
  7250. /**
  7251. * @property {Vec3} rayToWorld
  7252. */
  7253. this.rayToWorld = new Vec3();
  7254. /**
  7255. * @property {Vec3} hitNormalWorld
  7256. */
  7257. this.hitNormalWorld = new Vec3();
  7258. /**
  7259. * @property {Vec3} hitPointWorld
  7260. */
  7261. this.hitPointWorld = new Vec3();
  7262. /**
  7263. * @property {boolean} hasHit
  7264. */
  7265. this.hasHit = false;
  7266. /**
  7267. * The hit shape, or null.
  7268. * @property {Shape} shape
  7269. */
  7270. this.shape = null;
  7271. /**
  7272. * The hit body, or null.
  7273. * @property {Body} body
  7274. */
  7275. this.body = null;
  7276. /**
  7277. * The index of the hit triangle, if the hit shape was a trimesh.
  7278. * @property {number} hitFaceIndex
  7279. * @default -1
  7280. */
  7281. this.hitFaceIndex = -1;
  7282. /**
  7283. * Distance to the hit. Will be set to -1 if there was no hit.
  7284. * @property {number} distance
  7285. * @default -1
  7286. */
  7287. this.distance = -1;
  7288. /**
  7289. * If the ray should stop traversing the bodies.
  7290. * @private
  7291. * @property {Boolean} _shouldStop
  7292. * @default false
  7293. */
  7294. this._shouldStop = false;
  7295. }
  7296. /**
  7297. * Reset all result data.
  7298. * @method reset
  7299. */
  7300. RaycastResult.prototype.reset = function () {
  7301. this.rayFromWorld.setZero();
  7302. this.rayToWorld.setZero();
  7303. this.hitNormalWorld.setZero();
  7304. this.hitPointWorld.setZero();
  7305. this.hasHit = false;
  7306. this.shape = null;
  7307. this.body = null;
  7308. this.hitFaceIndex = -1;
  7309. this.distance = -1;
  7310. this._shouldStop = false;
  7311. };
  7312. /**
  7313. * @method abort
  7314. */
  7315. RaycastResult.prototype.abort = function(){
  7316. this._shouldStop = true;
  7317. };
  7318. /**
  7319. * @method set
  7320. * @param {Vec3} rayFromWorld
  7321. * @param {Vec3} rayToWorld
  7322. * @param {Vec3} hitNormalWorld
  7323. * @param {Vec3} hitPointWorld
  7324. * @param {Shape} shape
  7325. * @param {Body} body
  7326. * @param {number} distance
  7327. */
  7328. RaycastResult.prototype.set = function(
  7329. rayFromWorld,
  7330. rayToWorld,
  7331. hitNormalWorld,
  7332. hitPointWorld,
  7333. shape,
  7334. body,
  7335. distance
  7336. ){
  7337. this.rayFromWorld.copy(rayFromWorld);
  7338. this.rayToWorld.copy(rayToWorld);
  7339. this.hitNormalWorld.copy(hitNormalWorld);
  7340. this.hitPointWorld.copy(hitPointWorld);
  7341. this.shape = shape;
  7342. this.body = body;
  7343. this.distance = distance;
  7344. };
  7345. },{"../math/Vec3":52}],33:[function(require,module,exports){
  7346. var Shape = require('../shapes/Shape');
  7347. var Broadphase = require('../collision/Broadphase');
  7348. module.exports = SAPBroadphase;
  7349. /**
  7350. * Sweep and prune broadphase along one axis.
  7351. *
  7352. * @class SAPBroadphase
  7353. * @constructor
  7354. * @param {World} [world]
  7355. * @extends Broadphase
  7356. */
  7357. function SAPBroadphase(world){
  7358. Broadphase.apply(this);
  7359. /**
  7360. * List of bodies currently in the broadphase.
  7361. * @property axisList
  7362. * @type {Array}
  7363. */
  7364. this.axisList = [];
  7365. /**
  7366. * The world to search in.
  7367. * @property world
  7368. * @type {World}
  7369. */
  7370. this.world = null;
  7371. /**
  7372. * Axis to sort the bodies along. Set to 0 for x axis, and 1 for y axis. For best performance, choose an axis that the bodies are spread out more on.
  7373. * @property axisIndex
  7374. * @type {Number}
  7375. */
  7376. this.axisIndex = 0;
  7377. var axisList = this.axisList;
  7378. this._addBodyHandler = function(e){
  7379. axisList.push(e.body);
  7380. };
  7381. this._removeBodyHandler = function(e){
  7382. var idx = axisList.indexOf(e.body);
  7383. if(idx !== -1){
  7384. axisList.splice(idx,1);
  7385. }
  7386. };
  7387. if(world){
  7388. this.setWorld(world);
  7389. }
  7390. }
  7391. SAPBroadphase.prototype = new Broadphase();
  7392. /**
  7393. * Change the world
  7394. * @method setWorld
  7395. * @param {World} world
  7396. */
  7397. SAPBroadphase.prototype.setWorld = function(world){
  7398. // Clear the old axis array
  7399. this.axisList.length = 0;
  7400. // Add all bodies from the new world
  7401. for(var i=0; i<world.bodies.length; i++){
  7402. this.axisList.push(world.bodies[i]);
  7403. }
  7404. // Remove old handlers, if any
  7405. world.removeEventListener("addBody", this._addBodyHandler);
  7406. world.removeEventListener("removeBody", this._removeBodyHandler);
  7407. // Add handlers to update the list of bodies.
  7408. world.addEventListener("addBody", this._addBodyHandler);
  7409. world.addEventListener("removeBody", this._removeBodyHandler);
  7410. this.world = world;
  7411. this.dirty = true;
  7412. };
  7413. /**
  7414. * @static
  7415. * @method insertionSortX
  7416. * @param {Array} a
  7417. * @return {Array}
  7418. */
  7419. SAPBroadphase.insertionSortX = function(a) {
  7420. for(var i=1,l=a.length;i<l;i++) {
  7421. var v = a[i];
  7422. for(var j=i - 1;j>=0;j--) {
  7423. if(a[j].aabb.lowerBound.x <= v.aabb.lowerBound.x){
  7424. break;
  7425. }
  7426. a[j+1] = a[j];
  7427. }
  7428. a[j+1] = v;
  7429. }
  7430. return a;
  7431. };
  7432. /**
  7433. * @static
  7434. * @method insertionSortY
  7435. * @param {Array} a
  7436. * @return {Array}
  7437. */
  7438. SAPBroadphase.insertionSortY = function(a) {
  7439. for(var i=1,l=a.length;i<l;i++) {
  7440. var v = a[i];
  7441. for(var j=i - 1;j>=0;j--) {
  7442. if(a[j].aabb.lowerBound.y <= v.aabb.lowerBound.y){
  7443. break;
  7444. }
  7445. a[j+1] = a[j];
  7446. }
  7447. a[j+1] = v;
  7448. }
  7449. return a;
  7450. };
  7451. /**
  7452. * @static
  7453. * @method insertionSortZ
  7454. * @param {Array} a
  7455. * @return {Array}
  7456. */
  7457. SAPBroadphase.insertionSortZ = function(a) {
  7458. for(var i=1,l=a.length;i<l;i++) {
  7459. var v = a[i];
  7460. for(var j=i - 1;j>=0;j--) {
  7461. if(a[j].aabb.lowerBound.z <= v.aabb.lowerBound.z){
  7462. break;
  7463. }
  7464. a[j+1] = a[j];
  7465. }
  7466. a[j+1] = v;
  7467. }
  7468. return a;
  7469. };
  7470. /**
  7471. * Collect all collision pairs
  7472. * @method collisionPairs
  7473. * @param {World} world
  7474. * @param {Array} p1
  7475. * @param {Array} p2
  7476. */
  7477. SAPBroadphase.prototype.collisionPairs = function(world,p1,p2){
  7478. var bodies = this.axisList,
  7479. N = bodies.length,
  7480. axisIndex = this.axisIndex,
  7481. i, j;
  7482. if(this.dirty){
  7483. this.sortList();
  7484. this.dirty = false;
  7485. }
  7486. // Look through the list
  7487. for(i=0; i !== N; i++){
  7488. var bi = bodies[i];
  7489. for(j=i+1; j < N; j++){
  7490. var bj = bodies[j];
  7491. if(!this.needBroadphaseCollision(bi,bj)){
  7492. continue;
  7493. }
  7494. if(!SAPBroadphase.checkBounds(bi,bj,axisIndex)){
  7495. break;
  7496. }
  7497. this.intersectionTest(bi,bj,p1,p2);
  7498. }
  7499. }
  7500. };
  7501. SAPBroadphase.prototype.sortList = function(){
  7502. var axisList = this.axisList;
  7503. var axisIndex = this.axisIndex;
  7504. var N = axisList.length;
  7505. // Update AABBs
  7506. for(var i = 0; i!==N; i++){
  7507. var bi = axisList[i];
  7508. if(bi.aabbNeedsUpdate){
  7509. bi.computeAABB();
  7510. }
  7511. }
  7512. // Sort the list
  7513. if(axisIndex === 0){
  7514. SAPBroadphase.insertionSortX(axisList);
  7515. } else if(axisIndex === 1){
  7516. SAPBroadphase.insertionSortY(axisList);
  7517. } else if(axisIndex === 2){
  7518. SAPBroadphase.insertionSortZ(axisList);
  7519. }
  7520. };
  7521. /**
  7522. * Check if the bounds of two bodies overlap, along the given SAP axis.
  7523. * @static
  7524. * @method checkBounds
  7525. * @param {Body} bi
  7526. * @param {Body} bj
  7527. * @param {Number} axisIndex
  7528. * @return {Boolean}
  7529. */
  7530. SAPBroadphase.checkBounds = function(bi, bj, axisIndex){
  7531. var biPos;
  7532. var bjPos;
  7533. if(axisIndex === 0){
  7534. biPos = bi.position.x;
  7535. bjPos = bj.position.x;
  7536. } else if(axisIndex === 1){
  7537. biPos = bi.position.y;
  7538. bjPos = bj.position.y;
  7539. } else if(axisIndex === 2){
  7540. biPos = bi.position.z;
  7541. bjPos = bj.position.z;
  7542. }
  7543. var ri = bi.boundingRadius,
  7544. rj = bj.boundingRadius,
  7545. boundA1 = biPos - ri,
  7546. boundA2 = biPos + ri,
  7547. boundB1 = bjPos - rj,
  7548. boundB2 = bjPos + rj;
  7549. return boundB1 < boundA2;
  7550. };
  7551. /**
  7552. * Computes the variance of the body positions and estimates the best
  7553. * axis to use. Will automatically set property .axisIndex.
  7554. * @method autoDetectAxis
  7555. */
  7556. SAPBroadphase.prototype.autoDetectAxis = function(){
  7557. var sumX=0,
  7558. sumX2=0,
  7559. sumY=0,
  7560. sumY2=0,
  7561. sumZ=0,
  7562. sumZ2=0,
  7563. bodies = this.axisList,
  7564. N = bodies.length,
  7565. invN=1/N;
  7566. for(var i=0; i!==N; i++){
  7567. var b = bodies[i];
  7568. var centerX = b.position.x;
  7569. sumX += centerX;
  7570. sumX2 += centerX*centerX;
  7571. var centerY = b.position.y;
  7572. sumY += centerY;
  7573. sumY2 += centerY*centerY;
  7574. var centerZ = b.position.z;
  7575. sumZ += centerZ;
  7576. sumZ2 += centerZ*centerZ;
  7577. }
  7578. var varianceX = sumX2 - sumX*sumX*invN,
  7579. varianceY = sumY2 - sumY*sumY*invN,
  7580. varianceZ = sumZ2 - sumZ*sumZ*invN;
  7581. if(varianceX > varianceY){
  7582. if(varianceX > varianceZ){
  7583. this.axisIndex = 0;
  7584. } else{
  7585. this.axisIndex = 2;
  7586. }
  7587. } else if(varianceY > varianceZ){
  7588. this.axisIndex = 1;
  7589. } else{
  7590. this.axisIndex = 2;
  7591. }
  7592. };
  7593. /**
  7594. * Returns all the bodies within an AABB.
  7595. * @method aabbQuery
  7596. * @param {World} world
  7597. * @param {AABB} aabb
  7598. * @param {array} result An array to store resulting bodies in.
  7599. * @return {array}
  7600. */
  7601. SAPBroadphase.prototype.aabbQuery = function(world, aabb, result){
  7602. result = result || [];
  7603. if(this.dirty){
  7604. this.sortList();
  7605. this.dirty = false;
  7606. }
  7607. var axisIndex = this.axisIndex, axis = 'x';
  7608. if(axisIndex === 1){ axis = 'y'; }
  7609. if(axisIndex === 2){ axis = 'z'; }
  7610. var axisList = this.axisList;
  7611. var lower = aabb.lowerBound[axis];
  7612. var upper = aabb.upperBound[axis];
  7613. for(var i = 0; i < axisList.length; i++){
  7614. var b = axisList[i];
  7615. if(b.aabbNeedsUpdate){
  7616. b.computeAABB();
  7617. }
  7618. if(b.aabb.overlaps(aabb)){
  7619. result.push(b);
  7620. }
  7621. }
  7622. return result;
  7623. };
  7624. },{"../collision/Broadphase":26,"../shapes/Shape":65}],34:[function(require,module,exports){
  7625. module.exports = ConeTwistConstraint;
  7626. var Constraint = require('./Constraint');
  7627. var PointToPointConstraint = require('./PointToPointConstraint');
  7628. var ConeEquation = require('../equations/ConeEquation');
  7629. var RotationalEquation = require('../equations/RotationalEquation');
  7630. var ContactEquation = require('../equations/ContactEquation');
  7631. var Vec3 = require('../math/Vec3');
  7632. /**
  7633. * @class ConeTwistConstraint
  7634. * @constructor
  7635. * @author schteppe
  7636. * @param {Body} bodyA
  7637. * @param {Body} bodyB
  7638. * @param {object} [options]
  7639. * @param {Vec3} [options.pivotA]
  7640. * @param {Vec3} [options.pivotB]
  7641. * @param {Vec3} [options.axisA]
  7642. * @param {Vec3} [options.axisB]
  7643. * @param {Number} [options.maxForce=1e6]
  7644. * @extends PointToPointConstraint
  7645. */
  7646. function ConeTwistConstraint(bodyA, bodyB, options){
  7647. options = options || {};
  7648. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  7649. // Set pivot point in between
  7650. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  7651. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  7652. this.axisA = options.axisA ? options.axisA.clone() : new Vec3();
  7653. this.axisB = options.axisB ? options.axisB.clone() : new Vec3();
  7654. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  7655. this.collideConnected = !!options.collideConnected;
  7656. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  7657. /**
  7658. * @property {ConeEquation} coneEquation
  7659. */
  7660. var c = this.coneEquation = new ConeEquation(bodyA,bodyB,options);
  7661. /**
  7662. * @property {RotationalEquation} twistEquation
  7663. */
  7664. var t = this.twistEquation = new RotationalEquation(bodyA,bodyB,options);
  7665. this.twistAngle = typeof(options.twistAngle) !== 'undefined' ? options.twistAngle : 0;
  7666. // Make the cone equation push the bodies toward the cone axis, not outward
  7667. c.maxForce = 0;
  7668. c.minForce = -maxForce;
  7669. // Make the twist equation add torque toward the initial position
  7670. t.maxForce = 0;
  7671. t.minForce = -maxForce;
  7672. this.equations.push(c, t);
  7673. }
  7674. ConeTwistConstraint.prototype = new PointToPointConstraint();
  7675. ConeTwistConstraint.constructor = ConeTwistConstraint;
  7676. var ConeTwistConstraint_update_tmpVec1 = new Vec3();
  7677. var ConeTwistConstraint_update_tmpVec2 = new Vec3();
  7678. ConeTwistConstraint.prototype.update = function(){
  7679. var bodyA = this.bodyA,
  7680. bodyB = this.bodyB,
  7681. cone = this.coneEquation,
  7682. twist = this.twistEquation;
  7683. PointToPointConstraint.prototype.update.call(this);
  7684. // Update the axes to the cone constraint
  7685. bodyA.vectorToWorldFrame(this.axisA, cone.axisA);
  7686. bodyB.vectorToWorldFrame(this.axisB, cone.axisB);
  7687. // Update the world axes in the twist constraint
  7688. this.axisA.tangents(twist.axisA, twist.axisA);
  7689. bodyA.vectorToWorldFrame(twist.axisA, twist.axisA);
  7690. this.axisB.tangents(twist.axisB, twist.axisB);
  7691. bodyB.vectorToWorldFrame(twist.axisB, twist.axisB);
  7692. cone.angle = this.angle;
  7693. twist.maxAngle = this.twistAngle;
  7694. };
  7695. },{"../equations/ConeEquation":40,"../equations/ContactEquation":41,"../equations/RotationalEquation":44,"../math/Vec3":52,"./Constraint":35,"./PointToPointConstraint":39}],35:[function(require,module,exports){
  7696. module.exports = Constraint;
  7697. var Utils = require('../utils/Utils');
  7698. /**
  7699. * Constraint base class
  7700. * @class Constraint
  7701. * @author schteppe
  7702. * @constructor
  7703. * @param {Body} bodyA
  7704. * @param {Body} bodyB
  7705. * @param {object} [options]
  7706. * @param {boolean} [options.collideConnected=true]
  7707. * @param {boolean} [options.wakeUpBodies=true]
  7708. */
  7709. function Constraint(bodyA, bodyB, options){
  7710. options = Utils.defaults(options,{
  7711. collideConnected : true,
  7712. wakeUpBodies : true,
  7713. });
  7714. /**
  7715. * Equations to be solved in this constraint
  7716. * @property equations
  7717. * @type {Array}
  7718. */
  7719. this.equations = [];
  7720. /**
  7721. * @property {Body} bodyA
  7722. */
  7723. this.bodyA = bodyA;
  7724. /**
  7725. * @property {Body} bodyB
  7726. */
  7727. this.bodyB = bodyB;
  7728. /**
  7729. * @property {Number} id
  7730. */
  7731. this.id = Constraint.idCounter++;
  7732. /**
  7733. * Set to true if you want the bodies to collide when they are connected.
  7734. * @property collideConnected
  7735. * @type {boolean}
  7736. */
  7737. this.collideConnected = options.collideConnected;
  7738. if(options.wakeUpBodies){
  7739. if(bodyA){
  7740. bodyA.wakeUp();
  7741. }
  7742. if(bodyB){
  7743. bodyB.wakeUp();
  7744. }
  7745. }
  7746. }
  7747. /**
  7748. * Update all the equations with data.
  7749. * @method update
  7750. */
  7751. Constraint.prototype.update = function(){
  7752. throw new Error("method update() not implmemented in this Constraint subclass!");
  7753. };
  7754. /**
  7755. * Enables all equations in the constraint.
  7756. * @method enable
  7757. */
  7758. Constraint.prototype.enable = function(){
  7759. var eqs = this.equations;
  7760. for(var i=0; i<eqs.length; i++){
  7761. eqs[i].enabled = true;
  7762. }
  7763. };
  7764. /**
  7765. * Disables all equations in the constraint.
  7766. * @method disable
  7767. */
  7768. Constraint.prototype.disable = function(){
  7769. var eqs = this.equations;
  7770. for(var i=0; i<eqs.length; i++){
  7771. eqs[i].enabled = false;
  7772. }
  7773. };
  7774. Constraint.idCounter = 0;
  7775. },{"../utils/Utils":75}],36:[function(require,module,exports){
  7776. module.exports = DistanceConstraint;
  7777. var Constraint = require('./Constraint');
  7778. var ContactEquation = require('../equations/ContactEquation');
  7779. /**
  7780. * Constrains two bodies to be at a constant distance from each others center of mass.
  7781. * @class DistanceConstraint
  7782. * @constructor
  7783. * @author schteppe
  7784. * @param {Body} bodyA
  7785. * @param {Body} bodyB
  7786. * @param {Number} [distance] The distance to keep. If undefined, it will be set to the current distance between bodyA and bodyB
  7787. * @param {Number} [maxForce=1e6]
  7788. * @extends Constraint
  7789. */
  7790. function DistanceConstraint(bodyA,bodyB,distance,maxForce){
  7791. Constraint.call(this,bodyA,bodyB);
  7792. if(typeof(distance)==="undefined") {
  7793. distance = bodyA.position.distanceTo(bodyB.position);
  7794. }
  7795. if(typeof(maxForce)==="undefined") {
  7796. maxForce = 1e6;
  7797. }
  7798. /**
  7799. * @property {number} distance
  7800. */
  7801. this.distance = distance;
  7802. /**
  7803. * @property {ContactEquation} distanceEquation
  7804. */
  7805. var eq = this.distanceEquation = new ContactEquation(bodyA, bodyB);
  7806. this.equations.push(eq);
  7807. // Make it bidirectional
  7808. eq.minForce = -maxForce;
  7809. eq.maxForce = maxForce;
  7810. }
  7811. DistanceConstraint.prototype = new Constraint();
  7812. DistanceConstraint.prototype.update = function(){
  7813. var bodyA = this.bodyA;
  7814. var bodyB = this.bodyB;
  7815. var eq = this.distanceEquation;
  7816. var halfDist = this.distance * 0.5;
  7817. var normal = eq.ni;
  7818. bodyB.position.vsub(bodyA.position, normal);
  7819. normal.normalize();
  7820. normal.mult(halfDist, eq.ri);
  7821. normal.mult(-halfDist, eq.rj);
  7822. };
  7823. },{"../equations/ContactEquation":41,"./Constraint":35}],37:[function(require,module,exports){
  7824. module.exports = HingeConstraint;
  7825. var Constraint = require('./Constraint');
  7826. var PointToPointConstraint = require('./PointToPointConstraint');
  7827. var RotationalEquation = require('../equations/RotationalEquation');
  7828. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  7829. var ContactEquation = require('../equations/ContactEquation');
  7830. var Vec3 = require('../math/Vec3');
  7831. /**
  7832. * Hinge constraint. Think of it as a door hinge. It tries to keep the door in the correct place and with the correct orientation.
  7833. * @class HingeConstraint
  7834. * @constructor
  7835. * @author schteppe
  7836. * @param {Body} bodyA
  7837. * @param {Body} bodyB
  7838. * @param {object} [options]
  7839. * @param {Vec3} [options.pivotA] A point defined locally in bodyA. This defines the offset of axisA.
  7840. * @param {Vec3} [options.axisA] An axis that bodyA can rotate around, defined locally in bodyA.
  7841. * @param {Vec3} [options.pivotB]
  7842. * @param {Vec3} [options.axisB]
  7843. * @param {Number} [options.maxForce=1e6]
  7844. * @extends PointToPointConstraint
  7845. */
  7846. function HingeConstraint(bodyA, bodyB, options){
  7847. options = options || {};
  7848. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  7849. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  7850. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  7851. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  7852. /**
  7853. * Rotation axis, defined locally in bodyA.
  7854. * @property {Vec3} axisA
  7855. */
  7856. var axisA = this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1,0,0);
  7857. axisA.normalize();
  7858. /**
  7859. * Rotation axis, defined locally in bodyB.
  7860. * @property {Vec3} axisB
  7861. */
  7862. var axisB = this.axisB = options.axisB ? options.axisB.clone() : new Vec3(1,0,0);
  7863. axisB.normalize();
  7864. /**
  7865. * @property {RotationalEquation} rotationalEquation1
  7866. */
  7867. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  7868. /**
  7869. * @property {RotationalEquation} rotationalEquation2
  7870. */
  7871. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  7872. /**
  7873. * @property {RotationalMotorEquation} motorEquation
  7874. */
  7875. var motor = this.motorEquation = new RotationalMotorEquation(bodyA,bodyB,maxForce);
  7876. motor.enabled = false; // Not enabled by default
  7877. // Equations to be fed to the solver
  7878. this.equations.push(
  7879. r1, // rotational1
  7880. r2, // rotational2
  7881. motor
  7882. );
  7883. }
  7884. HingeConstraint.prototype = new PointToPointConstraint();
  7885. HingeConstraint.constructor = HingeConstraint;
  7886. /**
  7887. * @method enableMotor
  7888. */
  7889. HingeConstraint.prototype.enableMotor = function(){
  7890. this.motorEquation.enabled = true;
  7891. };
  7892. /**
  7893. * @method disableMotor
  7894. */
  7895. HingeConstraint.prototype.disableMotor = function(){
  7896. this.motorEquation.enabled = false;
  7897. };
  7898. /**
  7899. * @method setMotorSpeed
  7900. * @param {number} speed
  7901. */
  7902. HingeConstraint.prototype.setMotorSpeed = function(speed){
  7903. this.motorEquation.targetVelocity = speed;
  7904. };
  7905. /**
  7906. * @method setMotorMaxForce
  7907. * @param {number} maxForce
  7908. */
  7909. HingeConstraint.prototype.setMotorMaxForce = function(maxForce){
  7910. this.motorEquation.maxForce = maxForce;
  7911. this.motorEquation.minForce = -maxForce;
  7912. };
  7913. var HingeConstraint_update_tmpVec1 = new Vec3();
  7914. var HingeConstraint_update_tmpVec2 = new Vec3();
  7915. HingeConstraint.prototype.update = function(){
  7916. var bodyA = this.bodyA,
  7917. bodyB = this.bodyB,
  7918. motor = this.motorEquation,
  7919. r1 = this.rotationalEquation1,
  7920. r2 = this.rotationalEquation2,
  7921. worldAxisA = HingeConstraint_update_tmpVec1,
  7922. worldAxisB = HingeConstraint_update_tmpVec2;
  7923. var axisA = this.axisA;
  7924. var axisB = this.axisB;
  7925. PointToPointConstraint.prototype.update.call(this);
  7926. // Get world axes
  7927. bodyA.quaternion.vmult(axisA, worldAxisA);
  7928. bodyB.quaternion.vmult(axisB, worldAxisB);
  7929. worldAxisA.tangents(r1.axisA, r2.axisA);
  7930. r1.axisB.copy(worldAxisB);
  7931. r2.axisB.copy(worldAxisB);
  7932. if(this.motorEquation.enabled){
  7933. bodyA.quaternion.vmult(this.axisA, motor.axisA);
  7934. bodyB.quaternion.vmult(this.axisB, motor.axisB);
  7935. }
  7936. };
  7937. },{"../equations/ContactEquation":41,"../equations/RotationalEquation":44,"../equations/RotationalMotorEquation":45,"../math/Vec3":52,"./Constraint":35,"./PointToPointConstraint":39}],38:[function(require,module,exports){
  7938. module.exports = LockConstraint;
  7939. var Constraint = require('./Constraint');
  7940. var PointToPointConstraint = require('./PointToPointConstraint');
  7941. var RotationalEquation = require('../equations/RotationalEquation');
  7942. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  7943. var ContactEquation = require('../equations/ContactEquation');
  7944. var Vec3 = require('../math/Vec3');
  7945. /**
  7946. * Lock constraint. Will remove all degrees of freedom between the bodies.
  7947. * @class LockConstraint
  7948. * @constructor
  7949. * @author schteppe
  7950. * @param {Body} bodyA
  7951. * @param {Body} bodyB
  7952. * @param {object} [options]
  7953. * @param {Number} [options.maxForce=1e6]
  7954. * @extends PointToPointConstraint
  7955. */
  7956. function LockConstraint(bodyA, bodyB, options){
  7957. options = options || {};
  7958. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  7959. // Set pivot point in between
  7960. var pivotA = new Vec3();
  7961. var pivotB = new Vec3();
  7962. var halfWay = new Vec3();
  7963. bodyA.position.vadd(bodyB.position, halfWay);
  7964. halfWay.scale(0.5, halfWay);
  7965. bodyB.pointToLocalFrame(halfWay, pivotB);
  7966. bodyA.pointToLocalFrame(halfWay, pivotA);
  7967. // The point-to-point constraint will keep a point shared between the bodies
  7968. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  7969. // Store initial rotation of the bodies as unit vectors in the local body spaces
  7970. this.xA = bodyA.vectorToLocalFrame(Vec3.UNIT_X);
  7971. this.xB = bodyB.vectorToLocalFrame(Vec3.UNIT_X);
  7972. this.yA = bodyA.vectorToLocalFrame(Vec3.UNIT_Y);
  7973. this.yB = bodyB.vectorToLocalFrame(Vec3.UNIT_Y);
  7974. this.zA = bodyA.vectorToLocalFrame(Vec3.UNIT_Z);
  7975. this.zB = bodyB.vectorToLocalFrame(Vec3.UNIT_Z);
  7976. // ...and the following rotational equations will keep all rotational DOF's in place
  7977. /**
  7978. * @property {RotationalEquation} rotationalEquation1
  7979. */
  7980. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  7981. /**
  7982. * @property {RotationalEquation} rotationalEquation2
  7983. */
  7984. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  7985. /**
  7986. * @property {RotationalEquation} rotationalEquation3
  7987. */
  7988. var r3 = this.rotationalEquation3 = new RotationalEquation(bodyA,bodyB,options);
  7989. this.equations.push(r1, r2, r3);
  7990. }
  7991. LockConstraint.prototype = new PointToPointConstraint();
  7992. LockConstraint.constructor = LockConstraint;
  7993. var LockConstraint_update_tmpVec1 = new Vec3();
  7994. var LockConstraint_update_tmpVec2 = new Vec3();
  7995. LockConstraint.prototype.update = function(){
  7996. var bodyA = this.bodyA,
  7997. bodyB = this.bodyB,
  7998. motor = this.motorEquation,
  7999. r1 = this.rotationalEquation1,
  8000. r2 = this.rotationalEquation2,
  8001. r3 = this.rotationalEquation3,
  8002. worldAxisA = LockConstraint_update_tmpVec1,
  8003. worldAxisB = LockConstraint_update_tmpVec2;
  8004. PointToPointConstraint.prototype.update.call(this);
  8005. // These vector pairs must be orthogonal
  8006. bodyA.vectorToWorldFrame(this.xA, r1.axisA);
  8007. bodyB.vectorToWorldFrame(this.yB, r1.axisB);
  8008. bodyA.vectorToWorldFrame(this.yA, r2.axisA);
  8009. bodyB.vectorToWorldFrame(this.zB, r2.axisB);
  8010. bodyA.vectorToWorldFrame(this.zA, r3.axisA);
  8011. bodyB.vectorToWorldFrame(this.xB, r3.axisB);
  8012. };
  8013. },{"../equations/ContactEquation":41,"../equations/RotationalEquation":44,"../equations/RotationalMotorEquation":45,"../math/Vec3":52,"./Constraint":35,"./PointToPointConstraint":39}],39:[function(require,module,exports){
  8014. module.exports = PointToPointConstraint;
  8015. var Constraint = require('./Constraint');
  8016. var ContactEquation = require('../equations/ContactEquation');
  8017. var Vec3 = require('../math/Vec3');
  8018. /**
  8019. * Connects two bodies at given offset points.
  8020. * @class PointToPointConstraint
  8021. * @extends Constraint
  8022. * @constructor
  8023. * @param {Body} bodyA
  8024. * @param {Vec3} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
  8025. * @param {Body} bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
  8026. * @param {Vec3} pivotB See pivotA.
  8027. * @param {Number} maxForce The maximum force that should be applied to constrain the bodies.
  8028. *
  8029. * @example
  8030. * var bodyA = new Body({ mass: 1 });
  8031. * var bodyB = new Body({ mass: 1 });
  8032. * bodyA.position.set(-1, 0, 0);
  8033. * bodyB.position.set(1, 0, 0);
  8034. * bodyA.addShape(shapeA);
  8035. * bodyB.addShape(shapeB);
  8036. * world.addBody(bodyA);
  8037. * world.addBody(bodyB);
  8038. * var localPivotA = new Vec3(1, 0, 0);
  8039. * var localPivotB = new Vec3(-1, 0, 0);
  8040. * var constraint = new PointToPointConstraint(bodyA, localPivotA, bodyB, localPivotB);
  8041. * world.addConstraint(constraint);
  8042. */
  8043. function PointToPointConstraint(bodyA,pivotA,bodyB,pivotB,maxForce){
  8044. Constraint.call(this,bodyA,bodyB);
  8045. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  8046. /**
  8047. * Pivot, defined locally in bodyA.
  8048. * @property {Vec3} pivotA
  8049. */
  8050. this.pivotA = pivotA ? pivotA.clone() : new Vec3();
  8051. /**
  8052. * Pivot, defined locally in bodyB.
  8053. * @property {Vec3} pivotB
  8054. */
  8055. this.pivotB = pivotB ? pivotB.clone() : new Vec3();
  8056. /**
  8057. * @property {ContactEquation} equationX
  8058. */
  8059. var x = this.equationX = new ContactEquation(bodyA,bodyB);
  8060. /**
  8061. * @property {ContactEquation} equationY
  8062. */
  8063. var y = this.equationY = new ContactEquation(bodyA,bodyB);
  8064. /**
  8065. * @property {ContactEquation} equationZ
  8066. */
  8067. var z = this.equationZ = new ContactEquation(bodyA,bodyB);
  8068. // Equations to be fed to the solver
  8069. this.equations.push(x, y, z);
  8070. // Make the equations bidirectional
  8071. x.minForce = y.minForce = z.minForce = -maxForce;
  8072. x.maxForce = y.maxForce = z.maxForce = maxForce;
  8073. x.ni.set(1, 0, 0);
  8074. y.ni.set(0, 1, 0);
  8075. z.ni.set(0, 0, 1);
  8076. }
  8077. PointToPointConstraint.prototype = new Constraint();
  8078. PointToPointConstraint.prototype.update = function(){
  8079. var bodyA = this.bodyA;
  8080. var bodyB = this.bodyB;
  8081. var x = this.equationX;
  8082. var y = this.equationY;
  8083. var z = this.equationZ;
  8084. // Rotate the pivots to world space
  8085. bodyA.quaternion.vmult(this.pivotA,x.ri);
  8086. bodyB.quaternion.vmult(this.pivotB,x.rj);
  8087. y.ri.copy(x.ri);
  8088. y.rj.copy(x.rj);
  8089. z.ri.copy(x.ri);
  8090. z.rj.copy(x.rj);
  8091. };
  8092. },{"../equations/ContactEquation":41,"../math/Vec3":52,"./Constraint":35}],40:[function(require,module,exports){
  8093. module.exports = ConeEquation;
  8094. var Vec3 = require('../math/Vec3');
  8095. var Mat3 = require('../math/Mat3');
  8096. var Equation = require('./Equation');
  8097. /**
  8098. * Cone equation. Works to keep the given body world vectors aligned, or tilted within a given angle from each other.
  8099. * @class ConeEquation
  8100. * @constructor
  8101. * @author schteppe
  8102. * @param {Body} bodyA
  8103. * @param {Body} bodyB
  8104. * @param {Vec3} [options.axisA] Local axis in A
  8105. * @param {Vec3} [options.axisB] Local axis in B
  8106. * @param {Vec3} [options.angle] The "cone angle" to keep
  8107. * @param {number} [options.maxForce=1e6]
  8108. * @extends Equation
  8109. */
  8110. function ConeEquation(bodyA, bodyB, options){
  8111. options = options || {};
  8112. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  8113. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  8114. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  8115. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  8116. /**
  8117. * The cone angle to keep
  8118. * @property {number} angle
  8119. */
  8120. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  8121. }
  8122. ConeEquation.prototype = new Equation();
  8123. ConeEquation.prototype.constructor = ConeEquation;
  8124. var tmpVec1 = new Vec3();
  8125. var tmpVec2 = new Vec3();
  8126. ConeEquation.prototype.computeB = function(h){
  8127. var a = this.a,
  8128. b = this.b,
  8129. ni = this.axisA,
  8130. nj = this.axisB,
  8131. nixnj = tmpVec1,
  8132. njxni = tmpVec2,
  8133. GA = this.jacobianElementA,
  8134. GB = this.jacobianElementB;
  8135. // Caluclate cross products
  8136. ni.cross(nj, nixnj);
  8137. nj.cross(ni, njxni);
  8138. // The angle between two vector is:
  8139. // cos(theta) = a * b / (length(a) * length(b) = { len(a) = len(b) = 1 } = a * b
  8140. // g = a * b
  8141. // gdot = (b x a) * wi + (a x b) * wj
  8142. // G = [0 bxa 0 axb]
  8143. // W = [vi wi vj wj]
  8144. GA.rotational.copy(njxni);
  8145. GB.rotational.copy(nixnj);
  8146. var g = Math.cos(this.angle) - ni.dot(nj),
  8147. GW = this.computeGW(),
  8148. GiMf = this.computeGiMf();
  8149. var B = - g * a - GW * b - h * GiMf;
  8150. return B;
  8151. };
  8152. },{"../math/Mat3":49,"../math/Vec3":52,"./Equation":42}],41:[function(require,module,exports){
  8153. module.exports = ContactEquation;
  8154. var Equation = require('./Equation');
  8155. var Vec3 = require('../math/Vec3');
  8156. var Mat3 = require('../math/Mat3');
  8157. /**
  8158. * Contact/non-penetration constraint equation
  8159. * @class ContactEquation
  8160. * @constructor
  8161. * @author schteppe
  8162. * @param {Body} bodyA
  8163. * @param {Body} bodyB
  8164. * @extends Equation
  8165. */
  8166. function ContactEquation(bodyA, bodyB, maxForce){
  8167. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  8168. Equation.call(this, bodyA, bodyB, 0, maxForce);
  8169. /**
  8170. * @property restitution
  8171. * @type {Number}
  8172. */
  8173. this.restitution = 0.0; // "bounciness": u1 = -e*u0
  8174. /**
  8175. * World-oriented vector that goes from the center of bi to the contact point.
  8176. * @property {Vec3} ri
  8177. */
  8178. this.ri = new Vec3();
  8179. /**
  8180. * World-oriented vector that starts in body j position and goes to the contact point.
  8181. * @property {Vec3} rj
  8182. */
  8183. this.rj = new Vec3();
  8184. /**
  8185. * Contact normal, pointing out of body i.
  8186. * @property {Vec3} ni
  8187. */
  8188. this.ni = new Vec3();
  8189. }
  8190. ContactEquation.prototype = new Equation();
  8191. ContactEquation.prototype.constructor = ContactEquation;
  8192. var ContactEquation_computeB_temp1 = new Vec3(); // Temp vectors
  8193. var ContactEquation_computeB_temp2 = new Vec3();
  8194. var ContactEquation_computeB_temp3 = new Vec3();
  8195. ContactEquation.prototype.computeB = function(h){
  8196. var a = this.a,
  8197. b = this.b,
  8198. bi = this.bi,
  8199. bj = this.bj,
  8200. ri = this.ri,
  8201. rj = this.rj,
  8202. rixn = ContactEquation_computeB_temp1,
  8203. rjxn = ContactEquation_computeB_temp2,
  8204. vi = bi.velocity,
  8205. wi = bi.angularVelocity,
  8206. fi = bi.force,
  8207. taui = bi.torque,
  8208. vj = bj.velocity,
  8209. wj = bj.angularVelocity,
  8210. fj = bj.force,
  8211. tauj = bj.torque,
  8212. penetrationVec = ContactEquation_computeB_temp3,
  8213. GA = this.jacobianElementA,
  8214. GB = this.jacobianElementB,
  8215. n = this.ni;
  8216. // Caluclate cross products
  8217. ri.cross(n,rixn);
  8218. rj.cross(n,rjxn);
  8219. // g = xj+rj -(xi+ri)
  8220. // G = [ -ni -rixn ni rjxn ]
  8221. n.negate(GA.spatial);
  8222. rixn.negate(GA.rotational);
  8223. GB.spatial.copy(n);
  8224. GB.rotational.copy(rjxn);
  8225. // Calculate the penetration vector
  8226. penetrationVec.copy(bj.position);
  8227. penetrationVec.vadd(rj,penetrationVec);
  8228. penetrationVec.vsub(bi.position,penetrationVec);
  8229. penetrationVec.vsub(ri,penetrationVec);
  8230. var g = n.dot(penetrationVec);
  8231. // Compute iteration
  8232. var ePlusOne = this.restitution + 1;
  8233. var GW = ePlusOne * vj.dot(n) - ePlusOne * vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn);
  8234. var GiMf = this.computeGiMf();
  8235. var B = - g * a - GW * b - h*GiMf;
  8236. return B;
  8237. };
  8238. var ContactEquation_getImpactVelocityAlongNormal_vi = new Vec3();
  8239. var ContactEquation_getImpactVelocityAlongNormal_vj = new Vec3();
  8240. var ContactEquation_getImpactVelocityAlongNormal_xi = new Vec3();
  8241. var ContactEquation_getImpactVelocityAlongNormal_xj = new Vec3();
  8242. var ContactEquation_getImpactVelocityAlongNormal_relVel = new Vec3();
  8243. /**
  8244. * Get the current relative velocity in the contact point.
  8245. * @method getImpactVelocityAlongNormal
  8246. * @return {number}
  8247. */
  8248. ContactEquation.prototype.getImpactVelocityAlongNormal = function(){
  8249. var vi = ContactEquation_getImpactVelocityAlongNormal_vi;
  8250. var vj = ContactEquation_getImpactVelocityAlongNormal_vj;
  8251. var xi = ContactEquation_getImpactVelocityAlongNormal_xi;
  8252. var xj = ContactEquation_getImpactVelocityAlongNormal_xj;
  8253. var relVel = ContactEquation_getImpactVelocityAlongNormal_relVel;
  8254. this.bi.position.vadd(this.ri, xi);
  8255. this.bj.position.vadd(this.rj, xj);
  8256. this.bi.getVelocityAtWorldPoint(xi, vi);
  8257. this.bj.getVelocityAtWorldPoint(xj, vj);
  8258. vi.vsub(vj, relVel);
  8259. return this.ni.dot(relVel);
  8260. };
  8261. },{"../math/Mat3":49,"../math/Vec3":52,"./Equation":42}],42:[function(require,module,exports){
  8262. module.exports = Equation;
  8263. var JacobianElement = require('../math/JacobianElement'),
  8264. Vec3 = require('../math/Vec3');
  8265. /**
  8266. * Equation base class
  8267. * @class Equation
  8268. * @constructor
  8269. * @author schteppe
  8270. * @param {Body} bi
  8271. * @param {Body} bj
  8272. * @param {Number} minForce Minimum (read: negative max) force to be applied by the constraint.
  8273. * @param {Number} maxForce Maximum (read: positive max) force to be applied by the constraint.
  8274. */
  8275. function Equation(bi,bj,minForce,maxForce){
  8276. this.id = Equation.id++;
  8277. /**
  8278. * @property {number} minForce
  8279. */
  8280. this.minForce = typeof(minForce)==="undefined" ? -1e6 : minForce;
  8281. /**
  8282. * @property {number} maxForce
  8283. */
  8284. this.maxForce = typeof(maxForce)==="undefined" ? 1e6 : maxForce;
  8285. /**
  8286. * @property bi
  8287. * @type {Body}
  8288. */
  8289. this.bi = bi;
  8290. /**
  8291. * @property bj
  8292. * @type {Body}
  8293. */
  8294. this.bj = bj;
  8295. /**
  8296. * SPOOK parameter
  8297. * @property {number} a
  8298. */
  8299. this.a = 0.0;
  8300. /**
  8301. * SPOOK parameter
  8302. * @property {number} b
  8303. */
  8304. this.b = 0.0;
  8305. /**
  8306. * SPOOK parameter
  8307. * @property {number} eps
  8308. */
  8309. this.eps = 0.0;
  8310. /**
  8311. * @property {JacobianElement} jacobianElementA
  8312. */
  8313. this.jacobianElementA = new JacobianElement();
  8314. /**
  8315. * @property {JacobianElement} jacobianElementB
  8316. */
  8317. this.jacobianElementB = new JacobianElement();
  8318. /**
  8319. * @property {boolean} enabled
  8320. * @default true
  8321. */
  8322. this.enabled = true;
  8323. /**
  8324. * A number, proportional to the force added to the bodies.
  8325. * @property {number} multiplier
  8326. * @readonly
  8327. */
  8328. this.multiplier = 0;
  8329. // Set typical spook params
  8330. this.setSpookParams(1e7,4,1/60);
  8331. }
  8332. Equation.prototype.constructor = Equation;
  8333. Equation.id = 0;
  8334. /**
  8335. * Recalculates a,b,eps.
  8336. * @method setSpookParams
  8337. */
  8338. Equation.prototype.setSpookParams = function(stiffness,relaxation,timeStep){
  8339. var d = relaxation,
  8340. k = stiffness,
  8341. h = timeStep;
  8342. this.a = 4.0 / (h * (1 + 4 * d));
  8343. this.b = (4.0 * d) / (1 + 4 * d);
  8344. this.eps = 4.0 / (h * h * k * (1 + 4 * d));
  8345. };
  8346. /**
  8347. * Computes the RHS of the SPOOK equation
  8348. * @method computeB
  8349. * @return {Number}
  8350. */
  8351. Equation.prototype.computeB = function(a,b,h){
  8352. var GW = this.computeGW(),
  8353. Gq = this.computeGq(),
  8354. GiMf = this.computeGiMf();
  8355. return - Gq * a - GW * b - GiMf*h;
  8356. };
  8357. /**
  8358. * Computes G*q, where q are the generalized body coordinates
  8359. * @method computeGq
  8360. * @return {Number}
  8361. */
  8362. Equation.prototype.computeGq = function(){
  8363. var GA = this.jacobianElementA,
  8364. GB = this.jacobianElementB,
  8365. bi = this.bi,
  8366. bj = this.bj,
  8367. xi = bi.position,
  8368. xj = bj.position;
  8369. return GA.spatial.dot(xi) + GB.spatial.dot(xj);
  8370. };
  8371. var zero = new Vec3();
  8372. /**
  8373. * Computes G*W, where W are the body velocities
  8374. * @method computeGW
  8375. * @return {Number}
  8376. */
  8377. Equation.prototype.computeGW = function(){
  8378. var GA = this.jacobianElementA,
  8379. GB = this.jacobianElementB,
  8380. bi = this.bi,
  8381. bj = this.bj,
  8382. vi = bi.velocity,
  8383. vj = bj.velocity,
  8384. wi = bi.angularVelocity,
  8385. wj = bj.angularVelocity;
  8386. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  8387. };
  8388. /**
  8389. * Computes G*Wlambda, where W are the body velocities
  8390. * @method computeGWlambda
  8391. * @return {Number}
  8392. */
  8393. Equation.prototype.computeGWlambda = function(){
  8394. var GA = this.jacobianElementA,
  8395. GB = this.jacobianElementB,
  8396. bi = this.bi,
  8397. bj = this.bj,
  8398. vi = bi.vlambda,
  8399. vj = bj.vlambda,
  8400. wi = bi.wlambda,
  8401. wj = bj.wlambda;
  8402. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  8403. };
  8404. /**
  8405. * Computes G*inv(M)*f, where M is the mass matrix with diagonal blocks for each body, and f are the forces on the bodies.
  8406. * @method computeGiMf
  8407. * @return {Number}
  8408. */
  8409. var iMfi = new Vec3(),
  8410. iMfj = new Vec3(),
  8411. invIi_vmult_taui = new Vec3(),
  8412. invIj_vmult_tauj = new Vec3();
  8413. Equation.prototype.computeGiMf = function(){
  8414. var GA = this.jacobianElementA,
  8415. GB = this.jacobianElementB,
  8416. bi = this.bi,
  8417. bj = this.bj,
  8418. fi = bi.force,
  8419. ti = bi.torque,
  8420. fj = bj.force,
  8421. tj = bj.torque,
  8422. invMassi = bi.invMassSolve,
  8423. invMassj = bj.invMassSolve;
  8424. fi.scale(invMassi,iMfi);
  8425. fj.scale(invMassj,iMfj);
  8426. bi.invInertiaWorldSolve.vmult(ti,invIi_vmult_taui);
  8427. bj.invInertiaWorldSolve.vmult(tj,invIj_vmult_tauj);
  8428. return GA.multiplyVectors(iMfi,invIi_vmult_taui) + GB.multiplyVectors(iMfj,invIj_vmult_tauj);
  8429. };
  8430. /**
  8431. * Computes G*inv(M)*G'
  8432. * @method computeGiMGt
  8433. * @return {Number}
  8434. */
  8435. var tmp = new Vec3();
  8436. Equation.prototype.computeGiMGt = function(){
  8437. var GA = this.jacobianElementA,
  8438. GB = this.jacobianElementB,
  8439. bi = this.bi,
  8440. bj = this.bj,
  8441. invMassi = bi.invMassSolve,
  8442. invMassj = bj.invMassSolve,
  8443. invIi = bi.invInertiaWorldSolve,
  8444. invIj = bj.invInertiaWorldSolve,
  8445. result = invMassi + invMassj;
  8446. invIi.vmult(GA.rotational,tmp);
  8447. result += tmp.dot(GA.rotational);
  8448. invIj.vmult(GB.rotational,tmp);
  8449. result += tmp.dot(GB.rotational);
  8450. return result;
  8451. };
  8452. var addToWlambda_temp = new Vec3(),
  8453. addToWlambda_Gi = new Vec3(),
  8454. addToWlambda_Gj = new Vec3(),
  8455. addToWlambda_ri = new Vec3(),
  8456. addToWlambda_rj = new Vec3(),
  8457. addToWlambda_Mdiag = new Vec3();
  8458. /**
  8459. * Add constraint velocity to the bodies.
  8460. * @method addToWlambda
  8461. * @param {Number} deltalambda
  8462. */
  8463. Equation.prototype.addToWlambda = function(deltalambda){
  8464. var GA = this.jacobianElementA,
  8465. GB = this.jacobianElementB,
  8466. bi = this.bi,
  8467. bj = this.bj,
  8468. temp = addToWlambda_temp;
  8469. // Add to linear velocity
  8470. // v_lambda += inv(M) * delta_lamba * G
  8471. bi.vlambda.addScaledVector(bi.invMassSolve * deltalambda, GA.spatial, bi.vlambda);
  8472. bj.vlambda.addScaledVector(bj.invMassSolve * deltalambda, GB.spatial, bj.vlambda);
  8473. // Add to angular velocity
  8474. bi.invInertiaWorldSolve.vmult(GA.rotational,temp);
  8475. bi.wlambda.addScaledVector(deltalambda, temp, bi.wlambda);
  8476. bj.invInertiaWorldSolve.vmult(GB.rotational,temp);
  8477. bj.wlambda.addScaledVector(deltalambda, temp, bj.wlambda);
  8478. };
  8479. /**
  8480. * Compute the denominator part of the SPOOK equation: C = G*inv(M)*G' + eps
  8481. * @method computeInvC
  8482. * @param {Number} eps
  8483. * @return {Number}
  8484. */
  8485. Equation.prototype.computeC = function(){
  8486. return this.computeGiMGt() + this.eps;
  8487. };
  8488. },{"../math/JacobianElement":48,"../math/Vec3":52}],43:[function(require,module,exports){
  8489. module.exports = FrictionEquation;
  8490. var Equation = require('./Equation');
  8491. var Vec3 = require('../math/Vec3');
  8492. var Mat3 = require('../math/Mat3');
  8493. /**
  8494. * Constrains the slipping in a contact along a tangent
  8495. * @class FrictionEquation
  8496. * @constructor
  8497. * @author schteppe
  8498. * @param {Body} bodyA
  8499. * @param {Body} bodyB
  8500. * @param {Number} slipForce should be +-F_friction = +-mu * F_normal = +-mu * m * g
  8501. * @extends Equation
  8502. */
  8503. function FrictionEquation(bodyA, bodyB, slipForce){
  8504. Equation.call(this,bodyA, bodyB, -slipForce, slipForce);
  8505. this.ri = new Vec3();
  8506. this.rj = new Vec3();
  8507. this.t = new Vec3(); // tangent
  8508. }
  8509. FrictionEquation.prototype = new Equation();
  8510. FrictionEquation.prototype.constructor = FrictionEquation;
  8511. var FrictionEquation_computeB_temp1 = new Vec3();
  8512. var FrictionEquation_computeB_temp2 = new Vec3();
  8513. FrictionEquation.prototype.computeB = function(h){
  8514. var a = this.a,
  8515. b = this.b,
  8516. bi = this.bi,
  8517. bj = this.bj,
  8518. ri = this.ri,
  8519. rj = this.rj,
  8520. rixt = FrictionEquation_computeB_temp1,
  8521. rjxt = FrictionEquation_computeB_temp2,
  8522. t = this.t;
  8523. // Caluclate cross products
  8524. ri.cross(t,rixt);
  8525. rj.cross(t,rjxt);
  8526. // G = [-t -rixt t rjxt]
  8527. // And remember, this is a pure velocity constraint, g is always zero!
  8528. var GA = this.jacobianElementA,
  8529. GB = this.jacobianElementB;
  8530. t.negate(GA.spatial);
  8531. rixt.negate(GA.rotational);
  8532. GB.spatial.copy(t);
  8533. GB.rotational.copy(rjxt);
  8534. var GW = this.computeGW();
  8535. var GiMf = this.computeGiMf();
  8536. var B = - GW * b - h * GiMf;
  8537. return B;
  8538. };
  8539. },{"../math/Mat3":49,"../math/Vec3":52,"./Equation":42}],44:[function(require,module,exports){
  8540. module.exports = RotationalEquation;
  8541. var Vec3 = require('../math/Vec3');
  8542. var Mat3 = require('../math/Mat3');
  8543. var Equation = require('./Equation');
  8544. /**
  8545. * Rotational constraint. Works to keep the local vectors orthogonal to each other in world space.
  8546. * @class RotationalEquation
  8547. * @constructor
  8548. * @author schteppe
  8549. * @param {Body} bodyA
  8550. * @param {Body} bodyB
  8551. * @param {Vec3} [options.axisA]
  8552. * @param {Vec3} [options.axisB]
  8553. * @param {number} [options.maxForce]
  8554. * @extends Equation
  8555. */
  8556. function RotationalEquation(bodyA, bodyB, options){
  8557. options = options || {};
  8558. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  8559. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  8560. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  8561. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  8562. this.maxAngle = Math.PI / 2;
  8563. }
  8564. RotationalEquation.prototype = new Equation();
  8565. RotationalEquation.prototype.constructor = RotationalEquation;
  8566. var tmpVec1 = new Vec3();
  8567. var tmpVec2 = new Vec3();
  8568. RotationalEquation.prototype.computeB = function(h){
  8569. var a = this.a,
  8570. b = this.b,
  8571. ni = this.axisA,
  8572. nj = this.axisB,
  8573. nixnj = tmpVec1,
  8574. njxni = tmpVec2,
  8575. GA = this.jacobianElementA,
  8576. GB = this.jacobianElementB;
  8577. // Caluclate cross products
  8578. ni.cross(nj, nixnj);
  8579. nj.cross(ni, njxni);
  8580. // g = ni * nj
  8581. // gdot = (nj x ni) * wi + (ni x nj) * wj
  8582. // G = [0 njxni 0 nixnj]
  8583. // W = [vi wi vj wj]
  8584. GA.rotational.copy(njxni);
  8585. GB.rotational.copy(nixnj);
  8586. var g = Math.cos(this.maxAngle) - ni.dot(nj),
  8587. GW = this.computeGW(),
  8588. GiMf = this.computeGiMf();
  8589. var B = - g * a - GW * b - h * GiMf;
  8590. return B;
  8591. };
  8592. },{"../math/Mat3":49,"../math/Vec3":52,"./Equation":42}],45:[function(require,module,exports){
  8593. module.exports = RotationalMotorEquation;
  8594. var Vec3 = require('../math/Vec3');
  8595. var Mat3 = require('../math/Mat3');
  8596. var Equation = require('./Equation');
  8597. /**
  8598. * Rotational motor constraint. Tries to keep the relative angular velocity of the bodies to a given value.
  8599. * @class RotationalMotorEquation
  8600. * @constructor
  8601. * @author schteppe
  8602. * @param {Body} bodyA
  8603. * @param {Body} bodyB
  8604. * @param {Number} maxForce
  8605. * @extends Equation
  8606. */
  8607. function RotationalMotorEquation(bodyA, bodyB, maxForce){
  8608. maxForce = typeof(maxForce)!=='undefined' ? maxForce : 1e6;
  8609. Equation.call(this,bodyA,bodyB,-maxForce,maxForce);
  8610. /**
  8611. * World oriented rotational axis
  8612. * @property {Vec3} axisA
  8613. */
  8614. this.axisA = new Vec3();
  8615. /**
  8616. * World oriented rotational axis
  8617. * @property {Vec3} axisB
  8618. */
  8619. this.axisB = new Vec3(); // World oriented rotational axis
  8620. /**
  8621. * Motor velocity
  8622. * @property {Number} targetVelocity
  8623. */
  8624. this.targetVelocity = 0;
  8625. }
  8626. RotationalMotorEquation.prototype = new Equation();
  8627. RotationalMotorEquation.prototype.constructor = RotationalMotorEquation;
  8628. RotationalMotorEquation.prototype.computeB = function(h){
  8629. var a = this.a,
  8630. b = this.b,
  8631. bi = this.bi,
  8632. bj = this.bj,
  8633. axisA = this.axisA,
  8634. axisB = this.axisB,
  8635. GA = this.jacobianElementA,
  8636. GB = this.jacobianElementB;
  8637. // g = 0
  8638. // gdot = axisA * wi - axisB * wj
  8639. // gdot = G * W = G * [vi wi vj wj]
  8640. // =>
  8641. // G = [0 axisA 0 -axisB]
  8642. GA.rotational.copy(axisA);
  8643. axisB.negate(GB.rotational);
  8644. var GW = this.computeGW() - this.targetVelocity,
  8645. GiMf = this.computeGiMf();
  8646. var B = - GW * b - h * GiMf;
  8647. return B;
  8648. };
  8649. },{"../math/Mat3":49,"../math/Vec3":52,"./Equation":42}],46:[function(require,module,exports){
  8650. var Utils = require('../utils/Utils');
  8651. module.exports = ContactMaterial;
  8652. /**
  8653. * Defines what happens when two materials meet.
  8654. * @class ContactMaterial
  8655. * @constructor
  8656. * @param {Material} m1
  8657. * @param {Material} m2
  8658. * @param {object} [options]
  8659. * @param {Number} [options.friction=0.3]
  8660. * @param {Number} [options.restitution=0.3]
  8661. * @param {number} [options.contactEquationStiffness=1e7]
  8662. * @param {number} [options.contactEquationRelaxation=3]
  8663. * @param {number} [options.frictionEquationStiffness=1e7]
  8664. * @param {Number} [options.frictionEquationRelaxation=3]
  8665. */
  8666. function ContactMaterial(m1, m2, options){
  8667. options = Utils.defaults(options, {
  8668. friction: 0.3,
  8669. restitution: 0.3,
  8670. contactEquationStiffness: 1e7,
  8671. contactEquationRelaxation: 3,
  8672. frictionEquationStiffness: 1e7,
  8673. frictionEquationRelaxation: 3
  8674. });
  8675. /**
  8676. * Identifier of this material
  8677. * @property {Number} id
  8678. */
  8679. this.id = ContactMaterial.idCounter++;
  8680. /**
  8681. * Participating materials
  8682. * @property {Array} materials
  8683. * @todo Should be .materialA and .materialB instead
  8684. */
  8685. this.materials = [m1, m2];
  8686. /**
  8687. * Friction coefficient
  8688. * @property {Number} friction
  8689. */
  8690. this.friction = options.friction;
  8691. /**
  8692. * Restitution coefficient
  8693. * @property {Number} restitution
  8694. */
  8695. this.restitution = options.restitution;
  8696. /**
  8697. * Stiffness of the produced contact equations
  8698. * @property {Number} contactEquationStiffness
  8699. */
  8700. this.contactEquationStiffness = options.contactEquationStiffness;
  8701. /**
  8702. * Relaxation time of the produced contact equations
  8703. * @property {Number} contactEquationRelaxation
  8704. */
  8705. this.contactEquationRelaxation = options.contactEquationRelaxation;
  8706. /**
  8707. * Stiffness of the produced friction equations
  8708. * @property {Number} frictionEquationStiffness
  8709. */
  8710. this.frictionEquationStiffness = options.frictionEquationStiffness;
  8711. /**
  8712. * Relaxation time of the produced friction equations
  8713. * @property {Number} frictionEquationRelaxation
  8714. */
  8715. this.frictionEquationRelaxation = options.frictionEquationRelaxation;
  8716. }
  8717. ContactMaterial.idCounter = 0;
  8718. },{"../utils/Utils":75}],47:[function(require,module,exports){
  8719. module.exports = Material;
  8720. /**
  8721. * Defines a physics material.
  8722. * @class Material
  8723. * @constructor
  8724. * @param {object} [options]
  8725. * @author schteppe
  8726. */
  8727. function Material(options){
  8728. var name = '';
  8729. options = options || {};
  8730. // Backwards compatibility fix
  8731. if(typeof(options) === 'string'){
  8732. name = options;
  8733. options = {};
  8734. } else if(typeof(options) === 'object') {
  8735. name = '';
  8736. }
  8737. /**
  8738. * @property name
  8739. * @type {String}
  8740. */
  8741. this.name = name;
  8742. /**
  8743. * material id.
  8744. * @property id
  8745. * @type {number}
  8746. */
  8747. this.id = Material.idCounter++;
  8748. /**
  8749. * Friction for this material. If non-negative, it will be used instead of the friction given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
  8750. * @property {number} friction
  8751. */
  8752. this.friction = typeof(options.friction) !== 'undefined' ? options.friction : -1;
  8753. /**
  8754. * Restitution for this material. If non-negative, it will be used instead of the restitution given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
  8755. * @property {number} restitution
  8756. */
  8757. this.restitution = typeof(options.restitution) !== 'undefined' ? options.restitution : -1;
  8758. }
  8759. Material.idCounter = 0;
  8760. },{}],48:[function(require,module,exports){
  8761. module.exports = JacobianElement;
  8762. var Vec3 = require('./Vec3');
  8763. /**
  8764. * An element containing 6 entries, 3 spatial and 3 rotational degrees of freedom.
  8765. * @class JacobianElement
  8766. * @constructor
  8767. */
  8768. function JacobianElement(){
  8769. /**
  8770. * @property {Vec3} spatial
  8771. */
  8772. this.spatial = new Vec3();
  8773. /**
  8774. * @property {Vec3} rotational
  8775. */
  8776. this.rotational = new Vec3();
  8777. }
  8778. /**
  8779. * Multiply with other JacobianElement
  8780. * @method multiplyElement
  8781. * @param {JacobianElement} element
  8782. * @return {Number}
  8783. */
  8784. JacobianElement.prototype.multiplyElement = function(element){
  8785. return element.spatial.dot(this.spatial) + element.rotational.dot(this.rotational);
  8786. };
  8787. /**
  8788. * Multiply with two vectors
  8789. * @method multiplyVectors
  8790. * @param {Vec3} spatial
  8791. * @param {Vec3} rotational
  8792. * @return {Number}
  8793. */
  8794. JacobianElement.prototype.multiplyVectors = function(spatial,rotational){
  8795. return spatial.dot(this.spatial) + rotational.dot(this.rotational);
  8796. };
  8797. },{"./Vec3":52}],49:[function(require,module,exports){
  8798. module.exports = Mat3;
  8799. var Vec3 = require('./Vec3');
  8800. /**
  8801. * A 3x3 matrix.
  8802. * @class Mat3
  8803. * @constructor
  8804. * @param array elements Array of nine elements. Optional.
  8805. * @author schteppe / http://github.com/schteppe
  8806. */
  8807. function Mat3(elements){
  8808. /**
  8809. * A vector of length 9, containing all matrix elements
  8810. * @property {Array} elements
  8811. */
  8812. if(elements){
  8813. this.elements = elements;
  8814. } else {
  8815. this.elements = [0,0,0,0,0,0,0,0,0];
  8816. }
  8817. }
  8818. /**
  8819. * Sets the matrix to identity
  8820. * @method identity
  8821. * @todo Should perhaps be renamed to setIdentity() to be more clear.
  8822. * @todo Create another function that immediately creates an identity matrix eg. eye()
  8823. */
  8824. Mat3.prototype.identity = function(){
  8825. var e = this.elements;
  8826. e[0] = 1;
  8827. e[1] = 0;
  8828. e[2] = 0;
  8829. e[3] = 0;
  8830. e[4] = 1;
  8831. e[5] = 0;
  8832. e[6] = 0;
  8833. e[7] = 0;
  8834. e[8] = 1;
  8835. };
  8836. /**
  8837. * Set all elements to zero
  8838. * @method setZero
  8839. */
  8840. Mat3.prototype.setZero = function(){
  8841. var e = this.elements;
  8842. e[0] = 0;
  8843. e[1] = 0;
  8844. e[2] = 0;
  8845. e[3] = 0;
  8846. e[4] = 0;
  8847. e[5] = 0;
  8848. e[6] = 0;
  8849. e[7] = 0;
  8850. e[8] = 0;
  8851. };
  8852. /**
  8853. * Sets the matrix diagonal elements from a Vec3
  8854. * @method setTrace
  8855. * @param {Vec3} vec3
  8856. */
  8857. Mat3.prototype.setTrace = function(vec3){
  8858. var e = this.elements;
  8859. e[0] = vec3.x;
  8860. e[4] = vec3.y;
  8861. e[8] = vec3.z;
  8862. };
  8863. /**
  8864. * Gets the matrix diagonal elements
  8865. * @method getTrace
  8866. * @return {Vec3}
  8867. */
  8868. Mat3.prototype.getTrace = function(target){
  8869. var target = target || new Vec3();
  8870. var e = this.elements;
  8871. target.x = e[0];
  8872. target.y = e[4];
  8873. target.z = e[8];
  8874. };
  8875. /**
  8876. * Matrix-Vector multiplication
  8877. * @method vmult
  8878. * @param {Vec3} v The vector to multiply with
  8879. * @param {Vec3} target Optional, target to save the result in.
  8880. */
  8881. Mat3.prototype.vmult = function(v,target){
  8882. target = target || new Vec3();
  8883. var e = this.elements,
  8884. x = v.x,
  8885. y = v.y,
  8886. z = v.z;
  8887. target.x = e[0]*x + e[1]*y + e[2]*z;
  8888. target.y = e[3]*x + e[4]*y + e[5]*z;
  8889. target.z = e[6]*x + e[7]*y + e[8]*z;
  8890. return target;
  8891. };
  8892. /**
  8893. * Matrix-scalar multiplication
  8894. * @method smult
  8895. * @param {Number} s
  8896. */
  8897. Mat3.prototype.smult = function(s){
  8898. for(var i=0; i<this.elements.length; i++){
  8899. this.elements[i] *= s;
  8900. }
  8901. };
  8902. /**
  8903. * Matrix multiplication
  8904. * @method mmult
  8905. * @param {Mat3} m Matrix to multiply with from left side.
  8906. * @return {Mat3} The result.
  8907. */
  8908. Mat3.prototype.mmult = function(m,target){
  8909. var r = target || new Mat3();
  8910. for(var i=0; i<3; i++){
  8911. for(var j=0; j<3; j++){
  8912. var sum = 0.0;
  8913. for(var k=0; k<3; k++){
  8914. sum += m.elements[i+k*3] * this.elements[k+j*3];
  8915. }
  8916. r.elements[i+j*3] = sum;
  8917. }
  8918. }
  8919. return r;
  8920. };
  8921. /**
  8922. * Scale each column of the matrix
  8923. * @method scale
  8924. * @param {Vec3} v
  8925. * @return {Mat3} The result.
  8926. */
  8927. Mat3.prototype.scale = function(v,target){
  8928. target = target || new Mat3();
  8929. var e = this.elements,
  8930. t = target.elements;
  8931. for(var i=0; i!==3; i++){
  8932. t[3*i + 0] = v.x * e[3*i + 0];
  8933. t[3*i + 1] = v.y * e[3*i + 1];
  8934. t[3*i + 2] = v.z * e[3*i + 2];
  8935. }
  8936. return target;
  8937. };
  8938. /**
  8939. * Solve Ax=b
  8940. * @method solve
  8941. * @param {Vec3} b The right hand side
  8942. * @param {Vec3} target Optional. Target vector to save in.
  8943. * @return {Vec3} The solution x
  8944. * @todo should reuse arrays
  8945. */
  8946. Mat3.prototype.solve = function(b,target){
  8947. target = target || new Vec3();
  8948. // Construct equations
  8949. var nr = 3; // num rows
  8950. var nc = 4; // num cols
  8951. var eqns = [];
  8952. for(var i=0; i<nr*nc; i++){
  8953. eqns.push(0);
  8954. }
  8955. var i,j;
  8956. for(i=0; i<3; i++){
  8957. for(j=0; j<3; j++){
  8958. eqns[i+nc*j] = this.elements[i+3*j];
  8959. }
  8960. }
  8961. eqns[3+4*0] = b.x;
  8962. eqns[3+4*1] = b.y;
  8963. eqns[3+4*2] = b.z;
  8964. // Compute right upper triangular version of the matrix - Gauss elimination
  8965. var n = 3, k = n, np;
  8966. var kp = 4; // num rows
  8967. var p, els;
  8968. do {
  8969. i = k - n;
  8970. if (eqns[i+nc*i] === 0) {
  8971. // the pivot is null, swap lines
  8972. for (j = i + 1; j < k; j++) {
  8973. if (eqns[i+nc*j] !== 0) {
  8974. np = kp;
  8975. do { // do ligne( i ) = ligne( i ) + ligne( k )
  8976. p = kp - np;
  8977. eqns[p+nc*i] += eqns[p+nc*j];
  8978. } while (--np);
  8979. break;
  8980. }
  8981. }
  8982. }
  8983. if (eqns[i+nc*i] !== 0) {
  8984. for (j = i + 1; j < k; j++) {
  8985. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  8986. np = kp;
  8987. do { // do ligne( k ) = ligne( k ) - multiplier * ligne( i )
  8988. p = kp - np;
  8989. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  8990. } while (--np);
  8991. }
  8992. }
  8993. } while (--n);
  8994. // Get the solution
  8995. target.z = eqns[2*nc+3] / eqns[2*nc+2];
  8996. target.y = (eqns[1*nc+3] - eqns[1*nc+2]*target.z) / eqns[1*nc+1];
  8997. target.x = (eqns[0*nc+3] - eqns[0*nc+2]*target.z - eqns[0*nc+1]*target.y) / eqns[0*nc+0];
  8998. if(isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x===Infinity || target.y===Infinity || target.z===Infinity){
  8999. throw "Could not solve equation! Got x=["+target.toString()+"], b=["+b.toString()+"], A=["+this.toString()+"]";
  9000. }
  9001. return target;
  9002. };
  9003. /**
  9004. * Get an element in the matrix by index. Index starts at 0, not 1!!!
  9005. * @method e
  9006. * @param {Number} row
  9007. * @param {Number} column
  9008. * @param {Number} value Optional. If provided, the matrix element will be set to this value.
  9009. * @return {Number}
  9010. */
  9011. Mat3.prototype.e = function( row , column ,value){
  9012. if(value===undefined){
  9013. return this.elements[column+3*row];
  9014. } else {
  9015. // Set value
  9016. this.elements[column+3*row] = value;
  9017. }
  9018. };
  9019. /**
  9020. * Copy another matrix into this matrix object.
  9021. * @method copy
  9022. * @param {Mat3} source
  9023. * @return {Mat3} this
  9024. */
  9025. Mat3.prototype.copy = function(source){
  9026. for(var i=0; i < source.elements.length; i++){
  9027. this.elements[i] = source.elements[i];
  9028. }
  9029. return this;
  9030. };
  9031. /**
  9032. * Returns a string representation of the matrix.
  9033. * @method toString
  9034. * @return string
  9035. */
  9036. Mat3.prototype.toString = function(){
  9037. var r = "";
  9038. var sep = ",";
  9039. for(var i=0; i<9; i++){
  9040. r += this.elements[i] + sep;
  9041. }
  9042. return r;
  9043. };
  9044. /**
  9045. * reverse the matrix
  9046. * @method reverse
  9047. * @param {Mat3} target Optional. Target matrix to save in.
  9048. * @return {Mat3} The solution x
  9049. */
  9050. Mat3.prototype.reverse = function(target){
  9051. target = target || new Mat3();
  9052. // Construct equations
  9053. var nr = 3; // num rows
  9054. var nc = 6; // num cols
  9055. var eqns = [];
  9056. for(var i=0; i<nr*nc; i++){
  9057. eqns.push(0);
  9058. }
  9059. var i,j;
  9060. for(i=0; i<3; i++){
  9061. for(j=0; j<3; j++){
  9062. eqns[i+nc*j] = this.elements[i+3*j];
  9063. }
  9064. }
  9065. eqns[3+6*0] = 1;
  9066. eqns[3+6*1] = 0;
  9067. eqns[3+6*2] = 0;
  9068. eqns[4+6*0] = 0;
  9069. eqns[4+6*1] = 1;
  9070. eqns[4+6*2] = 0;
  9071. eqns[5+6*0] = 0;
  9072. eqns[5+6*1] = 0;
  9073. eqns[5+6*2] = 1;
  9074. // Compute right upper triangular version of the matrix - Gauss elimination
  9075. var n = 3, k = n, np;
  9076. var kp = nc; // num rows
  9077. var p;
  9078. do {
  9079. i = k - n;
  9080. if (eqns[i+nc*i] === 0) {
  9081. // the pivot is null, swap lines
  9082. for (j = i + 1; j < k; j++) {
  9083. if (eqns[i+nc*j] !== 0) {
  9084. np = kp;
  9085. do { // do line( i ) = line( i ) + line( k )
  9086. p = kp - np;
  9087. eqns[p+nc*i] += eqns[p+nc*j];
  9088. } while (--np);
  9089. break;
  9090. }
  9091. }
  9092. }
  9093. if (eqns[i+nc*i] !== 0) {
  9094. for (j = i + 1; j < k; j++) {
  9095. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  9096. np = kp;
  9097. do { // do line( k ) = line( k ) - multiplier * line( i )
  9098. p = kp - np;
  9099. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  9100. } while (--np);
  9101. }
  9102. }
  9103. } while (--n);
  9104. // eliminate the upper left triangle of the matrix
  9105. i = 2;
  9106. do {
  9107. j = i-1;
  9108. do {
  9109. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  9110. np = nc;
  9111. do {
  9112. p = nc - np;
  9113. eqns[p+nc*j] = eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  9114. } while (--np);
  9115. } while (j--);
  9116. } while (--i);
  9117. // operations on the diagonal
  9118. i = 2;
  9119. do {
  9120. var multiplier = 1 / eqns[i+nc*i];
  9121. np = nc;
  9122. do {
  9123. p = nc - np;
  9124. eqns[p+nc*i] = eqns[p+nc*i] * multiplier ;
  9125. } while (--np);
  9126. } while (i--);
  9127. i = 2;
  9128. do {
  9129. j = 2;
  9130. do {
  9131. p = eqns[nr+j+nc*i];
  9132. if( isNaN( p ) || p ===Infinity ){
  9133. throw "Could not reverse! A=["+this.toString()+"]";
  9134. }
  9135. target.e( i , j , p );
  9136. } while (j--);
  9137. } while (i--);
  9138. return target;
  9139. };
  9140. /**
  9141. * Set the matrix from a quaterion
  9142. * @method setRotationFromQuaternion
  9143. * @param {Quaternion} q
  9144. */
  9145. Mat3.prototype.setRotationFromQuaternion = function( q ) {
  9146. var x = q.x, y = q.y, z = q.z, w = q.w,
  9147. x2 = x + x, y2 = y + y, z2 = z + z,
  9148. xx = x * x2, xy = x * y2, xz = x * z2,
  9149. yy = y * y2, yz = y * z2, zz = z * z2,
  9150. wx = w * x2, wy = w * y2, wz = w * z2,
  9151. e = this.elements;
  9152. e[3*0 + 0] = 1 - ( yy + zz );
  9153. e[3*0 + 1] = xy - wz;
  9154. e[3*0 + 2] = xz + wy;
  9155. e[3*1 + 0] = xy + wz;
  9156. e[3*1 + 1] = 1 - ( xx + zz );
  9157. e[3*1 + 2] = yz - wx;
  9158. e[3*2 + 0] = xz - wy;
  9159. e[3*2 + 1] = yz + wx;
  9160. e[3*2 + 2] = 1 - ( xx + yy );
  9161. return this;
  9162. };
  9163. /**
  9164. * Transpose the matrix
  9165. * @method transpose
  9166. * @param {Mat3} target Where to store the result.
  9167. * @return {Mat3} The target Mat3, or a new Mat3 if target was omitted.
  9168. */
  9169. Mat3.prototype.transpose = function( target ) {
  9170. target = target || new Mat3();
  9171. var Mt = target.elements,
  9172. M = this.elements;
  9173. for(var i=0; i!==3; i++){
  9174. for(var j=0; j!==3; j++){
  9175. Mt[3*i + j] = M[3*j + i];
  9176. }
  9177. }
  9178. return target;
  9179. };
  9180. },{"./Vec3":52}],50:[function(require,module,exports){
  9181. module.exports = Quaternion;
  9182. var Vec3 = require('./Vec3');
  9183. /**
  9184. * A Quaternion describes a rotation in 3D space. The Quaternion is mathematically defined as Q = x*i + y*j + z*k + w, where (i,j,k) are imaginary basis vectors. (x,y,z) can be seen as a vector related to the axis of rotation, while the real multiplier, w, is related to the amount of rotation.
  9185. * @class Quaternion
  9186. * @constructor
  9187. * @param {Number} x Multiplier of the imaginary basis vector i.
  9188. * @param {Number} y Multiplier of the imaginary basis vector j.
  9189. * @param {Number} z Multiplier of the imaginary basis vector k.
  9190. * @param {Number} w Multiplier of the real part.
  9191. * @see http://en.wikipedia.org/wiki/Quaternion
  9192. */
  9193. function Quaternion(x,y,z,w){
  9194. /**
  9195. * @property {Number} x
  9196. */
  9197. this.x = x!==undefined ? x : 0;
  9198. /**
  9199. * @property {Number} y
  9200. */
  9201. this.y = y!==undefined ? y : 0;
  9202. /**
  9203. * @property {Number} z
  9204. */
  9205. this.z = z!==undefined ? z : 0;
  9206. /**
  9207. * The multiplier of the real quaternion basis vector.
  9208. * @property {Number} w
  9209. */
  9210. this.w = w!==undefined ? w : 1;
  9211. }
  9212. /**
  9213. * Set the value of the quaternion.
  9214. * @method set
  9215. * @param {Number} x
  9216. * @param {Number} y
  9217. * @param {Number} z
  9218. * @param {Number} w
  9219. */
  9220. Quaternion.prototype.set = function(x,y,z,w){
  9221. this.x = x;
  9222. this.y = y;
  9223. this.z = z;
  9224. this.w = w;
  9225. return this;
  9226. };
  9227. /**
  9228. * Convert to a readable format
  9229. * @method toString
  9230. * @return string
  9231. */
  9232. Quaternion.prototype.toString = function(){
  9233. return this.x+","+this.y+","+this.z+","+this.w;
  9234. };
  9235. /**
  9236. * Convert to an Array
  9237. * @method toArray
  9238. * @return Array
  9239. */
  9240. Quaternion.prototype.toArray = function(){
  9241. return [this.x, this.y, this.z, this.w];
  9242. };
  9243. /**
  9244. * Set the quaternion components given an axis and an angle.
  9245. * @method setFromAxisAngle
  9246. * @param {Vec3} axis
  9247. * @param {Number} angle in radians
  9248. */
  9249. Quaternion.prototype.setFromAxisAngle = function(axis,angle){
  9250. var s = Math.sin(angle*0.5);
  9251. this.x = axis.x * s;
  9252. this.y = axis.y * s;
  9253. this.z = axis.z * s;
  9254. this.w = Math.cos(angle*0.5);
  9255. return this;
  9256. };
  9257. /**
  9258. * Converts the quaternion to axis/angle representation.
  9259. * @method toAxisAngle
  9260. * @param {Vec3} [targetAxis] A vector object to reuse for storing the axis.
  9261. * @return {Array} An array, first elemnt is the axis and the second is the angle in radians.
  9262. */
  9263. Quaternion.prototype.toAxisAngle = function(targetAxis){
  9264. targetAxis = targetAxis || new Vec3();
  9265. this.normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
  9266. var angle = 2 * Math.acos(this.w);
  9267. var s = Math.sqrt(1-this.w*this.w); // assuming quaternion normalised then w is less than 1, so term always positive.
  9268. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
  9269. // if s close to zero then direction of axis not important
  9270. targetAxis.x = this.x; // if it is important that axis is normalised then replace with x=1; y=z=0;
  9271. targetAxis.y = this.y;
  9272. targetAxis.z = this.z;
  9273. } else {
  9274. targetAxis.x = this.x / s; // normalise axis
  9275. targetAxis.y = this.y / s;
  9276. targetAxis.z = this.z / s;
  9277. }
  9278. return [targetAxis,angle];
  9279. };
  9280. var sfv_t1 = new Vec3(),
  9281. sfv_t2 = new Vec3();
  9282. /**
  9283. * Set the quaternion value given two vectors. The resulting rotation will be the needed rotation to rotate u to v.
  9284. * @method setFromVectors
  9285. * @param {Vec3} u
  9286. * @param {Vec3} v
  9287. */
  9288. Quaternion.prototype.setFromVectors = function(u,v){
  9289. if(u.isAntiparallelTo(v)){
  9290. var t1 = sfv_t1;
  9291. var t2 = sfv_t2;
  9292. u.tangents(t1,t2);
  9293. this.setFromAxisAngle(t1,Math.PI);
  9294. } else {
  9295. var a = u.cross(v);
  9296. this.x = a.x;
  9297. this.y = a.y;
  9298. this.z = a.z;
  9299. this.w = Math.sqrt(Math.pow(u.norm(),2) * Math.pow(v.norm(),2)) + u.dot(v);
  9300. this.normalize();
  9301. }
  9302. return this;
  9303. };
  9304. /**
  9305. * Quaternion multiplication
  9306. * @method mult
  9307. * @param {Quaternion} q
  9308. * @param {Quaternion} target Optional.
  9309. * @return {Quaternion}
  9310. */
  9311. var Quaternion_mult_va = new Vec3();
  9312. var Quaternion_mult_vb = new Vec3();
  9313. var Quaternion_mult_vaxvb = new Vec3();
  9314. Quaternion.prototype.mult = function(q,target){
  9315. target = target || new Quaternion();
  9316. var ax = this.x, ay = this.y, az = this.z, aw = this.w,
  9317. bx = q.x, by = q.y, bz = q.z, bw = q.w;
  9318. target.x = ax * bw + aw * bx + ay * bz - az * by;
  9319. target.y = ay * bw + aw * by + az * bx - ax * bz;
  9320. target.z = az * bw + aw * bz + ax * by - ay * bx;
  9321. target.w = aw * bw - ax * bx - ay * by - az * bz;
  9322. return target;
  9323. };
  9324. /**
  9325. * Get the inverse quaternion rotation.
  9326. * @method inverse
  9327. * @param {Quaternion} target
  9328. * @return {Quaternion}
  9329. */
  9330. Quaternion.prototype.inverse = function(target){
  9331. var x = this.x, y = this.y, z = this.z, w = this.w;
  9332. target = target || new Quaternion();
  9333. this.conjugate(target);
  9334. var inorm2 = 1/(x*x + y*y + z*z + w*w);
  9335. target.x *= inorm2;
  9336. target.y *= inorm2;
  9337. target.z *= inorm2;
  9338. target.w *= inorm2;
  9339. return target;
  9340. };
  9341. /**
  9342. * Get the quaternion conjugate
  9343. * @method conjugate
  9344. * @param {Quaternion} target
  9345. * @return {Quaternion}
  9346. */
  9347. Quaternion.prototype.conjugate = function(target){
  9348. target = target || new Quaternion();
  9349. target.x = -this.x;
  9350. target.y = -this.y;
  9351. target.z = -this.z;
  9352. target.w = this.w;
  9353. return target;
  9354. };
  9355. /**
  9356. * Normalize the quaternion. Note that this changes the values of the quaternion.
  9357. * @method normalize
  9358. */
  9359. Quaternion.prototype.normalize = function(){
  9360. var l = Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);
  9361. if ( l === 0 ) {
  9362. this.x = 0;
  9363. this.y = 0;
  9364. this.z = 0;
  9365. this.w = 0;
  9366. } else {
  9367. l = 1 / l;
  9368. this.x *= l;
  9369. this.y *= l;
  9370. this.z *= l;
  9371. this.w *= l;
  9372. }
  9373. return this;
  9374. };
  9375. /**
  9376. * Approximation of quaternion normalization. Works best when quat is already almost-normalized.
  9377. * @method normalizeFast
  9378. * @see http://jsperf.com/fast-quaternion-normalization
  9379. * @author unphased, https://github.com/unphased
  9380. */
  9381. Quaternion.prototype.normalizeFast = function () {
  9382. var f = (3.0-(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w))/2.0;
  9383. if ( f === 0 ) {
  9384. this.x = 0;
  9385. this.y = 0;
  9386. this.z = 0;
  9387. this.w = 0;
  9388. } else {
  9389. this.x *= f;
  9390. this.y *= f;
  9391. this.z *= f;
  9392. this.w *= f;
  9393. }
  9394. return this;
  9395. };
  9396. /**
  9397. * Multiply the quaternion by a vector
  9398. * @method vmult
  9399. * @param {Vec3} v
  9400. * @param {Vec3} target Optional
  9401. * @return {Vec3}
  9402. */
  9403. Quaternion.prototype.vmult = function(v,target){
  9404. target = target || new Vec3();
  9405. var x = v.x,
  9406. y = v.y,
  9407. z = v.z;
  9408. var qx = this.x,
  9409. qy = this.y,
  9410. qz = this.z,
  9411. qw = this.w;
  9412. // q*v
  9413. var ix = qw * x + qy * z - qz * y,
  9414. iy = qw * y + qz * x - qx * z,
  9415. iz = qw * z + qx * y - qy * x,
  9416. iw = -qx * x - qy * y - qz * z;
  9417. target.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  9418. target.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  9419. target.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  9420. return target;
  9421. };
  9422. /**
  9423. * Copies value of source to this quaternion.
  9424. * @method copy
  9425. * @param {Quaternion} source
  9426. * @return {Quaternion} this
  9427. */
  9428. Quaternion.prototype.copy = function(source){
  9429. this.x = source.x;
  9430. this.y = source.y;
  9431. this.z = source.z;
  9432. this.w = source.w;
  9433. return this;
  9434. };
  9435. /**
  9436. * Convert the quaternion to euler angle representation. Order: YZX, as this page describes: http://www.euclideanspace.com/maths/standards/index.htm
  9437. * @method toEuler
  9438. * @param {Vec3} target
  9439. * @param string order Three-character string e.g. "YZX", which also is default.
  9440. */
  9441. Quaternion.prototype.toEuler = function(target,order){
  9442. order = order || "YZX";
  9443. var heading, attitude, bank;
  9444. var x = this.x, y = this.y, z = this.z, w = this.w;
  9445. switch(order){
  9446. case "YZX":
  9447. var test = x*y + z*w;
  9448. if (test > 0.499) { // singularity at north pole
  9449. heading = 2 * Math.atan2(x,w);
  9450. attitude = Math.PI/2;
  9451. bank = 0;
  9452. }
  9453. if (test < -0.499) { // singularity at south pole
  9454. heading = -2 * Math.atan2(x,w);
  9455. attitude = - Math.PI/2;
  9456. bank = 0;
  9457. }
  9458. if(isNaN(heading)){
  9459. var sqx = x*x;
  9460. var sqy = y*y;
  9461. var sqz = z*z;
  9462. heading = Math.atan2(2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz); // Heading
  9463. attitude = Math.asin(2*test); // attitude
  9464. bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
  9465. }
  9466. break;
  9467. default:
  9468. throw new Error("Euler order "+order+" not supported yet.");
  9469. }
  9470. target.y = heading;
  9471. target.z = attitude;
  9472. target.x = bank;
  9473. };
  9474. /**
  9475. * See http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
  9476. * @method setFromEuler
  9477. * @param {Number} x
  9478. * @param {Number} y
  9479. * @param {Number} z
  9480. * @param {String} order The order to apply angles: 'XYZ' or 'YXZ' or any other combination
  9481. */
  9482. Quaternion.prototype.setFromEuler = function ( x, y, z, order ) {
  9483. order = order || "XYZ";
  9484. var c1 = Math.cos( x / 2 );
  9485. var c2 = Math.cos( y / 2 );
  9486. var c3 = Math.cos( z / 2 );
  9487. var s1 = Math.sin( x / 2 );
  9488. var s2 = Math.sin( y / 2 );
  9489. var s3 = Math.sin( z / 2 );
  9490. if ( order === 'XYZ' ) {
  9491. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  9492. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  9493. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  9494. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  9495. } else if ( order === 'YXZ' ) {
  9496. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  9497. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  9498. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  9499. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  9500. } else if ( order === 'ZXY' ) {
  9501. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  9502. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  9503. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  9504. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  9505. } else if ( order === 'ZYX' ) {
  9506. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  9507. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  9508. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  9509. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  9510. } else if ( order === 'YZX' ) {
  9511. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  9512. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  9513. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  9514. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  9515. } else if ( order === 'XZY' ) {
  9516. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  9517. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  9518. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  9519. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  9520. }
  9521. return this;
  9522. };
  9523. /**
  9524. * @method clone
  9525. * @return {Quaternion}
  9526. */
  9527. Quaternion.prototype.clone = function(){
  9528. return new Quaternion(this.x, this.y, this.z, this.w);
  9529. };
  9530. /**
  9531. * Performs a spherical linear interpolation between two quat
  9532. *
  9533. * @method slerp
  9534. * @param {Quaternion} toQuat second operand
  9535. * @param {Number} t interpolation amount between the self quaternion and toQuat
  9536. * @param {Quaternion} [target] A quaternion to store the result in. If not provided, a new one will be created.
  9537. * @returns {Quaternion} The "target" object
  9538. */
  9539. Quaternion.prototype.slerp = function (toQuat, t, target) {
  9540. target = target || new Quaternion();
  9541. var ax = this.x,
  9542. ay = this.y,
  9543. az = this.z,
  9544. aw = this.w,
  9545. bx = toQuat.x,
  9546. by = toQuat.y,
  9547. bz = toQuat.z,
  9548. bw = toQuat.w;
  9549. var omega, cosom, sinom, scale0, scale1;
  9550. // calc cosine
  9551. cosom = ax * bx + ay * by + az * bz + aw * bw;
  9552. // adjust signs (if necessary)
  9553. if ( cosom < 0.0 ) {
  9554. cosom = -cosom;
  9555. bx = - bx;
  9556. by = - by;
  9557. bz = - bz;
  9558. bw = - bw;
  9559. }
  9560. // calculate coefficients
  9561. if ( (1.0 - cosom) > 0.000001 ) {
  9562. // standard case (slerp)
  9563. omega = Math.acos(cosom);
  9564. sinom = Math.sin(omega);
  9565. scale0 = Math.sin((1.0 - t) * omega) / sinom;
  9566. scale1 = Math.sin(t * omega) / sinom;
  9567. } else {
  9568. // "from" and "to" quaternions are very close
  9569. // ... so we can do a linear interpolation
  9570. scale0 = 1.0 - t;
  9571. scale1 = t;
  9572. }
  9573. // calculate final values
  9574. target.x = scale0 * ax + scale1 * bx;
  9575. target.y = scale0 * ay + scale1 * by;
  9576. target.z = scale0 * az + scale1 * bz;
  9577. target.w = scale0 * aw + scale1 * bw;
  9578. return target;
  9579. };
  9580. /**
  9581. * Rotate an absolute orientation quaternion given an angular velocity and a time step.
  9582. * @param {Vec3} angularVelocity
  9583. * @param {number} dt
  9584. * @param {Vec3} angularFactor
  9585. * @param {Quaternion} target
  9586. * @return {Quaternion} The "target" object
  9587. */
  9588. Quaternion.prototype.integrate = function(angularVelocity, dt, angularFactor, target){
  9589. target = target || new Quaternion();
  9590. var ax = angularVelocity.x * angularFactor.x,
  9591. ay = angularVelocity.y * angularFactor.y,
  9592. az = angularVelocity.z * angularFactor.z,
  9593. bx = this.x,
  9594. by = this.y,
  9595. bz = this.z,
  9596. bw = this.w;
  9597. var half_dt = dt * 0.5;
  9598. target.x += half_dt * (ax * bw + ay * bz - az * by);
  9599. target.y += half_dt * (ay * bw + az * bx - ax * bz);
  9600. target.z += half_dt * (az * bw + ax * by - ay * bx);
  9601. target.w += half_dt * (- ax * bx - ay * by - az * bz);
  9602. return target;
  9603. };
  9604. },{"./Vec3":52}],51:[function(require,module,exports){
  9605. var Vec3 = require('./Vec3');
  9606. var Quaternion = require('./Quaternion');
  9607. module.exports = Transform;
  9608. /**
  9609. * @class Transform
  9610. * @constructor
  9611. */
  9612. function Transform(options) {
  9613. options = options || {};
  9614. /**
  9615. * @property {Vec3} position
  9616. */
  9617. this.position = new Vec3();
  9618. if(options.position){
  9619. this.position.copy(options.position);
  9620. }
  9621. /**
  9622. * @property {Quaternion} quaternion
  9623. */
  9624. this.quaternion = new Quaternion();
  9625. if(options.quaternion){
  9626. this.quaternion.copy(options.quaternion);
  9627. }
  9628. }
  9629. var tmpQuat = new Quaternion();
  9630. /**
  9631. * @static
  9632. * @method pointToLocaFrame
  9633. * @param {Vec3} position
  9634. * @param {Quaternion} quaternion
  9635. * @param {Vec3} worldPoint
  9636. * @param {Vec3} result
  9637. */
  9638. Transform.pointToLocalFrame = function(position, quaternion, worldPoint, result){
  9639. var result = result || new Vec3();
  9640. worldPoint.vsub(position, result);
  9641. quaternion.conjugate(tmpQuat);
  9642. tmpQuat.vmult(result, result);
  9643. return result;
  9644. };
  9645. /**
  9646. * Get a global point in local transform coordinates.
  9647. * @method pointToLocal
  9648. * @param {Vec3} point
  9649. * @param {Vec3} result
  9650. * @return {Vec3} The "result" vector object
  9651. */
  9652. Transform.prototype.pointToLocal = function(worldPoint, result){
  9653. return Transform.pointToLocalFrame(this.position, this.quaternion, worldPoint, result);
  9654. };
  9655. /**
  9656. * @static
  9657. * @method pointToWorldFrame
  9658. * @param {Vec3} position
  9659. * @param {Vec3} quaternion
  9660. * @param {Vec3} localPoint
  9661. * @param {Vec3} result
  9662. */
  9663. Transform.pointToWorldFrame = function(position, quaternion, localPoint, result){
  9664. var result = result || new Vec3();
  9665. quaternion.vmult(localPoint, result);
  9666. result.vadd(position, result);
  9667. return result;
  9668. };
  9669. /**
  9670. * Get a local point in global transform coordinates.
  9671. * @method pointToWorld
  9672. * @param {Vec3} point
  9673. * @param {Vec3} result
  9674. * @return {Vec3} The "result" vector object
  9675. */
  9676. Transform.prototype.pointToWorld = function(localPoint, result){
  9677. return Transform.pointToWorldFrame(this.position, this.quaternion, localPoint, result);
  9678. };
  9679. Transform.prototype.vectorToWorldFrame = function(localVector, result){
  9680. var result = result || new Vec3();
  9681. this.quaternion.vmult(localVector, result);
  9682. return result;
  9683. };
  9684. Transform.vectorToWorldFrame = function(quaternion, localVector, result){
  9685. quaternion.vmult(localVector, result);
  9686. return result;
  9687. };
  9688. Transform.vectorToLocalFrame = function(position, quaternion, worldVector, result){
  9689. var result = result || new Vec3();
  9690. quaternion.w *= -1;
  9691. quaternion.vmult(worldVector, result);
  9692. quaternion.w *= -1;
  9693. return result;
  9694. };
  9695. },{"./Quaternion":50,"./Vec3":52}],52:[function(require,module,exports){
  9696. module.exports = Vec3;
  9697. var Mat3 = require('./Mat3');
  9698. /**
  9699. * 3-dimensional vector
  9700. * @class Vec3
  9701. * @constructor
  9702. * @param {Number} x
  9703. * @param {Number} y
  9704. * @param {Number} z
  9705. * @author schteppe
  9706. * @example
  9707. * var v = new Vec3(1, 2, 3);
  9708. * console.log('x=' + v.x); // x=1
  9709. */
  9710. function Vec3(x,y,z){
  9711. /**
  9712. * @property x
  9713. * @type {Number}
  9714. */
  9715. this.x = x||0.0;
  9716. /**
  9717. * @property y
  9718. * @type {Number}
  9719. */
  9720. this.y = y||0.0;
  9721. /**
  9722. * @property z
  9723. * @type {Number}
  9724. */
  9725. this.z = z||0.0;
  9726. }
  9727. /**
  9728. * @static
  9729. * @property {Vec3} ZERO
  9730. */
  9731. Vec3.ZERO = new Vec3(0, 0, 0);
  9732. /**
  9733. * @static
  9734. * @property {Vec3} UNIT_X
  9735. */
  9736. Vec3.UNIT_X = new Vec3(1, 0, 0);
  9737. /**
  9738. * @static
  9739. * @property {Vec3} UNIT_Y
  9740. */
  9741. Vec3.UNIT_Y = new Vec3(0, 1, 0);
  9742. /**
  9743. * @static
  9744. * @property {Vec3} UNIT_Z
  9745. */
  9746. Vec3.UNIT_Z = new Vec3(0, 0, 1);
  9747. /**
  9748. * Vector cross product
  9749. * @method cross
  9750. * @param {Vec3} v
  9751. * @param {Vec3} target Optional. Target to save in.
  9752. * @return {Vec3}
  9753. */
  9754. Vec3.prototype.cross = function(v,target){
  9755. var vx=v.x, vy=v.y, vz=v.z, x=this.x, y=this.y, z=this.z;
  9756. target = target || new Vec3();
  9757. target.x = (y * vz) - (z * vy);
  9758. target.y = (z * vx) - (x * vz);
  9759. target.z = (x * vy) - (y * vx);
  9760. return target;
  9761. };
  9762. /**
  9763. * Set the vectors' 3 elements
  9764. * @method set
  9765. * @param {Number} x
  9766. * @param {Number} y
  9767. * @param {Number} z
  9768. * @return Vec3
  9769. */
  9770. Vec3.prototype.set = function(x,y,z){
  9771. this.x = x;
  9772. this.y = y;
  9773. this.z = z;
  9774. return this;
  9775. };
  9776. /**
  9777. * Set all components of the vector to zero.
  9778. * @method setZero
  9779. */
  9780. Vec3.prototype.setZero = function(){
  9781. this.x = this.y = this.z = 0;
  9782. };
  9783. /**
  9784. * Vector addition
  9785. * @method vadd
  9786. * @param {Vec3} v
  9787. * @param {Vec3} target Optional.
  9788. * @return {Vec3}
  9789. */
  9790. Vec3.prototype.vadd = function(v,target){
  9791. if(target){
  9792. target.x = v.x + this.x;
  9793. target.y = v.y + this.y;
  9794. target.z = v.z + this.z;
  9795. } else {
  9796. return new Vec3(this.x + v.x,
  9797. this.y + v.y,
  9798. this.z + v.z);
  9799. }
  9800. };
  9801. /**
  9802. * Vector subtraction
  9803. * @method vsub
  9804. * @param {Vec3} v
  9805. * @param {Vec3} target Optional. Target to save in.
  9806. * @return {Vec3}
  9807. */
  9808. Vec3.prototype.vsub = function(v,target){
  9809. if(target){
  9810. target.x = this.x - v.x;
  9811. target.y = this.y - v.y;
  9812. target.z = this.z - v.z;
  9813. } else {
  9814. return new Vec3(this.x-v.x,
  9815. this.y-v.y,
  9816. this.z-v.z);
  9817. }
  9818. };
  9819. /**
  9820. * Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c
  9821. * @method crossmat
  9822. * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf
  9823. * @return {Mat3}
  9824. */
  9825. Vec3.prototype.crossmat = function(){
  9826. return new Mat3([ 0, -this.z, this.y,
  9827. this.z, 0, -this.x,
  9828. -this.y, this.x, 0]);
  9829. };
  9830. /**
  9831. * Normalize the vector. Note that this changes the values in the vector.
  9832. * @method normalize
  9833. * @return {Number} Returns the norm of the vector
  9834. */
  9835. Vec3.prototype.normalize = function(){
  9836. var x=this.x, y=this.y, z=this.z;
  9837. var n = Math.sqrt(x*x + y*y + z*z);
  9838. if(n>0.0){
  9839. var invN = 1/n;
  9840. this.x *= invN;
  9841. this.y *= invN;
  9842. this.z *= invN;
  9843. } else {
  9844. // Make something up
  9845. this.x = 0;
  9846. this.y = 0;
  9847. this.z = 0;
  9848. }
  9849. return n;
  9850. };
  9851. /**
  9852. * Get the version of this vector that is of length 1.
  9853. * @method unit
  9854. * @param {Vec3} target Optional target to save in
  9855. * @return {Vec3} Returns the unit vector
  9856. */
  9857. Vec3.prototype.unit = function(target){
  9858. target = target || new Vec3();
  9859. var x=this.x, y=this.y, z=this.z;
  9860. var ninv = Math.sqrt(x*x + y*y + z*z);
  9861. if(ninv>0.0){
  9862. ninv = 1.0/ninv;
  9863. target.x = x * ninv;
  9864. target.y = y * ninv;
  9865. target.z = z * ninv;
  9866. } else {
  9867. target.x = 1;
  9868. target.y = 0;
  9869. target.z = 0;
  9870. }
  9871. return target;
  9872. };
  9873. /**
  9874. * Get the length of the vector
  9875. * @method norm
  9876. * @return {Number}
  9877. * @deprecated Use .length() instead
  9878. */
  9879. Vec3.prototype.norm = function(){
  9880. var x=this.x, y=this.y, z=this.z;
  9881. return Math.sqrt(x*x + y*y + z*z);
  9882. };
  9883. /**
  9884. * Get the length of the vector
  9885. * @method length
  9886. * @return {Number}
  9887. */
  9888. Vec3.prototype.length = Vec3.prototype.norm;
  9889. /**
  9890. * Get the squared length of the vector
  9891. * @method norm2
  9892. * @return {Number}
  9893. * @deprecated Use .lengthSquared() instead.
  9894. */
  9895. Vec3.prototype.norm2 = function(){
  9896. return this.dot(this);
  9897. };
  9898. /**
  9899. * Get the squared length of the vector.
  9900. * @method lengthSquared
  9901. * @return {Number}
  9902. */
  9903. Vec3.prototype.lengthSquared = Vec3.prototype.norm2;
  9904. /**
  9905. * Get distance from this point to another point
  9906. * @method distanceTo
  9907. * @param {Vec3} p
  9908. * @return {Number}
  9909. */
  9910. Vec3.prototype.distanceTo = function(p){
  9911. var x=this.x, y=this.y, z=this.z;
  9912. var px=p.x, py=p.y, pz=p.z;
  9913. return Math.sqrt((px-x)*(px-x)+
  9914. (py-y)*(py-y)+
  9915. (pz-z)*(pz-z));
  9916. };
  9917. /**
  9918. * Get squared distance from this point to another point
  9919. * @method distanceSquared
  9920. * @param {Vec3} p
  9921. * @return {Number}
  9922. */
  9923. Vec3.prototype.distanceSquared = function(p){
  9924. var x=this.x, y=this.y, z=this.z;
  9925. var px=p.x, py=p.y, pz=p.z;
  9926. return (px-x)*(px-x) + (py-y)*(py-y) + (pz-z)*(pz-z);
  9927. };
  9928. /**
  9929. * Multiply all the components of the vector with a scalar.
  9930. * @deprecated Use .scale instead
  9931. * @method mult
  9932. * @param {Number} scalar
  9933. * @param {Vec3} target The vector to save the result in.
  9934. * @return {Vec3}
  9935. * @deprecated Use .scale() instead
  9936. */
  9937. Vec3.prototype.mult = function(scalar,target){
  9938. target = target || new Vec3();
  9939. var x = this.x,
  9940. y = this.y,
  9941. z = this.z;
  9942. target.x = scalar * x;
  9943. target.y = scalar * y;
  9944. target.z = scalar * z;
  9945. return target;
  9946. };
  9947. /**
  9948. * Multiply the vector with an other vector, component-wise.
  9949. * @method mult
  9950. * @param {Number} vector
  9951. * @param {Vec3} target The vector to save the result in.
  9952. * @return {Vec3}
  9953. */
  9954. Vec3.prototype.vmul = function(vector, target){
  9955. target = target || new Vec3();
  9956. target.x = vector.x * this.x;
  9957. target.y = vector.y * this.y;
  9958. target.z = vector.z * this.z;
  9959. return target;
  9960. };
  9961. /**
  9962. * Multiply the vector with a scalar.
  9963. * @method scale
  9964. * @param {Number} scalar
  9965. * @param {Vec3} target
  9966. * @return {Vec3}
  9967. */
  9968. Vec3.prototype.scale = Vec3.prototype.mult;
  9969. /**
  9970. * Scale a vector and add it to this vector. Save the result in "target". (target = this + vector * scalar)
  9971. * @method addScaledVector
  9972. * @param {Number} scalar
  9973. * @param {Vec3} vector
  9974. * @param {Vec3} target The vector to save the result in.
  9975. * @return {Vec3}
  9976. */
  9977. Vec3.prototype.addScaledVector = function(scalar, vector, target){
  9978. target = target || new Vec3();
  9979. target.x = this.x + scalar * vector.x;
  9980. target.y = this.y + scalar * vector.y;
  9981. target.z = this.z + scalar * vector.z;
  9982. return target;
  9983. };
  9984. /**
  9985. * Calculate dot product
  9986. * @method dot
  9987. * @param {Vec3} v
  9988. * @return {Number}
  9989. */
  9990. Vec3.prototype.dot = function(v){
  9991. return this.x * v.x + this.y * v.y + this.z * v.z;
  9992. };
  9993. /**
  9994. * @method isZero
  9995. * @return bool
  9996. */
  9997. Vec3.prototype.isZero = function(){
  9998. return this.x===0 && this.y===0 && this.z===0;
  9999. };
  10000. /**
  10001. * Make the vector point in the opposite direction.
  10002. * @method negate
  10003. * @param {Vec3} target Optional target to save in
  10004. * @return {Vec3}
  10005. */
  10006. Vec3.prototype.negate = function(target){
  10007. target = target || new Vec3();
  10008. target.x = -this.x;
  10009. target.y = -this.y;
  10010. target.z = -this.z;
  10011. return target;
  10012. };
  10013. /**
  10014. * Compute two artificial tangents to the vector
  10015. * @method tangents
  10016. * @param {Vec3} t1 Vector object to save the first tangent in
  10017. * @param {Vec3} t2 Vector object to save the second tangent in
  10018. */
  10019. var Vec3_tangents_n = new Vec3();
  10020. var Vec3_tangents_randVec = new Vec3();
  10021. Vec3.prototype.tangents = function(t1,t2){
  10022. var norm = this.norm();
  10023. if(norm>0.0){
  10024. var n = Vec3_tangents_n;
  10025. var inorm = 1/norm;
  10026. n.set(this.x*inorm,this.y*inorm,this.z*inorm);
  10027. var randVec = Vec3_tangents_randVec;
  10028. if(Math.abs(n.x) < 0.9){
  10029. randVec.set(1,0,0);
  10030. n.cross(randVec,t1);
  10031. } else {
  10032. randVec.set(0,1,0);
  10033. n.cross(randVec,t1);
  10034. }
  10035. n.cross(t1,t2);
  10036. } else {
  10037. // The normal length is zero, make something up
  10038. t1.set(1, 0, 0);
  10039. t2.set(0, 1, 0);
  10040. }
  10041. };
  10042. /**
  10043. * Converts to a more readable format
  10044. * @method toString
  10045. * @return string
  10046. */
  10047. Vec3.prototype.toString = function(){
  10048. return this.x+","+this.y+","+this.z;
  10049. };
  10050. /**
  10051. * Converts to an array
  10052. * @method toArray
  10053. * @return Array
  10054. */
  10055. Vec3.prototype.toArray = function(){
  10056. return [this.x, this.y, this.z];
  10057. };
  10058. /**
  10059. * Copies value of source to this vector.
  10060. * @method copy
  10061. * @param {Vec3} source
  10062. * @return {Vec3} this
  10063. */
  10064. Vec3.prototype.copy = function(source){
  10065. this.x = source.x;
  10066. this.y = source.y;
  10067. this.z = source.z;
  10068. return this;
  10069. };
  10070. /**
  10071. * Do a linear interpolation between two vectors
  10072. * @method lerp
  10073. * @param {Vec3} v
  10074. * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them.
  10075. * @param {Vec3} target
  10076. */
  10077. Vec3.prototype.lerp = function(v,t,target){
  10078. var x=this.x, y=this.y, z=this.z;
  10079. target.x = x + (v.x-x)*t;
  10080. target.y = y + (v.y-y)*t;
  10081. target.z = z + (v.z-z)*t;
  10082. };
  10083. /**
  10084. * Check if a vector equals is almost equal to another one.
  10085. * @method almostEquals
  10086. * @param {Vec3} v
  10087. * @param {Number} precision
  10088. * @return bool
  10089. */
  10090. Vec3.prototype.almostEquals = function(v,precision){
  10091. if(precision===undefined){
  10092. precision = 1e-6;
  10093. }
  10094. if( Math.abs(this.x-v.x)>precision ||
  10095. Math.abs(this.y-v.y)>precision ||
  10096. Math.abs(this.z-v.z)>precision){
  10097. return false;
  10098. }
  10099. return true;
  10100. };
  10101. /**
  10102. * Check if a vector is almost zero
  10103. * @method almostZero
  10104. * @param {Number} precision
  10105. */
  10106. Vec3.prototype.almostZero = function(precision){
  10107. if(precision===undefined){
  10108. precision = 1e-6;
  10109. }
  10110. if( Math.abs(this.x)>precision ||
  10111. Math.abs(this.y)>precision ||
  10112. Math.abs(this.z)>precision){
  10113. return false;
  10114. }
  10115. return true;
  10116. };
  10117. var antip_neg = new Vec3();
  10118. /**
  10119. * Check if the vector is anti-parallel to another vector.
  10120. * @method isAntiparallelTo
  10121. * @param {Vec3} v
  10122. * @param {Number} precision Set to zero for exact comparisons
  10123. * @return {Boolean}
  10124. */
  10125. Vec3.prototype.isAntiparallelTo = function(v,precision){
  10126. this.negate(antip_neg);
  10127. return antip_neg.almostEquals(v,precision);
  10128. };
  10129. /**
  10130. * Clone the vector
  10131. * @method clone
  10132. * @return {Vec3}
  10133. */
  10134. Vec3.prototype.clone = function(){
  10135. return new Vec3(this.x, this.y, this.z);
  10136. };
  10137. },{"./Mat3":49}],53:[function(require,module,exports){
  10138. module.exports = Body;
  10139. var EventTarget = require('../utils/EventTarget');
  10140. var Shape = require('../shapes/Shape');
  10141. var Vec3 = require('../math/Vec3');
  10142. var Mat3 = require('../math/Mat3');
  10143. var Quaternion = require('../math/Quaternion');
  10144. var Material = require('../material/Material');
  10145. var AABB = require('../collision/AABB');
  10146. var Box = require('../shapes/Box');
  10147. /**
  10148. * Base class for all body types.
  10149. * @class Body
  10150. * @constructor
  10151. * @extends EventTarget
  10152. * @param {object} [options]
  10153. * @param {Vec3} [options.position]
  10154. * @param {Vec3} [options.velocity]
  10155. * @param {Vec3} [options.angularVelocity]
  10156. * @param {Quaternion} [options.quaternion]
  10157. * @param {number} [options.mass]
  10158. * @param {Material} [options.material]
  10159. * @param {number} [options.type]
  10160. * @param {number} [options.linearDamping=0.01]
  10161. * @param {number} [options.angularDamping=0.01]
  10162. * @param {boolean} [options.allowSleep=true]
  10163. * @param {number} [options.sleepSpeedLimit=0.1]
  10164. * @param {number} [options.sleepTimeLimit=1]
  10165. * @param {number} [options.collisionFilterGroup=1]
  10166. * @param {number} [options.collisionFilterMask=1]
  10167. * @param {boolean} [options.fixedRotation=false]
  10168. * @param {Vec3} [options.linearFactor]
  10169. * @param {Vec3} [options.angularFactor]
  10170. * @param {Shape} [options.shape]
  10171. * @example
  10172. * var body = new Body({
  10173. * mass: 1
  10174. * });
  10175. * var shape = new Sphere(1);
  10176. * body.addShape(shape);
  10177. * world.addBody(body);
  10178. */
  10179. function Body(options){
  10180. options = options || {};
  10181. EventTarget.apply(this);
  10182. this.id = Body.idCounter++;
  10183. /**
  10184. * Reference to the world the body is living in
  10185. * @property world
  10186. * @type {World}
  10187. */
  10188. this.world = null;
  10189. /**
  10190. * Callback function that is used BEFORE stepping the system. Use it to apply forces, for example. Inside the function, "this" will refer to this Body object.
  10191. * @property preStep
  10192. * @type {Function}
  10193. * @deprecated Use World events instead
  10194. */
  10195. this.preStep = null;
  10196. /**
  10197. * Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this Body object.
  10198. * @property postStep
  10199. * @type {Function}
  10200. * @deprecated Use World events instead
  10201. */
  10202. this.postStep = null;
  10203. this.vlambda = new Vec3();
  10204. /**
  10205. * @property {Number} collisionFilterGroup
  10206. */
  10207. this.collisionFilterGroup = typeof(options.collisionFilterGroup) === 'number' ? options.collisionFilterGroup : 1;
  10208. /**
  10209. * @property {Number} collisionFilterMask
  10210. */
  10211. this.collisionFilterMask = typeof(options.collisionFilterMask) === 'number' ? options.collisionFilterMask : 1;
  10212. /**
  10213. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  10214. * @property {Number} collisionResponse
  10215. */
  10216. this.collisionResponse = true;
  10217. /**
  10218. * @property position
  10219. * @type {Vec3}
  10220. */
  10221. this.position = new Vec3();
  10222. /**
  10223. * @property {Vec3} previousPosition
  10224. */
  10225. this.previousPosition = new Vec3();
  10226. /**
  10227. * Interpolated position of the body.
  10228. * @property {Vec3} interpolatedPosition
  10229. */
  10230. this.interpolatedPosition = new Vec3();
  10231. /**
  10232. * Initial position of the body
  10233. * @property initPosition
  10234. * @type {Vec3}
  10235. */
  10236. this.initPosition = new Vec3();
  10237. if(options.position){
  10238. this.position.copy(options.position);
  10239. this.previousPosition.copy(options.position);
  10240. this.interpolatedPosition.copy(options.position);
  10241. this.initPosition.copy(options.position);
  10242. }
  10243. /**
  10244. * @property velocity
  10245. * @type {Vec3}
  10246. */
  10247. this.velocity = new Vec3();
  10248. if(options.velocity){
  10249. this.velocity.copy(options.velocity);
  10250. }
  10251. /**
  10252. * @property initVelocity
  10253. * @type {Vec3}
  10254. */
  10255. this.initVelocity = new Vec3();
  10256. /**
  10257. * Linear force on the body
  10258. * @property force
  10259. * @type {Vec3}
  10260. */
  10261. this.force = new Vec3();
  10262. var mass = typeof(options.mass) === 'number' ? options.mass : 0;
  10263. /**
  10264. * @property mass
  10265. * @type {Number}
  10266. * @default 0
  10267. */
  10268. this.mass = mass;
  10269. /**
  10270. * @property invMass
  10271. * @type {Number}
  10272. */
  10273. this.invMass = mass > 0 ? 1.0 / mass : 0;
  10274. /**
  10275. * @property material
  10276. * @type {Material}
  10277. */
  10278. this.material = options.material || null;
  10279. /**
  10280. * @property linearDamping
  10281. * @type {Number}
  10282. */
  10283. this.linearDamping = typeof(options.linearDamping) === 'number' ? options.linearDamping : 0.01;
  10284. /**
  10285. * One of: Body.DYNAMIC, Body.STATIC and Body.KINEMATIC.
  10286. * @property type
  10287. * @type {Number}
  10288. */
  10289. this.type = (mass <= 0.0 ? Body.STATIC : Body.DYNAMIC);
  10290. if(typeof(options.type) === typeof(Body.STATIC)){
  10291. this.type = options.type;
  10292. }
  10293. /**
  10294. * If true, the body will automatically fall to sleep.
  10295. * @property allowSleep
  10296. * @type {Boolean}
  10297. * @default true
  10298. */
  10299. this.allowSleep = typeof(options.allowSleep) !== 'undefined' ? options.allowSleep : true;
  10300. /**
  10301. * Current sleep state.
  10302. * @property sleepState
  10303. * @type {Number}
  10304. */
  10305. this.sleepState = 0;
  10306. /**
  10307. * If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  10308. * @property sleepSpeedLimit
  10309. * @type {Number}
  10310. * @default 0.1
  10311. */
  10312. this.sleepSpeedLimit = typeof(options.sleepSpeedLimit) !== 'undefined' ? options.sleepSpeedLimit : 0.1;
  10313. /**
  10314. * If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  10315. * @property sleepTimeLimit
  10316. * @type {Number}
  10317. * @default 1
  10318. */
  10319. this.sleepTimeLimit = typeof(options.sleepTimeLimit) !== 'undefined' ? options.sleepTimeLimit : 1;
  10320. this.timeLastSleepy = 0;
  10321. this._wakeUpAfterNarrowphase = false;
  10322. /**
  10323. * Rotational force on the body, around center of mass
  10324. * @property {Vec3} torque
  10325. */
  10326. this.torque = new Vec3();
  10327. /**
  10328. * Orientation of the body
  10329. * @property quaternion
  10330. * @type {Quaternion}
  10331. */
  10332. this.quaternion = new Quaternion();
  10333. /**
  10334. * @property initQuaternion
  10335. * @type {Quaternion}
  10336. */
  10337. this.initQuaternion = new Quaternion();
  10338. /**
  10339. * @property {Quaternion} previousQuaternion
  10340. */
  10341. this.previousQuaternion = new Quaternion();
  10342. /**
  10343. * Interpolated orientation of the body.
  10344. * @property {Quaternion} interpolatedQuaternion
  10345. */
  10346. this.interpolatedQuaternion = new Quaternion();
  10347. if(options.quaternion){
  10348. this.quaternion.copy(options.quaternion);
  10349. this.initQuaternion.copy(options.quaternion);
  10350. this.previousQuaternion.copy(options.quaternion);
  10351. this.interpolatedQuaternion.copy(options.quaternion);
  10352. }
  10353. /**
  10354. * @property angularVelocity
  10355. * @type {Vec3}
  10356. */
  10357. this.angularVelocity = new Vec3();
  10358. if(options.angularVelocity){
  10359. this.angularVelocity.copy(options.angularVelocity);
  10360. }
  10361. /**
  10362. * @property initAngularVelocity
  10363. * @type {Vec3}
  10364. */
  10365. this.initAngularVelocity = new Vec3();
  10366. /**
  10367. * @property shapes
  10368. * @type {array}
  10369. */
  10370. this.shapes = [];
  10371. /**
  10372. * @property shapeOffsets
  10373. * @type {array}
  10374. */
  10375. this.shapeOffsets = [];
  10376. /**
  10377. * @property shapeOrientations
  10378. * @type {array}
  10379. */
  10380. this.shapeOrientations = [];
  10381. /**
  10382. * @property inertia
  10383. * @type {Vec3}
  10384. */
  10385. this.inertia = new Vec3();
  10386. /**
  10387. * @property {Vec3} invInertia
  10388. */
  10389. this.invInertia = new Vec3();
  10390. /**
  10391. * @property {Mat3} invInertiaWorld
  10392. */
  10393. this.invInertiaWorld = new Mat3();
  10394. this.invMassSolve = 0;
  10395. /**
  10396. * @property {Vec3} invInertiaSolve
  10397. */
  10398. this.invInertiaSolve = new Vec3();
  10399. /**
  10400. * @property {Mat3} invInertiaWorldSolve
  10401. */
  10402. this.invInertiaWorldSolve = new Mat3();
  10403. /**
  10404. * Set to true if you don't want the body to rotate. Make sure to run .updateMassProperties() after changing this.
  10405. * @property {Boolean} fixedRotation
  10406. * @default false
  10407. */
  10408. this.fixedRotation = typeof(options.fixedRotation) !== "undefined" ? options.fixedRotation : false;
  10409. /**
  10410. * @property {Number} angularDamping
  10411. */
  10412. this.angularDamping = typeof(options.angularDamping) !== 'undefined' ? options.angularDamping : 0.01;
  10413. /**
  10414. * @property {Vec3} linearFactor
  10415. */
  10416. this.linearFactor = new Vec3(1,1,1);
  10417. if(options.linearFactor){
  10418. this.linearFactor.copy(options.linearFactor);
  10419. }
  10420. /**
  10421. * @property {Vec3} angularFactor
  10422. */
  10423. this.angularFactor = new Vec3(1,1,1);
  10424. if(options.angularFactor){
  10425. this.angularFactor.copy(options.angularFactor);
  10426. }
  10427. /**
  10428. * @property aabb
  10429. * @type {AABB}
  10430. */
  10431. this.aabb = new AABB();
  10432. /**
  10433. * Indicates if the AABB needs to be updated before use.
  10434. * @property aabbNeedsUpdate
  10435. * @type {Boolean}
  10436. */
  10437. this.aabbNeedsUpdate = true;
  10438. this.wlambda = new Vec3();
  10439. if(options.shape){
  10440. this.addShape(options.shape);
  10441. }
  10442. this.updateMassProperties();
  10443. }
  10444. Body.prototype = new EventTarget();
  10445. Body.prototype.constructor = Body;
  10446. /**
  10447. * Dispatched after two bodies collide. This event is dispatched on each
  10448. * of the two bodies involved in the collision.
  10449. * @event collide
  10450. * @param {Body} body The body that was involved in the collision.
  10451. * @param {ContactEquation} contact The details of the collision.
  10452. */
  10453. Body.COLLIDE_EVENT_NAME = "collide";
  10454. /**
  10455. * A dynamic body is fully simulated. Can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass.
  10456. * @static
  10457. * @property DYNAMIC
  10458. * @type {Number}
  10459. */
  10460. Body.DYNAMIC = 1;
  10461. /**
  10462. * A static body does not move during simulation and behaves as if it has infinite mass. Static bodies can be moved manually by setting the position of the body. The velocity of a static body is always zero. Static bodies do not collide with other static or kinematic bodies.
  10463. * @static
  10464. * @property STATIC
  10465. * @type {Number}
  10466. */
  10467. Body.STATIC = 2;
  10468. /**
  10469. * A kinematic body moves under simulation according to its velocity. They do not respond to forces. They can be moved manually, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass. Kinematic bodies do not collide with other static or kinematic bodies.
  10470. * @static
  10471. * @property KINEMATIC
  10472. * @type {Number}
  10473. */
  10474. Body.KINEMATIC = 4;
  10475. /**
  10476. * @static
  10477. * @property AWAKE
  10478. * @type {number}
  10479. */
  10480. Body.AWAKE = 0;
  10481. /**
  10482. * @static
  10483. * @property SLEEPY
  10484. * @type {number}
  10485. */
  10486. Body.SLEEPY = 1;
  10487. /**
  10488. * @static
  10489. * @property SLEEPING
  10490. * @type {number}
  10491. */
  10492. Body.SLEEPING = 2;
  10493. Body.idCounter = 0;
  10494. /**
  10495. * Dispatched after a sleeping body has woken up.
  10496. * @event wakeup
  10497. */
  10498. Body.wakeupEvent = {
  10499. type: "wakeup"
  10500. };
  10501. /**
  10502. * Wake the body up.
  10503. * @method wakeUp
  10504. */
  10505. Body.prototype.wakeUp = function(){
  10506. var s = this.sleepState;
  10507. this.sleepState = 0;
  10508. this._wakeUpAfterNarrowphase = false;
  10509. if(s === Body.SLEEPING){
  10510. this.dispatchEvent(Body.wakeupEvent);
  10511. }
  10512. };
  10513. /**
  10514. * Force body sleep
  10515. * @method sleep
  10516. */
  10517. Body.prototype.sleep = function(){
  10518. this.sleepState = Body.SLEEPING;
  10519. this.velocity.set(0,0,0);
  10520. this.angularVelocity.set(0,0,0);
  10521. this._wakeUpAfterNarrowphase = false;
  10522. };
  10523. /**
  10524. * Dispatched after a body has gone in to the sleepy state.
  10525. * @event sleepy
  10526. */
  10527. Body.sleepyEvent = {
  10528. type: "sleepy"
  10529. };
  10530. /**
  10531. * Dispatched after a body has fallen asleep.
  10532. * @event sleep
  10533. */
  10534. Body.sleepEvent = {
  10535. type: "sleep"
  10536. };
  10537. /**
  10538. * Called every timestep to update internal sleep timer and change sleep state if needed.
  10539. * @method sleepTick
  10540. * @param {Number} time The world time in seconds
  10541. */
  10542. Body.prototype.sleepTick = function(time){
  10543. if(this.allowSleep){
  10544. var sleepState = this.sleepState;
  10545. var speedSquared = this.velocity.norm2() + this.angularVelocity.norm2();
  10546. var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  10547. if(sleepState===Body.AWAKE && speedSquared < speedLimitSquared){
  10548. this.sleepState = Body.SLEEPY; // Sleepy
  10549. this.timeLastSleepy = time;
  10550. this.dispatchEvent(Body.sleepyEvent);
  10551. } else if(sleepState===Body.SLEEPY && speedSquared > speedLimitSquared){
  10552. this.wakeUp(); // Wake up
  10553. } else if(sleepState===Body.SLEEPY && (time - this.timeLastSleepy ) > this.sleepTimeLimit){
  10554. this.sleep(); // Sleeping
  10555. this.dispatchEvent(Body.sleepEvent);
  10556. }
  10557. }
  10558. };
  10559. /**
  10560. * If the body is sleeping, it should be immovable / have infinite mass during solve. We solve it by having a separate "solve mass".
  10561. * @method updateSolveMassProperties
  10562. */
  10563. Body.prototype.updateSolveMassProperties = function(){
  10564. if(this.sleepState === Body.SLEEPING || this.type === Body.KINEMATIC){
  10565. this.invMassSolve = 0;
  10566. this.invInertiaSolve.setZero();
  10567. this.invInertiaWorldSolve.setZero();
  10568. } else {
  10569. this.invMassSolve = this.invMass;
  10570. this.invInertiaSolve.copy(this.invInertia);
  10571. this.invInertiaWorldSolve.copy(this.invInertiaWorld);
  10572. }
  10573. };
  10574. /**
  10575. * Convert a world point to local body frame.
  10576. * @method pointToLocalFrame
  10577. * @param {Vec3} worldPoint
  10578. * @param {Vec3} result
  10579. * @return {Vec3}
  10580. */
  10581. Body.prototype.pointToLocalFrame = function(worldPoint,result){
  10582. var result = result || new Vec3();
  10583. worldPoint.vsub(this.position,result);
  10584. this.quaternion.conjugate().vmult(result,result);
  10585. return result;
  10586. };
  10587. /**
  10588. * Convert a world vector to local body frame.
  10589. * @method vectorToLocalFrame
  10590. * @param {Vec3} worldPoint
  10591. * @param {Vec3} result
  10592. * @return {Vec3}
  10593. */
  10594. Body.prototype.vectorToLocalFrame = function(worldVector, result){
  10595. var result = result || new Vec3();
  10596. this.quaternion.conjugate().vmult(worldVector,result);
  10597. return result;
  10598. };
  10599. /**
  10600. * Convert a local body point to world frame.
  10601. * @method pointToWorldFrame
  10602. * @param {Vec3} localPoint
  10603. * @param {Vec3} result
  10604. * @return {Vec3}
  10605. */
  10606. Body.prototype.pointToWorldFrame = function(localPoint,result){
  10607. var result = result || new Vec3();
  10608. this.quaternion.vmult(localPoint,result);
  10609. result.vadd(this.position,result);
  10610. return result;
  10611. };
  10612. /**
  10613. * Convert a local body point to world frame.
  10614. * @method vectorToWorldFrame
  10615. * @param {Vec3} localVector
  10616. * @param {Vec3} result
  10617. * @return {Vec3}
  10618. */
  10619. Body.prototype.vectorToWorldFrame = function(localVector, result){
  10620. var result = result || new Vec3();
  10621. this.quaternion.vmult(localVector, result);
  10622. return result;
  10623. };
  10624. var tmpVec = new Vec3();
  10625. var tmpQuat = new Quaternion();
  10626. /**
  10627. * Add a shape to the body with a local offset and orientation.
  10628. * @method addShape
  10629. * @param {Shape} shape
  10630. * @param {Vec3} [_offset]
  10631. * @param {Quaternion} [_orientation]
  10632. * @return {Body} The body object, for chainability.
  10633. */
  10634. Body.prototype.addShape = function(shape, _offset, _orientation){
  10635. var offset = new Vec3();
  10636. var orientation = new Quaternion();
  10637. if(_offset){
  10638. offset.copy(_offset);
  10639. }
  10640. if(_orientation){
  10641. orientation.copy(_orientation);
  10642. }
  10643. this.shapes.push(shape);
  10644. this.shapeOffsets.push(offset);
  10645. this.shapeOrientations.push(orientation);
  10646. this.updateMassProperties();
  10647. this.updateBoundingRadius();
  10648. this.aabbNeedsUpdate = true;
  10649. shape.body = this;
  10650. return this;
  10651. };
  10652. /**
  10653. * Update the bounding radius of the body. Should be done if any of the shapes are changed.
  10654. * @method updateBoundingRadius
  10655. */
  10656. Body.prototype.updateBoundingRadius = function(){
  10657. var shapes = this.shapes,
  10658. shapeOffsets = this.shapeOffsets,
  10659. N = shapes.length,
  10660. radius = 0;
  10661. for(var i=0; i!==N; i++){
  10662. var shape = shapes[i];
  10663. shape.updateBoundingSphereRadius();
  10664. var offset = shapeOffsets[i].norm(),
  10665. r = shape.boundingSphereRadius;
  10666. if(offset + r > radius){
  10667. radius = offset + r;
  10668. }
  10669. }
  10670. this.boundingRadius = radius;
  10671. };
  10672. var computeAABB_shapeAABB = new AABB();
  10673. /**
  10674. * Updates the .aabb
  10675. * @method computeAABB
  10676. * @todo rename to updateAABB()
  10677. */
  10678. Body.prototype.computeAABB = function(){
  10679. var shapes = this.shapes,
  10680. shapeOffsets = this.shapeOffsets,
  10681. shapeOrientations = this.shapeOrientations,
  10682. N = shapes.length,
  10683. offset = tmpVec,
  10684. orientation = tmpQuat,
  10685. bodyQuat = this.quaternion,
  10686. aabb = this.aabb,
  10687. shapeAABB = computeAABB_shapeAABB;
  10688. for(var i=0; i!==N; i++){
  10689. var shape = shapes[i];
  10690. // Get shape world position
  10691. bodyQuat.vmult(shapeOffsets[i], offset);
  10692. offset.vadd(this.position, offset);
  10693. // Get shape world quaternion
  10694. shapeOrientations[i].mult(bodyQuat, orientation);
  10695. // Get shape AABB
  10696. shape.calculateWorldAABB(offset, orientation, shapeAABB.lowerBound, shapeAABB.upperBound);
  10697. if(i === 0){
  10698. aabb.copy(shapeAABB);
  10699. } else {
  10700. aabb.extend(shapeAABB);
  10701. }
  10702. }
  10703. this.aabbNeedsUpdate = false;
  10704. };
  10705. var uiw_m1 = new Mat3(),
  10706. uiw_m2 = new Mat3(),
  10707. uiw_m3 = new Mat3();
  10708. /**
  10709. * Update .inertiaWorld and .invInertiaWorld
  10710. * @method updateInertiaWorld
  10711. */
  10712. Body.prototype.updateInertiaWorld = function(force){
  10713. var I = this.invInertia;
  10714. if (I.x === I.y && I.y === I.z && !force) {
  10715. // If inertia M = s*I, where I is identity and s a scalar, then
  10716. // R*M*R' = R*(s*I)*R' = s*R*I*R' = s*R*R' = s*I = M
  10717. // where R is the rotation matrix.
  10718. // In other words, we don't have to transform the inertia if all
  10719. // inertia diagonal entries are equal.
  10720. } else {
  10721. var m1 = uiw_m1,
  10722. m2 = uiw_m2,
  10723. m3 = uiw_m3;
  10724. m1.setRotationFromQuaternion(this.quaternion);
  10725. m1.transpose(m2);
  10726. m1.scale(I,m1);
  10727. m1.mmult(m2,this.invInertiaWorld);
  10728. }
  10729. };
  10730. /**
  10731. * Apply force to a world point. This could for example be a point on the Body surface. Applying force this way will add to Body.force and Body.torque.
  10732. * @method applyForce
  10733. * @param {Vec3} force The amount of force to add.
  10734. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  10735. */
  10736. var Body_applyForce_r = new Vec3();
  10737. var Body_applyForce_rotForce = new Vec3();
  10738. Body.prototype.applyForce = function(force,relativePoint){
  10739. if(this.type !== Body.DYNAMIC){ // Needed?
  10740. return;
  10741. }
  10742. // Compute produced rotational force
  10743. var rotForce = Body_applyForce_rotForce;
  10744. relativePoint.cross(force,rotForce);
  10745. // Add linear force
  10746. this.force.vadd(force,this.force);
  10747. // Add rotational force
  10748. this.torque.vadd(rotForce,this.torque);
  10749. };
  10750. /**
  10751. * Apply force to a local point in the body.
  10752. * @method applyLocalForce
  10753. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  10754. * @param {Vec3} localPoint A local point in the body to apply the force on.
  10755. */
  10756. var Body_applyLocalForce_worldForce = new Vec3();
  10757. var Body_applyLocalForce_relativePointWorld = new Vec3();
  10758. Body.prototype.applyLocalForce = function(localForce, localPoint){
  10759. if(this.type !== Body.DYNAMIC){
  10760. return;
  10761. }
  10762. var worldForce = Body_applyLocalForce_worldForce;
  10763. var relativePointWorld = Body_applyLocalForce_relativePointWorld;
  10764. // Transform the force vector to world space
  10765. this.vectorToWorldFrame(localForce, worldForce);
  10766. this.vectorToWorldFrame(localPoint, relativePointWorld);
  10767. this.applyForce(worldForce, relativePointWorld);
  10768. };
  10769. /**
  10770. * Apply impulse to a world point. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  10771. * @method applyImpulse
  10772. * @param {Vec3} impulse The amount of impulse to add.
  10773. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  10774. */
  10775. var Body_applyImpulse_r = new Vec3();
  10776. var Body_applyImpulse_velo = new Vec3();
  10777. var Body_applyImpulse_rotVelo = new Vec3();
  10778. Body.prototype.applyImpulse = function(impulse, relativePoint){
  10779. if(this.type !== Body.DYNAMIC){
  10780. return;
  10781. }
  10782. // Compute point position relative to the body center
  10783. var r = relativePoint;
  10784. // Compute produced central impulse velocity
  10785. var velo = Body_applyImpulse_velo;
  10786. velo.copy(impulse);
  10787. velo.mult(this.invMass,velo);
  10788. // Add linear impulse
  10789. this.velocity.vadd(velo, this.velocity);
  10790. // Compute produced rotational impulse velocity
  10791. var rotVelo = Body_applyImpulse_rotVelo;
  10792. r.cross(impulse,rotVelo);
  10793. /*
  10794. rotVelo.x *= this.invInertia.x;
  10795. rotVelo.y *= this.invInertia.y;
  10796. rotVelo.z *= this.invInertia.z;
  10797. */
  10798. this.invInertiaWorld.vmult(rotVelo,rotVelo);
  10799. // Add rotational Impulse
  10800. this.angularVelocity.vadd(rotVelo, this.angularVelocity);
  10801. };
  10802. /**
  10803. * Apply locally-defined impulse to a local point in the body.
  10804. * @method applyLocalImpulse
  10805. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  10806. * @param {Vec3} localPoint A local point in the body to apply the force on.
  10807. */
  10808. var Body_applyLocalImpulse_worldImpulse = new Vec3();
  10809. var Body_applyLocalImpulse_relativePoint = new Vec3();
  10810. Body.prototype.applyLocalImpulse = function(localImpulse, localPoint){
  10811. if(this.type !== Body.DYNAMIC){
  10812. return;
  10813. }
  10814. var worldImpulse = Body_applyLocalImpulse_worldImpulse;
  10815. var relativePointWorld = Body_applyLocalImpulse_relativePoint;
  10816. // Transform the force vector to world space
  10817. this.vectorToWorldFrame(localImpulse, worldImpulse);
  10818. this.vectorToWorldFrame(localPoint, relativePointWorld);
  10819. this.applyImpulse(worldImpulse, relativePointWorld);
  10820. };
  10821. var Body_updateMassProperties_halfExtents = new Vec3();
  10822. /**
  10823. * Should be called whenever you change the body shape or mass.
  10824. * @method updateMassProperties
  10825. */
  10826. Body.prototype.updateMassProperties = function(){
  10827. var halfExtents = Body_updateMassProperties_halfExtents;
  10828. this.invMass = this.mass > 0 ? 1.0 / this.mass : 0;
  10829. var I = this.inertia;
  10830. var fixed = this.fixedRotation;
  10831. // Approximate with AABB box
  10832. this.computeAABB();
  10833. halfExtents.set(
  10834. (this.aabb.upperBound.x-this.aabb.lowerBound.x) / 2,
  10835. (this.aabb.upperBound.y-this.aabb.lowerBound.y) / 2,
  10836. (this.aabb.upperBound.z-this.aabb.lowerBound.z) / 2
  10837. );
  10838. Box.calculateInertia(halfExtents, this.mass, I);
  10839. this.invInertia.set(
  10840. I.x > 0 && !fixed ? 1.0 / I.x : 0,
  10841. I.y > 0 && !fixed ? 1.0 / I.y : 0,
  10842. I.z > 0 && !fixed ? 1.0 / I.z : 0
  10843. );
  10844. this.updateInertiaWorld(true);
  10845. };
  10846. /**
  10847. * Get world velocity of a point in the body.
  10848. * @method getVelocityAtWorldPoint
  10849. * @param {Vec3} worldPoint
  10850. * @param {Vec3} result
  10851. * @return {Vec3} The result vector.
  10852. */
  10853. Body.prototype.getVelocityAtWorldPoint = function(worldPoint, result){
  10854. var r = new Vec3();
  10855. worldPoint.vsub(this.position, r);
  10856. this.angularVelocity.cross(r, result);
  10857. this.velocity.vadd(result, result);
  10858. return result;
  10859. };
  10860. var torque = new Vec3();
  10861. var invI_tau_dt = new Vec3();
  10862. var w = new Quaternion();
  10863. var wq = new Quaternion();
  10864. /**
  10865. * Move the body forward in time.
  10866. * @param {number} dt Time step
  10867. * @param {boolean} quatNormalize Set to true to normalize the body quaternion
  10868. * @param {boolean} quatNormalizeFast If the quaternion should be normalized using "fast" quaternion normalization
  10869. */
  10870. Body.prototype.integrate = function(dt, quatNormalize, quatNormalizeFast){
  10871. // Save previous position
  10872. this.previousPosition.copy(this.position);
  10873. this.previousQuaternion.copy(this.quaternion);
  10874. if(!(this.type === Body.DYNAMIC || this.type === Body.KINEMATIC) || this.sleepState === Body.SLEEPING){ // Only for dynamic
  10875. return;
  10876. }
  10877. var velo = this.velocity,
  10878. angularVelo = this.angularVelocity,
  10879. pos = this.position,
  10880. force = this.force,
  10881. torque = this.torque,
  10882. quat = this.quaternion,
  10883. invMass = this.invMass,
  10884. invInertia = this.invInertiaWorld,
  10885. linearFactor = this.linearFactor;
  10886. var iMdt = invMass * dt;
  10887. velo.x += force.x * iMdt * linearFactor.x;
  10888. velo.y += force.y * iMdt * linearFactor.y;
  10889. velo.z += force.z * iMdt * linearFactor.z;
  10890. var e = invInertia.elements;
  10891. var angularFactor = this.angularFactor;
  10892. var tx = torque.x * angularFactor.x;
  10893. var ty = torque.y * angularFactor.y;
  10894. var tz = torque.z * angularFactor.z;
  10895. angularVelo.x += dt * (e[0] * tx + e[1] * ty + e[2] * tz);
  10896. angularVelo.y += dt * (e[3] * tx + e[4] * ty + e[5] * tz);
  10897. angularVelo.z += dt * (e[6] * tx + e[7] * ty + e[8] * tz);
  10898. // Use new velocity - leap frog
  10899. pos.x += velo.x * dt;
  10900. pos.y += velo.y * dt;
  10901. pos.z += velo.z * dt;
  10902. quat.integrate(this.angularVelocity, dt, this.angularFactor, quat);
  10903. if(quatNormalize){
  10904. if(quatNormalizeFast){
  10905. quat.normalizeFast();
  10906. } else {
  10907. quat.normalize();
  10908. }
  10909. }
  10910. this.aabbNeedsUpdate = true;
  10911. // Update world inertia
  10912. this.updateInertiaWorld();
  10913. };
  10914. },{"../collision/AABB":24,"../material/Material":47,"../math/Mat3":49,"../math/Quaternion":50,"../math/Vec3":52,"../shapes/Box":59,"../shapes/Shape":65,"../utils/EventTarget":71}],54:[function(require,module,exports){
  10915. var Body = require('./Body');
  10916. var Vec3 = require('../math/Vec3');
  10917. var Quaternion = require('../math/Quaternion');
  10918. var RaycastResult = require('../collision/RaycastResult');
  10919. var Ray = require('../collision/Ray');
  10920. var WheelInfo = require('../objects/WheelInfo');
  10921. module.exports = RaycastVehicle;
  10922. /**
  10923. * Vehicle helper class that casts rays from the wheel positions towards the ground and applies forces.
  10924. * @class RaycastVehicle
  10925. * @constructor
  10926. * @param {object} [options]
  10927. * @param {Body} [options.chassisBody] The car chassis body.
  10928. * @param {integer} [options.indexRightAxis] Axis to use for right. x=0, y=1, z=2
  10929. * @param {integer} [options.indexLeftAxis]
  10930. * @param {integer} [options.indexUpAxis]
  10931. */
  10932. function RaycastVehicle(options){
  10933. /**
  10934. * @property {Body} chassisBody
  10935. */
  10936. this.chassisBody = options.chassisBody;
  10937. /**
  10938. * An array of WheelInfo objects.
  10939. * @property {array} wheelInfos
  10940. */
  10941. this.wheelInfos = [];
  10942. /**
  10943. * Will be set to true if the car is sliding.
  10944. * @property {boolean} sliding
  10945. */
  10946. this.sliding = false;
  10947. /**
  10948. * @property {World} world
  10949. */
  10950. this.world = null;
  10951. /**
  10952. * Index of the right axis, 0=x, 1=y, 2=z
  10953. * @property {integer} indexRightAxis
  10954. * @default 1
  10955. */
  10956. this.indexRightAxis = typeof(options.indexRightAxis) !== 'undefined' ? options.indexRightAxis : 1;
  10957. /**
  10958. * Index of the forward axis, 0=x, 1=y, 2=z
  10959. * @property {integer} indexForwardAxis
  10960. * @default 0
  10961. */
  10962. this.indexForwardAxis = typeof(options.indexForwardAxis) !== 'undefined' ? options.indexForwardAxis : 0;
  10963. /**
  10964. * Index of the up axis, 0=x, 1=y, 2=z
  10965. * @property {integer} indexUpAxis
  10966. * @default 2
  10967. */
  10968. this.indexUpAxis = typeof(options.indexUpAxis) !== 'undefined' ? options.indexUpAxis : 2;
  10969. }
  10970. var tmpVec1 = new Vec3();
  10971. var tmpVec2 = new Vec3();
  10972. var tmpVec3 = new Vec3();
  10973. var tmpVec4 = new Vec3();
  10974. var tmpVec5 = new Vec3();
  10975. var tmpVec6 = new Vec3();
  10976. var tmpRay = new Ray();
  10977. /**
  10978. * Add a wheel. For information about the options, see WheelInfo.
  10979. * @method addWheel
  10980. * @param {object} [options]
  10981. */
  10982. RaycastVehicle.prototype.addWheel = function(options){
  10983. options = options || {};
  10984. var info = new WheelInfo(options);
  10985. var index = this.wheelInfos.length;
  10986. this.wheelInfos.push(info);
  10987. return index;
  10988. };
  10989. /**
  10990. * Set the steering value of a wheel.
  10991. * @method setSteeringValue
  10992. * @param {number} value
  10993. * @param {integer} wheelIndex
  10994. */
  10995. RaycastVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  10996. var wheel = this.wheelInfos[wheelIndex];
  10997. wheel.steering = value;
  10998. };
  10999. var torque = new Vec3();
  11000. /**
  11001. * Set the wheel force to apply on one of the wheels each time step
  11002. * @method applyEngineForce
  11003. * @param {number} value
  11004. * @param {integer} wheelIndex
  11005. */
  11006. RaycastVehicle.prototype.applyEngineForce = function(value, wheelIndex){
  11007. this.wheelInfos[wheelIndex].engineForce = value;
  11008. };
  11009. /**
  11010. * Set the braking force of a wheel
  11011. * @method setBrake
  11012. * @param {number} brake
  11013. * @param {integer} wheelIndex
  11014. */
  11015. RaycastVehicle.prototype.setBrake = function(brake, wheelIndex){
  11016. this.wheelInfos[wheelIndex].brake = brake;
  11017. };
  11018. /**
  11019. * Add the vehicle including its constraints to the world.
  11020. * @method addToWorld
  11021. * @param {World} world
  11022. */
  11023. RaycastVehicle.prototype.addToWorld = function(world){
  11024. var constraints = this.constraints;
  11025. world.addBody(this.chassisBody);
  11026. var that = this;
  11027. this.preStepCallback = function(){
  11028. that.updateVehicle(world.dt);
  11029. };
  11030. world.addEventListener('preStep', this.preStepCallback);
  11031. this.world = world;
  11032. };
  11033. /**
  11034. * Get one of the wheel axles, world-oriented.
  11035. * @private
  11036. * @method getVehicleAxisWorld
  11037. * @param {integer} axisIndex
  11038. * @param {Vec3} result
  11039. */
  11040. RaycastVehicle.prototype.getVehicleAxisWorld = function(axisIndex, result){
  11041. result.set(
  11042. axisIndex === 0 ? 1 : 0,
  11043. axisIndex === 1 ? 1 : 0,
  11044. axisIndex === 2 ? 1 : 0
  11045. );
  11046. this.chassisBody.vectorToWorldFrame(result, result);
  11047. };
  11048. RaycastVehicle.prototype.updateVehicle = function(timeStep){
  11049. var wheelInfos = this.wheelInfos;
  11050. var numWheels = wheelInfos.length;
  11051. var chassisBody = this.chassisBody;
  11052. for (var i = 0; i < numWheels; i++) {
  11053. this.updateWheelTransform(i);
  11054. }
  11055. this.currentVehicleSpeedKmHour = 3.6 * chassisBody.velocity.norm();
  11056. var forwardWorld = new Vec3();
  11057. this.getVehicleAxisWorld(this.indexForwardAxis, forwardWorld);
  11058. if (forwardWorld.dot(chassisBody.velocity) < 0){
  11059. this.currentVehicleSpeedKmHour *= -1;
  11060. }
  11061. // simulate suspension
  11062. for (var i = 0; i < numWheels; i++) {
  11063. this.castRay(wheelInfos[i]);
  11064. }
  11065. this.updateSuspension(timeStep);
  11066. var impulse = new Vec3();
  11067. var relpos = new Vec3();
  11068. for (var i = 0; i < numWheels; i++) {
  11069. //apply suspension force
  11070. var wheel = wheelInfos[i];
  11071. var suspensionForce = wheel.suspensionForce;
  11072. if (suspensionForce > wheel.maxSuspensionForce) {
  11073. suspensionForce = wheel.maxSuspensionForce;
  11074. }
  11075. wheel.raycastResult.hitNormalWorld.scale(suspensionForce * timeStep, impulse);
  11076. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, relpos);
  11077. chassisBody.applyImpulse(impulse, relpos);
  11078. }
  11079. this.updateFriction(timeStep);
  11080. var hitNormalWorldScaledWithProj = new Vec3();
  11081. var fwd = new Vec3();
  11082. var vel = new Vec3();
  11083. for (i = 0; i < numWheels; i++) {
  11084. var wheel = wheelInfos[i];
  11085. //var relpos = new Vec3();
  11086. //wheel.chassisConnectionPointWorld.vsub(chassisBody.position, relpos);
  11087. chassisBody.getVelocityAtWorldPoint(wheel.chassisConnectionPointWorld, vel);
  11088. // Hack to get the rotation in the correct direction
  11089. var m = 1;
  11090. switch(this.indexUpAxis){
  11091. case 1:
  11092. m = -1;
  11093. break;
  11094. }
  11095. if (wheel.isInContact) {
  11096. this.getVehicleAxisWorld(this.indexForwardAxis, fwd);
  11097. var proj = fwd.dot(wheel.raycastResult.hitNormalWorld);
  11098. wheel.raycastResult.hitNormalWorld.scale(proj, hitNormalWorldScaledWithProj);
  11099. fwd.vsub(hitNormalWorldScaledWithProj, fwd);
  11100. var proj2 = fwd.dot(vel);
  11101. wheel.deltaRotation = m * proj2 * timeStep / wheel.radius;
  11102. }
  11103. if((wheel.sliding || !wheel.isInContact) && wheel.engineForce !== 0 && wheel.useCustomSlidingRotationalSpeed){
  11104. // Apply custom rotation when accelerating and sliding
  11105. wheel.deltaRotation = (wheel.engineForce > 0 ? 1 : -1) * wheel.customSlidingRotationalSpeed * timeStep;
  11106. }
  11107. // Lock wheels
  11108. if(Math.abs(wheel.brake) > Math.abs(wheel.engineForce)){
  11109. wheel.deltaRotation = 0;
  11110. }
  11111. wheel.rotation += wheel.deltaRotation; // Use the old value
  11112. wheel.deltaRotation *= 0.99; // damping of rotation when not in contact
  11113. }
  11114. };
  11115. RaycastVehicle.prototype.updateSuspension = function(deltaTime) {
  11116. var chassisBody = this.chassisBody;
  11117. var chassisMass = chassisBody.mass;
  11118. var wheelInfos = this.wheelInfos;
  11119. var numWheels = wheelInfos.length;
  11120. for (var w_it = 0; w_it < numWheels; w_it++){
  11121. var wheel = wheelInfos[w_it];
  11122. if (wheel.isInContact){
  11123. var force;
  11124. // Spring
  11125. var susp_length = wheel.suspensionRestLength;
  11126. var current_length = wheel.suspensionLength;
  11127. var length_diff = (susp_length - current_length);
  11128. force = wheel.suspensionStiffness * length_diff * wheel.clippedInvContactDotSuspension;
  11129. // Damper
  11130. var projected_rel_vel = wheel.suspensionRelativeVelocity;
  11131. var susp_damping;
  11132. if (projected_rel_vel < 0) {
  11133. susp_damping = wheel.dampingCompression;
  11134. } else {
  11135. susp_damping = wheel.dampingRelaxation;
  11136. }
  11137. force -= susp_damping * projected_rel_vel;
  11138. wheel.suspensionForce = force * chassisMass;
  11139. if (wheel.suspensionForce < 0) {
  11140. wheel.suspensionForce = 0;
  11141. }
  11142. } else {
  11143. wheel.suspensionForce = 0;
  11144. }
  11145. }
  11146. };
  11147. /**
  11148. * Remove the vehicle including its constraints from the world.
  11149. * @method removeFromWorld
  11150. * @param {World} world
  11151. */
  11152. RaycastVehicle.prototype.removeFromWorld = function(world){
  11153. var constraints = this.constraints;
  11154. world.remove(this.chassisBody);
  11155. world.removeEventListener('preStep', this.preStepCallback);
  11156. this.world = null;
  11157. };
  11158. var castRay_rayvector = new Vec3();
  11159. var castRay_target = new Vec3();
  11160. RaycastVehicle.prototype.castRay = function(wheel) {
  11161. var rayvector = castRay_rayvector;
  11162. var target = castRay_target;
  11163. this.updateWheelTransformWorld(wheel);
  11164. var chassisBody = this.chassisBody;
  11165. var depth = -1;
  11166. var raylen = wheel.suspensionRestLength + wheel.radius;
  11167. wheel.directionWorld.scale(raylen, rayvector);
  11168. var source = wheel.chassisConnectionPointWorld;
  11169. source.vadd(rayvector, target);
  11170. var raycastResult = wheel.raycastResult;
  11171. var param = 0;
  11172. raycastResult.reset();
  11173. // Turn off ray collision with the chassis temporarily
  11174. var oldState = chassisBody.collisionResponse;
  11175. chassisBody.collisionResponse = false;
  11176. // Cast ray against world
  11177. this.world.rayTest(source, target, raycastResult);
  11178. chassisBody.collisionResponse = oldState;
  11179. var object = raycastResult.body;
  11180. wheel.raycastResult.groundObject = 0;
  11181. if (object) {
  11182. depth = raycastResult.distance;
  11183. wheel.raycastResult.hitNormalWorld = raycastResult.hitNormalWorld;
  11184. wheel.isInContact = true;
  11185. var hitDistance = raycastResult.distance;
  11186. wheel.suspensionLength = hitDistance - wheel.radius;
  11187. // clamp on max suspension travel
  11188. var minSuspensionLength = wheel.suspensionRestLength - wheel.maxSuspensionTravel;
  11189. var maxSuspensionLength = wheel.suspensionRestLength + wheel.maxSuspensionTravel;
  11190. if (wheel.suspensionLength < minSuspensionLength) {
  11191. wheel.suspensionLength = minSuspensionLength;
  11192. }
  11193. if (wheel.suspensionLength > maxSuspensionLength) {
  11194. wheel.suspensionLength = maxSuspensionLength;
  11195. wheel.raycastResult.reset();
  11196. }
  11197. var denominator = wheel.raycastResult.hitNormalWorld.dot(wheel.directionWorld);
  11198. var chassis_velocity_at_contactPoint = new Vec3();
  11199. chassisBody.getVelocityAtWorldPoint(wheel.raycastResult.hitPointWorld, chassis_velocity_at_contactPoint);
  11200. var projVel = wheel.raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  11201. if (denominator >= -0.1) {
  11202. wheel.suspensionRelativeVelocity = 0;
  11203. wheel.clippedInvContactDotSuspension = 1 / 0.1;
  11204. } else {
  11205. var inv = -1 / denominator;
  11206. wheel.suspensionRelativeVelocity = projVel * inv;
  11207. wheel.clippedInvContactDotSuspension = inv;
  11208. }
  11209. } else {
  11210. //put wheel info as in rest position
  11211. wheel.suspensionLength = wheel.suspensionRestLength + 0 * wheel.maxSuspensionTravel;
  11212. wheel.suspensionRelativeVelocity = 0.0;
  11213. wheel.directionWorld.scale(-1, wheel.raycastResult.hitNormalWorld);
  11214. wheel.clippedInvContactDotSuspension = 1.0;
  11215. }
  11216. return depth;
  11217. };
  11218. RaycastVehicle.prototype.updateWheelTransformWorld = function(wheel){
  11219. wheel.isInContact = false;
  11220. var chassisBody = this.chassisBody;
  11221. chassisBody.pointToWorldFrame(wheel.chassisConnectionPointLocal, wheel.chassisConnectionPointWorld);
  11222. chassisBody.vectorToWorldFrame(wheel.directionLocal, wheel.directionWorld);
  11223. chassisBody.vectorToWorldFrame(wheel.axleLocal, wheel.axleWorld);
  11224. };
  11225. /**
  11226. * Update one of the wheel transform.
  11227. * Note when rendering wheels: during each step, wheel transforms are updated BEFORE the chassis; ie. their position becomes invalid after the step. Thus when you render wheels, you must update wheel transforms before rendering them. See raycastVehicle demo for an example.
  11228. * @method updateWheelTransform
  11229. * @param {integer} wheelIndex The wheel index to update.
  11230. */
  11231. RaycastVehicle.prototype.updateWheelTransform = function(wheelIndex){
  11232. var up = tmpVec4;
  11233. var right = tmpVec5;
  11234. var fwd = tmpVec6;
  11235. var wheel = this.wheelInfos[wheelIndex];
  11236. this.updateWheelTransformWorld(wheel);
  11237. wheel.directionLocal.scale(-1, up);
  11238. right.copy(wheel.axleLocal);
  11239. up.cross(right, fwd);
  11240. fwd.normalize();
  11241. right.normalize();
  11242. // Rotate around steering over the wheelAxle
  11243. var steering = wheel.steering;
  11244. var steeringOrn = new Quaternion();
  11245. steeringOrn.setFromAxisAngle(up, steering);
  11246. var rotatingOrn = new Quaternion();
  11247. rotatingOrn.setFromAxisAngle(right, wheel.rotation);
  11248. // World rotation of the wheel
  11249. var q = wheel.worldTransform.quaternion;
  11250. this.chassisBody.quaternion.mult(steeringOrn, q);
  11251. q.mult(rotatingOrn, q);
  11252. q.normalize();
  11253. // world position of the wheel
  11254. var p = wheel.worldTransform.position;
  11255. p.copy(wheel.directionWorld);
  11256. p.scale(wheel.suspensionLength, p);
  11257. p.vadd(wheel.chassisConnectionPointWorld, p);
  11258. };
  11259. var directions = [
  11260. new Vec3(1, 0, 0),
  11261. new Vec3(0, 1, 0),
  11262. new Vec3(0, 0, 1)
  11263. ];
  11264. /**
  11265. * Get the world transform of one of the wheels
  11266. * @method getWheelTransformWorld
  11267. * @param {integer} wheelIndex
  11268. * @return {Transform}
  11269. */
  11270. RaycastVehicle.prototype.getWheelTransformWorld = function(wheelIndex) {
  11271. return this.wheelInfos[wheelIndex].worldTransform;
  11272. };
  11273. var updateFriction_surfNormalWS_scaled_proj = new Vec3();
  11274. var updateFriction_axle = [];
  11275. var updateFriction_forwardWS = [];
  11276. var sideFrictionStiffness2 = 1;
  11277. RaycastVehicle.prototype.updateFriction = function(timeStep) {
  11278. var surfNormalWS_scaled_proj = updateFriction_surfNormalWS_scaled_proj;
  11279. //calculate the impulse, so that the wheels don't move sidewards
  11280. var wheelInfos = this.wheelInfos;
  11281. var numWheels = wheelInfos.length;
  11282. var chassisBody = this.chassisBody;
  11283. var forwardWS = updateFriction_forwardWS;
  11284. var axle = updateFriction_axle;
  11285. var numWheelsOnGround = 0;
  11286. for (var i = 0; i < numWheels; i++) {
  11287. var wheel = wheelInfos[i];
  11288. var groundObject = wheel.raycastResult.body;
  11289. if (groundObject){
  11290. numWheelsOnGround++;
  11291. }
  11292. wheel.sideImpulse = 0;
  11293. wheel.forwardImpulse = 0;
  11294. if(!forwardWS[i]){
  11295. forwardWS[i] = new Vec3();
  11296. }
  11297. if(!axle[i]){
  11298. axle[i] = new Vec3();
  11299. }
  11300. }
  11301. for (var i = 0; i < numWheels; i++){
  11302. var wheel = wheelInfos[i];
  11303. var groundObject = wheel.raycastResult.body;
  11304. if (groundObject) {
  11305. var axlei = axle[i];
  11306. var wheelTrans = this.getWheelTransformWorld(i);
  11307. // Get world axle
  11308. wheelTrans.vectorToWorldFrame(directions[this.indexRightAxis], axlei);
  11309. var surfNormalWS = wheel.raycastResult.hitNormalWorld;
  11310. var proj = axlei.dot(surfNormalWS);
  11311. surfNormalWS.scale(proj, surfNormalWS_scaled_proj);
  11312. axlei.vsub(surfNormalWS_scaled_proj, axlei);
  11313. axlei.normalize();
  11314. surfNormalWS.cross(axlei, forwardWS[i]);
  11315. forwardWS[i].normalize();
  11316. wheel.sideImpulse = resolveSingleBilateral(
  11317. chassisBody,
  11318. wheel.raycastResult.hitPointWorld,
  11319. groundObject,
  11320. wheel.raycastResult.hitPointWorld,
  11321. axlei
  11322. );
  11323. wheel.sideImpulse *= sideFrictionStiffness2;
  11324. }
  11325. }
  11326. var sideFactor = 1;
  11327. var fwdFactor = 0.5;
  11328. this.sliding = false;
  11329. for (var i = 0; i < numWheels; i++) {
  11330. var wheel = wheelInfos[i];
  11331. var groundObject = wheel.raycastResult.body;
  11332. var rollingFriction = 0;
  11333. wheel.slipInfo = 1;
  11334. if (groundObject) {
  11335. var defaultRollingFrictionImpulse = 0;
  11336. var maxImpulse = wheel.brake ? wheel.brake : defaultRollingFrictionImpulse;
  11337. // btWheelContactPoint contactPt(chassisBody,groundObject,wheelInfraycastInfo.hitPointWorld,forwardWS[wheel],maxImpulse);
  11338. // rollingFriction = calcRollingFriction(contactPt);
  11339. rollingFriction = calcRollingFriction(chassisBody, groundObject, wheel.raycastResult.hitPointWorld, forwardWS[i], maxImpulse);
  11340. rollingFriction += wheel.engineForce * timeStep;
  11341. // rollingFriction = 0;
  11342. var factor = maxImpulse / rollingFriction;
  11343. wheel.slipInfo *= factor;
  11344. }
  11345. //switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break)
  11346. wheel.forwardImpulse = 0;
  11347. wheel.skidInfo = 1;
  11348. if (groundObject) {
  11349. wheel.skidInfo = 1;
  11350. var maximp = wheel.suspensionForce * timeStep * wheel.frictionSlip;
  11351. var maximpSide = maximp;
  11352. var maximpSquared = maximp * maximpSide;
  11353. wheel.forwardImpulse = rollingFriction;//wheelInfo.engineForce* timeStep;
  11354. var x = wheel.forwardImpulse * fwdFactor;
  11355. var y = wheel.sideImpulse * sideFactor;
  11356. var impulseSquared = x * x + y * y;
  11357. wheel.sliding = false;
  11358. if (impulseSquared > maximpSquared) {
  11359. this.sliding = true;
  11360. wheel.sliding = true;
  11361. var factor = maximp / Math.sqrt(impulseSquared);
  11362. wheel.skidInfo *= factor;
  11363. }
  11364. }
  11365. }
  11366. if (this.sliding) {
  11367. for (var i = 0; i < numWheels; i++) {
  11368. var wheel = wheelInfos[i];
  11369. if (wheel.sideImpulse !== 0) {
  11370. if (wheel.skidInfo < 1){
  11371. wheel.forwardImpulse *= wheel.skidInfo;
  11372. wheel.sideImpulse *= wheel.skidInfo;
  11373. }
  11374. }
  11375. }
  11376. }
  11377. // apply the impulses
  11378. for (var i = 0; i < numWheels; i++) {
  11379. var wheel = wheelInfos[i];
  11380. var rel_pos = new Vec3();
  11381. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, rel_pos);
  11382. // cannons applyimpulse is using world coord for the position
  11383. //rel_pos.copy(wheel.raycastResult.hitPointWorld);
  11384. if (wheel.forwardImpulse !== 0) {
  11385. var impulse = new Vec3();
  11386. forwardWS[i].scale(wheel.forwardImpulse, impulse);
  11387. chassisBody.applyImpulse(impulse, rel_pos);
  11388. }
  11389. if (wheel.sideImpulse !== 0){
  11390. var groundObject = wheel.raycastResult.body;
  11391. var rel_pos2 = new Vec3();
  11392. wheel.raycastResult.hitPointWorld.vsub(groundObject.position, rel_pos2);
  11393. //rel_pos2.copy(wheel.raycastResult.hitPointWorld);
  11394. var sideImp = new Vec3();
  11395. axle[i].scale(wheel.sideImpulse, sideImp);
  11396. // Scale the relative position in the up direction with rollInfluence.
  11397. // If rollInfluence is 1, the impulse will be applied on the hitPoint (easy to roll over), if it is zero it will be applied in the same plane as the center of mass (not easy to roll over).
  11398. chassisBody.vectorToLocalFrame(rel_pos, rel_pos);
  11399. rel_pos['xyz'[this.indexUpAxis]] *= wheel.rollInfluence;
  11400. chassisBody.vectorToWorldFrame(rel_pos, rel_pos);
  11401. chassisBody.applyImpulse(sideImp, rel_pos);
  11402. //apply friction impulse on the ground
  11403. sideImp.scale(-1, sideImp);
  11404. groundObject.applyImpulse(sideImp, rel_pos2);
  11405. }
  11406. }
  11407. };
  11408. var calcRollingFriction_vel1 = new Vec3();
  11409. var calcRollingFriction_vel2 = new Vec3();
  11410. var calcRollingFriction_vel = new Vec3();
  11411. function calcRollingFriction(body0, body1, frictionPosWorld, frictionDirectionWorld, maxImpulse) {
  11412. var j1 = 0;
  11413. var contactPosWorld = frictionPosWorld;
  11414. // var rel_pos1 = new Vec3();
  11415. // var rel_pos2 = new Vec3();
  11416. var vel1 = calcRollingFriction_vel1;
  11417. var vel2 = calcRollingFriction_vel2;
  11418. var vel = calcRollingFriction_vel;
  11419. // contactPosWorld.vsub(body0.position, rel_pos1);
  11420. // contactPosWorld.vsub(body1.position, rel_pos2);
  11421. body0.getVelocityAtWorldPoint(contactPosWorld, vel1);
  11422. body1.getVelocityAtWorldPoint(contactPosWorld, vel2);
  11423. vel1.vsub(vel2, vel);
  11424. var vrel = frictionDirectionWorld.dot(vel);
  11425. var denom0 = computeImpulseDenominator(body0, frictionPosWorld, frictionDirectionWorld);
  11426. var denom1 = computeImpulseDenominator(body1, frictionPosWorld, frictionDirectionWorld);
  11427. var relaxation = 1;
  11428. var jacDiagABInv = relaxation / (denom0 + denom1);
  11429. // calculate j that moves us to zero relative velocity
  11430. j1 = -vrel * jacDiagABInv;
  11431. if (maxImpulse < j1) {
  11432. j1 = maxImpulse;
  11433. }
  11434. if (j1 < -maxImpulse) {
  11435. j1 = -maxImpulse;
  11436. }
  11437. return j1;
  11438. }
  11439. var computeImpulseDenominator_r0 = new Vec3();
  11440. var computeImpulseDenominator_c0 = new Vec3();
  11441. var computeImpulseDenominator_vec = new Vec3();
  11442. var computeImpulseDenominator_m = new Vec3();
  11443. function computeImpulseDenominator(body, pos, normal) {
  11444. var r0 = computeImpulseDenominator_r0;
  11445. var c0 = computeImpulseDenominator_c0;
  11446. var vec = computeImpulseDenominator_vec;
  11447. var m = computeImpulseDenominator_m;
  11448. pos.vsub(body.position, r0);
  11449. r0.cross(normal, c0);
  11450. body.invInertiaWorld.vmult(c0, m);
  11451. m.cross(r0, vec);
  11452. return body.invMass + normal.dot(vec);
  11453. }
  11454. var resolveSingleBilateral_vel1 = new Vec3();
  11455. var resolveSingleBilateral_vel2 = new Vec3();
  11456. var resolveSingleBilateral_vel = new Vec3();
  11457. //bilateral constraint between two dynamic objects
  11458. function resolveSingleBilateral(body1, pos1, body2, pos2, normal, impulse){
  11459. var normalLenSqr = normal.norm2();
  11460. if (normalLenSqr > 1.1){
  11461. return 0; // no impulse
  11462. }
  11463. // var rel_pos1 = new Vec3();
  11464. // var rel_pos2 = new Vec3();
  11465. // pos1.vsub(body1.position, rel_pos1);
  11466. // pos2.vsub(body2.position, rel_pos2);
  11467. var vel1 = resolveSingleBilateral_vel1;
  11468. var vel2 = resolveSingleBilateral_vel2;
  11469. var vel = resolveSingleBilateral_vel;
  11470. body1.getVelocityAtWorldPoint(pos1, vel1);
  11471. body2.getVelocityAtWorldPoint(pos2, vel2);
  11472. vel1.vsub(vel2, vel);
  11473. var rel_vel = normal.dot(vel);
  11474. var contactDamping = 0.2;
  11475. var massTerm = 1 / (body1.invMass + body2.invMass);
  11476. var impulse = - contactDamping * rel_vel * massTerm;
  11477. return impulse;
  11478. }
  11479. },{"../collision/Ray":31,"../collision/RaycastResult":32,"../math/Quaternion":50,"../math/Vec3":52,"../objects/WheelInfo":58,"./Body":53}],55:[function(require,module,exports){
  11480. var Body = require('./Body');
  11481. var Sphere = require('../shapes/Sphere');
  11482. var Box = require('../shapes/Box');
  11483. var Vec3 = require('../math/Vec3');
  11484. var HingeConstraint = require('../constraints/HingeConstraint');
  11485. module.exports = RigidVehicle;
  11486. /**
  11487. * Simple vehicle helper class with spherical rigid body wheels.
  11488. * @class RigidVehicle
  11489. * @constructor
  11490. * @param {Body} [options.chassisBody]
  11491. */
  11492. function RigidVehicle(options){
  11493. this.wheelBodies = [];
  11494. /**
  11495. * @property coordinateSystem
  11496. * @type {Vec3}
  11497. */
  11498. this.coordinateSystem = typeof(options.coordinateSystem)==='undefined' ? new Vec3(1, 2, 3) : options.coordinateSystem.clone();
  11499. /**
  11500. * @property {Body} chassisBody
  11501. */
  11502. this.chassisBody = options.chassisBody;
  11503. if(!this.chassisBody){
  11504. // No chassis body given. Create it!
  11505. var chassisShape = new Box(new Vec3(5, 2, 0.5));
  11506. this.chassisBody = new Body(1, chassisShape);
  11507. }
  11508. /**
  11509. * @property constraints
  11510. * @type {Array}
  11511. */
  11512. this.constraints = [];
  11513. this.wheelAxes = [];
  11514. this.wheelForces = [];
  11515. }
  11516. /**
  11517. * Add a wheel
  11518. * @method addWheel
  11519. * @param {object} options
  11520. * @param {boolean} [options.isFrontWheel]
  11521. * @param {Vec3} [options.position] Position of the wheel, locally in the chassis body.
  11522. * @param {Vec3} [options.direction] Slide direction of the wheel along the suspension.
  11523. * @param {Vec3} [options.axis] Axis of rotation of the wheel, locally defined in the chassis.
  11524. * @param {Body} [options.body] The wheel body.
  11525. */
  11526. RigidVehicle.prototype.addWheel = function(options){
  11527. options = options || {};
  11528. var wheelBody = options.body;
  11529. if(!wheelBody){
  11530. wheelBody = new Body(1, new Sphere(1.2));
  11531. }
  11532. this.wheelBodies.push(wheelBody);
  11533. this.wheelForces.push(0);
  11534. // Position constrain wheels
  11535. var zero = new Vec3();
  11536. var position = typeof(options.position) !== 'undefined' ? options.position.clone() : new Vec3();
  11537. // Set position locally to the chassis
  11538. var worldPosition = new Vec3();
  11539. this.chassisBody.pointToWorldFrame(position, worldPosition);
  11540. wheelBody.position.set(worldPosition.x, worldPosition.y, worldPosition.z);
  11541. // Constrain wheel
  11542. var axis = typeof(options.axis) !== 'undefined' ? options.axis.clone() : new Vec3(0, 1, 0);
  11543. this.wheelAxes.push(axis);
  11544. var hingeConstraint = new HingeConstraint(this.chassisBody, wheelBody, {
  11545. pivotA: position,
  11546. axisA: axis,
  11547. pivotB: Vec3.ZERO,
  11548. axisB: axis,
  11549. collideConnected: false
  11550. });
  11551. this.constraints.push(hingeConstraint);
  11552. return this.wheelBodies.length - 1;
  11553. };
  11554. /**
  11555. * Set the steering value of a wheel.
  11556. * @method setSteeringValue
  11557. * @param {number} value
  11558. * @param {integer} wheelIndex
  11559. * @todo check coordinateSystem
  11560. */
  11561. RigidVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  11562. // Set angle of the hinge axis
  11563. var axis = this.wheelAxes[wheelIndex];
  11564. var c = Math.cos(value),
  11565. s = Math.sin(value),
  11566. x = axis.x,
  11567. y = axis.y;
  11568. this.constraints[wheelIndex].axisA.set(
  11569. c*x -s*y,
  11570. s*x +c*y,
  11571. 0
  11572. );
  11573. };
  11574. /**
  11575. * Set the target rotational speed of the hinge constraint.
  11576. * @method setMotorSpeed
  11577. * @param {number} value
  11578. * @param {integer} wheelIndex
  11579. */
  11580. RigidVehicle.prototype.setMotorSpeed = function(value, wheelIndex){
  11581. var hingeConstraint = this.constraints[wheelIndex];
  11582. hingeConstraint.enableMotor();
  11583. hingeConstraint.motorTargetVelocity = value;
  11584. };
  11585. /**
  11586. * Set the target rotational speed of the hinge constraint.
  11587. * @method disableMotor
  11588. * @param {number} value
  11589. * @param {integer} wheelIndex
  11590. */
  11591. RigidVehicle.prototype.disableMotor = function(wheelIndex){
  11592. var hingeConstraint = this.constraints[wheelIndex];
  11593. hingeConstraint.disableMotor();
  11594. };
  11595. var torque = new Vec3();
  11596. /**
  11597. * Set the wheel force to apply on one of the wheels each time step
  11598. * @method setWheelForce
  11599. * @param {number} value
  11600. * @param {integer} wheelIndex
  11601. */
  11602. RigidVehicle.prototype.setWheelForce = function(value, wheelIndex){
  11603. this.wheelForces[wheelIndex] = value;
  11604. };
  11605. /**
  11606. * Apply a torque on one of the wheels.
  11607. * @method applyWheelForce
  11608. * @param {number} value
  11609. * @param {integer} wheelIndex
  11610. */
  11611. RigidVehicle.prototype.applyWheelForce = function(value, wheelIndex){
  11612. var axis = this.wheelAxes[wheelIndex];
  11613. var wheelBody = this.wheelBodies[wheelIndex];
  11614. var bodyTorque = wheelBody.torque;
  11615. axis.scale(value, torque);
  11616. wheelBody.vectorToWorldFrame(torque, torque);
  11617. bodyTorque.vadd(torque, bodyTorque);
  11618. };
  11619. /**
  11620. * Add the vehicle including its constraints to the world.
  11621. * @method addToWorld
  11622. * @param {World} world
  11623. */
  11624. RigidVehicle.prototype.addToWorld = function(world){
  11625. var constraints = this.constraints;
  11626. var bodies = this.wheelBodies.concat([this.chassisBody]);
  11627. for (var i = 0; i < bodies.length; i++) {
  11628. world.addBody(bodies[i]);
  11629. }
  11630. for (var i = 0; i < constraints.length; i++) {
  11631. world.addConstraint(constraints[i]);
  11632. }
  11633. world.addEventListener('preStep', this._update.bind(this));
  11634. };
  11635. RigidVehicle.prototype._update = function(){
  11636. var wheelForces = this.wheelForces;
  11637. for (var i = 0; i < wheelForces.length; i++) {
  11638. this.applyWheelForce(wheelForces[i], i);
  11639. }
  11640. };
  11641. /**
  11642. * Remove the vehicle including its constraints from the world.
  11643. * @method removeFromWorld
  11644. * @param {World} world
  11645. */
  11646. RigidVehicle.prototype.removeFromWorld = function(world){
  11647. var constraints = this.constraints;
  11648. var bodies = this.wheelBodies.concat([this.chassisBody]);
  11649. for (var i = 0; i < bodies.length; i++) {
  11650. world.remove(bodies[i]);
  11651. }
  11652. for (var i = 0; i < constraints.length; i++) {
  11653. world.removeConstraint(constraints[i]);
  11654. }
  11655. };
  11656. var worldAxis = new Vec3();
  11657. /**
  11658. * Get current rotational velocity of a wheel
  11659. * @method getWheelSpeed
  11660. * @param {integer} wheelIndex
  11661. */
  11662. RigidVehicle.prototype.getWheelSpeed = function(wheelIndex){
  11663. var axis = this.wheelAxes[wheelIndex];
  11664. var wheelBody = this.wheelBodies[wheelIndex];
  11665. var w = wheelBody.angularVelocity;
  11666. this.chassisBody.vectorToWorldFrame(axis, worldAxis);
  11667. return w.dot(worldAxis);
  11668. };
  11669. },{"../constraints/HingeConstraint":37,"../math/Vec3":52,"../shapes/Box":59,"../shapes/Sphere":66,"./Body":53}],56:[function(require,module,exports){
  11670. module.exports = SPHSystem;
  11671. var Shape = require('../shapes/Shape');
  11672. var Vec3 = require('../math/Vec3');
  11673. var Quaternion = require('../math/Quaternion');
  11674. var Particle = require('../shapes/Particle');
  11675. var Body = require('../objects/Body');
  11676. var Material = require('../material/Material');
  11677. /**
  11678. * Smoothed-particle hydrodynamics system
  11679. * @class SPHSystem
  11680. * @constructor
  11681. */
  11682. function SPHSystem(){
  11683. this.particles = [];
  11684. /**
  11685. * Density of the system (kg/m3).
  11686. * @property {number} density
  11687. */
  11688. this.density = 1;
  11689. /**
  11690. * Distance below which two particles are considered to be neighbors.
  11691. * It should be adjusted so there are about 15-20 neighbor particles within this radius.
  11692. * @property {number} smoothingRadius
  11693. */
  11694. this.smoothingRadius = 1;
  11695. this.speedOfSound = 1;
  11696. /**
  11697. * Viscosity of the system.
  11698. * @property {number} viscosity
  11699. */
  11700. this.viscosity = 0.01;
  11701. this.eps = 0.000001;
  11702. // Stuff Computed per particle
  11703. this.pressures = [];
  11704. this.densities = [];
  11705. this.neighbors = [];
  11706. }
  11707. /**
  11708. * Add a particle to the system.
  11709. * @method add
  11710. * @param {Body} particle
  11711. */
  11712. SPHSystem.prototype.add = function(particle){
  11713. this.particles.push(particle);
  11714. if(this.neighbors.length < this.particles.length){
  11715. this.neighbors.push([]);
  11716. }
  11717. };
  11718. /**
  11719. * Remove a particle from the system.
  11720. * @method remove
  11721. * @param {Body} particle
  11722. */
  11723. SPHSystem.prototype.remove = function(particle){
  11724. var idx = this.particles.indexOf(particle);
  11725. if(idx !== -1){
  11726. this.particles.splice(idx,1);
  11727. if(this.neighbors.length > this.particles.length){
  11728. this.neighbors.pop();
  11729. }
  11730. }
  11731. };
  11732. /**
  11733. * Get neighbors within smoothing volume, save in the array neighbors
  11734. * @method getNeighbors
  11735. * @param {Body} particle
  11736. * @param {Array} neighbors
  11737. */
  11738. var SPHSystem_getNeighbors_dist = new Vec3();
  11739. SPHSystem.prototype.getNeighbors = function(particle,neighbors){
  11740. var N = this.particles.length,
  11741. id = particle.id,
  11742. R2 = this.smoothingRadius * this.smoothingRadius,
  11743. dist = SPHSystem_getNeighbors_dist;
  11744. for(var i=0; i!==N; i++){
  11745. var p = this.particles[i];
  11746. p.position.vsub(particle.position,dist);
  11747. if(id!==p.id && dist.norm2() < R2){
  11748. neighbors.push(p);
  11749. }
  11750. }
  11751. };
  11752. // Temp vectors for calculation
  11753. var SPHSystem_update_dist = new Vec3(),
  11754. SPHSystem_update_a_pressure = new Vec3(),
  11755. SPHSystem_update_a_visc = new Vec3(),
  11756. SPHSystem_update_gradW = new Vec3(),
  11757. SPHSystem_update_r_vec = new Vec3(),
  11758. SPHSystem_update_u = new Vec3(); // Relative velocity
  11759. SPHSystem.prototype.update = function(){
  11760. var N = this.particles.length,
  11761. dist = SPHSystem_update_dist,
  11762. cs = this.speedOfSound,
  11763. eps = this.eps;
  11764. for(var i=0; i!==N; i++){
  11765. var p = this.particles[i]; // Current particle
  11766. var neighbors = this.neighbors[i];
  11767. // Get neighbors
  11768. neighbors.length = 0;
  11769. this.getNeighbors(p,neighbors);
  11770. neighbors.push(this.particles[i]); // Add current too
  11771. var numNeighbors = neighbors.length;
  11772. // Accumulate density for the particle
  11773. var sum = 0.0;
  11774. for(var j=0; j!==numNeighbors; j++){
  11775. //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
  11776. p.position.vsub(neighbors[j].position, dist);
  11777. var len = dist.norm();
  11778. var weight = this.w(len);
  11779. sum += neighbors[j].mass * weight;
  11780. }
  11781. // Save
  11782. this.densities[i] = sum;
  11783. this.pressures[i] = cs * cs * (this.densities[i] - this.density);
  11784. }
  11785. // Add forces
  11786. // Sum to these accelerations
  11787. var a_pressure= SPHSystem_update_a_pressure;
  11788. var a_visc = SPHSystem_update_a_visc;
  11789. var gradW = SPHSystem_update_gradW;
  11790. var r_vec = SPHSystem_update_r_vec;
  11791. var u = SPHSystem_update_u;
  11792. for(var i=0; i!==N; i++){
  11793. var particle = this.particles[i];
  11794. a_pressure.set(0,0,0);
  11795. a_visc.set(0,0,0);
  11796. // Init vars
  11797. var Pij;
  11798. var nabla;
  11799. var Vij;
  11800. // Sum up for all other neighbors
  11801. var neighbors = this.neighbors[i];
  11802. var numNeighbors = neighbors.length;
  11803. //printf("Neighbors: ");
  11804. for(var j=0; j!==numNeighbors; j++){
  11805. var neighbor = neighbors[j];
  11806. //printf("%d ",nj);
  11807. // Get r once for all..
  11808. particle.position.vsub(neighbor.position,r_vec);
  11809. var r = r_vec.norm();
  11810. // Pressure contribution
  11811. Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
  11812. this.gradw(r_vec, gradW);
  11813. // Add to pressure acceleration
  11814. gradW.mult(Pij , gradW);
  11815. a_pressure.vadd(gradW, a_pressure);
  11816. // Viscosity contribution
  11817. neighbor.velocity.vsub(particle.velocity, u);
  11818. u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
  11819. nabla = this.nablaw(r);
  11820. u.mult(nabla,u);
  11821. // Add to viscosity acceleration
  11822. a_visc.vadd( u, a_visc );
  11823. }
  11824. // Calculate force
  11825. a_visc.mult(particle.mass, a_visc);
  11826. a_pressure.mult(particle.mass, a_pressure);
  11827. // Add force to particles
  11828. particle.force.vadd(a_visc, particle.force);
  11829. particle.force.vadd(a_pressure, particle.force);
  11830. }
  11831. };
  11832. // Calculate the weight using the W(r) weightfunction
  11833. SPHSystem.prototype.w = function(r){
  11834. // 315
  11835. var h = this.smoothingRadius;
  11836. return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
  11837. };
  11838. // calculate gradient of the weight function
  11839. SPHSystem.prototype.gradw = function(rVec,resultVec){
  11840. var r = rVec.norm(),
  11841. h = this.smoothingRadius;
  11842. rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
  11843. };
  11844. // Calculate nabla(W)
  11845. SPHSystem.prototype.nablaw = function(r){
  11846. var h = this.smoothingRadius;
  11847. var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
  11848. return nabla;
  11849. };
  11850. },{"../material/Material":47,"../math/Quaternion":50,"../math/Vec3":52,"../objects/Body":53,"../shapes/Particle":63,"../shapes/Shape":65}],57:[function(require,module,exports){
  11851. var Vec3 = require('../math/Vec3');
  11852. module.exports = Spring;
  11853. /**
  11854. * A spring, connecting two bodies.
  11855. *
  11856. * @class Spring
  11857. * @constructor
  11858. * @param {Body} bodyA
  11859. * @param {Body} bodyB
  11860. * @param {Object} [options]
  11861. * @param {number} [options.restLength] A number > 0. Default: 1
  11862. * @param {number} [options.stiffness] A number >= 0. Default: 100
  11863. * @param {number} [options.damping] A number >= 0. Default: 1
  11864. * @param {Vec3} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates.
  11865. * @param {Vec3} [options.worldAnchorB]
  11866. * @param {Vec3} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates.
  11867. * @param {Vec3} [options.localAnchorB]
  11868. */
  11869. function Spring(bodyA,bodyB,options){
  11870. options = options || {};
  11871. /**
  11872. * Rest length of the spring.
  11873. * @property restLength
  11874. * @type {number}
  11875. */
  11876. this.restLength = typeof(options.restLength) === "number" ? options.restLength : 1;
  11877. /**
  11878. * Stiffness of the spring.
  11879. * @property stiffness
  11880. * @type {number}
  11881. */
  11882. this.stiffness = options.stiffness || 100;
  11883. /**
  11884. * Damping of the spring.
  11885. * @property damping
  11886. * @type {number}
  11887. */
  11888. this.damping = options.damping || 1;
  11889. /**
  11890. * First connected body.
  11891. * @property bodyA
  11892. * @type {Body}
  11893. */
  11894. this.bodyA = bodyA;
  11895. /**
  11896. * Second connected body.
  11897. * @property bodyB
  11898. * @type {Body}
  11899. */
  11900. this.bodyB = bodyB;
  11901. /**
  11902. * Anchor for bodyA in local bodyA coordinates.
  11903. * @property localAnchorA
  11904. * @type {Vec3}
  11905. */
  11906. this.localAnchorA = new Vec3();
  11907. /**
  11908. * Anchor for bodyB in local bodyB coordinates.
  11909. * @property localAnchorB
  11910. * @type {Vec3}
  11911. */
  11912. this.localAnchorB = new Vec3();
  11913. if(options.localAnchorA){
  11914. this.localAnchorA.copy(options.localAnchorA);
  11915. }
  11916. if(options.localAnchorB){
  11917. this.localAnchorB.copy(options.localAnchorB);
  11918. }
  11919. if(options.worldAnchorA){
  11920. this.setWorldAnchorA(options.worldAnchorA);
  11921. }
  11922. if(options.worldAnchorB){
  11923. this.setWorldAnchorB(options.worldAnchorB);
  11924. }
  11925. }
  11926. /**
  11927. * Set the anchor point on body A, using world coordinates.
  11928. * @method setWorldAnchorA
  11929. * @param {Vec3} worldAnchorA
  11930. */
  11931. Spring.prototype.setWorldAnchorA = function(worldAnchorA){
  11932. this.bodyA.pointToLocalFrame(worldAnchorA,this.localAnchorA);
  11933. };
  11934. /**
  11935. * Set the anchor point on body B, using world coordinates.
  11936. * @method setWorldAnchorB
  11937. * @param {Vec3} worldAnchorB
  11938. */
  11939. Spring.prototype.setWorldAnchorB = function(worldAnchorB){
  11940. this.bodyB.pointToLocalFrame(worldAnchorB,this.localAnchorB);
  11941. };
  11942. /**
  11943. * Get the anchor point on body A, in world coordinates.
  11944. * @method getWorldAnchorA
  11945. * @param {Vec3} result The vector to store the result in.
  11946. */
  11947. Spring.prototype.getWorldAnchorA = function(result){
  11948. this.bodyA.pointToWorldFrame(this.localAnchorA,result);
  11949. };
  11950. /**
  11951. * Get the anchor point on body B, in world coordinates.
  11952. * @method getWorldAnchorB
  11953. * @param {Vec3} result The vector to store the result in.
  11954. */
  11955. Spring.prototype.getWorldAnchorB = function(result){
  11956. this.bodyB.pointToWorldFrame(this.localAnchorB,result);
  11957. };
  11958. var applyForce_r = new Vec3(),
  11959. applyForce_r_unit = new Vec3(),
  11960. applyForce_u = new Vec3(),
  11961. applyForce_f = new Vec3(),
  11962. applyForce_worldAnchorA = new Vec3(),
  11963. applyForce_worldAnchorB = new Vec3(),
  11964. applyForce_ri = new Vec3(),
  11965. applyForce_rj = new Vec3(),
  11966. applyForce_ri_x_f = new Vec3(),
  11967. applyForce_rj_x_f = new Vec3(),
  11968. applyForce_tmp = new Vec3();
  11969. /**
  11970. * Apply the spring force to the connected bodies.
  11971. * @method applyForce
  11972. */
  11973. Spring.prototype.applyForce = function(){
  11974. var k = this.stiffness,
  11975. d = this.damping,
  11976. l = this.restLength,
  11977. bodyA = this.bodyA,
  11978. bodyB = this.bodyB,
  11979. r = applyForce_r,
  11980. r_unit = applyForce_r_unit,
  11981. u = applyForce_u,
  11982. f = applyForce_f,
  11983. tmp = applyForce_tmp;
  11984. var worldAnchorA = applyForce_worldAnchorA,
  11985. worldAnchorB = applyForce_worldAnchorB,
  11986. ri = applyForce_ri,
  11987. rj = applyForce_rj,
  11988. ri_x_f = applyForce_ri_x_f,
  11989. rj_x_f = applyForce_rj_x_f;
  11990. // Get world anchors
  11991. this.getWorldAnchorA(worldAnchorA);
  11992. this.getWorldAnchorB(worldAnchorB);
  11993. // Get offset points
  11994. worldAnchorA.vsub(bodyA.position,ri);
  11995. worldAnchorB.vsub(bodyB.position,rj);
  11996. // Compute distance vector between world anchor points
  11997. worldAnchorB.vsub(worldAnchorA,r);
  11998. var rlen = r.norm();
  11999. r_unit.copy(r);
  12000. r_unit.normalize();
  12001. // Compute relative velocity of the anchor points, u
  12002. bodyB.velocity.vsub(bodyA.velocity,u);
  12003. // Add rotational velocity
  12004. bodyB.angularVelocity.cross(rj,tmp);
  12005. u.vadd(tmp,u);
  12006. bodyA.angularVelocity.cross(ri,tmp);
  12007. u.vsub(tmp,u);
  12008. // F = - k * ( x - L ) - D * ( u )
  12009. r_unit.mult(-k*(rlen-l) - d*u.dot(r_unit), f);
  12010. // Add forces to bodies
  12011. bodyA.force.vsub(f,bodyA.force);
  12012. bodyB.force.vadd(f,bodyB.force);
  12013. // Angular force
  12014. ri.cross(f,ri_x_f);
  12015. rj.cross(f,rj_x_f);
  12016. bodyA.torque.vsub(ri_x_f,bodyA.torque);
  12017. bodyB.torque.vadd(rj_x_f,bodyB.torque);
  12018. };
  12019. },{"../math/Vec3":52}],58:[function(require,module,exports){
  12020. var Vec3 = require('../math/Vec3');
  12021. var Transform = require('../math/Transform');
  12022. var RaycastResult = require('../collision/RaycastResult');
  12023. var Utils = require('../utils/Utils');
  12024. module.exports = WheelInfo;
  12025. /**
  12026. * @class WheelInfo
  12027. * @constructor
  12028. * @param {Object} [options]
  12029. *
  12030. * @param {Vec3} [options.chassisConnectionPointLocal]
  12031. * @param {Vec3} [options.chassisConnectionPointWorld]
  12032. * @param {Vec3} [options.directionLocal]
  12033. * @param {Vec3} [options.directionWorld]
  12034. * @param {Vec3} [options.axleLocal]
  12035. * @param {Vec3} [options.axleWorld]
  12036. * @param {number} [options.suspensionRestLength=1]
  12037. * @param {number} [options.suspensionMaxLength=2]
  12038. * @param {number} [options.radius=1]
  12039. * @param {number} [options.suspensionStiffness=100]
  12040. * @param {number} [options.dampingCompression=10]
  12041. * @param {number} [options.dampingRelaxation=10]
  12042. * @param {number} [options.frictionSlip=10000]
  12043. * @param {number} [options.steering=0]
  12044. * @param {number} [options.rotation=0]
  12045. * @param {number} [options.deltaRotation=0]
  12046. * @param {number} [options.rollInfluence=0.01]
  12047. * @param {number} [options.maxSuspensionForce]
  12048. * @param {boolean} [options.isFrontWheel=true]
  12049. * @param {number} [options.clippedInvContactDotSuspension=1]
  12050. * @param {number} [options.suspensionRelativeVelocity=0]
  12051. * @param {number} [options.suspensionForce=0]
  12052. * @param {number} [options.skidInfo=0]
  12053. * @param {number} [options.suspensionLength=0]
  12054. * @param {number} [options.maxSuspensionTravel=1]
  12055. * @param {boolean} [options.useCustomSlidingRotationalSpeed=false]
  12056. * @param {number} [options.customSlidingRotationalSpeed=-0.1]
  12057. */
  12058. function WheelInfo(options){
  12059. options = Utils.defaults(options, {
  12060. chassisConnectionPointLocal: new Vec3(),
  12061. chassisConnectionPointWorld: new Vec3(),
  12062. directionLocal: new Vec3(),
  12063. directionWorld: new Vec3(),
  12064. axleLocal: new Vec3(),
  12065. axleWorld: new Vec3(),
  12066. suspensionRestLength: 1,
  12067. suspensionMaxLength: 2,
  12068. radius: 1,
  12069. suspensionStiffness: 100,
  12070. dampingCompression: 10,
  12071. dampingRelaxation: 10,
  12072. frictionSlip: 10000,
  12073. steering: 0,
  12074. rotation: 0,
  12075. deltaRotation: 0,
  12076. rollInfluence: 0.01,
  12077. maxSuspensionForce: Number.MAX_VALUE,
  12078. isFrontWheel: true,
  12079. clippedInvContactDotSuspension: 1,
  12080. suspensionRelativeVelocity: 0,
  12081. suspensionForce: 0,
  12082. skidInfo: 0,
  12083. suspensionLength: 0,
  12084. maxSuspensionTravel: 1,
  12085. useCustomSlidingRotationalSpeed: false,
  12086. customSlidingRotationalSpeed: -0.1
  12087. });
  12088. /**
  12089. * Max travel distance of the suspension, in meters.
  12090. * @property {number} maxSuspensionTravel
  12091. */
  12092. this.maxSuspensionTravel = options.maxSuspensionTravel;
  12093. /**
  12094. * Speed to apply to the wheel rotation when the wheel is sliding.
  12095. * @property {number} customSlidingRotationalSpeed
  12096. */
  12097. this.customSlidingRotationalSpeed = options.customSlidingRotationalSpeed;
  12098. /**
  12099. * If the customSlidingRotationalSpeed should be used.
  12100. * @property {Boolean} useCustomSlidingRotationalSpeed
  12101. */
  12102. this.useCustomSlidingRotationalSpeed = options.useCustomSlidingRotationalSpeed;
  12103. /**
  12104. * @property {Boolean} sliding
  12105. */
  12106. this.sliding = false;
  12107. /**
  12108. * Connection point, defined locally in the chassis body frame.
  12109. * @property {Vec3} chassisConnectionPointLocal
  12110. */
  12111. this.chassisConnectionPointLocal = options.chassisConnectionPointLocal.clone();
  12112. /**
  12113. * @property {Vec3} chassisConnectionPointWorld
  12114. */
  12115. this.chassisConnectionPointWorld = options.chassisConnectionPointWorld.clone();
  12116. /**
  12117. * @property {Vec3} directionLocal
  12118. */
  12119. this.directionLocal = options.directionLocal.clone();
  12120. /**
  12121. * @property {Vec3} directionWorld
  12122. */
  12123. this.directionWorld = options.directionWorld.clone();
  12124. /**
  12125. * @property {Vec3} axleLocal
  12126. */
  12127. this.axleLocal = options.axleLocal.clone();
  12128. /**
  12129. * @property {Vec3} axleWorld
  12130. */
  12131. this.axleWorld = options.axleWorld.clone();
  12132. /**
  12133. * @property {number} suspensionRestLength
  12134. */
  12135. this.suspensionRestLength = options.suspensionRestLength;
  12136. /**
  12137. * @property {number} suspensionMaxLength
  12138. */
  12139. this.suspensionMaxLength = options.suspensionMaxLength;
  12140. /**
  12141. * @property {number} radius
  12142. */
  12143. this.radius = options.radius;
  12144. /**
  12145. * @property {number} suspensionStiffness
  12146. */
  12147. this.suspensionStiffness = options.suspensionStiffness;
  12148. /**
  12149. * @property {number} dampingCompression
  12150. */
  12151. this.dampingCompression = options.dampingCompression;
  12152. /**
  12153. * @property {number} dampingRelaxation
  12154. */
  12155. this.dampingRelaxation = options.dampingRelaxation;
  12156. /**
  12157. * @property {number} frictionSlip
  12158. */
  12159. this.frictionSlip = options.frictionSlip;
  12160. /**
  12161. * @property {number} steering
  12162. */
  12163. this.steering = 0;
  12164. /**
  12165. * Rotation value, in radians.
  12166. * @property {number} rotation
  12167. */
  12168. this.rotation = 0;
  12169. /**
  12170. * @property {number} deltaRotation
  12171. */
  12172. this.deltaRotation = 0;
  12173. /**
  12174. * @property {number} rollInfluence
  12175. */
  12176. this.rollInfluence = options.rollInfluence;
  12177. /**
  12178. * @property {number} maxSuspensionForce
  12179. */
  12180. this.maxSuspensionForce = options.maxSuspensionForce;
  12181. /**
  12182. * @property {number} engineForce
  12183. */
  12184. this.engineForce = 0;
  12185. /**
  12186. * @property {number} brake
  12187. */
  12188. this.brake = 0;
  12189. /**
  12190. * @property {number} isFrontWheel
  12191. */
  12192. this.isFrontWheel = options.isFrontWheel;
  12193. /**
  12194. * @property {number} clippedInvContactDotSuspension
  12195. */
  12196. this.clippedInvContactDotSuspension = 1;
  12197. /**
  12198. * @property {number} suspensionRelativeVelocity
  12199. */
  12200. this.suspensionRelativeVelocity = 0;
  12201. /**
  12202. * @property {number} suspensionForce
  12203. */
  12204. this.suspensionForce = 0;
  12205. /**
  12206. * @property {number} skidInfo
  12207. */
  12208. this.skidInfo = 0;
  12209. /**
  12210. * @property {number} suspensionLength
  12211. */
  12212. this.suspensionLength = 0;
  12213. /**
  12214. * @property {number} sideImpulse
  12215. */
  12216. this.sideImpulse = 0;
  12217. /**
  12218. * @property {number} forwardImpulse
  12219. */
  12220. this.forwardImpulse = 0;
  12221. /**
  12222. * The result from raycasting
  12223. * @property {RaycastResult} raycastResult
  12224. */
  12225. this.raycastResult = new RaycastResult();
  12226. /**
  12227. * Wheel world transform
  12228. * @property {Transform} worldTransform
  12229. */
  12230. this.worldTransform = new Transform();
  12231. /**
  12232. * @property {boolean} isInContact
  12233. */
  12234. this.isInContact = false;
  12235. }
  12236. var chassis_velocity_at_contactPoint = new Vec3();
  12237. var relpos = new Vec3();
  12238. var chassis_velocity_at_contactPoint = new Vec3();
  12239. WheelInfo.prototype.updateWheel = function(chassis){
  12240. var raycastResult = this.raycastResult;
  12241. if (this.isInContact){
  12242. var project= raycastResult.hitNormalWorld.dot(raycastResult.directionWorld);
  12243. raycastResult.hitPointWorld.vsub(chassis.position, relpos);
  12244. chassis.getVelocityAtWorldPoint(relpos, chassis_velocity_at_contactPoint);
  12245. var projVel = raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  12246. if (project >= -0.1) {
  12247. this.suspensionRelativeVelocity = 0.0;
  12248. this.clippedInvContactDotSuspension = 1.0 / 0.1;
  12249. } else {
  12250. var inv = -1 / project;
  12251. this.suspensionRelativeVelocity = projVel * inv;
  12252. this.clippedInvContactDotSuspension = inv;
  12253. }
  12254. } else {
  12255. // Not in contact : position wheel in a nice (rest length) position
  12256. raycastResult.suspensionLength = this.suspensionRestLength;
  12257. this.suspensionRelativeVelocity = 0.0;
  12258. raycastResult.directionWorld.scale(-1, raycastResult.hitNormalWorld);
  12259. this.clippedInvContactDotSuspension = 1.0;
  12260. }
  12261. };
  12262. },{"../collision/RaycastResult":32,"../math/Transform":51,"../math/Vec3":52,"../utils/Utils":75}],59:[function(require,module,exports){
  12263. module.exports = Box;
  12264. var Shape = require('./Shape');
  12265. var Vec3 = require('../math/Vec3');
  12266. var ConvexPolyhedron = require('./ConvexPolyhedron');
  12267. /**
  12268. * A 3d box shape.
  12269. * @class Box
  12270. * @constructor
  12271. * @param {Vec3} halfExtents
  12272. * @author schteppe
  12273. * @extends Shape
  12274. */
  12275. function Box(halfExtents){
  12276. Shape.call(this);
  12277. this.type = Shape.types.BOX;
  12278. /**
  12279. * @property halfExtents
  12280. * @type {Vec3}
  12281. */
  12282. this.halfExtents = halfExtents;
  12283. /**
  12284. * Used by the contact generator to make contacts with other convex polyhedra for example
  12285. * @property convexPolyhedronRepresentation
  12286. * @type {ConvexPolyhedron}
  12287. */
  12288. this.convexPolyhedronRepresentation = null;
  12289. this.updateConvexPolyhedronRepresentation();
  12290. this.updateBoundingSphereRadius();
  12291. }
  12292. Box.prototype = new Shape();
  12293. Box.prototype.constructor = Box;
  12294. /**
  12295. * Updates the local convex polyhedron representation used for some collisions.
  12296. * @method updateConvexPolyhedronRepresentation
  12297. */
  12298. Box.prototype.updateConvexPolyhedronRepresentation = function(){
  12299. var sx = this.halfExtents.x;
  12300. var sy = this.halfExtents.y;
  12301. var sz = this.halfExtents.z;
  12302. var V = Vec3;
  12303. var vertices = [
  12304. new V(-sx,-sy,-sz),
  12305. new V( sx,-sy,-sz),
  12306. new V( sx, sy,-sz),
  12307. new V(-sx, sy,-sz),
  12308. new V(-sx,-sy, sz),
  12309. new V( sx,-sy, sz),
  12310. new V( sx, sy, sz),
  12311. new V(-sx, sy, sz)
  12312. ];
  12313. var indices = [
  12314. [3,2,1,0], // -z
  12315. [4,5,6,7], // +z
  12316. [5,4,0,1], // -y
  12317. [2,3,7,6], // +y
  12318. [0,4,7,3], // -x
  12319. [1,2,6,5], // +x
  12320. ];
  12321. var axes = [
  12322. new V(0, 0, 1),
  12323. new V(0, 1, 0),
  12324. new V(1, 0, 0)
  12325. ];
  12326. var h = new ConvexPolyhedron(vertices, indices);
  12327. this.convexPolyhedronRepresentation = h;
  12328. h.material = this.material;
  12329. };
  12330. /**
  12331. * @method calculateLocalInertia
  12332. * @param {Number} mass
  12333. * @param {Vec3} target
  12334. * @return {Vec3}
  12335. */
  12336. Box.prototype.calculateLocalInertia = function(mass,target){
  12337. target = target || new Vec3();
  12338. Box.calculateInertia(this.halfExtents, mass, target);
  12339. return target;
  12340. };
  12341. Box.calculateInertia = function(halfExtents,mass,target){
  12342. var e = halfExtents;
  12343. target.x = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.z*2*e.z );
  12344. target.y = 1.0 / 12.0 * mass * ( 2*e.x*2*e.x + 2*e.z*2*e.z );
  12345. target.z = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.x*2*e.x );
  12346. };
  12347. /**
  12348. * Get the box 6 side normals
  12349. * @method getSideNormals
  12350. * @param {array} sixTargetVectors An array of 6 vectors, to store the resulting side normals in.
  12351. * @param {Quaternion} quat Orientation to apply to the normal vectors. If not provided, the vectors will be in respect to the local frame.
  12352. * @return {array}
  12353. */
  12354. Box.prototype.getSideNormals = function(sixTargetVectors,quat){
  12355. var sides = sixTargetVectors;
  12356. var ex = this.halfExtents;
  12357. sides[0].set( ex.x, 0, 0);
  12358. sides[1].set( 0, ex.y, 0);
  12359. sides[2].set( 0, 0, ex.z);
  12360. sides[3].set( -ex.x, 0, 0);
  12361. sides[4].set( 0, -ex.y, 0);
  12362. sides[5].set( 0, 0, -ex.z);
  12363. if(quat!==undefined){
  12364. for(var i=0; i!==sides.length; i++){
  12365. quat.vmult(sides[i],sides[i]);
  12366. }
  12367. }
  12368. return sides;
  12369. };
  12370. Box.prototype.volume = function(){
  12371. return 8.0 * this.halfExtents.x * this.halfExtents.y * this.halfExtents.z;
  12372. };
  12373. Box.prototype.updateBoundingSphereRadius = function(){
  12374. this.boundingSphereRadius = this.halfExtents.norm();
  12375. };
  12376. var worldCornerTempPos = new Vec3();
  12377. var worldCornerTempNeg = new Vec3();
  12378. Box.prototype.forEachWorldCorner = function(pos,quat,callback){
  12379. var e = this.halfExtents;
  12380. var corners = [[ e.x, e.y, e.z],
  12381. [ -e.x, e.y, e.z],
  12382. [ -e.x, -e.y, e.z],
  12383. [ -e.x, -e.y, -e.z],
  12384. [ e.x, -e.y, -e.z],
  12385. [ e.x, e.y, -e.z],
  12386. [ -e.x, e.y, -e.z],
  12387. [ e.x, -e.y, e.z]];
  12388. for(var i=0; i<corners.length; i++){
  12389. worldCornerTempPos.set(corners[i][0],corners[i][1],corners[i][2]);
  12390. quat.vmult(worldCornerTempPos,worldCornerTempPos);
  12391. pos.vadd(worldCornerTempPos,worldCornerTempPos);
  12392. callback(worldCornerTempPos.x,
  12393. worldCornerTempPos.y,
  12394. worldCornerTempPos.z);
  12395. }
  12396. };
  12397. var worldCornersTemp = [
  12398. new Vec3(),
  12399. new Vec3(),
  12400. new Vec3(),
  12401. new Vec3(),
  12402. new Vec3(),
  12403. new Vec3(),
  12404. new Vec3(),
  12405. new Vec3()
  12406. ];
  12407. Box.prototype.calculateWorldAABB = function(pos,quat,min,max){
  12408. var e = this.halfExtents;
  12409. worldCornersTemp[0].set(e.x, e.y, e.z);
  12410. worldCornersTemp[1].set(-e.x, e.y, e.z);
  12411. worldCornersTemp[2].set(-e.x, -e.y, e.z);
  12412. worldCornersTemp[3].set(-e.x, -e.y, -e.z);
  12413. worldCornersTemp[4].set(e.x, -e.y, -e.z);
  12414. worldCornersTemp[5].set(e.x, e.y, -e.z);
  12415. worldCornersTemp[6].set(-e.x, e.y, -e.z);
  12416. worldCornersTemp[7].set(e.x, -e.y, e.z);
  12417. var wc = worldCornersTemp[0];
  12418. quat.vmult(wc, wc);
  12419. pos.vadd(wc, wc);
  12420. max.copy(wc);
  12421. min.copy(wc);
  12422. for(var i=1; i<8; i++){
  12423. var wc = worldCornersTemp[i];
  12424. quat.vmult(wc, wc);
  12425. pos.vadd(wc, wc);
  12426. var x = wc.x;
  12427. var y = wc.y;
  12428. var z = wc.z;
  12429. if(x > max.x){
  12430. max.x = x;
  12431. }
  12432. if(y > max.y){
  12433. max.y = y;
  12434. }
  12435. if(z > max.z){
  12436. max.z = z;
  12437. }
  12438. if(x < min.x){
  12439. min.x = x;
  12440. }
  12441. if(y < min.y){
  12442. min.y = y;
  12443. }
  12444. if(z < min.z){
  12445. min.z = z;
  12446. }
  12447. }
  12448. // Get each axis max
  12449. // min.set(Infinity,Infinity,Infinity);
  12450. // max.set(-Infinity,-Infinity,-Infinity);
  12451. // this.forEachWorldCorner(pos,quat,function(x,y,z){
  12452. // if(x > max.x){
  12453. // max.x = x;
  12454. // }
  12455. // if(y > max.y){
  12456. // max.y = y;
  12457. // }
  12458. // if(z > max.z){
  12459. // max.z = z;
  12460. // }
  12461. // if(x < min.x){
  12462. // min.x = x;
  12463. // }
  12464. // if(y < min.y){
  12465. // min.y = y;
  12466. // }
  12467. // if(z < min.z){
  12468. // min.z = z;
  12469. // }
  12470. // });
  12471. };
  12472. },{"../math/Vec3":52,"./ConvexPolyhedron":60,"./Shape":65}],60:[function(require,module,exports){
  12473. module.exports = ConvexPolyhedron;
  12474. var Shape = require('./Shape');
  12475. var Vec3 = require('../math/Vec3');
  12476. var Quaternion = require('../math/Quaternion');
  12477. var Transform = require('../math/Transform');
  12478. /**
  12479. * A set of polygons describing a convex shape.
  12480. * @class ConvexPolyhedron
  12481. * @constructor
  12482. * @extends Shape
  12483. * @description The shape MUST be convex for the code to work properly. No polygons may be coplanar (contained
  12484. * in the same 3D plane), instead these should be merged into one polygon.
  12485. *
  12486. * @param {array} points An array of Vec3's
  12487. * @param {array} faces Array of integer arrays, describing which vertices that is included in each face.
  12488. *
  12489. * @author qiao / https://github.com/qiao (original author, see https://github.com/qiao/three.js/commit/85026f0c769e4000148a67d45a9e9b9c5108836f)
  12490. * @author schteppe / https://github.com/schteppe
  12491. * @see http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/
  12492. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  12493. *
  12494. * @todo Move the clipping functions to ContactGenerator?
  12495. * @todo Automatically merge coplanar polygons in constructor.
  12496. */
  12497. function ConvexPolyhedron(points, faces, uniqueAxes) {
  12498. var that = this;
  12499. Shape.call(this);
  12500. this.type = Shape.types.CONVEXPOLYHEDRON;
  12501. /**
  12502. * Array of Vec3
  12503. * @property vertices
  12504. * @type {Array}
  12505. */
  12506. this.vertices = points||[];
  12507. this.worldVertices = []; // World transformed version of .vertices
  12508. this.worldVerticesNeedsUpdate = true;
  12509. /**
  12510. * Array of integer arrays, indicating which vertices each face consists of
  12511. * @property faces
  12512. * @type {Array}
  12513. */
  12514. this.faces = faces||[];
  12515. /**
  12516. * Array of Vec3
  12517. * @property faceNormals
  12518. * @type {Array}
  12519. */
  12520. this.faceNormals = [];
  12521. this.computeNormals();
  12522. this.worldFaceNormalsNeedsUpdate = true;
  12523. this.worldFaceNormals = []; // World transformed version of .faceNormals
  12524. /**
  12525. * Array of Vec3
  12526. * @property uniqueEdges
  12527. * @type {Array}
  12528. */
  12529. this.uniqueEdges = [];
  12530. /**
  12531. * If given, these locally defined, normalized axes are the only ones being checked when doing separating axis check.
  12532. * @property {Array} uniqueAxes
  12533. */
  12534. this.uniqueAxes = uniqueAxes ? uniqueAxes.slice() : null;
  12535. this.computeEdges();
  12536. this.updateBoundingSphereRadius();
  12537. }
  12538. ConvexPolyhedron.prototype = new Shape();
  12539. ConvexPolyhedron.prototype.constructor = ConvexPolyhedron;
  12540. var computeEdges_tmpEdge = new Vec3();
  12541. /**
  12542. * Computes uniqueEdges
  12543. * @method computeEdges
  12544. */
  12545. ConvexPolyhedron.prototype.computeEdges = function(){
  12546. var faces = this.faces;
  12547. var vertices = this.vertices;
  12548. var nv = vertices.length;
  12549. var edges = this.uniqueEdges;
  12550. edges.length = 0;
  12551. var edge = computeEdges_tmpEdge;
  12552. for(var i=0; i !== faces.length; i++){
  12553. var face = faces[i];
  12554. var numVertices = face.length;
  12555. for(var j = 0; j !== numVertices; j++){
  12556. var k = ( j+1 ) % numVertices;
  12557. vertices[face[j]].vsub(vertices[face[k]], edge);
  12558. edge.normalize();
  12559. var found = false;
  12560. for(var p=0; p !== edges.length; p++){
  12561. if (edges[p].almostEquals(edge) || edges[p].almostEquals(edge)){
  12562. found = true;
  12563. break;
  12564. }
  12565. }
  12566. if (!found){
  12567. edges.push(edge.clone());
  12568. }
  12569. }
  12570. }
  12571. };
  12572. /**
  12573. * Compute the normals of the faces. Will reuse existing Vec3 objects in the .faceNormals array if they exist.
  12574. * @method computeNormals
  12575. */
  12576. ConvexPolyhedron.prototype.computeNormals = function(){
  12577. this.faceNormals.length = this.faces.length;
  12578. // Generate normals
  12579. for(var i=0; i<this.faces.length; i++){
  12580. // Check so all vertices exists for this face
  12581. for(var j=0; j<this.faces[i].length; j++){
  12582. if(!this.vertices[this.faces[i][j]]){
  12583. throw new Error("Vertex "+this.faces[i][j]+" not found!");
  12584. }
  12585. }
  12586. var n = this.faceNormals[i] || new Vec3();
  12587. this.getFaceNormal(i,n);
  12588. n.negate(n);
  12589. this.faceNormals[i] = n;
  12590. var vertex = this.vertices[this.faces[i][0]];
  12591. if(n.dot(vertex) < 0){
  12592. console.error(".faceNormals[" + i + "] = Vec3("+n.toString()+") looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.");
  12593. for(var j=0; j<this.faces[i].length; j++){
  12594. console.warn(".vertices["+this.faces[i][j]+"] = Vec3("+this.vertices[this.faces[i][j]].toString()+")");
  12595. }
  12596. }
  12597. }
  12598. };
  12599. /**
  12600. * Get face normal given 3 vertices
  12601. * @static
  12602. * @method getFaceNormal
  12603. * @param {Vec3} va
  12604. * @param {Vec3} vb
  12605. * @param {Vec3} vc
  12606. * @param {Vec3} target
  12607. */
  12608. var cb = new Vec3();
  12609. var ab = new Vec3();
  12610. ConvexPolyhedron.computeNormal = function ( va, vb, vc, target ) {
  12611. vb.vsub(va,ab);
  12612. vc.vsub(vb,cb);
  12613. cb.cross(ab,target);
  12614. if ( !target.isZero() ) {
  12615. target.normalize();
  12616. }
  12617. };
  12618. /**
  12619. * Compute the normal of a face from its vertices
  12620. * @method getFaceNormal
  12621. * @param {Number} i
  12622. * @param {Vec3} target
  12623. */
  12624. ConvexPolyhedron.prototype.getFaceNormal = function(i,target){
  12625. var f = this.faces[i];
  12626. var va = this.vertices[f[0]];
  12627. var vb = this.vertices[f[1]];
  12628. var vc = this.vertices[f[2]];
  12629. return ConvexPolyhedron.computeNormal(va,vb,vc,target);
  12630. };
  12631. /**
  12632. * @method clipAgainstHull
  12633. * @param {Vec3} posA
  12634. * @param {Quaternion} quatA
  12635. * @param {ConvexPolyhedron} hullB
  12636. * @param {Vec3} posB
  12637. * @param {Quaternion} quatB
  12638. * @param {Vec3} separatingNormal
  12639. * @param {Number} minDist Clamp distance
  12640. * @param {Number} maxDist
  12641. * @param {array} result The an array of contact point objects, see clipFaceAgainstHull
  12642. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  12643. */
  12644. var cah_WorldNormal = new Vec3();
  12645. ConvexPolyhedron.prototype.clipAgainstHull = function(posA,quatA,hullB,posB,quatB,separatingNormal,minDist,maxDist,result){
  12646. var WorldNormal = cah_WorldNormal;
  12647. var hullA = this;
  12648. var curMaxDist = maxDist;
  12649. var closestFaceB = -1;
  12650. var dmax = -Number.MAX_VALUE;
  12651. for(var face=0; face < hullB.faces.length; face++){
  12652. WorldNormal.copy(hullB.faceNormals[face]);
  12653. quatB.vmult(WorldNormal,WorldNormal);
  12654. //posB.vadd(WorldNormal,WorldNormal);
  12655. var d = WorldNormal.dot(separatingNormal);
  12656. if (d > dmax){
  12657. dmax = d;
  12658. closestFaceB = face;
  12659. }
  12660. }
  12661. var worldVertsB1 = [];
  12662. var polyB = hullB.faces[closestFaceB];
  12663. var numVertices = polyB.length;
  12664. for(var e0=0; e0<numVertices; e0++){
  12665. var b = hullB.vertices[polyB[e0]];
  12666. var worldb = new Vec3();
  12667. worldb.copy(b);
  12668. quatB.vmult(worldb,worldb);
  12669. posB.vadd(worldb,worldb);
  12670. worldVertsB1.push(worldb);
  12671. }
  12672. if (closestFaceB>=0){
  12673. this.clipFaceAgainstHull(separatingNormal,
  12674. posA,
  12675. quatA,
  12676. worldVertsB1,
  12677. minDist,
  12678. maxDist,
  12679. result);
  12680. }
  12681. };
  12682. /**
  12683. * Find the separating axis between this hull and another
  12684. * @method findSeparatingAxis
  12685. * @param {ConvexPolyhedron} hullB
  12686. * @param {Vec3} posA
  12687. * @param {Quaternion} quatA
  12688. * @param {Vec3} posB
  12689. * @param {Quaternion} quatB
  12690. * @param {Vec3} target The target vector to save the axis in
  12691. * @return {bool} Returns false if a separation is found, else true
  12692. */
  12693. var fsa_faceANormalWS3 = new Vec3(),
  12694. fsa_Worldnormal1 = new Vec3(),
  12695. fsa_deltaC = new Vec3(),
  12696. fsa_worldEdge0 = new Vec3(),
  12697. fsa_worldEdge1 = new Vec3(),
  12698. fsa_Cross = new Vec3();
  12699. ConvexPolyhedron.prototype.findSeparatingAxis = function(hullB,posA,quatA,posB,quatB,target, faceListA, faceListB){
  12700. var faceANormalWS3 = fsa_faceANormalWS3,
  12701. Worldnormal1 = fsa_Worldnormal1,
  12702. deltaC = fsa_deltaC,
  12703. worldEdge0 = fsa_worldEdge0,
  12704. worldEdge1 = fsa_worldEdge1,
  12705. Cross = fsa_Cross;
  12706. var dmin = Number.MAX_VALUE;
  12707. var hullA = this;
  12708. var curPlaneTests=0;
  12709. if(!hullA.uniqueAxes){
  12710. var numFacesA = faceListA ? faceListA.length : hullA.faces.length;
  12711. // Test face normals from hullA
  12712. for(var i=0; i<numFacesA; i++){
  12713. var fi = faceListA ? faceListA[i] : i;
  12714. // Get world face normal
  12715. faceANormalWS3.copy(hullA.faceNormals[fi]);
  12716. quatA.vmult(faceANormalWS3,faceANormalWS3);
  12717. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  12718. if(d===false){
  12719. return false;
  12720. }
  12721. if(d<dmin){
  12722. dmin = d;
  12723. target.copy(faceANormalWS3);
  12724. }
  12725. }
  12726. } else {
  12727. // Test unique axes
  12728. for(var i = 0; i !== hullA.uniqueAxes.length; i++){
  12729. // Get world axis
  12730. quatA.vmult(hullA.uniqueAxes[i],faceANormalWS3);
  12731. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  12732. if(d===false){
  12733. return false;
  12734. }
  12735. if(d<dmin){
  12736. dmin = d;
  12737. target.copy(faceANormalWS3);
  12738. }
  12739. }
  12740. }
  12741. if(!hullB.uniqueAxes){
  12742. // Test face normals from hullB
  12743. var numFacesB = faceListB ? faceListB.length : hullB.faces.length;
  12744. for(var i=0;i<numFacesB;i++){
  12745. var fi = faceListB ? faceListB[i] : i;
  12746. Worldnormal1.copy(hullB.faceNormals[fi]);
  12747. quatB.vmult(Worldnormal1,Worldnormal1);
  12748. curPlaneTests++;
  12749. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  12750. if(d===false){
  12751. return false;
  12752. }
  12753. if(d<dmin){
  12754. dmin = d;
  12755. target.copy(Worldnormal1);
  12756. }
  12757. }
  12758. } else {
  12759. // Test unique axes in B
  12760. for(var i = 0; i !== hullB.uniqueAxes.length; i++){
  12761. quatB.vmult(hullB.uniqueAxes[i],Worldnormal1);
  12762. curPlaneTests++;
  12763. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  12764. if(d===false){
  12765. return false;
  12766. }
  12767. if(d<dmin){
  12768. dmin = d;
  12769. target.copy(Worldnormal1);
  12770. }
  12771. }
  12772. }
  12773. // Test edges
  12774. for(var e0=0; e0 !== hullA.uniqueEdges.length; e0++){
  12775. // Get world edge
  12776. quatA.vmult(hullA.uniqueEdges[e0],worldEdge0);
  12777. for(var e1=0; e1 !== hullB.uniqueEdges.length; e1++){
  12778. // Get world edge 2
  12779. quatB.vmult(hullB.uniqueEdges[e1], worldEdge1);
  12780. worldEdge0.cross(worldEdge1,Cross);
  12781. if(!Cross.almostZero()){
  12782. Cross.normalize();
  12783. var dist = hullA.testSepAxis(Cross, hullB, posA, quatA, posB, quatB);
  12784. if(dist === false){
  12785. return false;
  12786. }
  12787. if(dist < dmin){
  12788. dmin = dist;
  12789. target.copy(Cross);
  12790. }
  12791. }
  12792. }
  12793. }
  12794. posB.vsub(posA,deltaC);
  12795. if((deltaC.dot(target))>0.0){
  12796. target.negate(target);
  12797. }
  12798. return true;
  12799. };
  12800. var maxminA=[], maxminB=[];
  12801. /**
  12802. * Test separating axis against two hulls. Both hulls are projected onto the axis and the overlap size is returned if there is one.
  12803. * @method testSepAxis
  12804. * @param {Vec3} axis
  12805. * @param {ConvexPolyhedron} hullB
  12806. * @param {Vec3} posA
  12807. * @param {Quaternion} quatA
  12808. * @param {Vec3} posB
  12809. * @param {Quaternion} quatB
  12810. * @return {number} The overlap depth, or FALSE if no penetration.
  12811. */
  12812. ConvexPolyhedron.prototype.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
  12813. var hullA=this;
  12814. ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
  12815. ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
  12816. var maxA = maxminA[0];
  12817. var minA = maxminA[1];
  12818. var maxB = maxminB[0];
  12819. var minB = maxminB[1];
  12820. if(maxA<minB || maxB<minA){
  12821. return false; // Separated
  12822. }
  12823. var d0 = maxA - minB;
  12824. var d1 = maxB - minA;
  12825. var depth = d0<d1 ? d0:d1;
  12826. return depth;
  12827. };
  12828. var cli_aabbmin = new Vec3(),
  12829. cli_aabbmax = new Vec3();
  12830. /**
  12831. * @method calculateLocalInertia
  12832. * @param {Number} mass
  12833. * @param {Vec3} target
  12834. */
  12835. ConvexPolyhedron.prototype.calculateLocalInertia = function(mass,target){
  12836. // Approximate with box inertia
  12837. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  12838. this.computeLocalAABB(cli_aabbmin,cli_aabbmax);
  12839. var x = cli_aabbmax.x - cli_aabbmin.x,
  12840. y = cli_aabbmax.y - cli_aabbmin.y,
  12841. z = cli_aabbmax.z - cli_aabbmin.z;
  12842. target.x = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z );
  12843. target.y = 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z );
  12844. target.z = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x );
  12845. };
  12846. /**
  12847. * @method getPlaneConstantOfFace
  12848. * @param {Number} face_i Index of the face
  12849. * @return {Number}
  12850. */
  12851. ConvexPolyhedron.prototype.getPlaneConstantOfFace = function(face_i){
  12852. var f = this.faces[face_i];
  12853. var n = this.faceNormals[face_i];
  12854. var v = this.vertices[f[0]];
  12855. var c = -n.dot(v);
  12856. return c;
  12857. };
  12858. /**
  12859. * Clip a face against a hull.
  12860. * @method clipFaceAgainstHull
  12861. * @param {Vec3} separatingNormal
  12862. * @param {Vec3} posA
  12863. * @param {Quaternion} quatA
  12864. * @param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
  12865. * @param {Number} minDist Distance clamping
  12866. * @param {Number} maxDist
  12867. * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
  12868. */
  12869. var cfah_faceANormalWS = new Vec3(),
  12870. cfah_edge0 = new Vec3(),
  12871. cfah_WorldEdge0 = new Vec3(),
  12872. cfah_worldPlaneAnormal1 = new Vec3(),
  12873. cfah_planeNormalWS1 = new Vec3(),
  12874. cfah_worldA1 = new Vec3(),
  12875. cfah_localPlaneNormal = new Vec3(),
  12876. cfah_planeNormalWS = new Vec3();
  12877. ConvexPolyhedron.prototype.clipFaceAgainstHull = function(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist,result){
  12878. var faceANormalWS = cfah_faceANormalWS,
  12879. edge0 = cfah_edge0,
  12880. WorldEdge0 = cfah_WorldEdge0,
  12881. worldPlaneAnormal1 = cfah_worldPlaneAnormal1,
  12882. planeNormalWS1 = cfah_planeNormalWS1,
  12883. worldA1 = cfah_worldA1,
  12884. localPlaneNormal = cfah_localPlaneNormal,
  12885. planeNormalWS = cfah_planeNormalWS;
  12886. var hullA = this;
  12887. var worldVertsB2 = [];
  12888. var pVtxIn = worldVertsB1;
  12889. var pVtxOut = worldVertsB2;
  12890. // Find the face with normal closest to the separating axis
  12891. var closestFaceA = -1;
  12892. var dmin = Number.MAX_VALUE;
  12893. for(var face=0; face<hullA.faces.length; face++){
  12894. faceANormalWS.copy(hullA.faceNormals[face]);
  12895. quatA.vmult(faceANormalWS,faceANormalWS);
  12896. //posA.vadd(faceANormalWS,faceANormalWS);
  12897. var d = faceANormalWS.dot(separatingNormal);
  12898. if (d < dmin){
  12899. dmin = d;
  12900. closestFaceA = face;
  12901. }
  12902. }
  12903. if (closestFaceA < 0){
  12904. // console.log("--- did not find any closest face... ---");
  12905. return;
  12906. }
  12907. //console.log("closest A: ",closestFaceA);
  12908. // Get the face and construct connected faces
  12909. var polyA = hullA.faces[closestFaceA];
  12910. polyA.connectedFaces = [];
  12911. for(var i=0; i<hullA.faces.length; i++){
  12912. for(var j=0; j<hullA.faces[i].length; j++){
  12913. if(polyA.indexOf(hullA.faces[i][j])!==-1 /* Sharing a vertex*/ && i!==closestFaceA /* Not the one we are looking for connections from */ && polyA.connectedFaces.indexOf(i)===-1 /* Not already added */ ){
  12914. polyA.connectedFaces.push(i);
  12915. }
  12916. }
  12917. }
  12918. // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
  12919. var numContacts = pVtxIn.length;
  12920. var numVerticesA = polyA.length;
  12921. var res = [];
  12922. for(var e0=0; e0<numVerticesA; e0++){
  12923. var a = hullA.vertices[polyA[e0]];
  12924. var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
  12925. a.vsub(b,edge0);
  12926. WorldEdge0.copy(edge0);
  12927. quatA.vmult(WorldEdge0,WorldEdge0);
  12928. posA.vadd(WorldEdge0,WorldEdge0);
  12929. worldPlaneAnormal1.copy(this.faceNormals[closestFaceA]);//transA.getBasis()* btVector3(polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]);
  12930. quatA.vmult(worldPlaneAnormal1,worldPlaneAnormal1);
  12931. posA.vadd(worldPlaneAnormal1,worldPlaneAnormal1);
  12932. WorldEdge0.cross(worldPlaneAnormal1,planeNormalWS1);
  12933. planeNormalWS1.negate(planeNormalWS1);
  12934. worldA1.copy(a);
  12935. quatA.vmult(worldA1,worldA1);
  12936. posA.vadd(worldA1,worldA1);
  12937. var planeEqWS1 = -worldA1.dot(planeNormalWS1);
  12938. var planeEqWS;
  12939. if(true){
  12940. var otherFace = polyA.connectedFaces[e0];
  12941. localPlaneNormal.copy(this.faceNormals[otherFace]);
  12942. var localPlaneEq = this.getPlaneConstantOfFace(otherFace);
  12943. planeNormalWS.copy(localPlaneNormal);
  12944. quatA.vmult(planeNormalWS,planeNormalWS);
  12945. //posA.vadd(planeNormalWS,planeNormalWS);
  12946. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  12947. } else {
  12948. planeNormalWS.copy(planeNormalWS1);
  12949. planeEqWS = planeEqWS1;
  12950. }
  12951. // Clip face against our constructed plane
  12952. this.clipFaceAgainstPlane(pVtxIn, pVtxOut, planeNormalWS, planeEqWS);
  12953. // Throw away all clipped points, but save the reamining until next clip
  12954. while(pVtxIn.length){
  12955. pVtxIn.shift();
  12956. }
  12957. while(pVtxOut.length){
  12958. pVtxIn.push(pVtxOut.shift());
  12959. }
  12960. }
  12961. //console.log("Resulting points after clip:",pVtxIn);
  12962. // only keep contact points that are behind the witness face
  12963. localPlaneNormal.copy(this.faceNormals[closestFaceA]);
  12964. var localPlaneEq = this.getPlaneConstantOfFace(closestFaceA);
  12965. planeNormalWS.copy(localPlaneNormal);
  12966. quatA.vmult(planeNormalWS,planeNormalWS);
  12967. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  12968. for (var i=0; i<pVtxIn.length; i++){
  12969. var depth = planeNormalWS.dot(pVtxIn[i]) + planeEqWS; //???
  12970. /*console.log("depth calc from normal=",planeNormalWS.toString()," and constant "+planeEqWS+" and vertex ",pVtxIn[i].toString()," gives "+depth);*/
  12971. if (depth <=minDist){
  12972. console.log("clamped: depth="+depth+" to minDist="+(minDist+""));
  12973. depth = minDist;
  12974. }
  12975. if (depth <=maxDist){
  12976. var point = pVtxIn[i];
  12977. if(depth<=0){
  12978. /*console.log("Got contact point ",point.toString(),
  12979. ", depth=",depth,
  12980. "contact normal=",separatingNormal.toString(),
  12981. "plane",planeNormalWS.toString(),
  12982. "planeConstant",planeEqWS);*/
  12983. var p = {
  12984. point:point,
  12985. normal:planeNormalWS,
  12986. depth: depth,
  12987. };
  12988. result.push(p);
  12989. }
  12990. }
  12991. }
  12992. };
  12993. /**
  12994. * Clip a face in a hull against the back of a plane.
  12995. * @method clipFaceAgainstPlane
  12996. * @param {Array} inVertices
  12997. * @param {Array} outVertices
  12998. * @param {Vec3} planeNormal
  12999. * @param {Number} planeConstant The constant in the mathematical plane equation
  13000. */
  13001. ConvexPolyhedron.prototype.clipFaceAgainstPlane = function(inVertices,outVertices, planeNormal, planeConstant){
  13002. var n_dot_first, n_dot_last;
  13003. var numVerts = inVertices.length;
  13004. if(numVerts < 2){
  13005. return outVertices;
  13006. }
  13007. var firstVertex = inVertices[inVertices.length-1],
  13008. lastVertex = inVertices[0];
  13009. n_dot_first = planeNormal.dot(firstVertex) + planeConstant;
  13010. for(var vi = 0; vi < numVerts; vi++){
  13011. lastVertex = inVertices[vi];
  13012. n_dot_last = planeNormal.dot(lastVertex) + planeConstant;
  13013. if(n_dot_first < 0){
  13014. if(n_dot_last < 0){
  13015. // Start < 0, end < 0, so output lastVertex
  13016. var newv = new Vec3();
  13017. newv.copy(lastVertex);
  13018. outVertices.push(newv);
  13019. } else {
  13020. // Start < 0, end >= 0, so output intersection
  13021. var newv = new Vec3();
  13022. firstVertex.lerp(lastVertex,
  13023. n_dot_first / (n_dot_first - n_dot_last),
  13024. newv);
  13025. outVertices.push(newv);
  13026. }
  13027. } else {
  13028. if(n_dot_last<0){
  13029. // Start >= 0, end < 0 so output intersection and end
  13030. var newv = new Vec3();
  13031. firstVertex.lerp(lastVertex,
  13032. n_dot_first / (n_dot_first - n_dot_last),
  13033. newv);
  13034. outVertices.push(newv);
  13035. outVertices.push(lastVertex);
  13036. }
  13037. }
  13038. firstVertex = lastVertex;
  13039. n_dot_first = n_dot_last;
  13040. }
  13041. return outVertices;
  13042. };
  13043. // Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  13044. ConvexPolyhedron.prototype.computeWorldVertices = function(position,quat){
  13045. var N = this.vertices.length;
  13046. while(this.worldVertices.length < N){
  13047. this.worldVertices.push( new Vec3() );
  13048. }
  13049. var verts = this.vertices,
  13050. worldVerts = this.worldVertices;
  13051. for(var i=0; i!==N; i++){
  13052. quat.vmult( verts[i] , worldVerts[i] );
  13053. position.vadd( worldVerts[i] , worldVerts[i] );
  13054. }
  13055. this.worldVerticesNeedsUpdate = false;
  13056. };
  13057. var computeLocalAABB_worldVert = new Vec3();
  13058. ConvexPolyhedron.prototype.computeLocalAABB = function(aabbmin,aabbmax){
  13059. var n = this.vertices.length,
  13060. vertices = this.vertices,
  13061. worldVert = computeLocalAABB_worldVert;
  13062. aabbmin.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  13063. aabbmax.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  13064. for(var i=0; i<n; i++){
  13065. var v = vertices[i];
  13066. if (v.x < aabbmin.x){
  13067. aabbmin.x = v.x;
  13068. } else if(v.x > aabbmax.x){
  13069. aabbmax.x = v.x;
  13070. }
  13071. if (v.y < aabbmin.y){
  13072. aabbmin.y = v.y;
  13073. } else if(v.y > aabbmax.y){
  13074. aabbmax.y = v.y;
  13075. }
  13076. if (v.z < aabbmin.z){
  13077. aabbmin.z = v.z;
  13078. } else if(v.z > aabbmax.z){
  13079. aabbmax.z = v.z;
  13080. }
  13081. }
  13082. };
  13083. /**
  13084. * Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  13085. * @method computeWorldFaceNormals
  13086. * @param {Quaternion} quat
  13087. */
  13088. ConvexPolyhedron.prototype.computeWorldFaceNormals = function(quat){
  13089. var N = this.faceNormals.length;
  13090. while(this.worldFaceNormals.length < N){
  13091. this.worldFaceNormals.push( new Vec3() );
  13092. }
  13093. var normals = this.faceNormals,
  13094. worldNormals = this.worldFaceNormals;
  13095. for(var i=0; i!==N; i++){
  13096. quat.vmult( normals[i] , worldNormals[i] );
  13097. }
  13098. this.worldFaceNormalsNeedsUpdate = false;
  13099. };
  13100. /**
  13101. * @method updateBoundingSphereRadius
  13102. */
  13103. ConvexPolyhedron.prototype.updateBoundingSphereRadius = function(){
  13104. // Assume points are distributed with local (0,0,0) as center
  13105. var max2 = 0;
  13106. var verts = this.vertices;
  13107. for(var i=0, N=verts.length; i!==N; i++) {
  13108. var norm2 = verts[i].norm2();
  13109. if(norm2 > max2){
  13110. max2 = norm2;
  13111. }
  13112. }
  13113. this.boundingSphereRadius = Math.sqrt(max2);
  13114. };
  13115. var tempWorldVertex = new Vec3();
  13116. /**
  13117. * @method calculateWorldAABB
  13118. * @param {Vec3} pos
  13119. * @param {Quaternion} quat
  13120. * @param {Vec3} min
  13121. * @param {Vec3} max
  13122. */
  13123. ConvexPolyhedron.prototype.calculateWorldAABB = function(pos,quat,min,max){
  13124. var n = this.vertices.length, verts = this.vertices;
  13125. var minx,miny,minz,maxx,maxy,maxz;
  13126. for(var i=0; i<n; i++){
  13127. tempWorldVertex.copy(verts[i]);
  13128. quat.vmult(tempWorldVertex,tempWorldVertex);
  13129. pos.vadd(tempWorldVertex,tempWorldVertex);
  13130. var v = tempWorldVertex;
  13131. if (v.x < minx || minx===undefined){
  13132. minx = v.x;
  13133. } else if(v.x > maxx || maxx===undefined){
  13134. maxx = v.x;
  13135. }
  13136. if (v.y < miny || miny===undefined){
  13137. miny = v.y;
  13138. } else if(v.y > maxy || maxy===undefined){
  13139. maxy = v.y;
  13140. }
  13141. if (v.z < minz || minz===undefined){
  13142. minz = v.z;
  13143. } else if(v.z > maxz || maxz===undefined){
  13144. maxz = v.z;
  13145. }
  13146. }
  13147. min.set(minx,miny,minz);
  13148. max.set(maxx,maxy,maxz);
  13149. };
  13150. /**
  13151. * Get approximate convex volume
  13152. * @method volume
  13153. * @return {Number}
  13154. */
  13155. ConvexPolyhedron.prototype.volume = function(){
  13156. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  13157. };
  13158. /**
  13159. * Get an average of all the vertices positions
  13160. * @method getAveragePointLocal
  13161. * @param {Vec3} target
  13162. * @return {Vec3}
  13163. */
  13164. ConvexPolyhedron.prototype.getAveragePointLocal = function(target){
  13165. target = target || new Vec3();
  13166. var n = this.vertices.length,
  13167. verts = this.vertices;
  13168. for(var i=0; i<n; i++){
  13169. target.vadd(verts[i],target);
  13170. }
  13171. target.mult(1/n,target);
  13172. return target;
  13173. };
  13174. /**
  13175. * Transform all local points. Will change the .vertices
  13176. * @method transformAllPoints
  13177. * @param {Vec3} offset
  13178. * @param {Quaternion} quat
  13179. */
  13180. ConvexPolyhedron.prototype.transformAllPoints = function(offset,quat){
  13181. var n = this.vertices.length,
  13182. verts = this.vertices;
  13183. // Apply rotation
  13184. if(quat){
  13185. // Rotate vertices
  13186. for(var i=0; i<n; i++){
  13187. var v = verts[i];
  13188. quat.vmult(v,v);
  13189. }
  13190. // Rotate face normals
  13191. for(var i=0; i<this.faceNormals.length; i++){
  13192. var v = this.faceNormals[i];
  13193. quat.vmult(v,v);
  13194. }
  13195. /*
  13196. // Rotate edges
  13197. for(var i=0; i<this.uniqueEdges.length; i++){
  13198. var v = this.uniqueEdges[i];
  13199. quat.vmult(v,v);
  13200. }*/
  13201. }
  13202. // Apply offset
  13203. if(offset){
  13204. for(var i=0; i<n; i++){
  13205. var v = verts[i];
  13206. v.vadd(offset,v);
  13207. }
  13208. }
  13209. };
  13210. /**
  13211. * Checks whether p is inside the polyhedra. Must be in local coords. The point lies outside of the convex hull of the other points if and only if the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
  13212. * @method pointIsInside
  13213. * @param {Vec3} p A point given in local coordinates
  13214. * @return {Boolean}
  13215. */
  13216. var ConvexPolyhedron_pointIsInside = new Vec3();
  13217. var ConvexPolyhedron_vToP = new Vec3();
  13218. var ConvexPolyhedron_vToPointInside = new Vec3();
  13219. ConvexPolyhedron.prototype.pointIsInside = function(p){
  13220. var n = this.vertices.length,
  13221. verts = this.vertices,
  13222. faces = this.faces,
  13223. normals = this.faceNormals;
  13224. var positiveResult = null;
  13225. var N = this.faces.length;
  13226. var pointInside = ConvexPolyhedron_pointIsInside;
  13227. this.getAveragePointLocal(pointInside);
  13228. for(var i=0; i<N; i++){
  13229. var numVertices = this.faces[i].length;
  13230. var n = normals[i];
  13231. var v = verts[faces[i][0]]; // We only need one point in the face
  13232. // This dot product determines which side of the edge the point is
  13233. var vToP = ConvexPolyhedron_vToP;
  13234. p.vsub(v,vToP);
  13235. var r1 = n.dot(vToP);
  13236. var vToPointInside = ConvexPolyhedron_vToPointInside;
  13237. pointInside.vsub(v,vToPointInside);
  13238. var r2 = n.dot(vToPointInside);
  13239. if((r1<0 && r2>0) || (r1>0 && r2<0)){
  13240. return false; // Encountered some other sign. Exit.
  13241. } else {
  13242. }
  13243. }
  13244. // If we got here, all dot products were of the same sign.
  13245. return positiveResult ? 1 : -1;
  13246. };
  13247. /**
  13248. * Get max and min dot product of a convex hull at position (pos,quat) projected onto an axis. Results are saved in the array maxmin.
  13249. * @static
  13250. * @method project
  13251. * @param {ConvexPolyhedron} hull
  13252. * @param {Vec3} axis
  13253. * @param {Vec3} pos
  13254. * @param {Quaternion} quat
  13255. * @param {array} result result[0] and result[1] will be set to maximum and minimum, respectively.
  13256. */
  13257. var project_worldVertex = new Vec3();
  13258. var project_localAxis = new Vec3();
  13259. var project_localOrigin = new Vec3();
  13260. ConvexPolyhedron.project = function(hull, axis, pos, quat, result){
  13261. var n = hull.vertices.length,
  13262. worldVertex = project_worldVertex,
  13263. localAxis = project_localAxis,
  13264. max = 0,
  13265. min = 0,
  13266. localOrigin = project_localOrigin,
  13267. vs = hull.vertices;
  13268. localOrigin.setZero();
  13269. // Transform the axis to local
  13270. Transform.vectorToLocalFrame(pos, quat, axis, localAxis);
  13271. Transform.pointToLocalFrame(pos, quat, localOrigin, localOrigin);
  13272. var add = localOrigin.dot(localAxis);
  13273. min = max = vs[0].dot(localAxis);
  13274. for(var i = 1; i < n; i++){
  13275. var val = vs[i].dot(localAxis);
  13276. if(val > max){
  13277. max = val;
  13278. }
  13279. if(val < min){
  13280. min = val;
  13281. }
  13282. }
  13283. min -= add;
  13284. max -= add;
  13285. if(min > max){
  13286. // Inconsistent - swap
  13287. var temp = min;
  13288. min = max;
  13289. max = temp;
  13290. }
  13291. // Output
  13292. result[0] = max;
  13293. result[1] = min;
  13294. };
  13295. },{"../math/Quaternion":50,"../math/Transform":51,"../math/Vec3":52,"./Shape":65}],61:[function(require,module,exports){
  13296. module.exports = Cylinder;
  13297. var Shape = require('./Shape');
  13298. var Vec3 = require('../math/Vec3');
  13299. var Quaternion = require('../math/Quaternion');
  13300. var ConvexPolyhedron = require('./ConvexPolyhedron');
  13301. /**
  13302. * @class Cylinder
  13303. * @constructor
  13304. * @extends ConvexPolyhedron
  13305. * @author schteppe / https://github.com/schteppe
  13306. * @param {Number} radiusTop
  13307. * @param {Number} radiusBottom
  13308. * @param {Number} height
  13309. * @param {Number} numSegments The number of segments to build the cylinder out of
  13310. */
  13311. function Cylinder( radiusTop, radiusBottom, height , numSegments ) {
  13312. var N = numSegments,
  13313. verts = [],
  13314. axes = [],
  13315. faces = [],
  13316. bottomface = [],
  13317. topface = [],
  13318. cos = Math.cos,
  13319. sin = Math.sin;
  13320. // First bottom point
  13321. verts.push(new Vec3(radiusBottom*cos(0),
  13322. radiusBottom*sin(0),
  13323. -height*0.5));
  13324. bottomface.push(0);
  13325. // First top point
  13326. verts.push(new Vec3(radiusTop*cos(0),
  13327. radiusTop*sin(0),
  13328. height*0.5));
  13329. topface.push(1);
  13330. for(var i=0; i<N; i++){
  13331. var theta = 2*Math.PI/N * (i+1);
  13332. var thetaN = 2*Math.PI/N * (i+0.5);
  13333. if(i<N-1){
  13334. // Bottom
  13335. verts.push(new Vec3(radiusBottom*cos(theta),
  13336. radiusBottom*sin(theta),
  13337. -height*0.5));
  13338. bottomface.push(2*i+2);
  13339. // Top
  13340. verts.push(new Vec3(radiusTop*cos(theta),
  13341. radiusTop*sin(theta),
  13342. height*0.5));
  13343. topface.push(2*i+3);
  13344. // Face
  13345. faces.push([2*i+2, 2*i+3, 2*i+1,2*i]);
  13346. } else {
  13347. faces.push([0,1, 2*i+1, 2*i]); // Connect
  13348. }
  13349. // Axis: we can cut off half of them if we have even number of segments
  13350. if(N % 2 === 1 || i < N / 2){
  13351. axes.push(new Vec3(cos(thetaN), sin(thetaN), 0));
  13352. }
  13353. }
  13354. faces.push(topface);
  13355. axes.push(new Vec3(0,0,1));
  13356. // Reorder bottom face
  13357. var temp = [];
  13358. for(var i=0; i<bottomface.length; i++){
  13359. temp.push(bottomface[bottomface.length - i - 1]);
  13360. }
  13361. faces.push(temp);
  13362. this.type = Shape.types.CONVEXPOLYHEDRON;
  13363. ConvexPolyhedron.call( this, verts, faces, axes );
  13364. }
  13365. Cylinder.prototype = new ConvexPolyhedron();
  13366. },{"../math/Quaternion":50,"../math/Vec3":52,"./ConvexPolyhedron":60,"./Shape":65}],62:[function(require,module,exports){
  13367. var Shape = require('./Shape');
  13368. var ConvexPolyhedron = require('./ConvexPolyhedron');
  13369. var Vec3 = require('../math/Vec3');
  13370. var Utils = require('../utils/Utils');
  13371. module.exports = Heightfield;
  13372. /**
  13373. * Heightfield shape class. Height data is given as an array. These data points are spread out evenly with a given distance.
  13374. * @class Heightfield
  13375. * @extends Shape
  13376. * @constructor
  13377. * @param {Array} data An array of Y values that will be used to construct the terrain.
  13378. * @param {object} options
  13379. * @param {Number} [options.minValue] Minimum value of the data points in the data array. Will be computed automatically if not given.
  13380. * @param {Number} [options.maxValue] Maximum value.
  13381. * @param {Number} [options.elementSize=0.1] World spacing between the data points in X direction.
  13382. * @todo Should be possible to use along all axes, not just y
  13383. * @todo should be possible to scale along all axes
  13384. *
  13385. * @example
  13386. * // Generate some height data (y-values).
  13387. * var data = [];
  13388. * for(var i = 0; i < 1000; i++){
  13389. * var y = 0.5 * Math.cos(0.2 * i);
  13390. * data.push(y);
  13391. * }
  13392. *
  13393. * // Create the heightfield shape
  13394. * var heightfieldShape = new Heightfield(data, {
  13395. * elementSize: 1 // Distance between the data points in X and Y directions
  13396. * });
  13397. * var heightfieldBody = new Body();
  13398. * heightfieldBody.addShape(heightfieldShape);
  13399. * world.addBody(heightfieldBody);
  13400. */
  13401. function Heightfield(data, options){
  13402. options = Utils.defaults(options, {
  13403. maxValue : null,
  13404. minValue : null,
  13405. elementSize : 1
  13406. });
  13407. /**
  13408. * An array of numbers, or height values, that are spread out along the x axis.
  13409. * @property {array} data
  13410. */
  13411. this.data = data;
  13412. /**
  13413. * Max value of the data
  13414. * @property {number} maxValue
  13415. */
  13416. this.maxValue = options.maxValue;
  13417. /**
  13418. * Max value of the data
  13419. * @property {number} minValue
  13420. */
  13421. this.minValue = options.minValue;
  13422. /**
  13423. * The width of each element
  13424. * @property {number} elementSize
  13425. * @todo elementSizeX and Y
  13426. */
  13427. this.elementSize = options.elementSize;
  13428. if(options.minValue === null){
  13429. this.updateMinValue();
  13430. }
  13431. if(options.maxValue === null){
  13432. this.updateMaxValue();
  13433. }
  13434. this.cacheEnabled = true;
  13435. Shape.call(this);
  13436. this.pillarConvex = new ConvexPolyhedron();
  13437. this.pillarOffset = new Vec3();
  13438. this.type = Shape.types.HEIGHTFIELD;
  13439. this.updateBoundingSphereRadius();
  13440. // "i_j_isUpper" => { convex: ..., offset: ... }
  13441. // for example:
  13442. // _cachedPillars["0_2_1"]
  13443. this._cachedPillars = {};
  13444. }
  13445. Heightfield.prototype = new Shape();
  13446. /**
  13447. * Call whenever you change the data array.
  13448. * @method update
  13449. */
  13450. Heightfield.prototype.update = function(){
  13451. this._cachedPillars = {};
  13452. };
  13453. /**
  13454. * Update the .minValue property
  13455. * @method updateMinValue
  13456. */
  13457. Heightfield.prototype.updateMinValue = function(){
  13458. var data = this.data;
  13459. var minValue = data[0][0];
  13460. for(var i=0; i !== data.length; i++){
  13461. for(var j=0; j !== data[i].length; j++){
  13462. var v = data[i][j];
  13463. if(v < minValue){
  13464. minValue = v;
  13465. }
  13466. }
  13467. }
  13468. this.minValue = minValue;
  13469. };
  13470. /**
  13471. * Update the .maxValue property
  13472. * @method updateMaxValue
  13473. */
  13474. Heightfield.prototype.updateMaxValue = function(){
  13475. var data = this.data;
  13476. var maxValue = data[0][0];
  13477. for(var i=0; i !== data.length; i++){
  13478. for(var j=0; j !== data[i].length; j++){
  13479. var v = data[i][j];
  13480. if(v > maxValue){
  13481. maxValue = v;
  13482. }
  13483. }
  13484. }
  13485. this.maxValue = maxValue;
  13486. };
  13487. /**
  13488. * Set the height value at an index. Don't forget to update maxValue and minValue after you're done.
  13489. * @method setHeightValueAtIndex
  13490. * @param {integer} xi
  13491. * @param {integer} yi
  13492. * @param {number} value
  13493. */
  13494. Heightfield.prototype.setHeightValueAtIndex = function(xi, yi, value){
  13495. var data = this.data;
  13496. data[xi][yi] = value;
  13497. // Invalidate cache
  13498. this.clearCachedConvexTrianglePillar(xi, yi, false);
  13499. if(xi > 0){
  13500. this.clearCachedConvexTrianglePillar(xi - 1, yi, true);
  13501. this.clearCachedConvexTrianglePillar(xi - 1, yi, false);
  13502. }
  13503. if(yi > 0){
  13504. this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
  13505. this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
  13506. }
  13507. if(yi > 0 && xi > 0){
  13508. this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
  13509. }
  13510. };
  13511. /**
  13512. * Get max/min in a rectangle in the matrix data
  13513. * @method getRectMinMax
  13514. * @param {integer} iMinX
  13515. * @param {integer} iMinY
  13516. * @param {integer} iMaxX
  13517. * @param {integer} iMaxY
  13518. * @param {array} [result] An array to store the results in.
  13519. * @return {array} The result array, if it was passed in. Minimum will be at position 0 and max at 1.
  13520. */
  13521. Heightfield.prototype.getRectMinMax = function (iMinX, iMinY, iMaxX, iMaxY, result) {
  13522. result = result || [];
  13523. // Get max and min of the data
  13524. var data = this.data,
  13525. max = this.minValue; // Set first value
  13526. for(var i = iMinX; i <= iMaxX; i++){
  13527. for(var j = iMinY; j <= iMaxY; j++){
  13528. var height = data[i][j];
  13529. if(height > max){
  13530. max = height;
  13531. }
  13532. }
  13533. }
  13534. result[0] = this.minValue;
  13535. result[1] = max;
  13536. };
  13537. /**
  13538. * Get the index of a local position on the heightfield. The indexes indicate the rectangles, so if your terrain is made of N x N height data points, you will have rectangle indexes ranging from 0 to N-1.
  13539. * @method getIndexOfPosition
  13540. * @param {number} x
  13541. * @param {number} y
  13542. * @param {array} result Two-element array
  13543. * @param {boolean} clamp If the position should be clamped to the heightfield edge.
  13544. * @return {boolean}
  13545. */
  13546. Heightfield.prototype.getIndexOfPosition = function (x, y, result, clamp) {
  13547. // Get the index of the data points to test against
  13548. var w = this.elementSize;
  13549. var data = this.data;
  13550. var xi = Math.floor(x / w);
  13551. var yi = Math.floor(y / w);
  13552. result[0] = xi;
  13553. result[1] = yi;
  13554. if(clamp){
  13555. // Clamp index to edges
  13556. if(xi < 0){ xi = 0; }
  13557. if(yi < 0){ yi = 0; }
  13558. if(xi >= data.length - 1){ xi = data.length - 1; }
  13559. if(yi >= data[0].length - 1){ yi = data[0].length - 1; }
  13560. }
  13561. // Bail out if we are out of the terrain
  13562. if(xi < 0 || yi < 0 || xi >= data.length-1 || yi >= data[0].length-1){
  13563. return false;
  13564. }
  13565. return true;
  13566. };
  13567. var getHeightAt_idx = [];
  13568. var getHeightAt_weights = new Vec3();
  13569. var getHeightAt_a = new Vec3();
  13570. var getHeightAt_b = new Vec3();
  13571. var getHeightAt_c = new Vec3();
  13572. Heightfield.prototype.getTriangleAt = function(x, y, edgeClamp, a, b, c){
  13573. var idx = getHeightAt_idx;
  13574. this.getIndexOfPosition(x, y, idx, edgeClamp);
  13575. var xi = idx[0];
  13576. var yi = idx[1];
  13577. var data = this.data;
  13578. if(edgeClamp){
  13579. xi = Math.min(data.length - 2, Math.max(0, xi));
  13580. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  13581. }
  13582. var elementSize = this.elementSize;
  13583. var lowerDist2 = Math.pow(x / elementSize - xi, 2) + Math.pow(y / elementSize - yi, 2);
  13584. var upperDist2 = Math.pow(x / elementSize - (xi + 1), 2) + Math.pow(y / elementSize - (yi + 1), 2);
  13585. var upper = lowerDist2 > upperDist2;
  13586. this.getTriangle(xi, yi, upper, a, b, c);
  13587. return upper;
  13588. };
  13589. var getNormalAt_a = new Vec3();
  13590. var getNormalAt_b = new Vec3();
  13591. var getNormalAt_c = new Vec3();
  13592. var getNormalAt_e0 = new Vec3();
  13593. var getNormalAt_e1 = new Vec3();
  13594. Heightfield.prototype.getNormalAt = function(x, y, edgeClamp, result){
  13595. var a = getNormalAt_a;
  13596. var b = getNormalAt_b;
  13597. var c = getNormalAt_c;
  13598. var e0 = getNormalAt_e0;
  13599. var e1 = getNormalAt_e1;
  13600. this.getTriangleAt(x, y, edgeClamp, a, b, c);
  13601. b.vsub(a, e0);
  13602. c.vsub(a, e1);
  13603. e0.cross(e1, result);
  13604. result.normalize();
  13605. };
  13606. /**
  13607. * Get an AABB of a square in the heightfield
  13608. * @param {number} xi
  13609. * @param {number} yi
  13610. * @param {AABB} result
  13611. */
  13612. Heightfield.prototype.getAabbAtIndex = function(xi, yi, result){
  13613. var data = this.data;
  13614. var elementSize = this.elementSize;
  13615. result.lowerBound.set(
  13616. xi * elementSize,
  13617. yi * elementSize,
  13618. data[xi][yi]
  13619. );
  13620. result.upperBound.set(
  13621. (xi + 1) * elementSize,
  13622. (yi + 1) * elementSize,
  13623. data[xi + 1][yi + 1]
  13624. );
  13625. };
  13626. /**
  13627. * Get the height in the heightfield at a given position
  13628. * @param {number} x
  13629. * @param {number} y
  13630. * @param {boolean} edgeClamp
  13631. * @return {number}
  13632. */
  13633. Heightfield.prototype.getHeightAt = function(x, y, edgeClamp){
  13634. var data = this.data;
  13635. var a = getHeightAt_a;
  13636. var b = getHeightAt_b;
  13637. var c = getHeightAt_c;
  13638. var idx = getHeightAt_idx;
  13639. this.getIndexOfPosition(x, y, idx, edgeClamp);
  13640. var xi = idx[0];
  13641. var yi = idx[1];
  13642. if(edgeClamp){
  13643. xi = Math.min(data.length - 2, Math.max(0, xi));
  13644. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  13645. }
  13646. var upper = this.getTriangleAt(x, y, edgeClamp, a, b, c);
  13647. barycentricWeights(x, y, a.x, a.y, b.x, b.y, c.x, c.y, getHeightAt_weights);
  13648. var w = getHeightAt_weights;
  13649. if(upper){
  13650. // Top triangle verts
  13651. return data[xi + 1][yi + 1] * w.x + data[xi][yi + 1] * w.y + data[xi + 1][yi] * w.z;
  13652. } else {
  13653. // Top triangle verts
  13654. return data[xi][yi] * w.x + data[xi + 1][yi] * w.y + data[xi][yi + 1] * w.z;
  13655. }
  13656. };
  13657. // from https://en.wikipedia.org/wiki/Barycentric_coordinate_system
  13658. function barycentricWeights(x, y, ax, ay, bx, by, cx, cy, result){
  13659. result.x = ((by - cy) * (x - cx) + (cx - bx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  13660. result.y = ((cy - ay) * (x - cx) + (ax - cx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  13661. result.z = 1 - result.x - result.y;
  13662. }
  13663. Heightfield.prototype.getCacheConvexTrianglePillarKey = function(xi, yi, getUpperTriangle){
  13664. return xi + '_' + yi + '_' + (getUpperTriangle ? 1 : 0);
  13665. };
  13666. Heightfield.prototype.getCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  13667. return this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  13668. };
  13669. Heightfield.prototype.setCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle, convex, offset){
  13670. this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)] = {
  13671. convex: convex,
  13672. offset: offset
  13673. };
  13674. };
  13675. Heightfield.prototype.clearCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  13676. delete this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  13677. };
  13678. /**
  13679. * Get a triangle from the heightfield
  13680. * @param {number} xi
  13681. * @param {number} yi
  13682. * @param {boolean} upper
  13683. * @param {Vec3} a
  13684. * @param {Vec3} b
  13685. * @param {Vec3} c
  13686. */
  13687. Heightfield.prototype.getTriangle = function(xi, yi, upper, a, b, c){
  13688. var data = this.data;
  13689. var elementSize = this.elementSize;
  13690. if(upper){
  13691. // Top triangle verts
  13692. a.set(
  13693. (xi + 1) * elementSize,
  13694. (yi + 1) * elementSize,
  13695. data[xi + 1][yi + 1]
  13696. );
  13697. b.set(
  13698. xi * elementSize,
  13699. (yi + 1) * elementSize,
  13700. data[xi][yi + 1]
  13701. );
  13702. c.set(
  13703. (xi + 1) * elementSize,
  13704. yi * elementSize,
  13705. data[xi + 1][yi]
  13706. );
  13707. } else {
  13708. // Top triangle verts
  13709. a.set(
  13710. xi * elementSize,
  13711. yi * elementSize,
  13712. data[xi][yi]
  13713. );
  13714. b.set(
  13715. (xi + 1) * elementSize,
  13716. yi * elementSize,
  13717. data[xi + 1][yi]
  13718. );
  13719. c.set(
  13720. xi * elementSize,
  13721. (yi + 1) * elementSize,
  13722. data[xi][yi + 1]
  13723. );
  13724. }
  13725. };
  13726. /**
  13727. * Get a triangle in the terrain in the form of a triangular convex shape.
  13728. * @method getConvexTrianglePillar
  13729. * @param {integer} i
  13730. * @param {integer} j
  13731. * @param {boolean} getUpperTriangle
  13732. */
  13733. Heightfield.prototype.getConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  13734. var result = this.pillarConvex;
  13735. var offsetResult = this.pillarOffset;
  13736. if(this.cacheEnabled){
  13737. var data = this.getCachedConvexTrianglePillar(xi, yi, getUpperTriangle);
  13738. if(data){
  13739. this.pillarConvex = data.convex;
  13740. this.pillarOffset = data.offset;
  13741. return;
  13742. }
  13743. result = new ConvexPolyhedron();
  13744. offsetResult = new Vec3();
  13745. this.pillarConvex = result;
  13746. this.pillarOffset = offsetResult;
  13747. }
  13748. var data = this.data;
  13749. var elementSize = this.elementSize;
  13750. var faces = result.faces;
  13751. // Reuse verts if possible
  13752. result.vertices.length = 6;
  13753. for (var i = 0; i < 6; i++) {
  13754. if(!result.vertices[i]){
  13755. result.vertices[i] = new Vec3();
  13756. }
  13757. }
  13758. // Reuse faces if possible
  13759. faces.length = 5;
  13760. for (var i = 0; i < 5; i++) {
  13761. if(!faces[i]){
  13762. faces[i] = [];
  13763. }
  13764. }
  13765. var verts = result.vertices;
  13766. var h = (Math.min(
  13767. data[xi][yi],
  13768. data[xi+1][yi],
  13769. data[xi][yi+1],
  13770. data[xi+1][yi+1]
  13771. ) - this.minValue ) / 2 + this.minValue;
  13772. if (!getUpperTriangle) {
  13773. // Center of the triangle pillar - all polygons are given relative to this one
  13774. offsetResult.set(
  13775. (xi + 0.25) * elementSize, // sort of center of a triangle
  13776. (yi + 0.25) * elementSize,
  13777. h // vertical center
  13778. );
  13779. // Top triangle verts
  13780. verts[0].set(
  13781. -0.25 * elementSize,
  13782. -0.25 * elementSize,
  13783. data[xi][yi] - h
  13784. );
  13785. verts[1].set(
  13786. 0.75 * elementSize,
  13787. -0.25 * elementSize,
  13788. data[xi + 1][yi] - h
  13789. );
  13790. verts[2].set(
  13791. -0.25 * elementSize,
  13792. 0.75 * elementSize,
  13793. data[xi][yi + 1] - h
  13794. );
  13795. // bottom triangle verts
  13796. verts[3].set(
  13797. -0.25 * elementSize,
  13798. -0.25 * elementSize,
  13799. -h-1
  13800. );
  13801. verts[4].set(
  13802. 0.75 * elementSize,
  13803. -0.25 * elementSize,
  13804. -h-1
  13805. );
  13806. verts[5].set(
  13807. -0.25 * elementSize,
  13808. 0.75 * elementSize,
  13809. -h-1
  13810. );
  13811. // top triangle
  13812. faces[0][0] = 0;
  13813. faces[0][1] = 1;
  13814. faces[0][2] = 2;
  13815. // bottom triangle
  13816. faces[1][0] = 5;
  13817. faces[1][1] = 4;
  13818. faces[1][2] = 3;
  13819. // -x facing quad
  13820. faces[2][0] = 0;
  13821. faces[2][1] = 2;
  13822. faces[2][2] = 5;
  13823. faces[2][3] = 3;
  13824. // -y facing quad
  13825. faces[3][0] = 1;
  13826. faces[3][1] = 0;
  13827. faces[3][2] = 3;
  13828. faces[3][3] = 4;
  13829. // +xy facing quad
  13830. faces[4][0] = 4;
  13831. faces[4][1] = 5;
  13832. faces[4][2] = 2;
  13833. faces[4][3] = 1;
  13834. } else {
  13835. // Center of the triangle pillar - all polygons are given relative to this one
  13836. offsetResult.set(
  13837. (xi + 0.75) * elementSize, // sort of center of a triangle
  13838. (yi + 0.75) * elementSize,
  13839. h // vertical center
  13840. );
  13841. // Top triangle verts
  13842. verts[0].set(
  13843. 0.25 * elementSize,
  13844. 0.25 * elementSize,
  13845. data[xi + 1][yi + 1] - h
  13846. );
  13847. verts[1].set(
  13848. -0.75 * elementSize,
  13849. 0.25 * elementSize,
  13850. data[xi][yi + 1] - h
  13851. );
  13852. verts[2].set(
  13853. 0.25 * elementSize,
  13854. -0.75 * elementSize,
  13855. data[xi + 1][yi] - h
  13856. );
  13857. // bottom triangle verts
  13858. verts[3].set(
  13859. 0.25 * elementSize,
  13860. 0.25 * elementSize,
  13861. - h-1
  13862. );
  13863. verts[4].set(
  13864. -0.75 * elementSize,
  13865. 0.25 * elementSize,
  13866. - h-1
  13867. );
  13868. verts[5].set(
  13869. 0.25 * elementSize,
  13870. -0.75 * elementSize,
  13871. - h-1
  13872. );
  13873. // Top triangle
  13874. faces[0][0] = 0;
  13875. faces[0][1] = 1;
  13876. faces[0][2] = 2;
  13877. // bottom triangle
  13878. faces[1][0] = 5;
  13879. faces[1][1] = 4;
  13880. faces[1][2] = 3;
  13881. // +x facing quad
  13882. faces[2][0] = 2;
  13883. faces[2][1] = 5;
  13884. faces[2][2] = 3;
  13885. faces[2][3] = 0;
  13886. // +y facing quad
  13887. faces[3][0] = 3;
  13888. faces[3][1] = 4;
  13889. faces[3][2] = 1;
  13890. faces[3][3] = 0;
  13891. // -xy facing quad
  13892. faces[4][0] = 1;
  13893. faces[4][1] = 4;
  13894. faces[4][2] = 5;
  13895. faces[4][3] = 2;
  13896. }
  13897. result.computeNormals();
  13898. result.computeEdges();
  13899. result.updateBoundingSphereRadius();
  13900. this.setCachedConvexTrianglePillar(xi, yi, getUpperTriangle, result, offsetResult);
  13901. };
  13902. Heightfield.prototype.calculateLocalInertia = function(mass, target){
  13903. target = target || new Vec3();
  13904. target.set(0, 0, 0);
  13905. return target;
  13906. };
  13907. Heightfield.prototype.volume = function(){
  13908. return Number.MAX_VALUE; // The terrain is infinite
  13909. };
  13910. Heightfield.prototype.calculateWorldAABB = function(pos, quat, min, max){
  13911. // TODO: do it properly
  13912. min.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  13913. max.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  13914. };
  13915. Heightfield.prototype.updateBoundingSphereRadius = function(){
  13916. // Use the bounding box of the min/max values
  13917. var data = this.data,
  13918. s = this.elementSize;
  13919. this.boundingSphereRadius = new Vec3(data.length * s, data[0].length * s, Math.max(Math.abs(this.maxValue), Math.abs(this.minValue))).norm();
  13920. };
  13921. /**
  13922. * Sets the height values from an image. Currently only supported in browser.
  13923. * @method setHeightsFromImage
  13924. * @param {Image} image
  13925. * @param {Vec3} scale
  13926. */
  13927. Heightfield.prototype.setHeightsFromImage = function(image, scale){
  13928. var canvas = document.createElement('canvas');
  13929. canvas.width = image.width;
  13930. canvas.height = image.height;
  13931. var context = canvas.getContext('2d');
  13932. context.drawImage(image, 0, 0);
  13933. var imageData = context.getImageData(0, 0, image.width, image.height);
  13934. var matrix = this.data;
  13935. matrix.length = 0;
  13936. this.elementSize = Math.abs(scale.x) / imageData.width;
  13937. for(var i=0; i<imageData.height; i++){
  13938. var row = [];
  13939. for(var j=0; j<imageData.width; j++){
  13940. var a = imageData.data[(i*imageData.height + j) * 4];
  13941. var b = imageData.data[(i*imageData.height + j) * 4 + 1];
  13942. var c = imageData.data[(i*imageData.height + j) * 4 + 2];
  13943. var height = (a + b + c) / 4 / 255 * scale.z;
  13944. if(scale.x < 0){
  13945. row.push(height);
  13946. } else {
  13947. row.unshift(height);
  13948. }
  13949. }
  13950. if(scale.y < 0){
  13951. matrix.unshift(row);
  13952. } else {
  13953. matrix.push(row);
  13954. }
  13955. }
  13956. this.updateMaxValue();
  13957. this.updateMinValue();
  13958. this.update();
  13959. };
  13960. },{"../math/Vec3":52,"../utils/Utils":75,"./ConvexPolyhedron":60,"./Shape":65}],63:[function(require,module,exports){
  13961. module.exports = Particle;
  13962. var Shape = require('./Shape');
  13963. var Vec3 = require('../math/Vec3');
  13964. /**
  13965. * Particle shape.
  13966. * @class Particle
  13967. * @constructor
  13968. * @author schteppe
  13969. * @extends Shape
  13970. */
  13971. function Particle(){
  13972. Shape.call(this);
  13973. this.type = Shape.types.PARTICLE;
  13974. }
  13975. Particle.prototype = new Shape();
  13976. Particle.prototype.constructor = Particle;
  13977. /**
  13978. * @method calculateLocalInertia
  13979. * @param {Number} mass
  13980. * @param {Vec3} target
  13981. * @return {Vec3}
  13982. */
  13983. Particle.prototype.calculateLocalInertia = function(mass,target){
  13984. target = target || new Vec3();
  13985. target.set(0, 0, 0);
  13986. return target;
  13987. };
  13988. Particle.prototype.volume = function(){
  13989. return 0;
  13990. };
  13991. Particle.prototype.updateBoundingSphereRadius = function(){
  13992. this.boundingSphereRadius = 0;
  13993. };
  13994. Particle.prototype.calculateWorldAABB = function(pos,quat,min,max){
  13995. // Get each axis max
  13996. min.copy(pos);
  13997. max.copy(pos);
  13998. };
  13999. },{"../math/Vec3":52,"./Shape":65}],64:[function(require,module,exports){
  14000. module.exports = Plane;
  14001. var Shape = require('./Shape');
  14002. var Vec3 = require('../math/Vec3');
  14003. /**
  14004. * A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
  14005. * @class Plane
  14006. * @constructor
  14007. * @extends Shape
  14008. * @author schteppe
  14009. */
  14010. function Plane(){
  14011. Shape.call(this);
  14012. this.type = Shape.types.PLANE;
  14013. // World oriented normal
  14014. this.worldNormal = new Vec3();
  14015. this.worldNormalNeedsUpdate = true;
  14016. this.boundingSphereRadius = Number.MAX_VALUE;
  14017. }
  14018. Plane.prototype = new Shape();
  14019. Plane.prototype.constructor = Plane;
  14020. Plane.prototype.computeWorldNormal = function(quat){
  14021. var n = this.worldNormal;
  14022. n.set(0,0,1);
  14023. quat.vmult(n,n);
  14024. this.worldNormalNeedsUpdate = false;
  14025. };
  14026. Plane.prototype.calculateLocalInertia = function(mass,target){
  14027. target = target || new Vec3();
  14028. return target;
  14029. };
  14030. Plane.prototype.volume = function(){
  14031. return Number.MAX_VALUE; // The plane is infinite...
  14032. };
  14033. var tempNormal = new Vec3();
  14034. Plane.prototype.calculateWorldAABB = function(pos, quat, min, max){
  14035. // The plane AABB is infinite, except if the normal is pointing along any axis
  14036. tempNormal.set(0,0,1); // Default plane normal is z
  14037. quat.vmult(tempNormal,tempNormal);
  14038. var maxVal = Number.MAX_VALUE;
  14039. min.set(-maxVal, -maxVal, -maxVal);
  14040. max.set(maxVal, maxVal, maxVal);
  14041. if(tempNormal.x === 1){ max.x = pos.x; }
  14042. if(tempNormal.y === 1){ max.y = pos.y; }
  14043. if(tempNormal.z === 1){ max.z = pos.z; }
  14044. if(tempNormal.x === -1){ min.x = pos.x; }
  14045. if(tempNormal.y === -1){ min.y = pos.y; }
  14046. if(tempNormal.z === -1){ min.z = pos.z; }
  14047. };
  14048. Plane.prototype.updateBoundingSphereRadius = function(){
  14049. this.boundingSphereRadius = Number.MAX_VALUE;
  14050. };
  14051. },{"../math/Vec3":52,"./Shape":65}],65:[function(require,module,exports){
  14052. module.exports = Shape;
  14053. var Shape = require('./Shape');
  14054. var Vec3 = require('../math/Vec3');
  14055. var Quaternion = require('../math/Quaternion');
  14056. var Material = require('../material/Material');
  14057. /**
  14058. * Base class for shapes
  14059. * @class Shape
  14060. * @constructor
  14061. * @author schteppe
  14062. * @todo Should have a mechanism for caching bounding sphere radius instead of calculating it each time
  14063. */
  14064. function Shape(){
  14065. /**
  14066. * Identifyer of the Shape.
  14067. * @property {number} id
  14068. */
  14069. this.id = Shape.idCounter++;
  14070. /**
  14071. * The type of this shape. Must be set to an int > 0 by subclasses.
  14072. * @property type
  14073. * @type {Number}
  14074. * @see Shape.types
  14075. */
  14076. this.type = 0;
  14077. /**
  14078. * The local bounding sphere radius of this shape.
  14079. * @property {Number} boundingSphereRadius
  14080. */
  14081. this.boundingSphereRadius = 0;
  14082. /**
  14083. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  14084. * @property {boolean} collisionResponse
  14085. */
  14086. this.collisionResponse = true;
  14087. /**
  14088. * @property {Material} material
  14089. */
  14090. this.material = null;
  14091. /**
  14092. * @property {Body} body
  14093. */
  14094. this.body = null;
  14095. }
  14096. Shape.prototype.constructor = Shape;
  14097. /**
  14098. * Computes the bounding sphere radius. The result is stored in the property .boundingSphereRadius
  14099. * @method updateBoundingSphereRadius
  14100. */
  14101. Shape.prototype.updateBoundingSphereRadius = function(){
  14102. throw "computeBoundingSphereRadius() not implemented for shape type "+this.type;
  14103. };
  14104. /**
  14105. * Get the volume of this shape
  14106. * @method volume
  14107. * @return {Number}
  14108. */
  14109. Shape.prototype.volume = function(){
  14110. throw "volume() not implemented for shape type "+this.type;
  14111. };
  14112. /**
  14113. * Calculates the inertia in the local frame for this shape.
  14114. * @method calculateLocalInertia
  14115. * @param {Number} mass
  14116. * @param {Vec3} target
  14117. * @see http://en.wikipedia.org/wiki/List_of_moments_of_inertia
  14118. */
  14119. Shape.prototype.calculateLocalInertia = function(mass,target){
  14120. throw "calculateLocalInertia() not implemented for shape type "+this.type;
  14121. };
  14122. Shape.idCounter = 0;
  14123. /**
  14124. * The available shape types.
  14125. * @static
  14126. * @property types
  14127. * @type {Object}
  14128. */
  14129. Shape.types = {
  14130. SPHERE:1,
  14131. PLANE:2,
  14132. BOX:4,
  14133. COMPOUND:8,
  14134. CONVEXPOLYHEDRON:16,
  14135. HEIGHTFIELD:32,
  14136. PARTICLE:64,
  14137. CYLINDER:128,
  14138. TRIMESH:256
  14139. };
  14140. },{"../material/Material":47,"../math/Quaternion":50,"../math/Vec3":52,"./Shape":65}],66:[function(require,module,exports){
  14141. module.exports = Sphere;
  14142. var Shape = require('./Shape');
  14143. var Vec3 = require('../math/Vec3');
  14144. /**
  14145. * Spherical shape
  14146. * @class Sphere
  14147. * @constructor
  14148. * @extends Shape
  14149. * @param {Number} radius The radius of the sphere, a non-negative number.
  14150. * @author schteppe / http://github.com/schteppe
  14151. */
  14152. function Sphere(radius){
  14153. Shape.call(this);
  14154. /**
  14155. * @property {Number} radius
  14156. */
  14157. this.radius = radius!==undefined ? Number(radius) : 1.0;
  14158. this.type = Shape.types.SPHERE;
  14159. if(this.radius < 0){
  14160. throw new Error('The sphere radius cannot be negative.');
  14161. }
  14162. this.updateBoundingSphereRadius();
  14163. }
  14164. Sphere.prototype = new Shape();
  14165. Sphere.prototype.constructor = Sphere;
  14166. Sphere.prototype.calculateLocalInertia = function(mass,target){
  14167. target = target || new Vec3();
  14168. var I = 2.0*mass*this.radius*this.radius/5.0;
  14169. target.x = I;
  14170. target.y = I;
  14171. target.z = I;
  14172. return target;
  14173. };
  14174. Sphere.prototype.volume = function(){
  14175. return 4.0 * Math.PI * this.radius / 3.0;
  14176. };
  14177. Sphere.prototype.updateBoundingSphereRadius = function(){
  14178. this.boundingSphereRadius = this.radius;
  14179. };
  14180. Sphere.prototype.calculateWorldAABB = function(pos,quat,min,max){
  14181. var r = this.radius;
  14182. var axes = ['x','y','z'];
  14183. for(var i=0; i<axes.length; i++){
  14184. var ax = axes[i];
  14185. min[ax] = pos[ax] - r;
  14186. max[ax] = pos[ax] + r;
  14187. }
  14188. };
  14189. },{"../math/Vec3":52,"./Shape":65}],67:[function(require,module,exports){
  14190. module.exports = Trimesh;
  14191. var Shape = require('./Shape');
  14192. var Vec3 = require('../math/Vec3');
  14193. var Quaternion = require('../math/Quaternion');
  14194. var Transform = require('../math/Transform');
  14195. var AABB = require('../collision/AABB');
  14196. var Octree = require('../utils/Octree');
  14197. /**
  14198. * @class Trimesh
  14199. * @constructor
  14200. * @param {array} vertices
  14201. * @param {array} indices
  14202. * @extends Shape
  14203. * @example
  14204. * // How to make a mesh with a single triangle
  14205. * var vertices = [
  14206. * 0, 0, 0, // vertex 0
  14207. * 1, 0, 0, // vertex 1
  14208. * 0, 1, 0 // vertex 2
  14209. * ];
  14210. * var indices = [
  14211. * 0, 1, 2 // triangle 0
  14212. * ];
  14213. * var trimeshShape = new Trimesh(vertices, indices);
  14214. */
  14215. function Trimesh(vertices, indices) {
  14216. Shape.call(this);
  14217. this.type = Shape.types.TRIMESH;
  14218. /**
  14219. * @property vertices
  14220. * @type {Array}
  14221. */
  14222. this.vertices = new Float32Array(vertices);
  14223. /**
  14224. * Array of integers, indicating which vertices each triangle consists of. The length of this array is thus 3 times the number of triangles.
  14225. * @property indices
  14226. * @type {Array}
  14227. */
  14228. this.indices = new Int16Array(indices);
  14229. /**
  14230. * The normals data.
  14231. * @property normals
  14232. * @type {Array}
  14233. */
  14234. this.normals = new Float32Array(indices.length);
  14235. /**
  14236. * The local AABB of the mesh.
  14237. * @property aabb
  14238. * @type {Array}
  14239. */
  14240. this.aabb = new AABB();
  14241. /**
  14242. * References to vertex pairs, making up all unique edges in the trimesh.
  14243. * @property {array} edges
  14244. */
  14245. this.edges = null;
  14246. /**
  14247. * Local scaling of the mesh. Use .setScale() to set it.
  14248. * @property {Vec3} scale
  14249. */
  14250. this.scale = new Vec3(1, 1, 1);
  14251. /**
  14252. * The indexed triangles. Use .updateTree() to update it.
  14253. * @property {Octree} tree
  14254. */
  14255. this.tree = new Octree();
  14256. this.updateEdges();
  14257. this.updateNormals();
  14258. this.updateAABB();
  14259. this.updateBoundingSphereRadius();
  14260. this.updateTree();
  14261. }
  14262. Trimesh.prototype = new Shape();
  14263. Trimesh.prototype.constructor = Trimesh;
  14264. var computeNormals_n = new Vec3();
  14265. /**
  14266. * @method updateTree
  14267. */
  14268. Trimesh.prototype.updateTree = function(){
  14269. var tree = this.tree;
  14270. tree.reset();
  14271. tree.aabb.copy(this.aabb);
  14272. var scale = this.scale; // The local mesh AABB is scaled, but the octree AABB should be unscaled
  14273. tree.aabb.lowerBound.x *= 1 / scale.x;
  14274. tree.aabb.lowerBound.y *= 1 / scale.y;
  14275. tree.aabb.lowerBound.z *= 1 / scale.z;
  14276. tree.aabb.upperBound.x *= 1 / scale.x;
  14277. tree.aabb.upperBound.y *= 1 / scale.y;
  14278. tree.aabb.upperBound.z *= 1 / scale.z;
  14279. // Insert all triangles
  14280. var triangleAABB = new AABB();
  14281. var a = new Vec3();
  14282. var b = new Vec3();
  14283. var c = new Vec3();
  14284. var points = [a, b, c];
  14285. for (var i = 0; i < this.indices.length / 3; i++) {
  14286. //this.getTriangleVertices(i, a, b, c);
  14287. // Get unscaled triangle verts
  14288. var i3 = i * 3;
  14289. this._getUnscaledVertex(this.indices[i3], a);
  14290. this._getUnscaledVertex(this.indices[i3 + 1], b);
  14291. this._getUnscaledVertex(this.indices[i3 + 2], c);
  14292. triangleAABB.setFromPoints(points);
  14293. tree.insert(triangleAABB, i);
  14294. }
  14295. tree.removeEmptyNodes();
  14296. };
  14297. var unscaledAABB = new AABB();
  14298. /**
  14299. * Get triangles in a local AABB from the trimesh.
  14300. * @method getTrianglesInAABB
  14301. * @param {AABB} aabb
  14302. * @param {array} result An array of integers, referencing the queried triangles.
  14303. */
  14304. Trimesh.prototype.getTrianglesInAABB = function(aabb, result){
  14305. unscaledAABB.copy(aabb);
  14306. // Scale it to local
  14307. var scale = this.scale;
  14308. var isx = scale.x;
  14309. var isy = scale.y;
  14310. var isz = scale.z;
  14311. var l = unscaledAABB.lowerBound;
  14312. var u = unscaledAABB.upperBound;
  14313. l.x /= isx;
  14314. l.y /= isy;
  14315. l.z /= isz;
  14316. u.x /= isx;
  14317. u.y /= isy;
  14318. u.z /= isz;
  14319. return this.tree.aabbQuery(unscaledAABB, result);
  14320. };
  14321. /**
  14322. * @method setScale
  14323. * @param {Vec3} scale
  14324. */
  14325. Trimesh.prototype.setScale = function(scale){
  14326. var wasUniform = this.scale.x === this.scale.y === this.scale.z;
  14327. var isUniform = scale.x === scale.y === scale.z;
  14328. if(!(wasUniform && isUniform)){
  14329. // Non-uniform scaling. Need to update normals.
  14330. this.updateNormals();
  14331. }
  14332. this.scale.copy(scale);
  14333. this.updateAABB();
  14334. this.updateBoundingSphereRadius();
  14335. };
  14336. /**
  14337. * Compute the normals of the faces. Will save in the .normals array.
  14338. * @method updateNormals
  14339. */
  14340. Trimesh.prototype.updateNormals = function(){
  14341. var n = computeNormals_n;
  14342. // Generate normals
  14343. var normals = this.normals;
  14344. for(var i=0; i < this.indices.length / 3; i++){
  14345. var i3 = i * 3;
  14346. var a = this.indices[i3],
  14347. b = this.indices[i3 + 1],
  14348. c = this.indices[i3 + 2];
  14349. this.getVertex(a, va);
  14350. this.getVertex(b, vb);
  14351. this.getVertex(c, vc);
  14352. Trimesh.computeNormal(vb, va, vc, n);
  14353. normals[i3] = n.x;
  14354. normals[i3 + 1] = n.y;
  14355. normals[i3 + 2] = n.z;
  14356. }
  14357. };
  14358. /**
  14359. * Update the .edges property
  14360. * @method updateEdges
  14361. */
  14362. Trimesh.prototype.updateEdges = function(){
  14363. var edges = {};
  14364. var add = function(indexA, indexB){
  14365. var key = a < b ? a + '_' + b : b + '_' + a;
  14366. edges[key] = true;
  14367. };
  14368. for(var i=0; i < this.indices.length / 3; i++){
  14369. var i3 = i * 3;
  14370. var a = this.indices[i3],
  14371. b = this.indices[i3 + 1],
  14372. c = this.indices[i3 + 2];
  14373. add(a,b);
  14374. add(b,c);
  14375. add(c,a);
  14376. }
  14377. var keys = Object.keys(edges);
  14378. this.edges = new Int16Array(keys.length * 2);
  14379. for (var i = 0; i < keys.length; i++) {
  14380. var indices = keys[i].split('_');
  14381. this.edges[2 * i] = parseInt(indices[0], 10);
  14382. this.edges[2 * i + 1] = parseInt(indices[1], 10);
  14383. }
  14384. };
  14385. /**
  14386. * Get an edge vertex
  14387. * @method getEdgeVertex
  14388. * @param {number} edgeIndex
  14389. * @param {number} firstOrSecond 0 or 1, depending on which one of the vertices you need.
  14390. * @param {Vec3} vertexStore Where to store the result
  14391. */
  14392. Trimesh.prototype.getEdgeVertex = function(edgeIndex, firstOrSecond, vertexStore){
  14393. var vertexIndex = this.edges[edgeIndex * 2 + (firstOrSecond ? 1 : 0)];
  14394. this.getVertex(vertexIndex, vertexStore);
  14395. };
  14396. var getEdgeVector_va = new Vec3();
  14397. var getEdgeVector_vb = new Vec3();
  14398. /**
  14399. * Get a vector along an edge.
  14400. * @method getEdgeVector
  14401. * @param {number} edgeIndex
  14402. * @param {Vec3} vectorStore
  14403. */
  14404. Trimesh.prototype.getEdgeVector = function(edgeIndex, vectorStore){
  14405. var va = getEdgeVector_va;
  14406. var vb = getEdgeVector_vb;
  14407. this.getEdgeVertex(edgeIndex, 0, va);
  14408. this.getEdgeVertex(edgeIndex, 1, vb);
  14409. vb.vsub(va, vectorStore);
  14410. };
  14411. /**
  14412. * Get face normal given 3 vertices
  14413. * @static
  14414. * @method computeNormal
  14415. * @param {Vec3} va
  14416. * @param {Vec3} vb
  14417. * @param {Vec3} vc
  14418. * @param {Vec3} target
  14419. */
  14420. var cb = new Vec3();
  14421. var ab = new Vec3();
  14422. Trimesh.computeNormal = function ( va, vb, vc, target ) {
  14423. vb.vsub(va,ab);
  14424. vc.vsub(vb,cb);
  14425. cb.cross(ab,target);
  14426. if ( !target.isZero() ) {
  14427. target.normalize();
  14428. }
  14429. };
  14430. var va = new Vec3();
  14431. var vb = new Vec3();
  14432. var vc = new Vec3();
  14433. /**
  14434. * Get vertex i.
  14435. * @method getVertex
  14436. * @param {number} i
  14437. * @param {Vec3} out
  14438. * @return {Vec3} The "out" vector object
  14439. */
  14440. Trimesh.prototype.getVertex = function(i, out){
  14441. var scale = this.scale;
  14442. this._getUnscaledVertex(i, out);
  14443. out.x *= scale.x;
  14444. out.y *= scale.y;
  14445. out.z *= scale.z;
  14446. return out;
  14447. };
  14448. /**
  14449. * Get raw vertex i
  14450. * @private
  14451. * @method _getUnscaledVertex
  14452. * @param {number} i
  14453. * @param {Vec3} out
  14454. * @return {Vec3} The "out" vector object
  14455. */
  14456. Trimesh.prototype._getUnscaledVertex = function(i, out){
  14457. var i3 = i * 3;
  14458. var vertices = this.vertices;
  14459. return out.set(
  14460. vertices[i3],
  14461. vertices[i3 + 1],
  14462. vertices[i3 + 2]
  14463. );
  14464. };
  14465. /**
  14466. * Get a vertex from the trimesh,transformed by the given position and quaternion.
  14467. * @method getWorldVertex
  14468. * @param {number} i
  14469. * @param {Vec3} pos
  14470. * @param {Quaternion} quat
  14471. * @param {Vec3} out
  14472. * @return {Vec3} The "out" vector object
  14473. */
  14474. Trimesh.prototype.getWorldVertex = function(i, pos, quat, out){
  14475. this.getVertex(i, out);
  14476. Transform.pointToWorldFrame(pos, quat, out, out);
  14477. return out;
  14478. };
  14479. /**
  14480. * Get the three vertices for triangle i.
  14481. * @method getTriangleVertices
  14482. * @param {number} i
  14483. * @param {Vec3} a
  14484. * @param {Vec3} b
  14485. * @param {Vec3} c
  14486. */
  14487. Trimesh.prototype.getTriangleVertices = function(i, a, b, c){
  14488. var i3 = i * 3;
  14489. this.getVertex(this.indices[i3], a);
  14490. this.getVertex(this.indices[i3 + 1], b);
  14491. this.getVertex(this.indices[i3 + 2], c);
  14492. };
  14493. /**
  14494. * Compute the normal of triangle i.
  14495. * @method getNormal
  14496. * @param {Number} i
  14497. * @param {Vec3} target
  14498. * @return {Vec3} The "target" vector object
  14499. */
  14500. Trimesh.prototype.getNormal = function(i, target){
  14501. var i3 = i * 3;
  14502. return target.set(
  14503. this.normals[i3],
  14504. this.normals[i3 + 1],
  14505. this.normals[i3 + 2]
  14506. );
  14507. };
  14508. var cli_aabb = new AABB();
  14509. /**
  14510. * @method calculateLocalInertia
  14511. * @param {Number} mass
  14512. * @param {Vec3} target
  14513. * @return {Vec3} The "target" vector object
  14514. */
  14515. Trimesh.prototype.calculateLocalInertia = function(mass,target){
  14516. // Approximate with box inertia
  14517. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  14518. this.computeLocalAABB(cli_aabb);
  14519. var x = cli_aabb.upperBound.x - cli_aabb.lowerBound.x,
  14520. y = cli_aabb.upperBound.y - cli_aabb.lowerBound.y,
  14521. z = cli_aabb.upperBound.z - cli_aabb.lowerBound.z;
  14522. return target.set(
  14523. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z ),
  14524. 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z ),
  14525. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x )
  14526. );
  14527. };
  14528. var computeLocalAABB_worldVert = new Vec3();
  14529. /**
  14530. * Compute the local AABB for the trimesh
  14531. * @method computeLocalAABB
  14532. * @param {AABB} aabb
  14533. */
  14534. Trimesh.prototype.computeLocalAABB = function(aabb){
  14535. var l = aabb.lowerBound,
  14536. u = aabb.upperBound,
  14537. n = this.vertices.length,
  14538. vertices = this.vertices,
  14539. v = computeLocalAABB_worldVert;
  14540. this.getVertex(0, v);
  14541. l.copy(v);
  14542. u.copy(v);
  14543. for(var i=0; i !== n; i++){
  14544. this.getVertex(i, v);
  14545. if(v.x < l.x){
  14546. l.x = v.x;
  14547. } else if(v.x > u.x){
  14548. u.x = v.x;
  14549. }
  14550. if(v.y < l.y){
  14551. l.y = v.y;
  14552. } else if(v.y > u.y){
  14553. u.y = v.y;
  14554. }
  14555. if(v.z < l.z){
  14556. l.z = v.z;
  14557. } else if(v.z > u.z){
  14558. u.z = v.z;
  14559. }
  14560. }
  14561. };
  14562. /**
  14563. * Update the .aabb property
  14564. * @method updateAABB
  14565. */
  14566. Trimesh.prototype.updateAABB = function(){
  14567. this.computeLocalAABB(this.aabb);
  14568. };
  14569. /**
  14570. * Will update the .boundingSphereRadius property
  14571. * @method updateBoundingSphereRadius
  14572. */
  14573. Trimesh.prototype.updateBoundingSphereRadius = function(){
  14574. // Assume points are distributed with local (0,0,0) as center
  14575. var max2 = 0;
  14576. var vertices = this.vertices;
  14577. var v = new Vec3();
  14578. for(var i=0, N=vertices.length / 3; i !== N; i++) {
  14579. this.getVertex(i, v);
  14580. var norm2 = v.norm2();
  14581. if(norm2 > max2){
  14582. max2 = norm2;
  14583. }
  14584. }
  14585. this.boundingSphereRadius = Math.sqrt(max2);
  14586. };
  14587. var tempWorldVertex = new Vec3();
  14588. var calculateWorldAABB_frame = new Transform();
  14589. var calculateWorldAABB_aabb = new AABB();
  14590. /**
  14591. * @method calculateWorldAABB
  14592. * @param {Vec3} pos
  14593. * @param {Quaternion} quat
  14594. * @param {Vec3} min
  14595. * @param {Vec3} max
  14596. */
  14597. Trimesh.prototype.calculateWorldAABB = function(pos,quat,min,max){
  14598. /*
  14599. var n = this.vertices.length / 3,
  14600. verts = this.vertices;
  14601. var minx,miny,minz,maxx,maxy,maxz;
  14602. var v = tempWorldVertex;
  14603. for(var i=0; i<n; i++){
  14604. this.getVertex(i, v);
  14605. quat.vmult(v, v);
  14606. pos.vadd(v, v);
  14607. if (v.x < minx || minx===undefined){
  14608. minx = v.x;
  14609. } else if(v.x > maxx || maxx===undefined){
  14610. maxx = v.x;
  14611. }
  14612. if (v.y < miny || miny===undefined){
  14613. miny = v.y;
  14614. } else if(v.y > maxy || maxy===undefined){
  14615. maxy = v.y;
  14616. }
  14617. if (v.z < minz || minz===undefined){
  14618. minz = v.z;
  14619. } else if(v.z > maxz || maxz===undefined){
  14620. maxz = v.z;
  14621. }
  14622. }
  14623. min.set(minx,miny,minz);
  14624. max.set(maxx,maxy,maxz);
  14625. */
  14626. // Faster approximation using local AABB
  14627. var frame = calculateWorldAABB_frame;
  14628. var result = calculateWorldAABB_aabb;
  14629. frame.position = pos;
  14630. frame.quaternion = quat;
  14631. this.aabb.toWorldFrame(frame, result);
  14632. min.copy(result.lowerBound);
  14633. max.copy(result.upperBound);
  14634. };
  14635. /**
  14636. * Get approximate volume
  14637. * @method volume
  14638. * @return {Number}
  14639. */
  14640. Trimesh.prototype.volume = function(){
  14641. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  14642. };
  14643. /**
  14644. * Create a Trimesh instance, shaped as a torus.
  14645. * @static
  14646. * @method createTorus
  14647. * @param {number} [radius=1]
  14648. * @param {number} [tube=0.5]
  14649. * @param {number} [radialSegments=8]
  14650. * @param {number} [tubularSegments=6]
  14651. * @param {number} [arc=6.283185307179586]
  14652. * @return {Trimesh} A torus
  14653. */
  14654. Trimesh.createTorus = function (radius, tube, radialSegments, tubularSegments, arc) {
  14655. radius = radius || 1;
  14656. tube = tube || 0.5;
  14657. radialSegments = radialSegments || 8;
  14658. tubularSegments = tubularSegments || 6;
  14659. arc = arc || Math.PI * 2;
  14660. var vertices = [];
  14661. var indices = [];
  14662. for ( var j = 0; j <= radialSegments; j ++ ) {
  14663. for ( var i = 0; i <= tubularSegments; i ++ ) {
  14664. var u = i / tubularSegments * arc;
  14665. var v = j / radialSegments * Math.PI * 2;
  14666. var x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
  14667. var y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
  14668. var z = tube * Math.sin( v );
  14669. vertices.push( x, y, z );
  14670. }
  14671. }
  14672. for ( var j = 1; j <= radialSegments; j ++ ) {
  14673. for ( var i = 1; i <= tubularSegments; i ++ ) {
  14674. var a = ( tubularSegments + 1 ) * j + i - 1;
  14675. var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
  14676. var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
  14677. var d = ( tubularSegments + 1 ) * j + i;
  14678. indices.push(a, b, d);
  14679. indices.push(b, c, d);
  14680. }
  14681. }
  14682. return new Trimesh(vertices, indices);
  14683. };
  14684. },{"../collision/AABB":24,"../math/Quaternion":50,"../math/Transform":51,"../math/Vec3":52,"../utils/Octree":72,"./Shape":65}],68:[function(require,module,exports){
  14685. module.exports = GSSolver;
  14686. var Vec3 = require('../math/Vec3');
  14687. var Quaternion = require('../math/Quaternion');
  14688. var Solver = require('./Solver');
  14689. /**
  14690. * Constraint equation Gauss-Seidel solver.
  14691. * @class GSSolver
  14692. * @constructor
  14693. * @todo The spook parameters should be specified for each constraint, not globally.
  14694. * @author schteppe / https://github.com/schteppe
  14695. * @see https://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf
  14696. * @extends Solver
  14697. */
  14698. function GSSolver(){
  14699. Solver.call(this);
  14700. /**
  14701. * The number of solver iterations determines quality of the constraints in the world. The more iterations, the more correct simulation. More iterations need more computations though. If you have a large gravity force in your world, you will need more iterations.
  14702. * @property iterations
  14703. * @type {Number}
  14704. * @todo write more about solver and iterations in the wiki
  14705. */
  14706. this.iterations = 10;
  14707. /**
  14708. * When tolerance is reached, the system is assumed to be converged.
  14709. * @property tolerance
  14710. * @type {Number}
  14711. */
  14712. this.tolerance = 1e-7;
  14713. }
  14714. GSSolver.prototype = new Solver();
  14715. var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
  14716. var GSSolver_solve_invCs = [];
  14717. var GSSolver_solve_Bs = [];
  14718. GSSolver.prototype.solve = function(dt,world){
  14719. var iter = 0,
  14720. maxIter = this.iterations,
  14721. tolSquared = this.tolerance*this.tolerance,
  14722. equations = this.equations,
  14723. Neq = equations.length,
  14724. bodies = world.bodies,
  14725. Nbodies = bodies.length,
  14726. h = dt,
  14727. q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
  14728. // Update solve mass
  14729. if(Neq !== 0){
  14730. for(var i=0; i!==Nbodies; i++){
  14731. bodies[i].updateSolveMassProperties();
  14732. }
  14733. }
  14734. // Things that does not change during iteration can be computed once
  14735. var invCs = GSSolver_solve_invCs,
  14736. Bs = GSSolver_solve_Bs,
  14737. lambda = GSSolver_solve_lambda;
  14738. invCs.length = Neq;
  14739. Bs.length = Neq;
  14740. lambda.length = Neq;
  14741. for(var i=0; i!==Neq; i++){
  14742. var c = equations[i];
  14743. lambda[i] = 0.0;
  14744. Bs[i] = c.computeB(h);
  14745. invCs[i] = 1.0 / c.computeC();
  14746. }
  14747. if(Neq !== 0){
  14748. // Reset vlambda
  14749. for(var i=0; i!==Nbodies; i++){
  14750. var b=bodies[i],
  14751. vlambda=b.vlambda,
  14752. wlambda=b.wlambda;
  14753. vlambda.set(0,0,0);
  14754. wlambda.set(0,0,0);
  14755. }
  14756. // Iterate over equations
  14757. for(iter=0; iter!==maxIter; iter++){
  14758. // Accumulate the total error for each iteration.
  14759. deltalambdaTot = 0.0;
  14760. for(var j=0; j!==Neq; j++){
  14761. var c = equations[j];
  14762. // Compute iteration
  14763. B = Bs[j];
  14764. invC = invCs[j];
  14765. lambdaj = lambda[j];
  14766. GWlambda = c.computeGWlambda();
  14767. deltalambda = invC * ( B - GWlambda - c.eps * lambdaj );
  14768. // Clamp if we are not within the min/max interval
  14769. if(lambdaj + deltalambda < c.minForce){
  14770. deltalambda = c.minForce - lambdaj;
  14771. } else if(lambdaj + deltalambda > c.maxForce){
  14772. deltalambda = c.maxForce - lambdaj;
  14773. }
  14774. lambda[j] += deltalambda;
  14775. deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)
  14776. c.addToWlambda(deltalambda);
  14777. }
  14778. // If the total error is small enough - stop iterate
  14779. if(deltalambdaTot*deltalambdaTot < tolSquared){
  14780. break;
  14781. }
  14782. }
  14783. // Add result to velocity
  14784. for(var i=0; i!==Nbodies; i++){
  14785. var b=bodies[i],
  14786. v=b.velocity,
  14787. w=b.angularVelocity;
  14788. b.vlambda.vmul(b.linearFactor, b.vlambda);
  14789. v.vadd(b.vlambda, v);
  14790. b.wlambda.vmul(b.angularFactor, b.wlambda);
  14791. w.vadd(b.wlambda, w);
  14792. }
  14793. // Set the .multiplier property of each equation
  14794. var l = equations.length;
  14795. var invDt = 1 / h;
  14796. while(l--){
  14797. equations[l].multiplier = lambda[l] * invDt;
  14798. }
  14799. }
  14800. return iter;
  14801. };
  14802. },{"../math/Quaternion":50,"../math/Vec3":52,"./Solver":69}],69:[function(require,module,exports){
  14803. module.exports = Solver;
  14804. /**
  14805. * Constraint equation solver base class.
  14806. * @class Solver
  14807. * @constructor
  14808. * @author schteppe / https://github.com/schteppe
  14809. */
  14810. function Solver(){
  14811. /**
  14812. * All equations to be solved
  14813. * @property {Array} equations
  14814. */
  14815. this.equations = [];
  14816. }
  14817. /**
  14818. * Should be implemented in subclasses!
  14819. * @method solve
  14820. * @param {Number} dt
  14821. * @param {World} world
  14822. */
  14823. Solver.prototype.solve = function(dt,world){
  14824. // Should return the number of iterations done!
  14825. return 0;
  14826. };
  14827. /**
  14828. * Add an equation
  14829. * @method addEquation
  14830. * @param {Equation} eq
  14831. */
  14832. Solver.prototype.addEquation = function(eq){
  14833. if (eq.enabled) {
  14834. this.equations.push(eq);
  14835. }
  14836. };
  14837. /**
  14838. * Remove an equation
  14839. * @method removeEquation
  14840. * @param {Equation} eq
  14841. */
  14842. Solver.prototype.removeEquation = function(eq){
  14843. var eqs = this.equations;
  14844. var i = eqs.indexOf(eq);
  14845. if(i !== -1){
  14846. eqs.splice(i,1);
  14847. }
  14848. };
  14849. /**
  14850. * Add all equations
  14851. * @method removeAllEquations
  14852. */
  14853. Solver.prototype.removeAllEquations = function(){
  14854. this.equations.length = 0;
  14855. };
  14856. },{}],70:[function(require,module,exports){
  14857. module.exports = SplitSolver;
  14858. var Vec3 = require('../math/Vec3');
  14859. var Quaternion = require('../math/Quaternion');
  14860. var Solver = require('./Solver');
  14861. var Body = require('../objects/Body');
  14862. /**
  14863. * Splits the equations into islands and solves them independently. Can improve performance.
  14864. * @class SplitSolver
  14865. * @constructor
  14866. * @extends Solver
  14867. * @param {Solver} subsolver
  14868. */
  14869. function SplitSolver(subsolver){
  14870. Solver.call(this);
  14871. this.iterations = 10;
  14872. this.tolerance = 1e-7;
  14873. this.subsolver = subsolver;
  14874. this.nodes = [];
  14875. this.nodePool = [];
  14876. // Create needed nodes, reuse if possible
  14877. while(this.nodePool.length < 128){
  14878. this.nodePool.push(this.createNode());
  14879. }
  14880. }
  14881. SplitSolver.prototype = new Solver();
  14882. // Returns the number of subsystems
  14883. var SplitSolver_solve_nodes = []; // All allocated node objects
  14884. var SplitSolver_solve_nodePool = []; // All allocated node objects
  14885. var SplitSolver_solve_eqs = []; // Temp array
  14886. var SplitSolver_solve_bds = []; // Temp array
  14887. var SplitSolver_solve_dummyWorld = {bodies:[]}; // Temp object
  14888. var STATIC = Body.STATIC;
  14889. function getUnvisitedNode(nodes){
  14890. var Nnodes = nodes.length;
  14891. for(var i=0; i!==Nnodes; i++){
  14892. var node = nodes[i];
  14893. if(!node.visited && !(node.body.type & STATIC)){
  14894. return node;
  14895. }
  14896. }
  14897. return false;
  14898. }
  14899. var queue = [];
  14900. function bfs(root,visitFunc,bds,eqs){
  14901. queue.push(root);
  14902. root.visited = true;
  14903. visitFunc(root,bds,eqs);
  14904. while(queue.length) {
  14905. var node = queue.pop();
  14906. // Loop over unvisited child nodes
  14907. var child;
  14908. while((child = getUnvisitedNode(node.children))) {
  14909. child.visited = true;
  14910. visitFunc(child,bds,eqs);
  14911. queue.push(child);
  14912. }
  14913. }
  14914. }
  14915. function visitFunc(node,bds,eqs){
  14916. bds.push(node.body);
  14917. var Neqs = node.eqs.length;
  14918. for(var i=0; i!==Neqs; i++){
  14919. var eq = node.eqs[i];
  14920. if(eqs.indexOf(eq) === -1){
  14921. eqs.push(eq);
  14922. }
  14923. }
  14924. }
  14925. SplitSolver.prototype.createNode = function(){
  14926. return { body:null, children:[], eqs:[], visited:false };
  14927. };
  14928. /**
  14929. * Solve the subsystems
  14930. * @method solve
  14931. * @param {Number} dt
  14932. * @param {World} world
  14933. */
  14934. SplitSolver.prototype.solve = function(dt,world){
  14935. var nodes=SplitSolver_solve_nodes,
  14936. nodePool=this.nodePool,
  14937. bodies=world.bodies,
  14938. equations=this.equations,
  14939. Neq=equations.length,
  14940. Nbodies=bodies.length,
  14941. subsolver=this.subsolver;
  14942. // Create needed nodes, reuse if possible
  14943. while(nodePool.length < Nbodies){
  14944. nodePool.push(this.createNode());
  14945. }
  14946. nodes.length = Nbodies;
  14947. for (var i = 0; i < Nbodies; i++) {
  14948. nodes[i] = nodePool[i];
  14949. }
  14950. // Reset node values
  14951. for(var i=0; i!==Nbodies; i++){
  14952. var node = nodes[i];
  14953. node.body = bodies[i];
  14954. node.children.length = 0;
  14955. node.eqs.length = 0;
  14956. node.visited = false;
  14957. }
  14958. for(var k=0; k!==Neq; k++){
  14959. var eq=equations[k],
  14960. i=bodies.indexOf(eq.bi),
  14961. j=bodies.indexOf(eq.bj),
  14962. ni=nodes[i],
  14963. nj=nodes[j];
  14964. ni.children.push(nj);
  14965. ni.eqs.push(eq);
  14966. nj.children.push(ni);
  14967. nj.eqs.push(eq);
  14968. }
  14969. var child, n=0, eqs=SplitSolver_solve_eqs;
  14970. subsolver.tolerance = this.tolerance;
  14971. subsolver.iterations = this.iterations;
  14972. var dummyWorld = SplitSolver_solve_dummyWorld;
  14973. while((child = getUnvisitedNode(nodes))){
  14974. eqs.length = 0;
  14975. dummyWorld.bodies.length = 0;
  14976. bfs(child, visitFunc, dummyWorld.bodies, eqs);
  14977. var Neqs = eqs.length;
  14978. eqs = eqs.sort(sortById);
  14979. for(var i=0; i!==Neqs; i++){
  14980. subsolver.addEquation(eqs[i]);
  14981. }
  14982. var iter = subsolver.solve(dt,dummyWorld);
  14983. subsolver.removeAllEquations();
  14984. n++;
  14985. }
  14986. return n;
  14987. };
  14988. function sortById(a, b){
  14989. return b.id - a.id;
  14990. }
  14991. },{"../math/Quaternion":50,"../math/Vec3":52,"../objects/Body":53,"./Solver":69}],71:[function(require,module,exports){
  14992. /**
  14993. * Base class for objects that dispatches events.
  14994. * @class EventTarget
  14995. * @constructor
  14996. */
  14997. var EventTarget = function () {
  14998. };
  14999. module.exports = EventTarget;
  15000. EventTarget.prototype = {
  15001. constructor: EventTarget,
  15002. /**
  15003. * Add an event listener
  15004. * @method addEventListener
  15005. * @param {String} type
  15006. * @param {Function} listener
  15007. * @return {EventTarget} The self object, for chainability.
  15008. */
  15009. addEventListener: function ( type, listener ) {
  15010. if ( this._listeners === undefined ){ this._listeners = {}; }
  15011. var listeners = this._listeners;
  15012. if ( listeners[ type ] === undefined ) {
  15013. listeners[ type ] = [];
  15014. }
  15015. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  15016. listeners[ type ].push( listener );
  15017. }
  15018. return this;
  15019. },
  15020. /**
  15021. * Check if an event listener is added
  15022. * @method hasEventListener
  15023. * @param {String} type
  15024. * @param {Function} listener
  15025. * @return {Boolean}
  15026. */
  15027. hasEventListener: function ( type, listener ) {
  15028. if ( this._listeners === undefined ){ return false; }
  15029. var listeners = this._listeners;
  15030. if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
  15031. return true;
  15032. }
  15033. return false;
  15034. },
  15035. /**
  15036. * Check if any event listener of the given type is added
  15037. * @method hasAnyEventListener
  15038. * @param {String} type
  15039. * @return {Boolean}
  15040. */
  15041. hasAnyEventListener: function ( type ) {
  15042. if ( this._listeners === undefined ){ return false; }
  15043. var listeners = this._listeners;
  15044. return ( listeners[ type ] !== undefined );
  15045. },
  15046. /**
  15047. * Remove an event listener
  15048. * @method removeEventListener
  15049. * @param {String} type
  15050. * @param {Function} listener
  15051. * @return {EventTarget} The self object, for chainability.
  15052. */
  15053. removeEventListener: function ( type, listener ) {
  15054. if ( this._listeners === undefined ){ return this; }
  15055. var listeners = this._listeners;
  15056. if ( listeners[type] === undefined ){ return this; }
  15057. var index = listeners[ type ].indexOf( listener );
  15058. if ( index !== - 1 ) {
  15059. listeners[ type ].splice( index, 1 );
  15060. }
  15061. return this;
  15062. },
  15063. /**
  15064. * Emit an event.
  15065. * @method dispatchEvent
  15066. * @param {Object} event
  15067. * @param {String} event.type
  15068. * @return {EventTarget} The self object, for chainability.
  15069. */
  15070. dispatchEvent: function ( event ) {
  15071. if ( this._listeners === undefined ){ return this; }
  15072. var listeners = this._listeners;
  15073. var listenerArray = listeners[ event.type ];
  15074. if ( listenerArray !== undefined ) {
  15075. event.target = this;
  15076. for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
  15077. listenerArray[ i ].call( this, event );
  15078. }
  15079. }
  15080. return this;
  15081. }
  15082. };
  15083. },{}],72:[function(require,module,exports){
  15084. var AABB = require('../collision/AABB');
  15085. var Vec3 = require('../math/Vec3');
  15086. module.exports = Octree;
  15087. /**
  15088. * @class OctreeNode
  15089. * @param {object} [options]
  15090. * @param {Octree} [options.root]
  15091. * @param {AABB} [options.aabb]
  15092. */
  15093. function OctreeNode(options){
  15094. options = options || {};
  15095. /**
  15096. * The root node
  15097. * @property {OctreeNode} root
  15098. */
  15099. this.root = options.root || null;
  15100. /**
  15101. * Boundary of this node
  15102. * @property {AABB} aabb
  15103. */
  15104. this.aabb = options.aabb ? options.aabb.clone() : new AABB();
  15105. /**
  15106. * Contained data at the current node level.
  15107. * @property {Array} data
  15108. */
  15109. this.data = [];
  15110. /**
  15111. * Children to this node
  15112. * @property {Array} children
  15113. */
  15114. this.children = [];
  15115. }
  15116. /**
  15117. * @class Octree
  15118. * @param {AABB} aabb The total AABB of the tree
  15119. * @param {object} [options]
  15120. * @param {number} [options.maxDepth=8]
  15121. * @extends OctreeNode
  15122. */
  15123. function Octree(aabb, options){
  15124. options = options || {};
  15125. options.root = null;
  15126. options.aabb = aabb;
  15127. OctreeNode.call(this, options);
  15128. /**
  15129. * Maximum subdivision depth
  15130. * @property {number} maxDepth
  15131. */
  15132. this.maxDepth = typeof(options.maxDepth) !== 'undefined' ? options.maxDepth : 8;
  15133. }
  15134. Octree.prototype = new OctreeNode();
  15135. OctreeNode.prototype.reset = function(aabb, options){
  15136. this.children.length = this.data.length = 0;
  15137. };
  15138. /**
  15139. * Insert data into this node
  15140. * @method insert
  15141. * @param {AABB} aabb
  15142. * @param {object} elementData
  15143. * @return {boolean} True if successful, otherwise false
  15144. */
  15145. OctreeNode.prototype.insert = function(aabb, elementData, level){
  15146. var nodeData = this.data;
  15147. level = level || 0;
  15148. // Ignore objects that do not belong in this node
  15149. if (!this.aabb.contains(aabb)){
  15150. return false; // object cannot be added
  15151. }
  15152. var children = this.children;
  15153. if(level < (this.maxDepth || this.root.maxDepth)){
  15154. // Subdivide if there are no children yet
  15155. var subdivided = false;
  15156. if (!children.length){
  15157. this.subdivide();
  15158. subdivided = true;
  15159. }
  15160. // add to whichever node will accept it
  15161. for (var i = 0; i !== 8; i++) {
  15162. if (children[i].insert(aabb, elementData, level + 1)){
  15163. return true;
  15164. }
  15165. }
  15166. if(subdivided){
  15167. // No children accepted! Might as well just remove em since they contain none
  15168. children.length = 0;
  15169. }
  15170. }
  15171. // Too deep, or children didnt want it. add it in current node
  15172. nodeData.push(elementData);
  15173. return true;
  15174. };
  15175. var halfDiagonal = new Vec3();
  15176. /**
  15177. * Create 8 equally sized children nodes and put them in the .children array.
  15178. * @method subdivide
  15179. */
  15180. OctreeNode.prototype.subdivide = function() {
  15181. var aabb = this.aabb;
  15182. var l = aabb.lowerBound;
  15183. var u = aabb.upperBound;
  15184. var children = this.children;
  15185. children.push(
  15186. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,0) }) }),
  15187. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,0) }) }),
  15188. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,0) }) }),
  15189. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,1) }) }),
  15190. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,1) }) }),
  15191. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,1) }) }),
  15192. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,1) }) }),
  15193. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,0) }) })
  15194. );
  15195. u.vsub(l, halfDiagonal);
  15196. halfDiagonal.scale(0.5, halfDiagonal);
  15197. var root = this.root || this;
  15198. for (var i = 0; i !== 8; i++) {
  15199. var child = children[i];
  15200. // Set current node as root
  15201. child.root = root;
  15202. // Compute bounds
  15203. var lowerBound = child.aabb.lowerBound;
  15204. lowerBound.x *= halfDiagonal.x;
  15205. lowerBound.y *= halfDiagonal.y;
  15206. lowerBound.z *= halfDiagonal.z;
  15207. lowerBound.vadd(l, lowerBound);
  15208. // Upper bound is always lower bound + halfDiagonal
  15209. lowerBound.vadd(halfDiagonal, child.aabb.upperBound);
  15210. }
  15211. };
  15212. /**
  15213. * Get all data, potentially within an AABB
  15214. * @method aabbQuery
  15215. * @param {AABB} aabb
  15216. * @param {array} result
  15217. * @return {array} The "result" object
  15218. */
  15219. OctreeNode.prototype.aabbQuery = function(aabb, result) {
  15220. var nodeData = this.data;
  15221. // abort if the range does not intersect this node
  15222. // if (!this.aabb.overlaps(aabb)){
  15223. // return result;
  15224. // }
  15225. // Add objects at this level
  15226. // Array.prototype.push.apply(result, nodeData);
  15227. // Add child data
  15228. // @todo unwrap recursion into a queue / loop, that's faster in JS
  15229. var children = this.children;
  15230. // for (var i = 0, N = this.children.length; i !== N; i++) {
  15231. // children[i].aabbQuery(aabb, result);
  15232. // }
  15233. var queue = [this];
  15234. while (queue.length) {
  15235. var node = queue.pop();
  15236. if (node.aabb.overlaps(aabb)){
  15237. Array.prototype.push.apply(result, node.data);
  15238. }
  15239. Array.prototype.push.apply(queue, node.children);
  15240. }
  15241. return result;
  15242. };
  15243. var tmpAABB = new AABB();
  15244. /**
  15245. * Get all data, potentially intersected by a ray.
  15246. * @method rayQuery
  15247. * @param {Ray} ray
  15248. * @param {Transform} treeTransform
  15249. * @param {array} result
  15250. * @return {array} The "result" object
  15251. */
  15252. OctreeNode.prototype.rayQuery = function(ray, treeTransform, result) {
  15253. // Use aabb query for now.
  15254. // @todo implement real ray query which needs less lookups
  15255. ray.getAABB(tmpAABB);
  15256. tmpAABB.toLocalFrame(treeTransform, tmpAABB);
  15257. this.aabbQuery(tmpAABB, result);
  15258. return result;
  15259. };
  15260. /**
  15261. * @method removeEmptyNodes
  15262. */
  15263. OctreeNode.prototype.removeEmptyNodes = function() {
  15264. var queue = [this];
  15265. while (queue.length) {
  15266. var node = queue.pop();
  15267. for (var i = node.children.length - 1; i >= 0; i--) {
  15268. if(!node.children[i].data.length){
  15269. node.children.splice(i, 1);
  15270. }
  15271. }
  15272. Array.prototype.push.apply(queue, node.children);
  15273. }
  15274. };
  15275. },{"../collision/AABB":24,"../math/Vec3":52}],73:[function(require,module,exports){
  15276. module.exports = Pool;
  15277. /**
  15278. * For pooling objects that can be reused.
  15279. * @class Pool
  15280. * @constructor
  15281. */
  15282. function Pool(){
  15283. /**
  15284. * The pooled objects
  15285. * @property {Array} objects
  15286. */
  15287. this.objects = [];
  15288. /**
  15289. * Constructor of the objects
  15290. * @property {mixed} type
  15291. */
  15292. this.type = Object;
  15293. }
  15294. /**
  15295. * Release an object after use
  15296. * @method release
  15297. * @param {Object} obj
  15298. */
  15299. Pool.prototype.release = function(){
  15300. var Nargs = arguments.length;
  15301. for(var i=0; i!==Nargs; i++){
  15302. this.objects.push(arguments[i]);
  15303. }
  15304. return this;
  15305. };
  15306. /**
  15307. * Get an object
  15308. * @method get
  15309. * @return {mixed}
  15310. */
  15311. Pool.prototype.get = function(){
  15312. if(this.objects.length===0){
  15313. return this.constructObject();
  15314. } else {
  15315. return this.objects.pop();
  15316. }
  15317. };
  15318. /**
  15319. * Construct an object. Should be implmented in each subclass.
  15320. * @method constructObject
  15321. * @return {mixed}
  15322. */
  15323. Pool.prototype.constructObject = function(){
  15324. throw new Error("constructObject() not implemented in this Pool subclass yet!");
  15325. };
  15326. /**
  15327. * @method resize
  15328. * @param {number} size
  15329. * @return {Pool} Self, for chaining
  15330. */
  15331. Pool.prototype.resize = function (size) {
  15332. var objects = this.objects;
  15333. while (objects.length > size) {
  15334. objects.pop();
  15335. }
  15336. while (objects.length < size) {
  15337. objects.push(this.constructObject());
  15338. }
  15339. return this;
  15340. };
  15341. },{}],74:[function(require,module,exports){
  15342. module.exports = TupleDictionary;
  15343. /**
  15344. * @class TupleDictionary
  15345. * @constructor
  15346. */
  15347. function TupleDictionary() {
  15348. /**
  15349. * The data storage
  15350. * @property data
  15351. * @type {Object}
  15352. */
  15353. this.data = { keys:[] };
  15354. }
  15355. /**
  15356. * @method get
  15357. * @param {Number} i
  15358. * @param {Number} j
  15359. * @return {Number}
  15360. */
  15361. TupleDictionary.prototype.get = function(i, j) {
  15362. if (i > j) {
  15363. // swap
  15364. var temp = j;
  15365. j = i;
  15366. i = temp;
  15367. }
  15368. return this.data[i+'-'+j];
  15369. };
  15370. /**
  15371. * @method set
  15372. * @param {Number} i
  15373. * @param {Number} j
  15374. * @param {Number} value
  15375. */
  15376. TupleDictionary.prototype.set = function(i, j, value) {
  15377. if (i > j) {
  15378. var temp = j;
  15379. j = i;
  15380. i = temp;
  15381. }
  15382. var key = i+'-'+j;
  15383. // Check if key already exists
  15384. if(!this.get(i,j)){
  15385. this.data.keys.push(key);
  15386. }
  15387. this.data[key] = value;
  15388. };
  15389. /**
  15390. * @method reset
  15391. */
  15392. TupleDictionary.prototype.reset = function() {
  15393. var data = this.data,
  15394. keys = data.keys;
  15395. while(keys.length > 0){
  15396. var key = keys.pop();
  15397. delete data[key];
  15398. }
  15399. };
  15400. },{}],75:[function(require,module,exports){
  15401. function Utils(){}
  15402. module.exports = Utils;
  15403. /**
  15404. * Extend an options object with default values.
  15405. * @static
  15406. * @method defaults
  15407. * @param {object} options The options object. May be falsy: in this case, a new object is created and returned.
  15408. * @param {object} defaults An object containing default values.
  15409. * @return {object} The modified options object.
  15410. */
  15411. Utils.defaults = function(options, defaults){
  15412. options = options || {};
  15413. for(var key in defaults){
  15414. if(!(key in options)){
  15415. options[key] = defaults[key];
  15416. }
  15417. }
  15418. return options;
  15419. };
  15420. },{}],76:[function(require,module,exports){
  15421. module.exports = Vec3Pool;
  15422. var Vec3 = require('../math/Vec3');
  15423. var Pool = require('./Pool');
  15424. /**
  15425. * @class Vec3Pool
  15426. * @constructor
  15427. * @extends Pool
  15428. */
  15429. function Vec3Pool(){
  15430. Pool.call(this);
  15431. this.type = Vec3;
  15432. }
  15433. Vec3Pool.prototype = new Pool();
  15434. /**
  15435. * Construct a vector
  15436. * @method constructObject
  15437. * @return {Vec3}
  15438. */
  15439. Vec3Pool.prototype.constructObject = function(){
  15440. return new Vec3();
  15441. };
  15442. },{"../math/Vec3":52,"./Pool":73}],77:[function(require,module,exports){
  15443. module.exports = Narrowphase;
  15444. var AABB = require('../collision/AABB');
  15445. var Body = require('../objects/Body');
  15446. var Shape = require('../shapes/Shape');
  15447. var Ray = require('../collision/Ray');
  15448. var Vec3 = require('../math/Vec3');
  15449. var Transform = require('../math/Transform');
  15450. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  15451. var Quaternion = require('../math/Quaternion');
  15452. var Solver = require('../solver/Solver');
  15453. var Vec3Pool = require('../utils/Vec3Pool');
  15454. var ContactEquation = require('../equations/ContactEquation');
  15455. var FrictionEquation = require('../equations/FrictionEquation');
  15456. /**
  15457. * Helper class for the World. Generates ContactEquations.
  15458. * @class Narrowphase
  15459. * @constructor
  15460. * @todo Sphere-ConvexPolyhedron contacts
  15461. * @todo Contact reduction
  15462. * @todo should move methods to prototype
  15463. */
  15464. function Narrowphase(world){
  15465. /**
  15466. * Internal storage of pooled contact points.
  15467. * @property {Array} contactPointPool
  15468. */
  15469. this.contactPointPool = [];
  15470. this.frictionEquationPool = [];
  15471. this.result = [];
  15472. this.frictionResult = [];
  15473. /**
  15474. * Pooled vectors.
  15475. * @property {Vec3Pool} v3pool
  15476. */
  15477. this.v3pool = new Vec3Pool();
  15478. this.world = world;
  15479. this.currentContactMaterial = null;
  15480. /**
  15481. * @property {Boolean} enableFrictionReduction
  15482. */
  15483. this.enableFrictionReduction = false;
  15484. }
  15485. /**
  15486. * Make a contact object, by using the internal pool or creating a new one.
  15487. * @method createContactEquation
  15488. * @param {Body} bi
  15489. * @param {Body} bj
  15490. * @param {Shape} si
  15491. * @param {Shape} sj
  15492. * @param {Shape} overrideShapeA
  15493. * @param {Shape} overrideShapeB
  15494. * @return {ContactEquation}
  15495. */
  15496. Narrowphase.prototype.createContactEquation = function(bi, bj, si, sj, overrideShapeA, overrideShapeB){
  15497. var c;
  15498. if(this.contactPointPool.length){
  15499. c = this.contactPointPool.pop();
  15500. c.bi = bi;
  15501. c.bj = bj;
  15502. } else {
  15503. c = new ContactEquation(bi, bj);
  15504. }
  15505. c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  15506. var cm = this.currentContactMaterial;
  15507. c.restitution = cm.restitution;
  15508. c.setSpookParams(
  15509. cm.contactEquationStiffness,
  15510. cm.contactEquationRelaxation,
  15511. this.world.dt
  15512. );
  15513. var matA = si.material || bi.material;
  15514. var matB = sj.material || bj.material;
  15515. if(matA && matB && matA.restitution >= 0 && matB.restitution >= 0){
  15516. c.restitution = matA.restitution * matB.restitution;
  15517. }
  15518. c.si = overrideShapeA || si;
  15519. c.sj = overrideShapeB || sj;
  15520. return c;
  15521. };
  15522. Narrowphase.prototype.createFrictionEquationsFromContact = function(contactEquation, outArray){
  15523. var bodyA = contactEquation.bi;
  15524. var bodyB = contactEquation.bj;
  15525. var shapeA = contactEquation.si;
  15526. var shapeB = contactEquation.sj;
  15527. var world = this.world;
  15528. var cm = this.currentContactMaterial;
  15529. // If friction or restitution were specified in the material, use them
  15530. var friction = cm.friction;
  15531. var matA = shapeA.material || bodyA.material;
  15532. var matB = shapeB.material || bodyB.material;
  15533. if(matA && matB && matA.friction >= 0 && matB.friction >= 0){
  15534. friction = matA.friction * matB.friction;
  15535. }
  15536. if(friction > 0){
  15537. // Create 2 tangent equations
  15538. var mug = friction * world.gravity.length();
  15539. var reducedMass = (bodyA.invMass + bodyB.invMass);
  15540. if(reducedMass > 0){
  15541. reducedMass = 1/reducedMass;
  15542. }
  15543. var pool = this.frictionEquationPool;
  15544. var c1 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  15545. var c2 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  15546. c1.bi = c2.bi = bodyA;
  15547. c1.bj = c2.bj = bodyB;
  15548. c1.minForce = c2.minForce = -mug*reducedMass;
  15549. c1.maxForce = c2.maxForce = mug*reducedMass;
  15550. // Copy over the relative vectors
  15551. c1.ri.copy(contactEquation.ri);
  15552. c1.rj.copy(contactEquation.rj);
  15553. c2.ri.copy(contactEquation.ri);
  15554. c2.rj.copy(contactEquation.rj);
  15555. // Construct tangents
  15556. contactEquation.ni.tangents(c1.t, c2.t);
  15557. // Set spook params
  15558. c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  15559. c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  15560. c1.enabled = c2.enabled = contactEquation.enabled;
  15561. outArray.push(c1, c2);
  15562. return true;
  15563. }
  15564. return false;
  15565. };
  15566. var averageNormal = new Vec3();
  15567. var averageContactPointA = new Vec3();
  15568. var averageContactPointB = new Vec3();
  15569. // Take the average N latest contact point on the plane.
  15570. Narrowphase.prototype.createFrictionFromAverage = function(numContacts){
  15571. // The last contactEquation
  15572. var c = this.result[this.result.length - 1];
  15573. // Create the result: two "average" friction equations
  15574. if (!this.createFrictionEquationsFromContact(c, this.frictionResult) || numContacts === 1) {
  15575. return;
  15576. }
  15577. var f1 = this.frictionResult[this.frictionResult.length - 2];
  15578. var f2 = this.frictionResult[this.frictionResult.length - 1];
  15579. averageNormal.setZero();
  15580. averageContactPointA.setZero();
  15581. averageContactPointB.setZero();
  15582. var bodyA = c.bi;
  15583. var bodyB = c.bj;
  15584. for(var i=0; i!==numContacts; i++){
  15585. c = this.result[this.result.length - 1 - i];
  15586. if(c.bodyA !== bodyA){
  15587. averageNormal.vadd(c.ni, averageNormal);
  15588. averageContactPointA.vadd(c.ri, averageContactPointA);
  15589. averageContactPointB.vadd(c.rj, averageContactPointB);
  15590. } else {
  15591. averageNormal.vsub(c.ni, averageNormal);
  15592. averageContactPointA.vadd(c.rj, averageContactPointA);
  15593. averageContactPointB.vadd(c.ri, averageContactPointB);
  15594. }
  15595. }
  15596. var invNumContacts = 1 / numContacts;
  15597. averageContactPointA.scale(invNumContacts, f1.ri);
  15598. averageContactPointB.scale(invNumContacts, f1.rj);
  15599. f2.ri.copy(f1.ri); // Should be the same
  15600. f2.rj.copy(f1.rj);
  15601. averageNormal.normalize();
  15602. averageNormal.tangents(f1.t, f2.t);
  15603. // return eq;
  15604. };
  15605. var tmpVec1 = new Vec3();
  15606. var tmpVec2 = new Vec3();
  15607. var tmpQuat1 = new Quaternion();
  15608. var tmpQuat2 = new Quaternion();
  15609. /**
  15610. * Generate all contacts between a list of body pairs
  15611. * @method getContacts
  15612. * @param {array} p1 Array of body indices
  15613. * @param {array} p2 Array of body indices
  15614. * @param {World} world
  15615. * @param {array} result Array to store generated contacts
  15616. * @param {array} oldcontacts Optional. Array of reusable contact objects
  15617. */
  15618. Narrowphase.prototype.getContacts = function(p1, p2, world, result, oldcontacts, frictionResult, frictionPool){
  15619. // Save old contact objects
  15620. this.contactPointPool = oldcontacts;
  15621. this.frictionEquationPool = frictionPool;
  15622. this.result = result;
  15623. this.frictionResult = frictionResult;
  15624. var qi = tmpQuat1;
  15625. var qj = tmpQuat2;
  15626. var xi = tmpVec1;
  15627. var xj = tmpVec2;
  15628. for(var k=0, N=p1.length; k!==N; k++){
  15629. // Get current collision bodies
  15630. var bi = p1[k],
  15631. bj = p2[k];
  15632. // Get contact material
  15633. var bodyContactMaterial = null;
  15634. if(bi.material && bj.material){
  15635. bodyContactMaterial = world.getContactMaterial(bi.material,bj.material) || null;
  15636. }
  15637. var justTest = (
  15638. (
  15639. (bi.type & Body.KINEMATIC) && (bj.type & Body.STATIC)
  15640. ) || (
  15641. (bi.type & Body.STATIC) && (bj.type & Body.KINEMATIC)
  15642. ) || (
  15643. (bi.type & Body.KINEMATIC) && (bj.type & Body.KINEMATIC)
  15644. )
  15645. );
  15646. for (var i = 0; i < bi.shapes.length; i++) {
  15647. bi.quaternion.mult(bi.shapeOrientations[i], qi);
  15648. bi.quaternion.vmult(bi.shapeOffsets[i], xi);
  15649. xi.vadd(bi.position, xi);
  15650. var si = bi.shapes[i];
  15651. for (var j = 0; j < bj.shapes.length; j++) {
  15652. // Compute world transform of shapes
  15653. bj.quaternion.mult(bj.shapeOrientations[j], qj);
  15654. bj.quaternion.vmult(bj.shapeOffsets[j], xj);
  15655. xj.vadd(bj.position, xj);
  15656. var sj = bj.shapes[j];
  15657. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  15658. continue;
  15659. }
  15660. // Get collision material
  15661. var shapeContactMaterial = null;
  15662. if(si.material && sj.material){
  15663. shapeContactMaterial = world.getContactMaterial(si.material,sj.material) || null;
  15664. }
  15665. this.currentContactMaterial = shapeContactMaterial || bodyContactMaterial || world.defaultContactMaterial;
  15666. // Get contacts
  15667. var resolver = this[si.type | sj.type];
  15668. if(resolver){
  15669. var retval = false;
  15670. if (si.type < sj.type) {
  15671. retval = resolver.call(this, si, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
  15672. } else {
  15673. retval = resolver.call(this, sj, si, xj, xi, qj, qi, bj, bi, si, sj, justTest);
  15674. }
  15675. if(retval && justTest){
  15676. // Register overlap
  15677. world.shapeOverlapKeeper.set(si.id, sj.id);
  15678. world.bodyOverlapKeeper.set(bi.id, bj.id);
  15679. }
  15680. }
  15681. }
  15682. }
  15683. }
  15684. };
  15685. var numWarnings = 0;
  15686. var maxWarnings = 10;
  15687. function warn(msg){
  15688. if(numWarnings > maxWarnings){
  15689. return;
  15690. }
  15691. numWarnings++;
  15692. console.warn(msg);
  15693. }
  15694. Narrowphase.prototype[Shape.types.BOX | Shape.types.BOX] =
  15695. Narrowphase.prototype.boxBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  15696. si.convexPolyhedronRepresentation.material = si.material;
  15697. sj.convexPolyhedronRepresentation.material = sj.material;
  15698. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  15699. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  15700. return this.convexConvex(si.convexPolyhedronRepresentation,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  15701. };
  15702. Narrowphase.prototype[Shape.types.BOX | Shape.types.CONVEXPOLYHEDRON] =
  15703. Narrowphase.prototype.boxConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  15704. si.convexPolyhedronRepresentation.material = si.material;
  15705. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  15706. return this.convexConvex(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  15707. };
  15708. Narrowphase.prototype[Shape.types.BOX | Shape.types.PARTICLE] =
  15709. Narrowphase.prototype.boxParticle = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  15710. si.convexPolyhedronRepresentation.material = si.material;
  15711. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  15712. return this.convexParticle(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  15713. };
  15714. /**
  15715. * @method sphereSphere
  15716. * @param {Shape} si
  15717. * @param {Shape} sj
  15718. * @param {Vec3} xi
  15719. * @param {Vec3} xj
  15720. * @param {Quaternion} qi
  15721. * @param {Quaternion} qj
  15722. * @param {Body} bi
  15723. * @param {Body} bj
  15724. */
  15725. Narrowphase.prototype[Shape.types.SPHERE] =
  15726. Narrowphase.prototype.sphereSphere = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  15727. if(justTest){
  15728. return xi.distanceSquared(xj) < Math.pow(si.radius + sj.radius, 2);
  15729. }
  15730. // We will have only one contact in this case
  15731. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  15732. // Contact normal
  15733. xj.vsub(xi, r.ni);
  15734. r.ni.normalize();
  15735. // Contact point locations
  15736. r.ri.copy(r.ni);
  15737. r.rj.copy(r.ni);
  15738. r.ri.mult(si.radius, r.ri);
  15739. r.rj.mult(-sj.radius, r.rj);
  15740. r.ri.vadd(xi, r.ri);
  15741. r.ri.vsub(bi.position, r.ri);
  15742. r.rj.vadd(xj, r.rj);
  15743. r.rj.vsub(bj.position, r.rj);
  15744. this.result.push(r);
  15745. this.createFrictionEquationsFromContact(r, this.frictionResult);
  15746. };
  15747. /**
  15748. * @method planeTrimesh
  15749. * @param {Shape} si
  15750. * @param {Shape} sj
  15751. * @param {Vec3} xi
  15752. * @param {Vec3} xj
  15753. * @param {Quaternion} qi
  15754. * @param {Quaternion} qj
  15755. * @param {Body} bi
  15756. * @param {Body} bj
  15757. */
  15758. var planeTrimesh_normal = new Vec3();
  15759. var planeTrimesh_relpos = new Vec3();
  15760. var planeTrimesh_projected = new Vec3();
  15761. Narrowphase.prototype[Shape.types.PLANE | Shape.types.TRIMESH] =
  15762. Narrowphase.prototype.planeTrimesh = function(
  15763. planeShape,
  15764. trimeshShape,
  15765. planePos,
  15766. trimeshPos,
  15767. planeQuat,
  15768. trimeshQuat,
  15769. planeBody,
  15770. trimeshBody,
  15771. rsi,
  15772. rsj,
  15773. justTest
  15774. ){
  15775. // Make contacts!
  15776. var v = new Vec3();
  15777. var normal = planeTrimesh_normal;
  15778. normal.set(0,0,1);
  15779. planeQuat.vmult(normal,normal); // Turn normal according to plane
  15780. for(var i=0; i<trimeshShape.vertices.length / 3; i++){
  15781. // Get world vertex from trimesh
  15782. trimeshShape.getVertex(i, v);
  15783. // Safe up
  15784. var v2 = new Vec3();
  15785. v2.copy(v);
  15786. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  15787. // Check plane side
  15788. var relpos = planeTrimesh_relpos;
  15789. v.vsub(planePos, relpos);
  15790. var dot = normal.dot(relpos);
  15791. if(dot <= 0.0){
  15792. if(justTest){
  15793. return true;
  15794. }
  15795. var r = this.createContactEquation(planeBody,trimeshBody,planeShape,trimeshShape,rsi,rsj);
  15796. r.ni.copy(normal); // Contact normal is the plane normal
  15797. // Get vertex position projected on plane
  15798. var projected = planeTrimesh_projected;
  15799. normal.scale(relpos.dot(normal), projected);
  15800. v.vsub(projected,projected);
  15801. // ri is the projected world position minus plane position
  15802. r.ri.copy(projected);
  15803. r.ri.vsub(planeBody.position, r.ri);
  15804. r.rj.copy(v);
  15805. r.rj.vsub(trimeshBody.position, r.rj);
  15806. // Store result
  15807. this.result.push(r);
  15808. this.createFrictionEquationsFromContact(r, this.frictionResult);
  15809. }
  15810. }
  15811. };
  15812. /**
  15813. * @method sphereTrimesh
  15814. * @param {Shape} sphereShape
  15815. * @param {Shape} trimeshShape
  15816. * @param {Vec3} spherePos
  15817. * @param {Vec3} trimeshPos
  15818. * @param {Quaternion} sphereQuat
  15819. * @param {Quaternion} trimeshQuat
  15820. * @param {Body} sphereBody
  15821. * @param {Body} trimeshBody
  15822. */
  15823. var sphereTrimesh_normal = new Vec3();
  15824. var sphereTrimesh_relpos = new Vec3();
  15825. var sphereTrimesh_projected = new Vec3();
  15826. var sphereTrimesh_v = new Vec3();
  15827. var sphereTrimesh_v2 = new Vec3();
  15828. var sphereTrimesh_edgeVertexA = new Vec3();
  15829. var sphereTrimesh_edgeVertexB = new Vec3();
  15830. var sphereTrimesh_edgeVector = new Vec3();
  15831. var sphereTrimesh_edgeVectorUnit = new Vec3();
  15832. var sphereTrimesh_localSpherePos = new Vec3();
  15833. var sphereTrimesh_tmp = new Vec3();
  15834. var sphereTrimesh_va = new Vec3();
  15835. var sphereTrimesh_vb = new Vec3();
  15836. var sphereTrimesh_vc = new Vec3();
  15837. var sphereTrimesh_localSphereAABB = new AABB();
  15838. var sphereTrimesh_triangles = [];
  15839. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.TRIMESH] =
  15840. Narrowphase.prototype.sphereTrimesh = function (
  15841. sphereShape,
  15842. trimeshShape,
  15843. spherePos,
  15844. trimeshPos,
  15845. sphereQuat,
  15846. trimeshQuat,
  15847. sphereBody,
  15848. trimeshBody,
  15849. rsi,
  15850. rsj,
  15851. justTest
  15852. ) {
  15853. var edgeVertexA = sphereTrimesh_edgeVertexA;
  15854. var edgeVertexB = sphereTrimesh_edgeVertexB;
  15855. var edgeVector = sphereTrimesh_edgeVector;
  15856. var edgeVectorUnit = sphereTrimesh_edgeVectorUnit;
  15857. var localSpherePos = sphereTrimesh_localSpherePos;
  15858. var tmp = sphereTrimesh_tmp;
  15859. var localSphereAABB = sphereTrimesh_localSphereAABB;
  15860. var v2 = sphereTrimesh_v2;
  15861. var relpos = sphereTrimesh_relpos;
  15862. var triangles = sphereTrimesh_triangles;
  15863. // Convert sphere position to local in the trimesh
  15864. Transform.pointToLocalFrame(trimeshPos, trimeshQuat, spherePos, localSpherePos);
  15865. // Get the aabb of the sphere locally in the trimesh
  15866. var sphereRadius = sphereShape.radius;
  15867. localSphereAABB.lowerBound.set(
  15868. localSpherePos.x - sphereRadius,
  15869. localSpherePos.y - sphereRadius,
  15870. localSpherePos.z - sphereRadius
  15871. );
  15872. localSphereAABB.upperBound.set(
  15873. localSpherePos.x + sphereRadius,
  15874. localSpherePos.y + sphereRadius,
  15875. localSpherePos.z + sphereRadius
  15876. );
  15877. trimeshShape.getTrianglesInAABB(localSphereAABB, triangles);
  15878. //for (var i = 0; i < trimeshShape.indices.length / 3; i++) triangles.push(i); // All
  15879. // Vertices
  15880. var v = sphereTrimesh_v;
  15881. var radiusSquared = sphereShape.radius * sphereShape.radius;
  15882. for(var i=0; i<triangles.length; i++){
  15883. for (var j = 0; j < 3; j++) {
  15884. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], v);
  15885. // Check vertex overlap in sphere
  15886. v.vsub(localSpherePos, relpos);
  15887. if(relpos.norm2() <= radiusSquared){
  15888. // Safe up
  15889. v2.copy(v);
  15890. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  15891. v.vsub(spherePos, relpos);
  15892. if(justTest){
  15893. return true;
  15894. }
  15895. var r = this.createContactEquation(sphereBody,trimeshBody,sphereShape,trimeshShape,rsi,rsj);
  15896. r.ni.copy(relpos);
  15897. r.ni.normalize();
  15898. // ri is the vector from sphere center to the sphere surface
  15899. r.ri.copy(r.ni);
  15900. r.ri.scale(sphereShape.radius, r.ri);
  15901. r.ri.vadd(spherePos, r.ri);
  15902. r.ri.vsub(sphereBody.position, r.ri);
  15903. r.rj.copy(v);
  15904. r.rj.vsub(trimeshBody.position, r.rj);
  15905. // Store result
  15906. this.result.push(r);
  15907. this.createFrictionEquationsFromContact(r, this.frictionResult);
  15908. }
  15909. }
  15910. }
  15911. // Check all edges
  15912. for(var i=0; i<triangles.length; i++){
  15913. for (var j = 0; j < 3; j++) {
  15914. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], edgeVertexA);
  15915. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + ((j+1)%3)], edgeVertexB);
  15916. edgeVertexB.vsub(edgeVertexA, edgeVector);
  15917. // Project sphere position to the edge
  15918. localSpherePos.vsub(edgeVertexB, tmp);
  15919. var positionAlongEdgeB = tmp.dot(edgeVector);
  15920. localSpherePos.vsub(edgeVertexA, tmp);
  15921. var positionAlongEdgeA = tmp.dot(edgeVector);
  15922. if(positionAlongEdgeA > 0 && positionAlongEdgeB < 0){
  15923. // Now check the orthogonal distance from edge to sphere center
  15924. localSpherePos.vsub(edgeVertexA, tmp);
  15925. edgeVectorUnit.copy(edgeVector);
  15926. edgeVectorUnit.normalize();
  15927. positionAlongEdgeA = tmp.dot(edgeVectorUnit);
  15928. edgeVectorUnit.scale(positionAlongEdgeA, tmp);
  15929. tmp.vadd(edgeVertexA, tmp);
  15930. // tmp is now the sphere center position projected to the edge, defined locally in the trimesh frame
  15931. var dist = tmp.distanceTo(localSpherePos);
  15932. if(dist < sphereShape.radius){
  15933. if(justTest){
  15934. return true;
  15935. }
  15936. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  15937. tmp.vsub(localSpherePos, r.ni);
  15938. r.ni.normalize();
  15939. r.ni.scale(sphereShape.radius, r.ri);
  15940. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  15941. tmp.vsub(trimeshBody.position, r.rj);
  15942. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  15943. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  15944. this.result.push(r);
  15945. this.createFrictionEquationsFromContact(r, this.frictionResult);
  15946. }
  15947. }
  15948. }
  15949. }
  15950. // Triangle faces
  15951. var va = sphereTrimesh_va;
  15952. var vb = sphereTrimesh_vb;
  15953. var vc = sphereTrimesh_vc;
  15954. var normal = sphereTrimesh_normal;
  15955. for(var i=0, N = triangles.length; i !== N; i++){
  15956. trimeshShape.getTriangleVertices(triangles[i], va, vb, vc);
  15957. trimeshShape.getNormal(triangles[i], normal);
  15958. localSpherePos.vsub(va, tmp);
  15959. var dist = tmp.dot(normal);
  15960. normal.scale(dist, tmp);
  15961. localSpherePos.vsub(tmp, tmp);
  15962. // tmp is now the sphere position projected to the triangle plane
  15963. dist = tmp.distanceTo(localSpherePos);
  15964. if(Ray.pointInTriangle(tmp, va, vb, vc) && dist < sphereShape.radius){
  15965. if(justTest){
  15966. return true;
  15967. }
  15968. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  15969. tmp.vsub(localSpherePos, r.ni);
  15970. r.ni.normalize();
  15971. r.ni.scale(sphereShape.radius, r.ri);
  15972. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  15973. tmp.vsub(trimeshBody.position, r.rj);
  15974. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  15975. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  15976. this.result.push(r);
  15977. this.createFrictionEquationsFromContact(r, this.frictionResult);
  15978. }
  15979. }
  15980. triangles.length = 0;
  15981. };
  15982. var point_on_plane_to_sphere = new Vec3();
  15983. var plane_to_sphere_ortho = new Vec3();
  15984. /**
  15985. * @method spherePlane
  15986. * @param {Shape} si
  15987. * @param {Shape} sj
  15988. * @param {Vec3} xi
  15989. * @param {Vec3} xj
  15990. * @param {Quaternion} qi
  15991. * @param {Quaternion} qj
  15992. * @param {Body} bi
  15993. * @param {Body} bj
  15994. */
  15995. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.PLANE] =
  15996. Narrowphase.prototype.spherePlane = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  15997. // We will have one contact in this case
  15998. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  15999. // Contact normal
  16000. r.ni.set(0,0,1);
  16001. qj.vmult(r.ni, r.ni);
  16002. r.ni.negate(r.ni); // body i is the sphere, flip normal
  16003. r.ni.normalize(); // Needed?
  16004. // Vector from sphere center to contact point
  16005. r.ni.mult(si.radius, r.ri);
  16006. // Project down sphere on plane
  16007. xi.vsub(xj, point_on_plane_to_sphere);
  16008. r.ni.mult(r.ni.dot(point_on_plane_to_sphere), plane_to_sphere_ortho);
  16009. point_on_plane_to_sphere.vsub(plane_to_sphere_ortho,r.rj); // The sphere position projected to plane
  16010. if(-point_on_plane_to_sphere.dot(r.ni) <= si.radius){
  16011. if(justTest){
  16012. return true;
  16013. }
  16014. // Make it relative to the body
  16015. var ri = r.ri;
  16016. var rj = r.rj;
  16017. ri.vadd(xi, ri);
  16018. ri.vsub(bi.position, ri);
  16019. rj.vadd(xj, rj);
  16020. rj.vsub(bj.position, rj);
  16021. this.result.push(r);
  16022. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16023. }
  16024. };
  16025. // See http://bulletphysics.com/Bullet/BulletFull/SphereTriangleDetector_8cpp_source.html
  16026. var pointInPolygon_edge = new Vec3();
  16027. var pointInPolygon_edge_x_normal = new Vec3();
  16028. var pointInPolygon_vtp = new Vec3();
  16029. function pointInPolygon(verts, normal, p){
  16030. var positiveResult = null;
  16031. var N = verts.length;
  16032. for(var i=0; i!==N; i++){
  16033. var v = verts[i];
  16034. // Get edge to the next vertex
  16035. var edge = pointInPolygon_edge;
  16036. verts[(i+1) % (N)].vsub(v,edge);
  16037. // Get cross product between polygon normal and the edge
  16038. var edge_x_normal = pointInPolygon_edge_x_normal;
  16039. //var edge_x_normal = new Vec3();
  16040. edge.cross(normal,edge_x_normal);
  16041. // Get vector between point and current vertex
  16042. var vertex_to_p = pointInPolygon_vtp;
  16043. p.vsub(v,vertex_to_p);
  16044. // This dot product determines which side of the edge the point is
  16045. var r = edge_x_normal.dot(vertex_to_p);
  16046. // If all such dot products have same sign, we are inside the polygon.
  16047. if(positiveResult===null || (r>0 && positiveResult===true) || (r<=0 && positiveResult===false)){
  16048. if(positiveResult===null){
  16049. positiveResult = r>0;
  16050. }
  16051. continue;
  16052. } else {
  16053. return false; // Encountered some other sign. Exit.
  16054. }
  16055. }
  16056. // If we got here, all dot products were of the same sign.
  16057. return true;
  16058. }
  16059. var box_to_sphere = new Vec3();
  16060. var sphereBox_ns = new Vec3();
  16061. var sphereBox_ns1 = new Vec3();
  16062. var sphereBox_ns2 = new Vec3();
  16063. var sphereBox_sides = [new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3()];
  16064. var sphereBox_sphere_to_corner = new Vec3();
  16065. var sphereBox_side_ns = new Vec3();
  16066. var sphereBox_side_ns1 = new Vec3();
  16067. var sphereBox_side_ns2 = new Vec3();
  16068. /**
  16069. * @method sphereBox
  16070. * @param {Shape} si
  16071. * @param {Shape} sj
  16072. * @param {Vec3} xi
  16073. * @param {Vec3} xj
  16074. * @param {Quaternion} qi
  16075. * @param {Quaternion} qj
  16076. * @param {Body} bi
  16077. * @param {Body} bj
  16078. */
  16079. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.BOX] =
  16080. Narrowphase.prototype.sphereBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  16081. var v3pool = this.v3pool;
  16082. // we refer to the box as body j
  16083. var sides = sphereBox_sides;
  16084. xi.vsub(xj,box_to_sphere);
  16085. sj.getSideNormals(sides,qj);
  16086. var R = si.radius;
  16087. var penetrating_sides = [];
  16088. // Check side (plane) intersections
  16089. var found = false;
  16090. // Store the resulting side penetration info
  16091. var side_ns = sphereBox_side_ns;
  16092. var side_ns1 = sphereBox_side_ns1;
  16093. var side_ns2 = sphereBox_side_ns2;
  16094. var side_h = null;
  16095. var side_penetrations = 0;
  16096. var side_dot1 = 0;
  16097. var side_dot2 = 0;
  16098. var side_distance = null;
  16099. for(var idx=0,nsides=sides.length; idx!==nsides && found===false; idx++){
  16100. // Get the plane side normal (ns)
  16101. var ns = sphereBox_ns;
  16102. ns.copy(sides[idx]);
  16103. var h = ns.norm();
  16104. ns.normalize();
  16105. // The normal/distance dot product tells which side of the plane we are
  16106. var dot = box_to_sphere.dot(ns);
  16107. if(dot<h+R && dot>0){
  16108. // Intersects plane. Now check the other two dimensions
  16109. var ns1 = sphereBox_ns1;
  16110. var ns2 = sphereBox_ns2;
  16111. ns1.copy(sides[(idx+1)%3]);
  16112. ns2.copy(sides[(idx+2)%3]);
  16113. var h1 = ns1.norm();
  16114. var h2 = ns2.norm();
  16115. ns1.normalize();
  16116. ns2.normalize();
  16117. var dot1 = box_to_sphere.dot(ns1);
  16118. var dot2 = box_to_sphere.dot(ns2);
  16119. if(dot1<h1 && dot1>-h1 && dot2<h2 && dot2>-h2){
  16120. var dist = Math.abs(dot-h-R);
  16121. if(side_distance===null || dist < side_distance){
  16122. side_distance = dist;
  16123. side_dot1 = dot1;
  16124. side_dot2 = dot2;
  16125. side_h = h;
  16126. side_ns.copy(ns);
  16127. side_ns1.copy(ns1);
  16128. side_ns2.copy(ns2);
  16129. side_penetrations++;
  16130. if(justTest){
  16131. return true;
  16132. }
  16133. }
  16134. }
  16135. }
  16136. }
  16137. if(side_penetrations){
  16138. found = true;
  16139. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16140. side_ns.mult(-R,r.ri); // Sphere r
  16141. r.ni.copy(side_ns);
  16142. r.ni.negate(r.ni); // Normal should be out of sphere
  16143. side_ns.mult(side_h,side_ns);
  16144. side_ns1.mult(side_dot1,side_ns1);
  16145. side_ns.vadd(side_ns1,side_ns);
  16146. side_ns2.mult(side_dot2,side_ns2);
  16147. side_ns.vadd(side_ns2,r.rj);
  16148. // Make relative to bodies
  16149. r.ri.vadd(xi, r.ri);
  16150. r.ri.vsub(bi.position, r.ri);
  16151. r.rj.vadd(xj, r.rj);
  16152. r.rj.vsub(bj.position, r.rj);
  16153. this.result.push(r);
  16154. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16155. }
  16156. // Check corners
  16157. var rj = v3pool.get();
  16158. var sphere_to_corner = sphereBox_sphere_to_corner;
  16159. for(var j=0; j!==2 && !found; j++){
  16160. for(var k=0; k!==2 && !found; k++){
  16161. for(var l=0; l!==2 && !found; l++){
  16162. rj.set(0,0,0);
  16163. if(j){
  16164. rj.vadd(sides[0],rj);
  16165. } else {
  16166. rj.vsub(sides[0],rj);
  16167. }
  16168. if(k){
  16169. rj.vadd(sides[1],rj);
  16170. } else {
  16171. rj.vsub(sides[1],rj);
  16172. }
  16173. if(l){
  16174. rj.vadd(sides[2],rj);
  16175. } else {
  16176. rj.vsub(sides[2],rj);
  16177. }
  16178. // World position of corner
  16179. xj.vadd(rj,sphere_to_corner);
  16180. sphere_to_corner.vsub(xi,sphere_to_corner);
  16181. if(sphere_to_corner.norm2() < R*R){
  16182. if(justTest){
  16183. return true;
  16184. }
  16185. found = true;
  16186. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16187. r.ri.copy(sphere_to_corner);
  16188. r.ri.normalize();
  16189. r.ni.copy(r.ri);
  16190. r.ri.mult(R,r.ri);
  16191. r.rj.copy(rj);
  16192. // Make relative to bodies
  16193. r.ri.vadd(xi, r.ri);
  16194. r.ri.vsub(bi.position, r.ri);
  16195. r.rj.vadd(xj, r.rj);
  16196. r.rj.vsub(bj.position, r.rj);
  16197. this.result.push(r);
  16198. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16199. }
  16200. }
  16201. }
  16202. }
  16203. v3pool.release(rj);
  16204. rj = null;
  16205. // Check edges
  16206. var edgeTangent = v3pool.get();
  16207. var edgeCenter = v3pool.get();
  16208. var r = v3pool.get(); // r = edge center to sphere center
  16209. var orthogonal = v3pool.get();
  16210. var dist = v3pool.get();
  16211. var Nsides = sides.length;
  16212. for(var j=0; j!==Nsides && !found; j++){
  16213. for(var k=0; k!==Nsides && !found; k++){
  16214. if(j%3 !== k%3){
  16215. // Get edge tangent
  16216. sides[k].cross(sides[j],edgeTangent);
  16217. edgeTangent.normalize();
  16218. sides[j].vadd(sides[k], edgeCenter);
  16219. r.copy(xi);
  16220. r.vsub(edgeCenter,r);
  16221. r.vsub(xj,r);
  16222. var orthonorm = r.dot(edgeTangent); // distance from edge center to sphere center in the tangent direction
  16223. edgeTangent.mult(orthonorm,orthogonal); // Vector from edge center to sphere center in the tangent direction
  16224. // Find the third side orthogonal to this one
  16225. var l = 0;
  16226. while(l===j%3 || l===k%3){
  16227. l++;
  16228. }
  16229. // vec from edge center to sphere projected to the plane orthogonal to the edge tangent
  16230. dist.copy(xi);
  16231. dist.vsub(orthogonal,dist);
  16232. dist.vsub(edgeCenter,dist);
  16233. dist.vsub(xj,dist);
  16234. // Distances in tangent direction and distance in the plane orthogonal to it
  16235. var tdist = Math.abs(orthonorm);
  16236. var ndist = dist.norm();
  16237. if(tdist < sides[l].norm() && ndist<R){
  16238. if(justTest){
  16239. return true;
  16240. }
  16241. found = true;
  16242. var res = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16243. edgeCenter.vadd(orthogonal,res.rj); // box rj
  16244. res.rj.copy(res.rj);
  16245. dist.negate(res.ni);
  16246. res.ni.normalize();
  16247. res.ri.copy(res.rj);
  16248. res.ri.vadd(xj,res.ri);
  16249. res.ri.vsub(xi,res.ri);
  16250. res.ri.normalize();
  16251. res.ri.mult(R,res.ri);
  16252. // Make relative to bodies
  16253. res.ri.vadd(xi, res.ri);
  16254. res.ri.vsub(bi.position, res.ri);
  16255. res.rj.vadd(xj, res.rj);
  16256. res.rj.vsub(bj.position, res.rj);
  16257. this.result.push(res);
  16258. this.createFrictionEquationsFromContact(res, this.frictionResult);
  16259. }
  16260. }
  16261. }
  16262. }
  16263. v3pool.release(edgeTangent,edgeCenter,r,orthogonal,dist);
  16264. };
  16265. var convex_to_sphere = new Vec3();
  16266. var sphereConvex_edge = new Vec3();
  16267. var sphereConvex_edgeUnit = new Vec3();
  16268. var sphereConvex_sphereToCorner = new Vec3();
  16269. var sphereConvex_worldCorner = new Vec3();
  16270. var sphereConvex_worldNormal = new Vec3();
  16271. var sphereConvex_worldPoint = new Vec3();
  16272. var sphereConvex_worldSpherePointClosestToPlane = new Vec3();
  16273. var sphereConvex_penetrationVec = new Vec3();
  16274. var sphereConvex_sphereToWorldPoint = new Vec3();
  16275. /**
  16276. * @method sphereConvex
  16277. * @param {Shape} si
  16278. * @param {Shape} sj
  16279. * @param {Vec3} xi
  16280. * @param {Vec3} xj
  16281. * @param {Quaternion} qi
  16282. * @param {Quaternion} qj
  16283. * @param {Body} bi
  16284. * @param {Body} bj
  16285. */
  16286. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.CONVEXPOLYHEDRON] =
  16287. Narrowphase.prototype.sphereConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  16288. var v3pool = this.v3pool;
  16289. xi.vsub(xj,convex_to_sphere);
  16290. var normals = sj.faceNormals;
  16291. var faces = sj.faces;
  16292. var verts = sj.vertices;
  16293. var R = si.radius;
  16294. var penetrating_sides = [];
  16295. // if(convex_to_sphere.norm2() > si.boundingSphereRadius + sj.boundingSphereRadius){
  16296. // return;
  16297. // }
  16298. // Check corners
  16299. for(var i=0; i!==verts.length; i++){
  16300. var v = verts[i];
  16301. // World position of corner
  16302. var worldCorner = sphereConvex_worldCorner;
  16303. qj.vmult(v,worldCorner);
  16304. xj.vadd(worldCorner,worldCorner);
  16305. var sphere_to_corner = sphereConvex_sphereToCorner;
  16306. worldCorner.vsub(xi, sphere_to_corner);
  16307. if(sphere_to_corner.norm2() < R * R){
  16308. if(justTest){
  16309. return true;
  16310. }
  16311. found = true;
  16312. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16313. r.ri.copy(sphere_to_corner);
  16314. r.ri.normalize();
  16315. r.ni.copy(r.ri);
  16316. r.ri.mult(R,r.ri);
  16317. worldCorner.vsub(xj,r.rj);
  16318. // Should be relative to the body.
  16319. r.ri.vadd(xi, r.ri);
  16320. r.ri.vsub(bi.position, r.ri);
  16321. // Should be relative to the body.
  16322. r.rj.vadd(xj, r.rj);
  16323. r.rj.vsub(bj.position, r.rj);
  16324. this.result.push(r);
  16325. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16326. return;
  16327. }
  16328. }
  16329. // Check side (plane) intersections
  16330. var found = false;
  16331. for(var i=0, nfaces=faces.length; i!==nfaces && found===false; i++){
  16332. var normal = normals[i];
  16333. var face = faces[i];
  16334. // Get world-transformed normal of the face
  16335. var worldNormal = sphereConvex_worldNormal;
  16336. qj.vmult(normal,worldNormal);
  16337. // Get a world vertex from the face
  16338. var worldPoint = sphereConvex_worldPoint;
  16339. qj.vmult(verts[face[0]],worldPoint);
  16340. worldPoint.vadd(xj,worldPoint);
  16341. // Get a point on the sphere, closest to the face normal
  16342. var worldSpherePointClosestToPlane = sphereConvex_worldSpherePointClosestToPlane;
  16343. worldNormal.mult(-R, worldSpherePointClosestToPlane);
  16344. xi.vadd(worldSpherePointClosestToPlane, worldSpherePointClosestToPlane);
  16345. // Vector from a face point to the closest point on the sphere
  16346. var penetrationVec = sphereConvex_penetrationVec;
  16347. worldSpherePointClosestToPlane.vsub(worldPoint,penetrationVec);
  16348. // The penetration. Negative value means overlap.
  16349. var penetration = penetrationVec.dot(worldNormal);
  16350. var worldPointToSphere = sphereConvex_sphereToWorldPoint;
  16351. xi.vsub(worldPoint, worldPointToSphere);
  16352. if(penetration < 0 && worldPointToSphere.dot(worldNormal)>0){
  16353. // Intersects plane. Now check if the sphere is inside the face polygon
  16354. var faceVerts = []; // Face vertices, in world coords
  16355. for(var j=0, Nverts=face.length; j!==Nverts; j++){
  16356. var worldVertex = v3pool.get();
  16357. qj.vmult(verts[face[j]], worldVertex);
  16358. xj.vadd(worldVertex,worldVertex);
  16359. faceVerts.push(worldVertex);
  16360. }
  16361. if(pointInPolygon(faceVerts,worldNormal,xi)){ // Is the sphere center in the face polygon?
  16362. if(justTest){
  16363. return true;
  16364. }
  16365. found = true;
  16366. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16367. worldNormal.mult(-R, r.ri); // Contact offset, from sphere center to contact
  16368. worldNormal.negate(r.ni); // Normal pointing out of sphere
  16369. var penetrationVec2 = v3pool.get();
  16370. worldNormal.mult(-penetration, penetrationVec2);
  16371. var penetrationSpherePoint = v3pool.get();
  16372. worldNormal.mult(-R, penetrationSpherePoint);
  16373. //xi.vsub(xj).vadd(penetrationSpherePoint).vadd(penetrationVec2 , r.rj);
  16374. xi.vsub(xj,r.rj);
  16375. r.rj.vadd(penetrationSpherePoint,r.rj);
  16376. r.rj.vadd(penetrationVec2 , r.rj);
  16377. // Should be relative to the body.
  16378. r.rj.vadd(xj, r.rj);
  16379. r.rj.vsub(bj.position, r.rj);
  16380. // Should be relative to the body.
  16381. r.ri.vadd(xi, r.ri);
  16382. r.ri.vsub(bi.position, r.ri);
  16383. v3pool.release(penetrationVec2);
  16384. v3pool.release(penetrationSpherePoint);
  16385. this.result.push(r);
  16386. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16387. // Release world vertices
  16388. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  16389. v3pool.release(faceVerts[j]);
  16390. }
  16391. return; // We only expect *one* face contact
  16392. } else {
  16393. // Edge?
  16394. for(var j=0; j!==face.length; j++){
  16395. // Get two world transformed vertices
  16396. var v1 = v3pool.get();
  16397. var v2 = v3pool.get();
  16398. qj.vmult(verts[face[(j+1)%face.length]], v1);
  16399. qj.vmult(verts[face[(j+2)%face.length]], v2);
  16400. xj.vadd(v1, v1);
  16401. xj.vadd(v2, v2);
  16402. // Construct edge vector
  16403. var edge = sphereConvex_edge;
  16404. v2.vsub(v1,edge);
  16405. // Construct the same vector, but normalized
  16406. var edgeUnit = sphereConvex_edgeUnit;
  16407. edge.unit(edgeUnit);
  16408. // p is xi projected onto the edge
  16409. var p = v3pool.get();
  16410. var v1_to_xi = v3pool.get();
  16411. xi.vsub(v1, v1_to_xi);
  16412. var dot = v1_to_xi.dot(edgeUnit);
  16413. edgeUnit.mult(dot, p);
  16414. p.vadd(v1, p);
  16415. // Compute a vector from p to the center of the sphere
  16416. var xi_to_p = v3pool.get();
  16417. p.vsub(xi, xi_to_p);
  16418. // Collision if the edge-sphere distance is less than the radius
  16419. // AND if p is in between v1 and v2
  16420. if(dot > 0 && dot*dot<edge.norm2() && xi_to_p.norm2() < R*R){ // Collision if the edge-sphere distance is less than the radius
  16421. // Edge contact!
  16422. if(justTest){
  16423. return true;
  16424. }
  16425. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16426. p.vsub(xj,r.rj);
  16427. p.vsub(xi,r.ni);
  16428. r.ni.normalize();
  16429. r.ni.mult(R,r.ri);
  16430. // Should be relative to the body.
  16431. r.rj.vadd(xj, r.rj);
  16432. r.rj.vsub(bj.position, r.rj);
  16433. // Should be relative to the body.
  16434. r.ri.vadd(xi, r.ri);
  16435. r.ri.vsub(bi.position, r.ri);
  16436. this.result.push(r);
  16437. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16438. // Release world vertices
  16439. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  16440. v3pool.release(faceVerts[j]);
  16441. }
  16442. v3pool.release(v1);
  16443. v3pool.release(v2);
  16444. v3pool.release(p);
  16445. v3pool.release(xi_to_p);
  16446. v3pool.release(v1_to_xi);
  16447. return;
  16448. }
  16449. v3pool.release(v1);
  16450. v3pool.release(v2);
  16451. v3pool.release(p);
  16452. v3pool.release(xi_to_p);
  16453. v3pool.release(v1_to_xi);
  16454. }
  16455. }
  16456. // Release world vertices
  16457. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  16458. v3pool.release(faceVerts[j]);
  16459. }
  16460. }
  16461. }
  16462. };
  16463. var planeBox_normal = new Vec3();
  16464. var plane_to_corner = new Vec3();
  16465. /**
  16466. * @method planeBox
  16467. * @param {Array} result
  16468. * @param {Shape} si
  16469. * @param {Shape} sj
  16470. * @param {Vec3} xi
  16471. * @param {Vec3} xj
  16472. * @param {Quaternion} qi
  16473. * @param {Quaternion} qj
  16474. * @param {Body} bi
  16475. * @param {Body} bj
  16476. */
  16477. Narrowphase.prototype[Shape.types.PLANE | Shape.types.BOX] =
  16478. Narrowphase.prototype.planeBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  16479. sj.convexPolyhedronRepresentation.material = sj.material;
  16480. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  16481. sj.convexPolyhedronRepresentation.id = sj.id;
  16482. return this.planeConvex(si,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  16483. };
  16484. var planeConvex_v = new Vec3();
  16485. var planeConvex_normal = new Vec3();
  16486. var planeConvex_relpos = new Vec3();
  16487. var planeConvex_projected = new Vec3();
  16488. /**
  16489. * @method planeConvex
  16490. * @param {Shape} si
  16491. * @param {Shape} sj
  16492. * @param {Vec3} xi
  16493. * @param {Vec3} xj
  16494. * @param {Quaternion} qi
  16495. * @param {Quaternion} qj
  16496. * @param {Body} bi
  16497. * @param {Body} bj
  16498. */
  16499. Narrowphase.prototype[Shape.types.PLANE | Shape.types.CONVEXPOLYHEDRON] =
  16500. Narrowphase.prototype.planeConvex = function(
  16501. planeShape,
  16502. convexShape,
  16503. planePosition,
  16504. convexPosition,
  16505. planeQuat,
  16506. convexQuat,
  16507. planeBody,
  16508. convexBody,
  16509. si,
  16510. sj,
  16511. justTest
  16512. ){
  16513. // Simply return the points behind the plane.
  16514. var worldVertex = planeConvex_v,
  16515. worldNormal = planeConvex_normal;
  16516. worldNormal.set(0,0,1);
  16517. planeQuat.vmult(worldNormal,worldNormal); // Turn normal according to plane orientation
  16518. var numContacts = 0;
  16519. var relpos = planeConvex_relpos;
  16520. for(var i = 0; i !== convexShape.vertices.length; i++){
  16521. // Get world convex vertex
  16522. worldVertex.copy(convexShape.vertices[i]);
  16523. convexQuat.vmult(worldVertex, worldVertex);
  16524. convexPosition.vadd(worldVertex, worldVertex);
  16525. worldVertex.vsub(planePosition, relpos);
  16526. var dot = worldNormal.dot(relpos);
  16527. if(dot <= 0.0){
  16528. if(justTest){
  16529. return true;
  16530. }
  16531. var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj);
  16532. // Get vertex position projected on plane
  16533. var projected = planeConvex_projected;
  16534. worldNormal.mult(worldNormal.dot(relpos),projected);
  16535. worldVertex.vsub(projected, projected);
  16536. projected.vsub(planePosition, r.ri); // From plane to vertex projected on plane
  16537. r.ni.copy(worldNormal); // Contact normal is the plane normal out from plane
  16538. // rj is now just the vector from the convex center to the vertex
  16539. worldVertex.vsub(convexPosition, r.rj);
  16540. // Make it relative to the body
  16541. r.ri.vadd(planePosition, r.ri);
  16542. r.ri.vsub(planeBody.position, r.ri);
  16543. r.rj.vadd(convexPosition, r.rj);
  16544. r.rj.vsub(convexBody.position, r.rj);
  16545. this.result.push(r);
  16546. numContacts++;
  16547. if(!this.enableFrictionReduction){
  16548. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16549. }
  16550. }
  16551. }
  16552. if(this.enableFrictionReduction && numContacts){
  16553. this.createFrictionFromAverage(numContacts);
  16554. }
  16555. };
  16556. var convexConvex_sepAxis = new Vec3();
  16557. var convexConvex_q = new Vec3();
  16558. /**
  16559. * @method convexConvex
  16560. * @param {Shape} si
  16561. * @param {Shape} sj
  16562. * @param {Vec3} xi
  16563. * @param {Vec3} xj
  16564. * @param {Quaternion} qi
  16565. * @param {Quaternion} qj
  16566. * @param {Body} bi
  16567. * @param {Body} bj
  16568. */
  16569. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON] =
  16570. Narrowphase.prototype.convexConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest,faceListA,faceListB){
  16571. var sepAxis = convexConvex_sepAxis;
  16572. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  16573. return;
  16574. }
  16575. if(si.findSeparatingAxis(sj,xi,qi,xj,qj,sepAxis,faceListA,faceListB)){
  16576. var res = [];
  16577. var q = convexConvex_q;
  16578. si.clipAgainstHull(xi,qi,sj,xj,qj,sepAxis,-100,100,res);
  16579. var numContacts = 0;
  16580. for(var j = 0; j !== res.length; j++){
  16581. if(justTest){
  16582. return true;
  16583. }
  16584. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  16585. ri = r.ri,
  16586. rj = r.rj;
  16587. sepAxis.negate(r.ni);
  16588. res[j].normal.negate(q);
  16589. q.mult(res[j].depth, q);
  16590. res[j].point.vadd(q, ri);
  16591. rj.copy(res[j].point);
  16592. // Contact points are in world coordinates. Transform back to relative
  16593. ri.vsub(xi,ri);
  16594. rj.vsub(xj,rj);
  16595. // Make relative to bodies
  16596. ri.vadd(xi, ri);
  16597. ri.vsub(bi.position, ri);
  16598. rj.vadd(xj, rj);
  16599. rj.vsub(bj.position, rj);
  16600. this.result.push(r);
  16601. numContacts++;
  16602. if(!this.enableFrictionReduction){
  16603. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16604. }
  16605. }
  16606. if(this.enableFrictionReduction && numContacts){
  16607. this.createFrictionFromAverage(numContacts);
  16608. }
  16609. }
  16610. };
  16611. /**
  16612. * @method convexTrimesh
  16613. * @param {Array} result
  16614. * @param {Shape} si
  16615. * @param {Shape} sj
  16616. * @param {Vec3} xi
  16617. * @param {Vec3} xj
  16618. * @param {Quaternion} qi
  16619. * @param {Quaternion} qj
  16620. * @param {Body} bi
  16621. * @param {Body} bj
  16622. */
  16623. // Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.TRIMESH] =
  16624. // Narrowphase.prototype.convexTrimesh = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,faceListA,faceListB){
  16625. // var sepAxis = convexConvex_sepAxis;
  16626. // if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  16627. // return;
  16628. // }
  16629. // // Construct a temp hull for each triangle
  16630. // var hullB = new ConvexPolyhedron();
  16631. // hullB.faces = [[0,1,2]];
  16632. // var va = new Vec3();
  16633. // var vb = new Vec3();
  16634. // var vc = new Vec3();
  16635. // hullB.vertices = [
  16636. // va,
  16637. // vb,
  16638. // vc
  16639. // ];
  16640. // for (var i = 0; i < sj.indices.length / 3; i++) {
  16641. // var triangleNormal = new Vec3();
  16642. // sj.getNormal(i, triangleNormal);
  16643. // hullB.faceNormals = [triangleNormal];
  16644. // sj.getTriangleVertices(i, va, vb, vc);
  16645. // var d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  16646. // if(!d){
  16647. // triangleNormal.scale(-1, triangleNormal);
  16648. // d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  16649. // if(!d){
  16650. // continue;
  16651. // }
  16652. // }
  16653. // var res = [];
  16654. // var q = convexConvex_q;
  16655. // si.clipAgainstHull(xi,qi,hullB,xj,qj,triangleNormal,-100,100,res);
  16656. // for(var j = 0; j !== res.length; j++){
  16657. // var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  16658. // ri = r.ri,
  16659. // rj = r.rj;
  16660. // r.ni.copy(triangleNormal);
  16661. // r.ni.negate(r.ni);
  16662. // res[j].normal.negate(q);
  16663. // q.mult(res[j].depth, q);
  16664. // res[j].point.vadd(q, ri);
  16665. // rj.copy(res[j].point);
  16666. // // Contact points are in world coordinates. Transform back to relative
  16667. // ri.vsub(xi,ri);
  16668. // rj.vsub(xj,rj);
  16669. // // Make relative to bodies
  16670. // ri.vadd(xi, ri);
  16671. // ri.vsub(bi.position, ri);
  16672. // rj.vadd(xj, rj);
  16673. // rj.vsub(bj.position, rj);
  16674. // result.push(r);
  16675. // }
  16676. // }
  16677. // };
  16678. var particlePlane_normal = new Vec3();
  16679. var particlePlane_relpos = new Vec3();
  16680. var particlePlane_projected = new Vec3();
  16681. /**
  16682. * @method particlePlane
  16683. * @param {Array} result
  16684. * @param {Shape} si
  16685. * @param {Shape} sj
  16686. * @param {Vec3} xi
  16687. * @param {Vec3} xj
  16688. * @param {Quaternion} qi
  16689. * @param {Quaternion} qj
  16690. * @param {Body} bi
  16691. * @param {Body} bj
  16692. */
  16693. Narrowphase.prototype[Shape.types.PLANE | Shape.types.PARTICLE] =
  16694. Narrowphase.prototype.planeParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  16695. var normal = particlePlane_normal;
  16696. normal.set(0,0,1);
  16697. bj.quaternion.vmult(normal,normal); // Turn normal according to plane orientation
  16698. var relpos = particlePlane_relpos;
  16699. xi.vsub(bj.position,relpos);
  16700. var dot = normal.dot(relpos);
  16701. if(dot <= 0.0){
  16702. if(justTest){
  16703. return true;
  16704. }
  16705. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16706. r.ni.copy(normal); // Contact normal is the plane normal
  16707. r.ni.negate(r.ni);
  16708. r.ri.set(0,0,0); // Center of particle
  16709. // Get particle position projected on plane
  16710. var projected = particlePlane_projected;
  16711. normal.mult(normal.dot(xi),projected);
  16712. xi.vsub(projected,projected);
  16713. //projected.vadd(bj.position,projected);
  16714. // rj is now the projected world position minus plane position
  16715. r.rj.copy(projected);
  16716. this.result.push(r);
  16717. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16718. }
  16719. };
  16720. var particleSphere_normal = new Vec3();
  16721. /**
  16722. * @method particleSphere
  16723. * @param {Array} result
  16724. * @param {Shape} si
  16725. * @param {Shape} sj
  16726. * @param {Vec3} xi
  16727. * @param {Vec3} xj
  16728. * @param {Quaternion} qi
  16729. * @param {Quaternion} qj
  16730. * @param {Body} bi
  16731. * @param {Body} bj
  16732. */
  16733. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.SPHERE] =
  16734. Narrowphase.prototype.sphereParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  16735. // The normal is the unit vector from sphere center to particle center
  16736. var normal = particleSphere_normal;
  16737. normal.set(0,0,1);
  16738. xi.vsub(xj,normal);
  16739. var lengthSquared = normal.norm2();
  16740. if(lengthSquared <= sj.radius * sj.radius){
  16741. if(justTest){
  16742. return true;
  16743. }
  16744. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16745. normal.normalize();
  16746. r.rj.copy(normal);
  16747. r.rj.mult(sj.radius,r.rj);
  16748. r.ni.copy(normal); // Contact normal
  16749. r.ni.negate(r.ni);
  16750. r.ri.set(0,0,0); // Center of particle
  16751. this.result.push(r);
  16752. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16753. }
  16754. };
  16755. // WIP
  16756. var cqj = new Quaternion();
  16757. var convexParticle_local = new Vec3();
  16758. var convexParticle_normal = new Vec3();
  16759. var convexParticle_penetratedFaceNormal = new Vec3();
  16760. var convexParticle_vertexToParticle = new Vec3();
  16761. var convexParticle_worldPenetrationVec = new Vec3();
  16762. /**
  16763. * @method convexParticle
  16764. * @param {Array} result
  16765. * @param {Shape} si
  16766. * @param {Shape} sj
  16767. * @param {Vec3} xi
  16768. * @param {Vec3} xj
  16769. * @param {Quaternion} qi
  16770. * @param {Quaternion} qj
  16771. * @param {Body} bi
  16772. * @param {Body} bj
  16773. */
  16774. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.CONVEXPOLYHEDRON] =
  16775. Narrowphase.prototype.convexParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  16776. var penetratedFaceIndex = -1;
  16777. var penetratedFaceNormal = convexParticle_penetratedFaceNormal;
  16778. var worldPenetrationVec = convexParticle_worldPenetrationVec;
  16779. var minPenetration = null;
  16780. var numDetectedFaces = 0;
  16781. // Convert particle position xi to local coords in the convex
  16782. var local = convexParticle_local;
  16783. local.copy(xi);
  16784. local.vsub(xj,local); // Convert position to relative the convex origin
  16785. qj.conjugate(cqj);
  16786. cqj.vmult(local,local);
  16787. if(sj.pointIsInside(local)){
  16788. if(sj.worldVerticesNeedsUpdate){
  16789. sj.computeWorldVertices(xj,qj);
  16790. }
  16791. if(sj.worldFaceNormalsNeedsUpdate){
  16792. sj.computeWorldFaceNormals(qj);
  16793. }
  16794. // For each world polygon in the polyhedra
  16795. for(var i=0,nfaces=sj.faces.length; i!==nfaces; i++){
  16796. // Construct world face vertices
  16797. var verts = [ sj.worldVertices[ sj.faces[i][0] ] ];
  16798. var normal = sj.worldFaceNormals[i];
  16799. // Check how much the particle penetrates the polygon plane.
  16800. xi.vsub(verts[0],convexParticle_vertexToParticle);
  16801. var penetration = -normal.dot(convexParticle_vertexToParticle);
  16802. if(minPenetration===null || Math.abs(penetration)<Math.abs(minPenetration)){
  16803. if(justTest){
  16804. return true;
  16805. }
  16806. minPenetration = penetration;
  16807. penetratedFaceIndex = i;
  16808. penetratedFaceNormal.copy(normal);
  16809. numDetectedFaces++;
  16810. }
  16811. }
  16812. if(penetratedFaceIndex!==-1){
  16813. // Setup contact
  16814. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  16815. penetratedFaceNormal.mult(minPenetration, worldPenetrationVec);
  16816. // rj is the particle position projected to the face
  16817. worldPenetrationVec.vadd(xi,worldPenetrationVec);
  16818. worldPenetrationVec.vsub(xj,worldPenetrationVec);
  16819. r.rj.copy(worldPenetrationVec);
  16820. //var projectedToFace = xi.vsub(xj).vadd(worldPenetrationVec);
  16821. //projectedToFace.copy(r.rj);
  16822. //qj.vmult(r.rj,r.rj);
  16823. penetratedFaceNormal.negate( r.ni ); // Contact normal
  16824. r.ri.set(0,0,0); // Center of particle
  16825. var ri = r.ri,
  16826. rj = r.rj;
  16827. // Make relative to bodies
  16828. ri.vadd(xi, ri);
  16829. ri.vsub(bi.position, ri);
  16830. rj.vadd(xj, rj);
  16831. rj.vsub(bj.position, rj);
  16832. this.result.push(r);
  16833. this.createFrictionEquationsFromContact(r, this.frictionResult);
  16834. } else {
  16835. console.warn("Point found inside convex, but did not find penetrating face!");
  16836. }
  16837. }
  16838. };
  16839. Narrowphase.prototype[Shape.types.BOX | Shape.types.HEIGHTFIELD] =
  16840. Narrowphase.prototype.boxHeightfield = function (si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  16841. si.convexPolyhedronRepresentation.material = si.material;
  16842. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  16843. return this.convexHeightfield(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  16844. };
  16845. var convexHeightfield_tmp1 = new Vec3();
  16846. var convexHeightfield_tmp2 = new Vec3();
  16847. var convexHeightfield_faceList = [0];
  16848. /**
  16849. * @method convexHeightfield
  16850. */
  16851. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.HEIGHTFIELD] =
  16852. Narrowphase.prototype.convexHeightfield = function (
  16853. convexShape,
  16854. hfShape,
  16855. convexPos,
  16856. hfPos,
  16857. convexQuat,
  16858. hfQuat,
  16859. convexBody,
  16860. hfBody,
  16861. rsi,
  16862. rsj,
  16863. justTest
  16864. ){
  16865. var data = hfShape.data,
  16866. w = hfShape.elementSize,
  16867. radius = convexShape.boundingSphereRadius,
  16868. worldPillarOffset = convexHeightfield_tmp2,
  16869. faceList = convexHeightfield_faceList;
  16870. // Get sphere position to heightfield local!
  16871. var localConvexPos = convexHeightfield_tmp1;
  16872. Transform.pointToLocalFrame(hfPos, hfQuat, convexPos, localConvexPos);
  16873. // Get the index of the data points to test against
  16874. var iMinX = Math.floor((localConvexPos.x - radius) / w) - 1,
  16875. iMaxX = Math.ceil((localConvexPos.x + radius) / w) + 1,
  16876. iMinY = Math.floor((localConvexPos.y - radius) / w) - 1,
  16877. iMaxY = Math.ceil((localConvexPos.y + radius) / w) + 1;
  16878. // Bail out if we are out of the terrain
  16879. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length){
  16880. return;
  16881. }
  16882. // Clamp index to edges
  16883. if(iMinX < 0){ iMinX = 0; }
  16884. if(iMaxX < 0){ iMaxX = 0; }
  16885. if(iMinY < 0){ iMinY = 0; }
  16886. if(iMaxY < 0){ iMaxY = 0; }
  16887. if(iMinX >= data.length){ iMinX = data.length - 1; }
  16888. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  16889. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  16890. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  16891. var minMax = [];
  16892. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  16893. var min = minMax[0];
  16894. var max = minMax[1];
  16895. // Bail out if we're cant touch the bounding height box
  16896. if(localConvexPos.z - radius > max || localConvexPos.z + radius < min){
  16897. return;
  16898. }
  16899. for(var i = iMinX; i < iMaxX; i++){
  16900. for(var j = iMinY; j < iMaxY; j++){
  16901. var intersecting = false;
  16902. // Lower triangle
  16903. hfShape.getConvexTrianglePillar(i, j, false);
  16904. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  16905. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  16906. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  16907. }
  16908. if(justTest && intersecting){
  16909. return true;
  16910. }
  16911. // Upper triangle
  16912. hfShape.getConvexTrianglePillar(i, j, true);
  16913. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  16914. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  16915. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  16916. }
  16917. if(justTest && intersecting){
  16918. return true;
  16919. }
  16920. }
  16921. }
  16922. };
  16923. var sphereHeightfield_tmp1 = new Vec3();
  16924. var sphereHeightfield_tmp2 = new Vec3();
  16925. /**
  16926. * @method sphereHeightfield
  16927. */
  16928. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.HEIGHTFIELD] =
  16929. Narrowphase.prototype.sphereHeightfield = function (
  16930. sphereShape,
  16931. hfShape,
  16932. spherePos,
  16933. hfPos,
  16934. sphereQuat,
  16935. hfQuat,
  16936. sphereBody,
  16937. hfBody,
  16938. rsi,
  16939. rsj,
  16940. justTest
  16941. ){
  16942. var data = hfShape.data,
  16943. radius = sphereShape.radius,
  16944. w = hfShape.elementSize,
  16945. worldPillarOffset = sphereHeightfield_tmp2;
  16946. // Get sphere position to heightfield local!
  16947. var localSpherePos = sphereHeightfield_tmp1;
  16948. Transform.pointToLocalFrame(hfPos, hfQuat, spherePos, localSpherePos);
  16949. // Get the index of the data points to test against
  16950. var iMinX = Math.floor((localSpherePos.x - radius) / w) - 1,
  16951. iMaxX = Math.ceil((localSpherePos.x + radius) / w) + 1,
  16952. iMinY = Math.floor((localSpherePos.y - radius) / w) - 1,
  16953. iMaxY = Math.ceil((localSpherePos.y + radius) / w) + 1;
  16954. // Bail out if we are out of the terrain
  16955. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMaxY > data[0].length){
  16956. return;
  16957. }
  16958. // Clamp index to edges
  16959. if(iMinX < 0){ iMinX = 0; }
  16960. if(iMaxX < 0){ iMaxX = 0; }
  16961. if(iMinY < 0){ iMinY = 0; }
  16962. if(iMaxY < 0){ iMaxY = 0; }
  16963. if(iMinX >= data.length){ iMinX = data.length - 1; }
  16964. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  16965. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  16966. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  16967. var minMax = [];
  16968. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  16969. var min = minMax[0];
  16970. var max = minMax[1];
  16971. // Bail out if we're cant touch the bounding height box
  16972. if(localSpherePos.z - radius > max || localSpherePos.z + radius < min){
  16973. return;
  16974. }
  16975. var result = this.result;
  16976. for(var i = iMinX; i < iMaxX; i++){
  16977. for(var j = iMinY; j < iMaxY; j++){
  16978. var numContactsBefore = result.length;
  16979. var intersecting = false;
  16980. // Lower triangle
  16981. hfShape.getConvexTrianglePillar(i, j, false);
  16982. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  16983. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  16984. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  16985. }
  16986. if(justTest && intersecting){
  16987. return true;
  16988. }
  16989. // Upper triangle
  16990. hfShape.getConvexTrianglePillar(i, j, true);
  16991. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  16992. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  16993. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  16994. }
  16995. if(justTest && intersecting){
  16996. return true;
  16997. }
  16998. var numContacts = result.length - numContactsBefore;
  16999. if(numContacts > 2){
  17000. return;
  17001. }
  17002. /*
  17003. // Skip all but 1
  17004. for (var k = 0; k < numContacts - 1; k++) {
  17005. result.pop();
  17006. }
  17007. */
  17008. }
  17009. }
  17010. };
  17011. },{"../collision/AABB":24,"../collision/Ray":31,"../equations/ContactEquation":41,"../equations/FrictionEquation":43,"../math/Quaternion":50,"../math/Transform":51,"../math/Vec3":52,"../objects/Body":53,"../shapes/ConvexPolyhedron":60,"../shapes/Shape":65,"../solver/Solver":69,"../utils/Vec3Pool":76}],78:[function(require,module,exports){
  17012. /* global performance */
  17013. module.exports = World;
  17014. var Shape = require('../shapes/Shape');
  17015. var Vec3 = require('../math/Vec3');
  17016. var Quaternion = require('../math/Quaternion');
  17017. var GSSolver = require('../solver/GSSolver');
  17018. var ContactEquation = require('../equations/ContactEquation');
  17019. var FrictionEquation = require('../equations/FrictionEquation');
  17020. var Narrowphase = require('./Narrowphase');
  17021. var EventTarget = require('../utils/EventTarget');
  17022. var ArrayCollisionMatrix = require('../collision/ArrayCollisionMatrix');
  17023. var OverlapKeeper = require('../collision/OverlapKeeper');
  17024. var Material = require('../material/Material');
  17025. var ContactMaterial = require('../material/ContactMaterial');
  17026. var Body = require('../objects/Body');
  17027. var TupleDictionary = require('../utils/TupleDictionary');
  17028. var RaycastResult = require('../collision/RaycastResult');
  17029. var AABB = require('../collision/AABB');
  17030. var Ray = require('../collision/Ray');
  17031. var NaiveBroadphase = require('../collision/NaiveBroadphase');
  17032. /**
  17033. * The physics world
  17034. * @class World
  17035. * @constructor
  17036. * @extends EventTarget
  17037. * @param {object} [options]
  17038. * @param {Vec3} [options.gravity]
  17039. * @param {boolean} [options.allowSleep]
  17040. * @param {Broadphase} [options.broadphase]
  17041. * @param {Solver} [options.solver]
  17042. * @param {boolean} [options.quatNormalizeFast]
  17043. * @param {number} [options.quatNormalizeSkip]
  17044. */
  17045. function World(options){
  17046. options = options || {};
  17047. EventTarget.apply(this);
  17048. /**
  17049. * Currently / last used timestep. Is set to -1 if not available. This value is updated before each internal step, which means that it is "fresh" inside event callbacks.
  17050. * @property {Number} dt
  17051. */
  17052. this.dt = -1;
  17053. /**
  17054. * Makes bodies go to sleep when they've been inactive
  17055. * @property allowSleep
  17056. * @type {Boolean}
  17057. * @default false
  17058. */
  17059. this.allowSleep = !!options.allowSleep;
  17060. /**
  17061. * All the current contacts (instances of ContactEquation) in the world.
  17062. * @property contacts
  17063. * @type {Array}
  17064. */
  17065. this.contacts = [];
  17066. this.frictionEquations = [];
  17067. /**
  17068. * How often to normalize quaternions. Set to 0 for every step, 1 for every second etc.. A larger value increases performance. If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
  17069. * @property quatNormalizeSkip
  17070. * @type {Number}
  17071. * @default 0
  17072. */
  17073. this.quatNormalizeSkip = options.quatNormalizeSkip !== undefined ? options.quatNormalizeSkip : 0;
  17074. /**
  17075. * Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
  17076. * @property quatNormalizeFast
  17077. * @type {Boolean}
  17078. * @see Quaternion.normalizeFast
  17079. * @see Quaternion.normalize
  17080. * @default false
  17081. */
  17082. this.quatNormalizeFast = options.quatNormalizeFast !== undefined ? options.quatNormalizeFast : false;
  17083. /**
  17084. * The wall-clock time since simulation start
  17085. * @property time
  17086. * @type {Number}
  17087. */
  17088. this.time = 0.0;
  17089. /**
  17090. * Number of timesteps taken since start
  17091. * @property stepnumber
  17092. * @type {Number}
  17093. */
  17094. this.stepnumber = 0;
  17095. /// Default and last timestep sizes
  17096. this.default_dt = 1/60;
  17097. this.nextId = 0;
  17098. /**
  17099. * @property gravity
  17100. * @type {Vec3}
  17101. */
  17102. this.gravity = new Vec3();
  17103. if(options.gravity){
  17104. this.gravity.copy(options.gravity);
  17105. }
  17106. /**
  17107. * The broadphase algorithm to use. Default is NaiveBroadphase
  17108. * @property broadphase
  17109. * @type {Broadphase}
  17110. */
  17111. this.broadphase = options.broadphase !== undefined ? options.broadphase : new NaiveBroadphase();
  17112. /**
  17113. * @property bodies
  17114. * @type {Array}
  17115. */
  17116. this.bodies = [];
  17117. /**
  17118. * The solver algorithm to use. Default is GSSolver
  17119. * @property solver
  17120. * @type {Solver}
  17121. */
  17122. this.solver = options.solver !== undefined ? options.solver : new GSSolver();
  17123. /**
  17124. * @property constraints
  17125. * @type {Array}
  17126. */
  17127. this.constraints = [];
  17128. /**
  17129. * @property narrowphase
  17130. * @type {Narrowphase}
  17131. */
  17132. this.narrowphase = new Narrowphase(this);
  17133. /**
  17134. * @property {ArrayCollisionMatrix} collisionMatrix
  17135. * @type {ArrayCollisionMatrix}
  17136. */
  17137. this.collisionMatrix = new ArrayCollisionMatrix();
  17138. /**
  17139. * CollisionMatrix from the previous step.
  17140. * @property {ArrayCollisionMatrix} collisionMatrixPrevious
  17141. * @type {ArrayCollisionMatrix}
  17142. */
  17143. this.collisionMatrixPrevious = new ArrayCollisionMatrix();
  17144. this.bodyOverlapKeeper = new OverlapKeeper();
  17145. this.shapeOverlapKeeper = new OverlapKeeper();
  17146. /**
  17147. * All added materials
  17148. * @property materials
  17149. * @type {Array}
  17150. */
  17151. this.materials = [];
  17152. /**
  17153. * @property contactmaterials
  17154. * @type {Array}
  17155. */
  17156. this.contactmaterials = [];
  17157. /**
  17158. * Used to look up a ContactMaterial given two instances of Material.
  17159. * @property {TupleDictionary} contactMaterialTable
  17160. */
  17161. this.contactMaterialTable = new TupleDictionary();
  17162. this.defaultMaterial = new Material("default");
  17163. /**
  17164. * This contact material is used if no suitable contactmaterial is found for a contact.
  17165. * @property defaultContactMaterial
  17166. * @type {ContactMaterial}
  17167. */
  17168. this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial, this.defaultMaterial, { friction: 0.3, restitution: 0.0 });
  17169. /**
  17170. * @property doProfiling
  17171. * @type {Boolean}
  17172. */
  17173. this.doProfiling = false;
  17174. /**
  17175. * @property profile
  17176. * @type {Object}
  17177. */
  17178. this.profile = {
  17179. solve:0,
  17180. makeContactConstraints:0,
  17181. broadphase:0,
  17182. integrate:0,
  17183. narrowphase:0,
  17184. };
  17185. /**
  17186. * Time accumulator for interpolation. See http://gafferongames.com/game-physics/fix-your-timestep/
  17187. * @property {Number} accumulator
  17188. */
  17189. this.accumulator = 0;
  17190. /**
  17191. * @property subsystems
  17192. * @type {Array}
  17193. */
  17194. this.subsystems = [];
  17195. /**
  17196. * Dispatched after a body has been added to the world.
  17197. * @event addBody
  17198. * @param {Body} body The body that has been added to the world.
  17199. */
  17200. this.addBodyEvent = {
  17201. type:"addBody",
  17202. body : null
  17203. };
  17204. /**
  17205. * Dispatched after a body has been removed from the world.
  17206. * @event removeBody
  17207. * @param {Body} body The body that has been removed from the world.
  17208. */
  17209. this.removeBodyEvent = {
  17210. type:"removeBody",
  17211. body : null
  17212. };
  17213. this.idToBodyMap = {};
  17214. this.broadphase.setWorld(this);
  17215. }
  17216. World.prototype = new EventTarget();
  17217. // Temp stuff
  17218. var tmpAABB1 = new AABB();
  17219. var tmpArray1 = [];
  17220. var tmpRay = new Ray();
  17221. /**
  17222. * Get the contact material between materials m1 and m2
  17223. * @method getContactMaterial
  17224. * @param {Material} m1
  17225. * @param {Material} m2
  17226. * @return {ContactMaterial} The contact material if it was found.
  17227. */
  17228. World.prototype.getContactMaterial = function(m1,m2){
  17229. return this.contactMaterialTable.get(m1.id,m2.id); //this.contactmaterials[this.mats2cmat[i+j*this.materials.length]];
  17230. };
  17231. /**
  17232. * Get number of objects in the world.
  17233. * @method numObjects
  17234. * @return {Number}
  17235. * @deprecated
  17236. */
  17237. World.prototype.numObjects = function(){
  17238. return this.bodies.length;
  17239. };
  17240. /**
  17241. * Store old collision state info
  17242. * @method collisionMatrixTick
  17243. */
  17244. World.prototype.collisionMatrixTick = function(){
  17245. var temp = this.collisionMatrixPrevious;
  17246. this.collisionMatrixPrevious = this.collisionMatrix;
  17247. this.collisionMatrix = temp;
  17248. this.collisionMatrix.reset();
  17249. this.bodyOverlapKeeper.tick();
  17250. this.shapeOverlapKeeper.tick();
  17251. };
  17252. /**
  17253. * Add a rigid body to the simulation.
  17254. * @method add
  17255. * @param {Body} body
  17256. * @todo If the simulation has not yet started, why recrete and copy arrays for each body? Accumulate in dynamic arrays in this case.
  17257. * @todo Adding an array of bodies should be possible. This would save some loops too
  17258. * @deprecated Use .addBody instead
  17259. */
  17260. World.prototype.add = World.prototype.addBody = function(body){
  17261. if(this.bodies.indexOf(body) !== -1){
  17262. return;
  17263. }
  17264. body.index = this.bodies.length;
  17265. this.bodies.push(body);
  17266. body.world = this;
  17267. body.initPosition.copy(body.position);
  17268. body.initVelocity.copy(body.velocity);
  17269. body.timeLastSleepy = this.time;
  17270. if(body instanceof Body){
  17271. body.initAngularVelocity.copy(body.angularVelocity);
  17272. body.initQuaternion.copy(body.quaternion);
  17273. }
  17274. this.collisionMatrix.setNumObjects(this.bodies.length);
  17275. this.addBodyEvent.body = body;
  17276. this.idToBodyMap[body.id] = body;
  17277. this.dispatchEvent(this.addBodyEvent);
  17278. };
  17279. /**
  17280. * Add a constraint to the simulation.
  17281. * @method addConstraint
  17282. * @param {Constraint} c
  17283. */
  17284. World.prototype.addConstraint = function(c){
  17285. this.constraints.push(c);
  17286. };
  17287. /**
  17288. * Removes a constraint
  17289. * @method removeConstraint
  17290. * @param {Constraint} c
  17291. */
  17292. World.prototype.removeConstraint = function(c){
  17293. var idx = this.constraints.indexOf(c);
  17294. if(idx!==-1){
  17295. this.constraints.splice(idx,1);
  17296. }
  17297. };
  17298. /**
  17299. * Raycast test
  17300. * @method rayTest
  17301. * @param {Vec3} from
  17302. * @param {Vec3} to
  17303. * @param {RaycastResult} result
  17304. * @deprecated Use .raycastAll, .raycastClosest or .raycastAny instead.
  17305. */
  17306. World.prototype.rayTest = function(from, to, result){
  17307. if(result instanceof RaycastResult){
  17308. // Do raycastclosest
  17309. this.raycastClosest(from, to, {
  17310. skipBackfaces: true
  17311. }, result);
  17312. } else {
  17313. // Do raycastAll
  17314. this.raycastAll(from, to, {
  17315. skipBackfaces: true
  17316. }, result);
  17317. }
  17318. };
  17319. /**
  17320. * Ray cast against all bodies. The provided callback will be executed for each hit with a RaycastResult as single argument.
  17321. * @method raycastAll
  17322. * @param {Vec3} from
  17323. * @param {Vec3} to
  17324. * @param {Object} options
  17325. * @param {number} [options.collisionFilterMask=-1]
  17326. * @param {number} [options.collisionFilterGroup=-1]
  17327. * @param {boolean} [options.skipBackfaces=false]
  17328. * @param {boolean} [options.checkCollisionResponse=true]
  17329. * @param {Function} callback
  17330. * @return {boolean} True if any body was hit.
  17331. */
  17332. World.prototype.raycastAll = function(from, to, options, callback){
  17333. options.mode = Ray.ALL;
  17334. options.from = from;
  17335. options.to = to;
  17336. options.callback = callback;
  17337. return tmpRay.intersectWorld(this, options);
  17338. };
  17339. /**
  17340. * Ray cast, and stop at the first result. Note that the order is random - but the method is fast.
  17341. * @method raycastAny
  17342. * @param {Vec3} from
  17343. * @param {Vec3} to
  17344. * @param {Object} options
  17345. * @param {number} [options.collisionFilterMask=-1]
  17346. * @param {number} [options.collisionFilterGroup=-1]
  17347. * @param {boolean} [options.skipBackfaces=false]
  17348. * @param {boolean} [options.checkCollisionResponse=true]
  17349. * @param {RaycastResult} result
  17350. * @return {boolean} True if any body was hit.
  17351. */
  17352. World.prototype.raycastAny = function(from, to, options, result){
  17353. options.mode = Ray.ANY;
  17354. options.from = from;
  17355. options.to = to;
  17356. options.result = result;
  17357. return tmpRay.intersectWorld(this, options);
  17358. };
  17359. /**
  17360. * Ray cast, and return information of the closest hit.
  17361. * @method raycastClosest
  17362. * @param {Vec3} from
  17363. * @param {Vec3} to
  17364. * @param {Object} options
  17365. * @param {number} [options.collisionFilterMask=-1]
  17366. * @param {number} [options.collisionFilterGroup=-1]
  17367. * @param {boolean} [options.skipBackfaces=false]
  17368. * @param {boolean} [options.checkCollisionResponse=true]
  17369. * @param {RaycastResult} result
  17370. * @return {boolean} True if any body was hit.
  17371. */
  17372. World.prototype.raycastClosest = function(from, to, options, result){
  17373. options.mode = Ray.CLOSEST;
  17374. options.from = from;
  17375. options.to = to;
  17376. options.result = result;
  17377. return tmpRay.intersectWorld(this, options);
  17378. };
  17379. /**
  17380. * Remove a rigid body from the simulation.
  17381. * @method remove
  17382. * @param {Body} body
  17383. * @deprecated Use .removeBody instead
  17384. */
  17385. World.prototype.remove = function(body){
  17386. body.world = null;
  17387. var n = this.bodies.length - 1,
  17388. bodies = this.bodies,
  17389. idx = bodies.indexOf(body);
  17390. if(idx !== -1){
  17391. bodies.splice(idx, 1); // Todo: should use a garbage free method
  17392. // Recompute index
  17393. for(var i=0; i!==bodies.length; i++){
  17394. bodies[i].index = i;
  17395. }
  17396. this.collisionMatrix.setNumObjects(n);
  17397. this.removeBodyEvent.body = body;
  17398. delete this.idToBodyMap[body.id];
  17399. this.dispatchEvent(this.removeBodyEvent);
  17400. }
  17401. };
  17402. /**
  17403. * Remove a rigid body from the simulation.
  17404. * @method removeBody
  17405. * @param {Body} body
  17406. */
  17407. World.prototype.removeBody = World.prototype.remove;
  17408. World.prototype.getBodyById = function(id){
  17409. return this.idToBodyMap[id];
  17410. };
  17411. // TODO Make a faster map
  17412. World.prototype.getShapeById = function(id){
  17413. var bodies = this.bodies;
  17414. for(var i=0, bl = bodies.length; i<bl; i++){
  17415. var shapes = bodies[i].shapes;
  17416. for (var j = 0, sl = shapes.length; j < sl; j++) {
  17417. var shape = shapes[j];
  17418. if(shape.id === id){
  17419. return shape;
  17420. }
  17421. }
  17422. }
  17423. };
  17424. /**
  17425. * Adds a material to the World.
  17426. * @method addMaterial
  17427. * @param {Material} m
  17428. * @todo Necessary?
  17429. */
  17430. World.prototype.addMaterial = function(m){
  17431. this.materials.push(m);
  17432. };
  17433. /**
  17434. * Adds a contact material to the World
  17435. * @method addContactMaterial
  17436. * @param {ContactMaterial} cmat
  17437. */
  17438. World.prototype.addContactMaterial = function(cmat) {
  17439. // Add contact material
  17440. this.contactmaterials.push(cmat);
  17441. // Add current contact material to the material table
  17442. this.contactMaterialTable.set(cmat.materials[0].id,cmat.materials[1].id,cmat);
  17443. };
  17444. // performance.now()
  17445. if(typeof performance === 'undefined'){
  17446. performance = {};
  17447. }
  17448. if(!performance.now){
  17449. var nowOffset = Date.now();
  17450. if (performance.timing && performance.timing.navigationStart){
  17451. nowOffset = performance.timing.navigationStart;
  17452. }
  17453. performance.now = function(){
  17454. return Date.now() - nowOffset;
  17455. };
  17456. }
  17457. var step_tmp1 = new Vec3();
  17458. /**
  17459. * Step the physics world forward in time.
  17460. *
  17461. * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
  17462. *
  17463. * @method step
  17464. * @param {Number} dt The fixed time step size to use.
  17465. * @param {Number} [timeSinceLastCalled] The time elapsed since the function was last called.
  17466. * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
  17467. *
  17468. * @example
  17469. * // fixed timestepping without interpolation
  17470. * world.step(1/60);
  17471. *
  17472. * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  17473. */
  17474. World.prototype.step = function(dt, timeSinceLastCalled, maxSubSteps){
  17475. maxSubSteps = maxSubSteps || 10;
  17476. timeSinceLastCalled = timeSinceLastCalled || 0;
  17477. if(timeSinceLastCalled === 0){ // Fixed, simple stepping
  17478. this.internalStep(dt);
  17479. // Increment time
  17480. this.time += dt;
  17481. } else {
  17482. this.accumulator += timeSinceLastCalled;
  17483. var substeps = 0;
  17484. while (this.accumulator >= dt && substeps < maxSubSteps) {
  17485. // Do fixed steps to catch up
  17486. this.internalStep(dt);
  17487. this.accumulator -= dt;
  17488. substeps++;
  17489. }
  17490. var t = (this.accumulator % dt) / dt;
  17491. for(var j=0; j !== this.bodies.length; j++){
  17492. var b = this.bodies[j];
  17493. b.previousPosition.lerp(b.position, t, b.interpolatedPosition);
  17494. b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion);
  17495. b.previousQuaternion.normalize();
  17496. }
  17497. this.time += timeSinceLastCalled;
  17498. }
  17499. };
  17500. var
  17501. /**
  17502. * Dispatched after the world has stepped forward in time.
  17503. * @event postStep
  17504. */
  17505. World_step_postStepEvent = {type:"postStep"}, // Reusable event objects to save memory
  17506. /**
  17507. * Dispatched before the world steps forward in time.
  17508. * @event preStep
  17509. */
  17510. World_step_preStepEvent = {type:"preStep"},
  17511. World_step_collideEvent = {type:Body.COLLIDE_EVENT_NAME, body:null, contact:null },
  17512. World_step_oldContacts = [], // Pools for unused objects
  17513. World_step_frictionEquationPool = [],
  17514. World_step_p1 = [], // Reusable arrays for collision pairs
  17515. World_step_p2 = [],
  17516. World_step_gvec = new Vec3(), // Temporary vectors and quats
  17517. World_step_vi = new Vec3(),
  17518. World_step_vj = new Vec3(),
  17519. World_step_wi = new Vec3(),
  17520. World_step_wj = new Vec3(),
  17521. World_step_t1 = new Vec3(),
  17522. World_step_t2 = new Vec3(),
  17523. World_step_rixn = new Vec3(),
  17524. World_step_rjxn = new Vec3(),
  17525. World_step_step_q = new Quaternion(),
  17526. World_step_step_w = new Quaternion(),
  17527. World_step_step_wq = new Quaternion(),
  17528. invI_tau_dt = new Vec3();
  17529. World.prototype.internalStep = function(dt){
  17530. this.dt = dt;
  17531. var world = this,
  17532. that = this,
  17533. contacts = this.contacts,
  17534. p1 = World_step_p1,
  17535. p2 = World_step_p2,
  17536. N = this.numObjects(),
  17537. bodies = this.bodies,
  17538. solver = this.solver,
  17539. gravity = this.gravity,
  17540. doProfiling = this.doProfiling,
  17541. profile = this.profile,
  17542. DYNAMIC = Body.DYNAMIC,
  17543. profilingStart,
  17544. constraints = this.constraints,
  17545. frictionEquationPool = World_step_frictionEquationPool,
  17546. gnorm = gravity.norm(),
  17547. gx = gravity.x,
  17548. gy = gravity.y,
  17549. gz = gravity.z,
  17550. i=0;
  17551. if(doProfiling){
  17552. profilingStart = performance.now();
  17553. }
  17554. // Add gravity to all objects
  17555. for(i=0; i!==N; i++){
  17556. var bi = bodies[i];
  17557. if(bi.type === DYNAMIC){ // Only for dynamic bodies
  17558. var f = bi.force, m = bi.mass;
  17559. f.x += m*gx;
  17560. f.y += m*gy;
  17561. f.z += m*gz;
  17562. }
  17563. }
  17564. // Update subsystems
  17565. for(var i=0, Nsubsystems=this.subsystems.length; i!==Nsubsystems; i++){
  17566. this.subsystems[i].update();
  17567. }
  17568. // Collision detection
  17569. if(doProfiling){ profilingStart = performance.now(); }
  17570. p1.length = 0; // Clean up pair arrays from last step
  17571. p2.length = 0;
  17572. this.broadphase.collisionPairs(this,p1,p2);
  17573. if(doProfiling){ profile.broadphase = performance.now() - profilingStart; }
  17574. // Remove constrained pairs with collideConnected == false
  17575. var Nconstraints = constraints.length;
  17576. for(i=0; i!==Nconstraints; i++){
  17577. var c = constraints[i];
  17578. if(!c.collideConnected){
  17579. for(var j = p1.length-1; j>=0; j-=1){
  17580. if( (c.bodyA === p1[j] && c.bodyB === p2[j]) ||
  17581. (c.bodyB === p1[j] && c.bodyA === p2[j])){
  17582. p1.splice(j, 1);
  17583. p2.splice(j, 1);
  17584. }
  17585. }
  17586. }
  17587. }
  17588. this.collisionMatrixTick();
  17589. // Generate contacts
  17590. if(doProfiling){ profilingStart = performance.now(); }
  17591. var oldcontacts = World_step_oldContacts;
  17592. var NoldContacts = contacts.length;
  17593. for(i=0; i!==NoldContacts; i++){
  17594. oldcontacts.push(contacts[i]);
  17595. }
  17596. contacts.length = 0;
  17597. // Transfer FrictionEquation from current list to the pool for reuse
  17598. var NoldFrictionEquations = this.frictionEquations.length;
  17599. for(i=0; i!==NoldFrictionEquations; i++){
  17600. frictionEquationPool.push(this.frictionEquations[i]);
  17601. }
  17602. this.frictionEquations.length = 0;
  17603. this.narrowphase.getContacts(
  17604. p1,
  17605. p2,
  17606. this,
  17607. contacts,
  17608. oldcontacts, // To be reused
  17609. this.frictionEquations,
  17610. frictionEquationPool
  17611. );
  17612. if(doProfiling){
  17613. profile.narrowphase = performance.now() - profilingStart;
  17614. }
  17615. // Loop over all collisions
  17616. if(doProfiling){
  17617. profilingStart = performance.now();
  17618. }
  17619. // Add all friction eqs
  17620. for (var i = 0; i < this.frictionEquations.length; i++) {
  17621. solver.addEquation(this.frictionEquations[i]);
  17622. }
  17623. var ncontacts = contacts.length;
  17624. for(var k=0; k!==ncontacts; k++){
  17625. // Current contact
  17626. var c = contacts[k];
  17627. // Get current collision indeces
  17628. var bi = c.bi,
  17629. bj = c.bj,
  17630. si = c.si,
  17631. sj = c.sj;
  17632. // Get collision properties
  17633. var cm;
  17634. if(bi.material && bj.material){
  17635. cm = this.getContactMaterial(bi.material,bj.material) || this.defaultContactMaterial;
  17636. } else {
  17637. cm = this.defaultContactMaterial;
  17638. }
  17639. // c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  17640. var mu = cm.friction;
  17641. // c.restitution = cm.restitution;
  17642. // If friction or restitution were specified in the material, use them
  17643. if(bi.material && bj.material){
  17644. if(bi.material.friction >= 0 && bj.material.friction >= 0){
  17645. mu = bi.material.friction * bj.material.friction;
  17646. }
  17647. if(bi.material.restitution >= 0 && bj.material.restitution >= 0){
  17648. c.restitution = bi.material.restitution * bj.material.restitution;
  17649. }
  17650. }
  17651. // c.setSpookParams(
  17652. // cm.contactEquationStiffness,
  17653. // cm.contactEquationRelaxation,
  17654. // dt
  17655. // );
  17656. solver.addEquation(c);
  17657. // // Add friction constraint equation
  17658. // if(mu > 0){
  17659. // // Create 2 tangent equations
  17660. // var mug = mu * gnorm;
  17661. // var reducedMass = (bi.invMass + bj.invMass);
  17662. // if(reducedMass > 0){
  17663. // reducedMass = 1/reducedMass;
  17664. // }
  17665. // var pool = frictionEquationPool;
  17666. // var c1 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  17667. // var c2 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  17668. // this.frictionEquations.push(c1, c2);
  17669. // c1.bi = c2.bi = bi;
  17670. // c1.bj = c2.bj = bj;
  17671. // c1.minForce = c2.minForce = -mug*reducedMass;
  17672. // c1.maxForce = c2.maxForce = mug*reducedMass;
  17673. // // Copy over the relative vectors
  17674. // c1.ri.copy(c.ri);
  17675. // c1.rj.copy(c.rj);
  17676. // c2.ri.copy(c.ri);
  17677. // c2.rj.copy(c.rj);
  17678. // // Construct tangents
  17679. // c.ni.tangents(c1.t, c2.t);
  17680. // // Set spook params
  17681. // c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  17682. // c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  17683. // c1.enabled = c2.enabled = c.enabled;
  17684. // // Add equations to solver
  17685. // solver.addEquation(c1);
  17686. // solver.addEquation(c2);
  17687. // }
  17688. if( bi.allowSleep &&
  17689. bi.type === Body.DYNAMIC &&
  17690. bi.sleepState === Body.SLEEPING &&
  17691. bj.sleepState === Body.AWAKE &&
  17692. bj.type !== Body.STATIC
  17693. ){
  17694. var speedSquaredB = bj.velocity.norm2() + bj.angularVelocity.norm2();
  17695. var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
  17696. if(speedSquaredB >= speedLimitSquaredB*2){
  17697. bi._wakeUpAfterNarrowphase = true;
  17698. }
  17699. }
  17700. if( bj.allowSleep &&
  17701. bj.type === Body.DYNAMIC &&
  17702. bj.sleepState === Body.SLEEPING &&
  17703. bi.sleepState === Body.AWAKE &&
  17704. bi.type !== Body.STATIC
  17705. ){
  17706. var speedSquaredA = bi.velocity.norm2() + bi.angularVelocity.norm2();
  17707. var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
  17708. if(speedSquaredA >= speedLimitSquaredA*2){
  17709. bj._wakeUpAfterNarrowphase = true;
  17710. }
  17711. }
  17712. // Now we know that i and j are in contact. Set collision matrix state
  17713. this.collisionMatrix.set(bi, bj, true);
  17714. if (!this.collisionMatrixPrevious.get(bi, bj)) {
  17715. // First contact!
  17716. // We reuse the collideEvent object, otherwise we will end up creating new objects for each new contact, even if there's no event listener attached.
  17717. World_step_collideEvent.body = bj;
  17718. World_step_collideEvent.contact = c;
  17719. bi.dispatchEvent(World_step_collideEvent);
  17720. World_step_collideEvent.body = bi;
  17721. bj.dispatchEvent(World_step_collideEvent);
  17722. }
  17723. this.bodyOverlapKeeper.set(bi.id, bj.id);
  17724. this.shapeOverlapKeeper.set(si.id, sj.id);
  17725. }
  17726. this.emitContactEvents();
  17727. if(doProfiling){
  17728. profile.makeContactConstraints = performance.now() - profilingStart;
  17729. profilingStart = performance.now();
  17730. }
  17731. // Wake up bodies
  17732. for(i=0; i!==N; i++){
  17733. var bi = bodies[i];
  17734. if(bi._wakeUpAfterNarrowphase){
  17735. bi.wakeUp();
  17736. bi._wakeUpAfterNarrowphase = false;
  17737. }
  17738. }
  17739. // Add user-added constraints
  17740. var Nconstraints = constraints.length;
  17741. for(i=0; i!==Nconstraints; i++){
  17742. var c = constraints[i];
  17743. c.update();
  17744. for(var j=0, Neq=c.equations.length; j!==Neq; j++){
  17745. var eq = c.equations[j];
  17746. solver.addEquation(eq);
  17747. }
  17748. }
  17749. // Solve the constrained system
  17750. solver.solve(dt,this);
  17751. if(doProfiling){
  17752. profile.solve = performance.now() - profilingStart;
  17753. }
  17754. // Remove all contacts from solver
  17755. solver.removeAllEquations();
  17756. // Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details
  17757. var pow = Math.pow;
  17758. for(i=0; i!==N; i++){
  17759. var bi = bodies[i];
  17760. if(bi.type & DYNAMIC){ // Only for dynamic bodies
  17761. var ld = pow(1.0 - bi.linearDamping,dt);
  17762. var v = bi.velocity;
  17763. v.mult(ld,v);
  17764. var av = bi.angularVelocity;
  17765. if(av){
  17766. var ad = pow(1.0 - bi.angularDamping,dt);
  17767. av.mult(ad,av);
  17768. }
  17769. }
  17770. }
  17771. this.dispatchEvent(World_step_preStepEvent);
  17772. // Invoke pre-step callbacks
  17773. for(i=0; i!==N; i++){
  17774. var bi = bodies[i];
  17775. if(bi.preStep){
  17776. bi.preStep.call(bi);
  17777. }
  17778. }
  17779. // Leap frog
  17780. // vnew = v + h*f/m
  17781. // xnew = x + h*vnew
  17782. if(doProfiling){
  17783. profilingStart = performance.now();
  17784. }
  17785. var stepnumber = this.stepnumber;
  17786. var quatNormalize = stepnumber % (this.quatNormalizeSkip + 1) === 0;
  17787. var quatNormalizeFast = this.quatNormalizeFast;
  17788. for(i=0; i!==N; i++){
  17789. bodies[i].integrate(dt, quatNormalize, quatNormalizeFast);
  17790. }
  17791. this.clearForces();
  17792. this.broadphase.dirty = true;
  17793. if(doProfiling){
  17794. profile.integrate = performance.now() - profilingStart;
  17795. }
  17796. // Update world time
  17797. this.time += dt;
  17798. this.stepnumber += 1;
  17799. this.dispatchEvent(World_step_postStepEvent);
  17800. // Invoke post-step callbacks
  17801. for(i=0; i!==N; i++){
  17802. var bi = bodies[i];
  17803. var postStep = bi.postStep;
  17804. if(postStep){
  17805. postStep.call(bi);
  17806. }
  17807. }
  17808. // Sleeping update
  17809. if(this.allowSleep){
  17810. for(i=0; i!==N; i++){
  17811. bodies[i].sleepTick(this.time);
  17812. }
  17813. }
  17814. };
  17815. World.prototype.emitContactEvents = (function(){
  17816. var additions = [];
  17817. var removals = [];
  17818. var beginContactEvent = {
  17819. type: 'beginContact',
  17820. bodyA: null,
  17821. bodyB: null
  17822. };
  17823. var endContactEvent = {
  17824. type: 'endContact',
  17825. bodyA: null,
  17826. bodyB: null
  17827. };
  17828. var beginShapeContactEvent = {
  17829. type: 'beginShapeContact',
  17830. bodyA: null,
  17831. bodyB: null,
  17832. shapeA: null,
  17833. shapeB: null
  17834. };
  17835. var endShapeContactEvent = {
  17836. type: 'endShapeContact',
  17837. bodyA: null,
  17838. bodyB: null,
  17839. shapeA: null,
  17840. shapeB: null
  17841. };
  17842. return function(){
  17843. var hasBeginContact = this.hasAnyEventListener('beginContact');
  17844. var hasEndContact = this.hasAnyEventListener('endContact');
  17845. if(hasBeginContact || hasEndContact){
  17846. this.bodyOverlapKeeper.getDiff(additions, removals);
  17847. }
  17848. if(hasBeginContact){
  17849. for (var i = 0, l = additions.length; i < l; i += 2) {
  17850. beginContactEvent.bodyA = this.getBodyById(additions[i]);
  17851. beginContactEvent.bodyB = this.getBodyById(additions[i+1]);
  17852. this.dispatchEvent(beginContactEvent);
  17853. }
  17854. beginContactEvent.bodyA = beginContactEvent.bodyB = null;
  17855. }
  17856. if(hasEndContact){
  17857. for (var i = 0, l = removals.length; i < l; i += 2) {
  17858. endContactEvent.bodyA = this.getBodyById(removals[i]);
  17859. endContactEvent.bodyB = this.getBodyById(removals[i+1]);
  17860. this.dispatchEvent(endContactEvent);
  17861. }
  17862. endContactEvent.bodyA = endContactEvent.bodyB = null;
  17863. }
  17864. additions.length = removals.length = 0;
  17865. var hasBeginShapeContact = this.hasAnyEventListener('beginShapeContact');
  17866. var hasEndShapeContact = this.hasAnyEventListener('endShapeContact');
  17867. if(hasBeginShapeContact || hasEndShapeContact){
  17868. this.shapeOverlapKeeper.getDiff(additions, removals);
  17869. }
  17870. if(hasBeginShapeContact){
  17871. for (var i = 0, l = additions.length; i < l; i += 2) {
  17872. var shapeA = this.getShapeById(additions[i]);
  17873. var shapeB = this.getShapeById(additions[i+1]);
  17874. beginShapeContactEvent.shapeA = shapeA;
  17875. beginShapeContactEvent.shapeB = shapeB;
  17876. beginShapeContactEvent.bodyA = shapeA.body;
  17877. beginShapeContactEvent.bodyB = shapeB.body;
  17878. this.dispatchEvent(beginShapeContactEvent);
  17879. }
  17880. beginShapeContactEvent.bodyA = beginShapeContactEvent.bodyB = beginShapeContactEvent.shapeA = beginShapeContactEvent.shapeB = null;
  17881. }
  17882. if(hasEndShapeContact){
  17883. for (var i = 0, l = removals.length; i < l; i += 2) {
  17884. var shapeA = this.getShapeById(removals[i]);
  17885. var shapeB = this.getShapeById(removals[i+1]);
  17886. endShapeContactEvent.shapeA = shapeA;
  17887. endShapeContactEvent.shapeB = shapeB;
  17888. endShapeContactEvent.bodyA = shapeA.body;
  17889. endShapeContactEvent.bodyB = shapeB.body;
  17890. this.dispatchEvent(endShapeContactEvent);
  17891. }
  17892. endShapeContactEvent.bodyA = endShapeContactEvent.bodyB = endShapeContactEvent.shapeA = endShapeContactEvent.shapeB = null;
  17893. }
  17894. };
  17895. })();
  17896. /**
  17897. * Sets all body forces in the world to zero.
  17898. * @method clearForces
  17899. */
  17900. World.prototype.clearForces = function(){
  17901. var bodies = this.bodies;
  17902. var N = bodies.length;
  17903. for(var i=0; i !== N; i++){
  17904. var b = bodies[i],
  17905. force = b.force,
  17906. tau = b.torque;
  17907. b.force.set(0,0,0);
  17908. b.torque.set(0,0,0);
  17909. }
  17910. };
  17911. },{"../collision/AABB":24,"../collision/ArrayCollisionMatrix":25,"../collision/NaiveBroadphase":28,"../collision/OverlapKeeper":30,"../collision/Ray":31,"../collision/RaycastResult":32,"../equations/ContactEquation":41,"../equations/FrictionEquation":43,"../material/ContactMaterial":46,"../material/Material":47,"../math/Quaternion":50,"../math/Vec3":52,"../objects/Body":53,"../shapes/Shape":65,"../solver/GSSolver":68,"../utils/EventTarget":71,"../utils/TupleDictionary":74,"./Narrowphase":77}],79:[function(require,module,exports){
  17912. const BinaryHeap = require('./BinaryHeap');
  17913. const utils = require('./utils.js');
  17914. class AStar {
  17915. static init (graph) {
  17916. for (let x = 0; x < graph.length; x++) {
  17917. //for(var x in graph) {
  17918. const node = graph[x];
  17919. node.f = 0;
  17920. node.g = 0;
  17921. node.h = 0;
  17922. node.cost = 1.0;
  17923. node.visited = false;
  17924. node.closed = false;
  17925. node.parent = null;
  17926. }
  17927. }
  17928. static cleanUp (graph) {
  17929. for (let x = 0; x < graph.length; x++) {
  17930. const node = graph[x];
  17931. delete node.f;
  17932. delete node.g;
  17933. delete node.h;
  17934. delete node.cost;
  17935. delete node.visited;
  17936. delete node.closed;
  17937. delete node.parent;
  17938. }
  17939. }
  17940. static heap () {
  17941. return new BinaryHeap(function (node) {
  17942. return node.f;
  17943. });
  17944. }
  17945. static search (graph, start, end) {
  17946. this.init(graph);
  17947. //heuristic = heuristic || astar.manhattan;
  17948. const openHeap = this.heap();
  17949. openHeap.push(start);
  17950. while (openHeap.size() > 0) {
  17951. // Grab the lowest f(x) to process next. Heap keeps this sorted for us.
  17952. const currentNode = openHeap.pop();
  17953. // End case -- result has been found, return the traced path.
  17954. if (currentNode === end) {
  17955. let curr = currentNode;
  17956. const ret = [];
  17957. while (curr.parent) {
  17958. ret.push(curr);
  17959. curr = curr.parent;
  17960. }
  17961. this.cleanUp(ret);
  17962. return ret.reverse();
  17963. }
  17964. // Normal case -- move currentNode from open to closed, process each of its neighbours.
  17965. currentNode.closed = true;
  17966. // Find all neighbours for the current node. Optionally find diagonal neighbours as well (false by default).
  17967. const neighbours = this.neighbours(graph, currentNode);
  17968. for (let i = 0, il = neighbours.length; i < il; i++) {
  17969. const neighbour = neighbours[i];
  17970. if (neighbour.closed) {
  17971. // Not a valid node to process, skip to next neighbour.
  17972. continue;
  17973. }
  17974. // The g score is the shortest distance from start to current node.
  17975. // We need to check if the path we have arrived at this neighbour is the shortest one we have seen yet.
  17976. const gScore = currentNode.g + neighbour.cost;
  17977. const beenVisited = neighbour.visited;
  17978. if (!beenVisited || gScore < neighbour.g) {
  17979. // Found an optimal (so far) path to this node. Take score for node to see how good it is.
  17980. neighbour.visited = true;
  17981. neighbour.parent = currentNode;
  17982. if (!neighbour.centroid || !end.centroid) throw new Error('Unexpected state');
  17983. neighbour.h = neighbour.h || this.heuristic(neighbour.centroid, end.centroid);
  17984. neighbour.g = gScore;
  17985. neighbour.f = neighbour.g + neighbour.h;
  17986. if (!beenVisited) {
  17987. // Pushing to heap will put it in proper place based on the 'f' value.
  17988. openHeap.push(neighbour);
  17989. } else {
  17990. // Already seen the node, but since it has been rescored we need to reorder it in the heap
  17991. openHeap.rescoreElement(neighbour);
  17992. }
  17993. }
  17994. }
  17995. }
  17996. // No result was found - empty array signifies failure to find path.
  17997. return [];
  17998. }
  17999. static heuristic (pos1, pos2) {
  18000. return utils.distanceToSquared(pos1, pos2);
  18001. }
  18002. static neighbours (graph, node) {
  18003. const ret = [];
  18004. for (let e = 0; e < node.neighbours.length; e++) {
  18005. ret.push(graph[node.neighbours[e]]);
  18006. }
  18007. return ret;
  18008. }
  18009. }
  18010. module.exports = AStar;
  18011. },{"./BinaryHeap":80,"./utils.js":83}],80:[function(require,module,exports){
  18012. // javascript-astar
  18013. // http://github.com/bgrins/javascript-astar
  18014. // Freely distributable under the MIT License.
  18015. // Implements the astar search algorithm in javascript using a binary heap.
  18016. class BinaryHeap {
  18017. constructor (scoreFunction) {
  18018. this.content = [];
  18019. this.scoreFunction = scoreFunction;
  18020. }
  18021. push (element) {
  18022. // Add the new element to the end of the array.
  18023. this.content.push(element);
  18024. // Allow it to sink down.
  18025. this.sinkDown(this.content.length - 1);
  18026. }
  18027. pop () {
  18028. // Store the first element so we can return it later.
  18029. const result = this.content[0];
  18030. // Get the element at the end of the array.
  18031. const end = this.content.pop();
  18032. // If there are any elements left, put the end element at the
  18033. // start, and let it bubble up.
  18034. if (this.content.length > 0) {
  18035. this.content[0] = end;
  18036. this.bubbleUp(0);
  18037. }
  18038. return result;
  18039. }
  18040. remove (node) {
  18041. const i = this.content.indexOf(node);
  18042. // When it is found, the process seen in 'pop' is repeated
  18043. // to fill up the hole.
  18044. const end = this.content.pop();
  18045. if (i !== this.content.length - 1) {
  18046. this.content[i] = end;
  18047. if (this.scoreFunction(end) < this.scoreFunction(node)) {
  18048. this.sinkDown(i);
  18049. } else {
  18050. this.bubbleUp(i);
  18051. }
  18052. }
  18053. }
  18054. size () {
  18055. return this.content.length;
  18056. }
  18057. rescoreElement (node) {
  18058. this.sinkDown(this.content.indexOf(node));
  18059. }
  18060. sinkDown (n) {
  18061. // Fetch the element that has to be sunk.
  18062. const element = this.content[n];
  18063. // When at 0, an element can not sink any further.
  18064. while (n > 0) {
  18065. // Compute the parent element's index, and fetch it.
  18066. const parentN = ((n + 1) >> 1) - 1;
  18067. const parent = this.content[parentN];
  18068. if (this.scoreFunction(element) < this.scoreFunction(parent)) {
  18069. // Swap the elements if the parent is greater.
  18070. this.content[parentN] = element;
  18071. this.content[n] = parent;
  18072. // Update 'n' to continue at the new position.
  18073. n = parentN;
  18074. } else {
  18075. // Found a parent that is less, no need to sink any further.
  18076. break;
  18077. }
  18078. }
  18079. }
  18080. bubbleUp (n) {
  18081. // Look up the target element and its score.
  18082. const length = this.content.length,
  18083. element = this.content[n],
  18084. elemScore = this.scoreFunction(element);
  18085. while (true) {
  18086. // Compute the indices of the child elements.
  18087. const child2N = (n + 1) << 1,
  18088. child1N = child2N - 1;
  18089. // This is used to store the new position of the element,
  18090. // if any.
  18091. let swap = null;
  18092. let child1Score;
  18093. // If the first child exists (is inside the array)...
  18094. if (child1N < length) {
  18095. // Look it up and compute its score.
  18096. const child1 = this.content[child1N];
  18097. child1Score = this.scoreFunction(child1);
  18098. // If the score is less than our element's, we need to swap.
  18099. if (child1Score < elemScore) {
  18100. swap = child1N;
  18101. }
  18102. }
  18103. // Do the same checks for the other child.
  18104. if (child2N < length) {
  18105. const child2 = this.content[child2N],
  18106. child2Score = this.scoreFunction(child2);
  18107. if (child2Score < (swap === null ? elemScore : child1Score)) {
  18108. swap = child2N;
  18109. }
  18110. }
  18111. // If the element needs to be moved, swap it, and continue.
  18112. if (swap !== null) {
  18113. this.content[n] = this.content[swap];
  18114. this.content[swap] = element;
  18115. n = swap;
  18116. }
  18117. // Otherwise, we are done.
  18118. else {
  18119. break;
  18120. }
  18121. }
  18122. }
  18123. }
  18124. module.exports = BinaryHeap;
  18125. },{}],81:[function(require,module,exports){
  18126. const utils = require('./utils');
  18127. class Channel {
  18128. constructor () {
  18129. this.portals = [];
  18130. }
  18131. push (p1, p2) {
  18132. if (p2 === undefined) p2 = p1;
  18133. this.portals.push({
  18134. left: p1,
  18135. right: p2
  18136. });
  18137. }
  18138. stringPull () {
  18139. const portals = this.portals;
  18140. const pts = [];
  18141. // Init scan state
  18142. let portalApex, portalLeft, portalRight;
  18143. let apexIndex = 0,
  18144. leftIndex = 0,
  18145. rightIndex = 0;
  18146. portalApex = portals[0].left;
  18147. portalLeft = portals[0].left;
  18148. portalRight = portals[0].right;
  18149. // Add start point.
  18150. pts.push(portalApex);
  18151. for (let i = 1; i < portals.length; i++) {
  18152. const left = portals[i].left;
  18153. const right = portals[i].right;
  18154. // Update right vertex.
  18155. if (utils.triarea2(portalApex, portalRight, right) <= 0.0) {
  18156. if (utils.vequal(portalApex, portalRight) || utils.triarea2(portalApex, portalLeft, right) > 0.0) {
  18157. // Tighten the funnel.
  18158. portalRight = right;
  18159. rightIndex = i;
  18160. } else {
  18161. // Right over left, insert left to path and restart scan from portal left point.
  18162. pts.push(portalLeft);
  18163. // Make current left the new apex.
  18164. portalApex = portalLeft;
  18165. apexIndex = leftIndex;
  18166. // Reset portal
  18167. portalLeft = portalApex;
  18168. portalRight = portalApex;
  18169. leftIndex = apexIndex;
  18170. rightIndex = apexIndex;
  18171. // Restart scan
  18172. i = apexIndex;
  18173. continue;
  18174. }
  18175. }
  18176. // Update left vertex.
  18177. if (utils.triarea2(portalApex, portalLeft, left) >= 0.0) {
  18178. if (utils.vequal(portalApex, portalLeft) || utils.triarea2(portalApex, portalRight, left) < 0.0) {
  18179. // Tighten the funnel.
  18180. portalLeft = left;
  18181. leftIndex = i;
  18182. } else {
  18183. // Left over right, insert right to path and restart scan from portal right point.
  18184. pts.push(portalRight);
  18185. // Make current right the new apex.
  18186. portalApex = portalRight;
  18187. apexIndex = rightIndex;
  18188. // Reset portal
  18189. portalLeft = portalApex;
  18190. portalRight = portalApex;
  18191. leftIndex = apexIndex;
  18192. rightIndex = apexIndex;
  18193. // Restart scan
  18194. i = apexIndex;
  18195. continue;
  18196. }
  18197. }
  18198. }
  18199. if ((pts.length === 0) || (!utils.vequal(pts[pts.length - 1], portals[portals.length - 1].left))) {
  18200. // Append last point to path.
  18201. pts.push(portals[portals.length - 1].left);
  18202. }
  18203. this.path = pts;
  18204. return pts;
  18205. }
  18206. }
  18207. module.exports = Channel;
  18208. },{"./utils":83}],82:[function(require,module,exports){
  18209. const utils = require('./utils');
  18210. const AStar = require('./AStar');
  18211. const Channel = require('./Channel');
  18212. var polygonId = 1;
  18213. var buildPolygonGroups = function (navigationMesh) {
  18214. var polygons = navigationMesh.polygons;
  18215. var polygonGroups = [];
  18216. var groupCount = 0;
  18217. var spreadGroupId = function (polygon) {
  18218. polygon.neighbours.forEach((neighbour) => {
  18219. if (neighbour.group === undefined) {
  18220. neighbour.group = polygon.group;
  18221. spreadGroupId(neighbour);
  18222. }
  18223. });
  18224. };
  18225. polygons.forEach((polygon) => {
  18226. if (polygon.group === undefined) {
  18227. polygon.group = groupCount++;
  18228. // Spread it
  18229. spreadGroupId(polygon);
  18230. }
  18231. if (!polygonGroups[polygon.group]) polygonGroups[polygon.group] = [];
  18232. polygonGroups[polygon.group].push(polygon);
  18233. });
  18234. console.log('Groups built: ', polygonGroups.length);
  18235. return polygonGroups;
  18236. };
  18237. var buildPolygonNeighbours = function (polygon, navigationMesh) {
  18238. polygon.neighbours = [];
  18239. // All other nodes that contain at least two of our vertices are our neighbours
  18240. for (var i = 0, len = navigationMesh.polygons.length; i < len; i++) {
  18241. if (polygon === navigationMesh.polygons[i]) continue;
  18242. // Don't check polygons that are too far, since the intersection tests take a long time
  18243. if (polygon.centroid.distanceToSquared(navigationMesh.polygons[i].centroid) > 100 * 100) continue;
  18244. var matches = utils.array_intersect(polygon.vertexIds, navigationMesh.polygons[i].vertexIds);
  18245. if (matches.length >= 2) {
  18246. polygon.neighbours.push(navigationMesh.polygons[i]);
  18247. }
  18248. }
  18249. };
  18250. var buildPolygonsFromGeometry = function (geometry) {
  18251. console.log('Vertices:', geometry.vertices.length, 'polygons:', geometry.faces.length);
  18252. var polygons = [];
  18253. var vertices = geometry.vertices;
  18254. var faceVertexUvs = geometry.faceVertexUvs;
  18255. // Convert the faces into a custom format that supports more than 3 vertices
  18256. geometry.faces.forEach((face) => {
  18257. polygons.push({
  18258. id: polygonId++,
  18259. vertexIds: [face.a, face.b, face.c],
  18260. centroid: face.centroid,
  18261. normal: face.normal,
  18262. neighbours: []
  18263. });
  18264. });
  18265. var navigationMesh = {
  18266. polygons: polygons,
  18267. vertices: vertices,
  18268. faceVertexUvs: faceVertexUvs
  18269. };
  18270. // Build a list of adjacent polygons
  18271. polygons.forEach((polygon) => {
  18272. buildPolygonNeighbours(polygon, navigationMesh);
  18273. });
  18274. return navigationMesh;
  18275. };
  18276. var buildNavigationMesh = function (geometry) {
  18277. // Prepare geometry
  18278. utils.computeCentroids(geometry);
  18279. geometry.mergeVertices();
  18280. return buildPolygonsFromGeometry(geometry);
  18281. };
  18282. var getSharedVerticesInOrder = function (a, b) {
  18283. var aList = a.vertexIds;
  18284. var bList = b.vertexIds;
  18285. var sharedVertices = [];
  18286. aList.forEach((vId) => {
  18287. if (bList.includes(vId)) {
  18288. sharedVertices.push(vId);
  18289. }
  18290. });
  18291. if (sharedVertices.length < 2) return [];
  18292. // console.log("TRYING aList:", aList, ", bList:", bList, ", sharedVertices:", sharedVertices);
  18293. if (sharedVertices.includes(aList[0]) && sharedVertices.includes(aList[aList.length - 1])) {
  18294. // Vertices on both edges are bad, so shift them once to the left
  18295. aList.push(aList.shift());
  18296. }
  18297. if (sharedVertices.includes(bList[0]) && sharedVertices.includes(bList[bList.length - 1])) {
  18298. // Vertices on both edges are bad, so shift them once to the left
  18299. bList.push(bList.shift());
  18300. }
  18301. // Again!
  18302. sharedVertices = [];
  18303. aList.forEach((vId) => {
  18304. if (bList.includes(vId)) {
  18305. sharedVertices.push(vId);
  18306. }
  18307. });
  18308. return sharedVertices;
  18309. };
  18310. var groupNavMesh = function (navigationMesh) {
  18311. var saveObj = {};
  18312. navigationMesh.vertices.forEach((v) => {
  18313. v.x = utils.roundNumber(v.x, 2);
  18314. v.y = utils.roundNumber(v.y, 2);
  18315. v.z = utils.roundNumber(v.z, 2);
  18316. });
  18317. saveObj.vertices = navigationMesh.vertices;
  18318. var groups = buildPolygonGroups(navigationMesh);
  18319. saveObj.groups = [];
  18320. var findPolygonIndex = function (group, p) {
  18321. for (var i = 0; i < group.length; i++) {
  18322. if (p === group[i]) return i;
  18323. }
  18324. };
  18325. groups.forEach((group) => {
  18326. var newGroup = [];
  18327. group.forEach((p) => {
  18328. var neighbours = [];
  18329. p.neighbours.forEach((n) => {
  18330. neighbours.push(findPolygonIndex(group, n));
  18331. });
  18332. // Build a portal list to each neighbour
  18333. var portals = [];
  18334. p.neighbours.forEach((n) => {
  18335. portals.push(getSharedVerticesInOrder(p, n));
  18336. });
  18337. p.centroid.x = utils.roundNumber(p.centroid.x, 2);
  18338. p.centroid.y = utils.roundNumber(p.centroid.y, 2);
  18339. p.centroid.z = utils.roundNumber(p.centroid.z, 2);
  18340. newGroup.push({
  18341. id: findPolygonIndex(group, p),
  18342. neighbours: neighbours,
  18343. vertexIds: p.vertexIds,
  18344. centroid: p.centroid,
  18345. portals: portals
  18346. });
  18347. });
  18348. saveObj.groups.push(newGroup);
  18349. });
  18350. return saveObj;
  18351. };
  18352. var zoneNodes = {};
  18353. module.exports = {
  18354. buildNodes: function (geometry) {
  18355. var navigationMesh = buildNavigationMesh(geometry);
  18356. var zoneNodes = groupNavMesh(navigationMesh);
  18357. return zoneNodes;
  18358. },
  18359. setZoneData: function (zone, data) {
  18360. zoneNodes[zone] = data;
  18361. },
  18362. getGroup: function (zone, position) {
  18363. if (!zoneNodes[zone]) return null;
  18364. var closestNodeGroup = null;
  18365. var distance = Math.pow(50, 2);
  18366. zoneNodes[zone].groups.forEach((group, index) => {
  18367. group.forEach((node) => {
  18368. var measuredDistance = utils.distanceToSquared(node.centroid, position);
  18369. if (measuredDistance < distance) {
  18370. closestNodeGroup = index;
  18371. distance = measuredDistance;
  18372. }
  18373. });
  18374. });
  18375. return closestNodeGroup;
  18376. },
  18377. getRandomNode: function (zone, group, nearPosition, nearRange) {
  18378. if (!zoneNodes[zone]) return new THREE.Vector3();
  18379. nearPosition = nearPosition || null;
  18380. nearRange = nearRange || 0;
  18381. var candidates = [];
  18382. var polygons = zoneNodes[zone].groups[group];
  18383. polygons.forEach((p) => {
  18384. if (nearPosition && nearRange) {
  18385. if (utils.distanceToSquared(nearPosition, p.centroid) < nearRange * nearRange) {
  18386. candidates.push(p.centroid);
  18387. }
  18388. } else {
  18389. candidates.push(p.centroid);
  18390. }
  18391. });
  18392. return utils.sample(candidates) || new THREE.Vector3();
  18393. },
  18394. getClosestNode: function (position, zone, group, checkPolygon = false) {
  18395. const nodes = zoneNodes[zone].groups[group];
  18396. const vertices = zoneNodes[zone].vertices;
  18397. let closestNode = null;
  18398. let closestDistance = Infinity;
  18399. nodes.forEach((node) => {
  18400. const distance = utils.distanceToSquared(node.centroid, position);
  18401. if (distance < closestDistance
  18402. && (!checkPolygon || utils.isVectorInPolygon(position, node, vertices))) {
  18403. closestNode = node;
  18404. closestDistance = distance;
  18405. }
  18406. });
  18407. return closestNode;
  18408. },
  18409. findPath: function (startPosition, targetPosition, zone, group) {
  18410. const nodes = zoneNodes[zone].groups[group];
  18411. const vertices = zoneNodes[zone].vertices;
  18412. const closestNode = this.getClosestNode(startPosition, zone, group);
  18413. const farthestNode = this.getClosestNode(targetPosition, zone, group, true);
  18414. // If we can't find any node, just go straight to the target
  18415. if (!closestNode || !farthestNode) {
  18416. return null;
  18417. }
  18418. const paths = AStar.search(nodes, closestNode, farthestNode);
  18419. const getPortalFromTo = function (a, b) {
  18420. for (var i = 0; i < a.neighbours.length; i++) {
  18421. if (a.neighbours[i] === b.id) {
  18422. return a.portals[i];
  18423. }
  18424. }
  18425. };
  18426. // We have the corridor, now pull the rope.
  18427. const channel = new Channel();
  18428. channel.push(startPosition);
  18429. for (let i = 0; i < paths.length; i++) {
  18430. const polygon = paths[i];
  18431. const nextPolygon = paths[i + 1];
  18432. if (nextPolygon) {
  18433. const portals = getPortalFromTo(polygon, nextPolygon);
  18434. channel.push(
  18435. vertices[portals[0]],
  18436. vertices[portals[1]]
  18437. );
  18438. }
  18439. }
  18440. channel.push(targetPosition);
  18441. channel.stringPull();
  18442. // Return the path, omitting first position (which is already known).
  18443. const path = channel.path.map((c) => new THREE.Vector3(c.x, c.y, c.z));
  18444. path.shift();
  18445. return path;
  18446. }
  18447. };
  18448. },{"./AStar":79,"./Channel":81,"./utils":83}],83:[function(require,module,exports){
  18449. class Utils {
  18450. static computeCentroids (geometry) {
  18451. var f, fl, face;
  18452. for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
  18453. face = geometry.faces[ f ];
  18454. face.centroid = new THREE.Vector3( 0, 0, 0 );
  18455. face.centroid.add( geometry.vertices[ face.a ] );
  18456. face.centroid.add( geometry.vertices[ face.b ] );
  18457. face.centroid.add( geometry.vertices[ face.c ] );
  18458. face.centroid.divideScalar( 3 );
  18459. }
  18460. }
  18461. static roundNumber (number, decimals) {
  18462. var newnumber = Number(number + '').toFixed(parseInt(decimals));
  18463. return parseFloat(newnumber);
  18464. }
  18465. static sample (list) {
  18466. return list[Math.floor(Math.random() * list.length)];
  18467. }
  18468. static mergeVertexIds (aList, bList) {
  18469. var sharedVertices = [];
  18470. aList.forEach((vID) => {
  18471. if (bList.indexOf(vID) >= 0) {
  18472. sharedVertices.push(vID);
  18473. }
  18474. });
  18475. if (sharedVertices.length < 2) return [];
  18476. if (sharedVertices.includes(aList[0]) && sharedVertices.includes(aList[aList.length - 1])) {
  18477. // Vertices on both edges are bad, so shift them once to the left
  18478. aList.push(aList.shift());
  18479. }
  18480. if (sharedVertices.includes(bList[0]) && sharedVertices.includes(bList[bList.length - 1])) {
  18481. // Vertices on both edges are bad, so shift them once to the left
  18482. bList.push(bList.shift());
  18483. }
  18484. // Again!
  18485. sharedVertices = [];
  18486. aList.forEach((vId) => {
  18487. if (bList.includes(vId)) {
  18488. sharedVertices.push(vId);
  18489. }
  18490. });
  18491. var clockwiseMostSharedVertex = sharedVertices[1];
  18492. var counterClockwiseMostSharedVertex = sharedVertices[0];
  18493. var cList = aList.slice();
  18494. while (cList[0] !== clockwiseMostSharedVertex) {
  18495. cList.push(cList.shift());
  18496. }
  18497. var c = 0;
  18498. var temp = bList.slice();
  18499. while (temp[0] !== counterClockwiseMostSharedVertex) {
  18500. temp.push(temp.shift());
  18501. if (c++ > 10) throw new Error('Unexpected state');
  18502. }
  18503. // Shave
  18504. temp.shift();
  18505. temp.pop();
  18506. cList = cList.concat(temp);
  18507. return cList;
  18508. }
  18509. static setPolygonCentroid (polygon, navigationMesh) {
  18510. var sum = new THREE.Vector3();
  18511. var vertices = navigationMesh.vertices;
  18512. polygon.vertexIds.forEach((vId) => {
  18513. sum.add(vertices[vId]);
  18514. });
  18515. sum.divideScalar(polygon.vertexIds.length);
  18516. polygon.centroid.copy(sum);
  18517. }
  18518. static cleanPolygon (polygon, navigationMesh) {
  18519. var newVertexIds = [];
  18520. var vertices = navigationMesh.vertices;
  18521. for (var i = 0; i < polygon.vertexIds.length; i++) {
  18522. var vertex = vertices[polygon.vertexIds[i]];
  18523. var nextVertexId, previousVertexId;
  18524. var nextVertex, previousVertex;
  18525. // console.log("nextVertex: ", nextVertex);
  18526. if (i === 0) {
  18527. nextVertexId = polygon.vertexIds[1];
  18528. previousVertexId = polygon.vertexIds[polygon.vertexIds.length - 1];
  18529. } else if (i === polygon.vertexIds.length - 1) {
  18530. nextVertexId = polygon.vertexIds[0];
  18531. previousVertexId = polygon.vertexIds[polygon.vertexIds.length - 2];
  18532. } else {
  18533. nextVertexId = polygon.vertexIds[i + 1];
  18534. previousVertexId = polygon.vertexIds[i - 1];
  18535. }
  18536. nextVertex = vertices[nextVertexId];
  18537. previousVertex = vertices[previousVertexId];
  18538. var a = nextVertex.clone().sub(vertex);
  18539. var b = previousVertex.clone().sub(vertex);
  18540. var angle = a.angleTo(b);
  18541. // console.log(angle);
  18542. if (angle > Math.PI - 0.01 && angle < Math.PI + 0.01) {
  18543. // Unneccesary vertex
  18544. // console.log("Unneccesary vertex: ", polygon.vertexIds[i]);
  18545. // console.log("Angle between "+previousVertexId+", "+polygon.vertexIds[i]+" "+nextVertexId+" was: ", angle);
  18546. // Remove the neighbours who had this vertex
  18547. var goodNeighbours = [];
  18548. polygon.neighbours.forEach((neighbour) => {
  18549. if (!neighbour.vertexIds.includes(polygon.vertexIds[i])) {
  18550. goodNeighbours.push(neighbour);
  18551. }
  18552. });
  18553. polygon.neighbours = goodNeighbours;
  18554. // TODO cleanup the list of vertices and rebuild vertexIds for all polygons
  18555. } else {
  18556. newVertexIds.push(polygon.vertexIds[i]);
  18557. }
  18558. }
  18559. // console.log("New vertexIds: ", newVertexIds);
  18560. polygon.vertexIds = newVertexIds;
  18561. setPolygonCentroid(polygon, navigationMesh);
  18562. }
  18563. static isConvex (polygon, navigationMesh) {
  18564. var vertices = navigationMesh.vertices;
  18565. if (polygon.vertexIds.length < 3) return false;
  18566. var convex = true;
  18567. var total = 0;
  18568. var results = [];
  18569. for (var i = 0; i < polygon.vertexIds.length; i++) {
  18570. var vertex = vertices[polygon.vertexIds[i]];
  18571. var nextVertex, previousVertex;
  18572. if (i === 0) {
  18573. nextVertex = vertices[polygon.vertexIds[1]];
  18574. previousVertex = vertices[polygon.vertexIds[polygon.vertexIds.length - 1]];
  18575. } else if (i === polygon.vertexIds.length - 1) {
  18576. nextVertex = vertices[polygon.vertexIds[0]];
  18577. previousVertex = vertices[polygon.vertexIds[polygon.vertexIds.length - 2]];
  18578. } else {
  18579. nextVertex = vertices[polygon.vertexIds[i + 1]];
  18580. previousVertex = vertices[polygon.vertexIds[i - 1]];
  18581. }
  18582. var a = nextVertex.clone().sub(vertex);
  18583. var b = previousVertex.clone().sub(vertex);
  18584. var angle = a.angleTo(b);
  18585. total += angle;
  18586. if (angle === Math.PI || angle === 0) return false;
  18587. var r = a.cross(b).y;
  18588. results.push(r);
  18589. }
  18590. // if ( total > (polygon.vertexIds.length-2)*Math.PI ) return false;
  18591. results.forEach((r) => {
  18592. if (r === 0) convex = false;
  18593. });
  18594. if (results[0] > 0) {
  18595. results.forEach((r) => {
  18596. if (r < 0) convex = false;
  18597. });
  18598. } else {
  18599. results.forEach((r) => {
  18600. if (r > 0) convex = false;
  18601. });
  18602. }
  18603. return convex;
  18604. }
  18605. static distanceToSquared (a, b) {
  18606. var dx = a.x - b.x;
  18607. var dy = a.y - b.y;
  18608. var dz = a.z - b.z;
  18609. return dx * dx + dy * dy + dz * dz;
  18610. }
  18611. //+ Jonas Raoni Soares Silva
  18612. //@ http://jsfromhell.com/math/is-point-in-poly [rev. #0]
  18613. static isPointInPoly (poly, pt) {
  18614. for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
  18615. ((poly[i].z <= pt.z && pt.z < poly[j].z) || (poly[j].z <= pt.z && pt.z < poly[i].z)) && (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x) && (c = !c);
  18616. return c;
  18617. }
  18618. static isVectorInPolygon (vector, polygon, vertices) {
  18619. // reference point will be the centroid of the polygon
  18620. // We need to rotate the vector as well as all the points which the polygon uses
  18621. var lowestPoint = 100000;
  18622. var highestPoint = -100000;
  18623. var polygonVertices = [];
  18624. polygon.vertexIds.forEach((vId) => {
  18625. lowestPoint = Math.min(vertices[vId].y, lowestPoint);
  18626. highestPoint = Math.max(vertices[vId].y, highestPoint);
  18627. polygonVertices.push(vertices[vId]);
  18628. });
  18629. if (vector.y < highestPoint + 0.5 && vector.y > lowestPoint - 0.5 &&
  18630. this.isPointInPoly(polygonVertices, vector)) {
  18631. return true;
  18632. }
  18633. return false;
  18634. }
  18635. static triarea2 (a, b, c) {
  18636. var ax = b.x - a.x;
  18637. var az = b.z - a.z;
  18638. var bx = c.x - a.x;
  18639. var bz = c.z - a.z;
  18640. return bx * az - ax * bz;
  18641. }
  18642. static vequal (a, b) {
  18643. return this.distanceToSquared(a, b) < 0.00001;
  18644. }
  18645. static array_intersect () {
  18646. let i, shortest, nShortest, n, len, ret = [],
  18647. obj = {},
  18648. nOthers;
  18649. nOthers = arguments.length - 1;
  18650. nShortest = arguments[0].length;
  18651. shortest = 0;
  18652. for (i = 0; i <= nOthers; i++) {
  18653. n = arguments[i].length;
  18654. if (n < nShortest) {
  18655. shortest = i;
  18656. nShortest = n;
  18657. }
  18658. }
  18659. for (i = 0; i <= nOthers; i++) {
  18660. n = (i === shortest) ? 0 : (i || shortest); //Read the shortest array first. Read the first array instead of the shortest
  18661. len = arguments[n].length;
  18662. for (var j = 0; j < len; j++) {
  18663. var elem = arguments[n][j];
  18664. if (obj[elem] === i - 1) {
  18665. if (i === nOthers) {
  18666. ret.push(elem);
  18667. obj[elem] = 0;
  18668. } else {
  18669. obj[elem] = i;
  18670. }
  18671. } else if (i === 0) {
  18672. obj[elem] = 0;
  18673. }
  18674. }
  18675. }
  18676. return ret;
  18677. }
  18678. }
  18679. module.exports = Utils;
  18680. },{}],84:[function(require,module,exports){
  18681. var CANNON = require('cannon'),
  18682. quickhull = require('./lib/THREE.quickhull');
  18683. var PI_2 = Math.PI / 2;
  18684. var Type = {
  18685. BOX: 'Box',
  18686. CYLINDER: 'Cylinder',
  18687. SPHERE: 'Sphere',
  18688. HULL: 'ConvexPolyhedron',
  18689. MESH: 'Trimesh'
  18690. };
  18691. /**
  18692. * Given a THREE.Object3D instance, creates a corresponding CANNON shape.
  18693. * @param {THREE.Object3D} object
  18694. * @return {CANNON.Shape}
  18695. */
  18696. module.exports = CANNON.mesh2shape = function (object, options) {
  18697. options = options || {};
  18698. var geometry;
  18699. if (options.type === Type.BOX) {
  18700. return createBoundingBoxShape(object);
  18701. } else if (options.type === Type.CYLINDER) {
  18702. return createBoundingCylinderShape(object, options);
  18703. } else if (options.type === Type.SPHERE) {
  18704. return createBoundingSphereShape(object, options);
  18705. } else if (options.type === Type.HULL) {
  18706. return createConvexPolyhedron(object);
  18707. } else if (options.type === Type.MESH) {
  18708. geometry = getGeometry(object);
  18709. return geometry ? createTrimeshShape(geometry) : null;
  18710. } else if (options.type) {
  18711. throw new Error('[CANNON.mesh2shape] Invalid type "%s".', options.type);
  18712. }
  18713. geometry = getGeometry(object);
  18714. if (!geometry) return null;
  18715. var type = geometry.metadata
  18716. ? geometry.metadata.type
  18717. : geometry.type;
  18718. switch (type) {
  18719. case 'BoxGeometry':
  18720. case 'BoxBufferGeometry':
  18721. return createBoxShape(geometry);
  18722. case 'CylinderGeometry':
  18723. case 'CylinderBufferGeometry':
  18724. return createCylinderShape(geometry);
  18725. case 'PlaneGeometry':
  18726. case 'PlaneBufferGeometry':
  18727. return createPlaneShape(geometry);
  18728. case 'SphereGeometry':
  18729. case 'SphereBufferGeometry':
  18730. return createSphereShape(geometry);
  18731. case 'TubeGeometry':
  18732. case 'Geometry':
  18733. case 'BufferGeometry':
  18734. return createBoundingBoxShape(object);
  18735. default:
  18736. console.warn('Unrecognized geometry: "%s". Using bounding box as shape.', geometry.type);
  18737. return createBoxShape(geometry);
  18738. }
  18739. };
  18740. CANNON.mesh2shape.Type = Type;
  18741. /******************************************************************************
  18742. * Shape construction
  18743. */
  18744. /**
  18745. * @param {THREE.Geometry} geometry
  18746. * @return {CANNON.Shape}
  18747. */
  18748. function createBoxShape (geometry) {
  18749. var vertices = getVertices(geometry);
  18750. if (!vertices.length) return null;
  18751. geometry.computeBoundingBox();
  18752. var box = geometry.boundingBox;
  18753. return new CANNON.Box(new CANNON.Vec3(
  18754. (box.max.x - box.min.x) / 2,
  18755. (box.max.y - box.min.y) / 2,
  18756. (box.max.z - box.min.z) / 2
  18757. ));
  18758. }
  18759. /**
  18760. * Bounding box needs to be computed with the entire mesh, not just geometry.
  18761. * @param {THREE.Object3D} mesh
  18762. * @return {CANNON.Shape}
  18763. */
  18764. function createBoundingBoxShape (object) {
  18765. var shape, localPosition, worldPosition,
  18766. box = new THREE.Box3();
  18767. box.setFromObject(object);
  18768. if (!isFinite(box.min.lengthSq())) return null;
  18769. shape = new CANNON.Box(new CANNON.Vec3(
  18770. (box.max.x - box.min.x) / 2,
  18771. (box.max.y - box.min.y) / 2,
  18772. (box.max.z - box.min.z) / 2
  18773. ));
  18774. object.updateMatrixWorld();
  18775. worldPosition = new THREE.Vector3();
  18776. worldPosition.setFromMatrixPosition(object.matrixWorld);
  18777. localPosition = box.translate(worldPosition.negate()).getCenter();
  18778. if (localPosition.lengthSq()) {
  18779. shape.offset = localPosition;
  18780. }
  18781. return shape;
  18782. }
  18783. /**
  18784. * Computes 3D convex hull as a CANNON.ConvexPolyhedron.
  18785. * @param {THREE.Object3D} mesh
  18786. * @return {CANNON.Shape}
  18787. */
  18788. function createConvexPolyhedron (object) {
  18789. var i, vertices, faces, hull,
  18790. eps = 1e-4,
  18791. geometry = getGeometry(object);
  18792. if (!geometry || !geometry.vertices.length) return null;
  18793. // Perturb.
  18794. for (i = 0; i < geometry.vertices.length; i++) {
  18795. geometry.vertices[i].x += (Math.random() - 0.5) * eps;
  18796. geometry.vertices[i].y += (Math.random() - 0.5) * eps;
  18797. geometry.vertices[i].z += (Math.random() - 0.5) * eps;
  18798. }
  18799. // Compute the 3D convex hull.
  18800. hull = quickhull(geometry);
  18801. // Convert from THREE.Vector3 to CANNON.Vec3.
  18802. vertices = new Array(hull.vertices.length);
  18803. for (i = 0; i < hull.vertices.length; i++) {
  18804. vertices[i] = new CANNON.Vec3(hull.vertices[i].x, hull.vertices[i].y, hull.vertices[i].z);
  18805. }
  18806. // Convert from THREE.Face to Array<number>.
  18807. faces = new Array(hull.faces.length);
  18808. for (i = 0; i < hull.faces.length; i++) {
  18809. faces[i] = [hull.faces[i].a, hull.faces[i].b, hull.faces[i].c];
  18810. }
  18811. return new CANNON.ConvexPolyhedron(vertices, faces);
  18812. }
  18813. /**
  18814. * @param {THREE.Geometry} geometry
  18815. * @return {CANNON.Shape}
  18816. */
  18817. function createCylinderShape (geometry) {
  18818. var shape,
  18819. params = geometry.metadata
  18820. ? geometry.metadata.parameters
  18821. : geometry.parameters;
  18822. shape = new CANNON.Cylinder(
  18823. params.radiusTop,
  18824. params.radiusBottom,
  18825. params.height,
  18826. params.radialSegments
  18827. );
  18828. // Include metadata for serialization.
  18829. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  18830. shape.radiusTop = params.radiusTop;
  18831. shape.radiusBottom = params.radiusBottom;
  18832. shape.height = params.height;
  18833. shape.numSegments = params.radialSegments;
  18834. shape.orientation = new CANNON.Quaternion();
  18835. shape.orientation.setFromEuler(THREE.Math.degToRad(-90), 0, 0, 'XYZ').normalize();
  18836. return shape;
  18837. }
  18838. /**
  18839. * @param {THREE.Object3D} object
  18840. * @return {CANNON.Shape}
  18841. */
  18842. function createBoundingCylinderShape (object, options) {
  18843. var shape, height, radius,
  18844. box = new THREE.Box3(),
  18845. axes = ['x', 'y', 'z'],
  18846. majorAxis = options.cylinderAxis || 'y',
  18847. minorAxes = axes.splice(axes.indexOf(majorAxis), 1) && axes;
  18848. box.setFromObject(object);
  18849. if (!isFinite(box.min.lengthSq())) return null;
  18850. // Compute cylinder dimensions.
  18851. height = box.max[majorAxis] - box.min[majorAxis];
  18852. radius = 0.5 * Math.max(
  18853. box.max[minorAxes[0]] - box.min[minorAxes[0]],
  18854. box.max[minorAxes[1]] - box.min[minorAxes[1]]
  18855. );
  18856. // Create shape.
  18857. shape = new CANNON.Cylinder(radius, radius, height, 12);
  18858. // Include metadata for serialization.
  18859. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  18860. shape.radiusTop = radius;
  18861. shape.radiusBottom = radius;
  18862. shape.height = height;
  18863. shape.numSegments = 12;
  18864. shape.orientation = new CANNON.Quaternion();
  18865. shape.orientation.setFromEuler(
  18866. majorAxis === 'y' ? PI_2 : 0,
  18867. majorAxis === 'z' ? PI_2 : 0,
  18868. 0,
  18869. 'XYZ'
  18870. ).normalize();
  18871. return shape;
  18872. }
  18873. /**
  18874. * @param {THREE.Geometry} geometry
  18875. * @return {CANNON.Shape}
  18876. */
  18877. function createPlaneShape (geometry) {
  18878. geometry.computeBoundingBox();
  18879. var box = geometry.boundingBox;
  18880. return new CANNON.Box(new CANNON.Vec3(
  18881. (box.max.x - box.min.x) / 2 || 0.1,
  18882. (box.max.y - box.min.y) / 2 || 0.1,
  18883. (box.max.z - box.min.z) / 2 || 0.1
  18884. ));
  18885. }
  18886. /**
  18887. * @param {THREE.Geometry} geometry
  18888. * @return {CANNON.Shape}
  18889. */
  18890. function createSphereShape (geometry) {
  18891. var params = geometry.metadata
  18892. ? geometry.metadata.parameters
  18893. : geometry.parameters;
  18894. return new CANNON.Sphere(params.radius);
  18895. }
  18896. /**
  18897. * @param {THREE.Object3D} object
  18898. * @return {CANNON.Shape}
  18899. */
  18900. function createBoundingSphereShape (object, options) {
  18901. if (options.sphereRadius) {
  18902. return new CANNON.Sphere(options.sphereRadius);
  18903. }
  18904. var geometry = getGeometry(object);
  18905. if (!geometry) return null;
  18906. geometry.computeBoundingSphere();
  18907. return new CANNON.Sphere(geometry.boundingSphere.radius);
  18908. }
  18909. /**
  18910. * @param {THREE.Geometry} geometry
  18911. * @return {CANNON.Shape}
  18912. */
  18913. function createTrimeshShape (geometry) {
  18914. var indices,
  18915. vertices = getVertices(geometry);
  18916. if (!vertices.length) return null;
  18917. indices = Object.keys(vertices).map(Number);
  18918. return new CANNON.Trimesh(vertices, indices);
  18919. }
  18920. /******************************************************************************
  18921. * Utils
  18922. */
  18923. /**
  18924. * Returns a single geometry for the given object. If the object is compound,
  18925. * its geometries are automatically merged.
  18926. * @param {THREE.Object3D} object
  18927. * @return {THREE.Geometry}
  18928. */
  18929. function getGeometry (object) {
  18930. var matrix, mesh,
  18931. meshes = getMeshes(object),
  18932. tmp = new THREE.Geometry(),
  18933. combined = new THREE.Geometry();
  18934. if (meshes.length === 0) return null;
  18935. // Apply scale – it can't easily be applied to a CANNON.Shape later.
  18936. if (meshes.length === 1) {
  18937. var position = new THREE.Vector3(),
  18938. quaternion = new THREE.Quaternion(),
  18939. scale = new THREE.Vector3();
  18940. if (meshes[0].geometry.isBufferGeometry) {
  18941. if (meshes[0].geometry.attributes.position) {
  18942. tmp.fromBufferGeometry(meshes[0].geometry);
  18943. }
  18944. } else {
  18945. tmp = meshes[0].geometry.clone();
  18946. }
  18947. tmp.metadata = meshes[0].geometry.metadata;
  18948. meshes[0].updateMatrixWorld();
  18949. meshes[0].matrixWorld.decompose(position, quaternion, scale);
  18950. return tmp.scale(scale.x, scale.y, scale.z);
  18951. }
  18952. // Recursively merge geometry, preserving local transforms.
  18953. while ((mesh = meshes.pop())) {
  18954. mesh.updateMatrixWorld();
  18955. if (mesh.geometry.isBufferGeometry) {
  18956. tmp.fromBufferGeometry(mesh.geometry);
  18957. combined.merge(tmp, mesh.matrixWorld);
  18958. } else {
  18959. combined.merge(mesh.geometry, mesh.matrixWorld);
  18960. }
  18961. }
  18962. matrix = new THREE.Matrix4();
  18963. matrix.scale(object.scale);
  18964. combined.applyMatrix(matrix);
  18965. return combined;
  18966. }
  18967. /**
  18968. * @param {THREE.Geometry} geometry
  18969. * @return {Array<number>}
  18970. */
  18971. function getVertices (geometry) {
  18972. if (!geometry.attributes) {
  18973. geometry = new THREE.BufferGeometry().fromGeometry(geometry);
  18974. }
  18975. return (geometry.attributes.position || {}).array || [];
  18976. }
  18977. /**
  18978. * Returns a flat array of THREE.Mesh instances from the given object. If
  18979. * nested transformations are found, they are applied to child meshes
  18980. * as mesh.userData.matrix, so that each mesh has its position/rotation/scale
  18981. * independently of all of its parents except the top-level object.
  18982. * @param {THREE.Object3D} object
  18983. * @return {Array<THREE.Mesh>}
  18984. */
  18985. function getMeshes (object) {
  18986. var meshes = [];
  18987. object.traverse(function (o) {
  18988. if (o.type === 'Mesh') {
  18989. meshes.push(o);
  18990. }
  18991. });
  18992. return meshes;
  18993. }
  18994. },{"./lib/THREE.quickhull":85,"cannon":23}],85:[function(require,module,exports){
  18995. /**
  18996. QuickHull
  18997. ---------
  18998. The MIT License
  18999. Copyright &copy; 2010-2014 three.js authors
  19000. Permission is hereby granted, free of charge, to any person obtaining a copy
  19001. of this software and associated documentation files (the "Software"), to deal
  19002. in the Software without restriction, including without limitation the rights
  19003. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  19004. copies of the Software, and to permit persons to whom the Software is
  19005. furnished to do so, subject to the following conditions:
  19006. The above copyright notice and this permission notice shall be included in
  19007. all copies or substantial portions of the Software.
  19008. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19009. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19010. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19011. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19012. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19013. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19014. THE SOFTWARE.
  19015. @author mark lundin / http://mark-lundin.com
  19016. This is a 3D implementation of the Quick Hull algorithm.
  19017. It is a fast way of computing a convex hull with average complexity
  19018. of O(n log(n)).
  19019. It uses depends on three.js and is supposed to create THREE.Geometry.
  19020. It's also very messy
  19021. */
  19022. module.exports = (function(){
  19023. var faces = [],
  19024. faceStack = [],
  19025. i, NUM_POINTS, extremes,
  19026. max = 0,
  19027. dcur, current, j, v0, v1, v2, v3,
  19028. N, D;
  19029. var ab, ac, ax,
  19030. suba, subb, normal,
  19031. diff, subaA, subaB, subC;
  19032. function reset(){
  19033. ab = new THREE.Vector3(),
  19034. ac = new THREE.Vector3(),
  19035. ax = new THREE.Vector3(),
  19036. suba = new THREE.Vector3(),
  19037. subb = new THREE.Vector3(),
  19038. normal = new THREE.Vector3(),
  19039. diff = new THREE.Vector3(),
  19040. subaA = new THREE.Vector3(),
  19041. subaB = new THREE.Vector3(),
  19042. subC = new THREE.Vector3();
  19043. }
  19044. //temporary vectors
  19045. function process( points ){
  19046. // Iterate through all the faces and remove
  19047. while( faceStack.length > 0 ){
  19048. cull( faceStack.shift(), points );
  19049. }
  19050. }
  19051. var norm = function(){
  19052. var ca = new THREE.Vector3(),
  19053. ba = new THREE.Vector3(),
  19054. N = new THREE.Vector3();
  19055. return function( a, b, c ){
  19056. ca.subVectors( c, a );
  19057. ba.subVectors( b, a );
  19058. N.crossVectors( ca, ba );
  19059. return N.normalize();
  19060. }
  19061. }();
  19062. function getNormal( face, points ){
  19063. if( face.normal !== undefined ) return face.normal;
  19064. var p0 = points[face[0]],
  19065. p1 = points[face[1]],
  19066. p2 = points[face[2]];
  19067. ab.subVectors( p1, p0 );
  19068. ac.subVectors( p2, p0 );
  19069. normal.crossVectors( ac, ab );
  19070. normal.normalize();
  19071. return face.normal = normal.clone();
  19072. }
  19073. function assignPoints( face, pointset, points ){
  19074. // ASSIGNING POINTS TO FACE
  19075. var p0 = points[face[0]],
  19076. dots = [], apex,
  19077. norm = getNormal( face, points );
  19078. // Sory all the points by there distance from the plane
  19079. pointset.sort( function( aItem, bItem ){
  19080. dots[aItem.x/3] = dots[aItem.x/3] !== undefined ? dots[aItem.x/3] : norm.dot( suba.subVectors( aItem, p0 ));
  19081. dots[bItem.x/3] = dots[bItem.x/3] !== undefined ? dots[bItem.x/3] : norm.dot( subb.subVectors( bItem, p0 ));
  19082. return dots[aItem.x/3] - dots[bItem.x/3] ;
  19083. });
  19084. //TODO :: Must be a faster way of finding and index in this array
  19085. var index = pointset.length;
  19086. if( index === 1 ) dots[pointset[0].x/3] = norm.dot( suba.subVectors( pointset[0], p0 ));
  19087. while( index-- > 0 && dots[pointset[index].x/3] > 0 )
  19088. var point;
  19089. if( index + 1 < pointset.length && dots[pointset[index+1].x/3] > 0 ){
  19090. face.visiblePoints = pointset.splice( index + 1 );
  19091. }
  19092. }
  19093. function cull( face, points ){
  19094. var i = faces.length,
  19095. dot, visibleFace, currentFace,
  19096. visibleFaces = [face];
  19097. var apex = points.indexOf( face.visiblePoints.pop() );
  19098. // Iterate through all other faces...
  19099. while( i-- > 0 ){
  19100. currentFace = faces[i];
  19101. if( currentFace !== face ){
  19102. // ...and check if they're pointing in the same direction
  19103. dot = getNormal( currentFace, points ).dot( diff.subVectors( points[apex], points[currentFace[0]] ));
  19104. if( dot > 0 ){
  19105. visibleFaces.push( currentFace );
  19106. }
  19107. }
  19108. }
  19109. var index, neighbouringIndex, vertex;
  19110. // Determine Perimeter - Creates a bounded horizon
  19111. // 1. Pick an edge A out of all possible edges
  19112. // 2. Check if A is shared by any other face. a->b === b->a
  19113. // 2.1 for each edge in each triangle, isShared = ( f1.a == f2.a && f1.b == f2.b ) || ( f1.a == f2.b && f1.b == f2.a )
  19114. // 3. If not shared, then add to convex horizon set,
  19115. //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
  19116. //Restart from 1.
  19117. // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
  19118. // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
  19119. var j = i = visibleFaces.length;
  19120. var isDistinct = false,
  19121. hasOneVisibleFace = i === 1,
  19122. cull = [],
  19123. perimeter = [],
  19124. edgeIndex = 0, compareFace, nextIndex,
  19125. a, b;
  19126. var allPoints = [];
  19127. var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
  19128. if( visibleFaces.length === 1 ){
  19129. currentFace = visibleFaces[0];
  19130. perimeter = [currentFace[0], currentFace[1], currentFace[1], currentFace[2], currentFace[2], currentFace[0]];
  19131. // remove visible face from list of faces
  19132. if( faceStack.indexOf( currentFace ) > -1 ){
  19133. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  19134. }
  19135. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  19136. faces.splice( faces.indexOf( currentFace ), 1 );
  19137. }else{
  19138. while( i-- > 0 ){ // for each visible face
  19139. currentFace = visibleFaces[i];
  19140. // remove visible face from list of faces
  19141. if( faceStack.indexOf( currentFace ) > -1 ){
  19142. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  19143. }
  19144. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  19145. faces.splice( faces.indexOf( currentFace ), 1 );
  19146. var isSharedEdge;
  19147. cEdgeIndex = 0;
  19148. while( cEdgeIndex < 3 ){ // Iterate through it's edges
  19149. isSharedEdge = false;
  19150. j = visibleFaces.length;
  19151. a = currentFace[cEdgeIndex]
  19152. b = currentFace[(cEdgeIndex+1)%3];
  19153. while( j-- > 0 && !isSharedEdge ){ // find another visible faces
  19154. compareFace = visibleFaces[j];
  19155. edgeIndex = 0;
  19156. // isSharedEdge = compareFace == currentFace;
  19157. if( compareFace !== currentFace ){
  19158. while( edgeIndex < 3 && !isSharedEdge ){ //Check all it's indices
  19159. nextIndex = ( edgeIndex + 1 );
  19160. isSharedEdge = ( compareFace[edgeIndex] === a && compareFace[nextIndex%3] === b ) ||
  19161. ( compareFace[edgeIndex] === b && compareFace[nextIndex%3] === a );
  19162. edgeIndex++;
  19163. }
  19164. }
  19165. }
  19166. if( !isSharedEdge || hasOneVisibleFace ){
  19167. perimeter.push( a );
  19168. perimeter.push( b );
  19169. }
  19170. cEdgeIndex++;
  19171. }
  19172. }
  19173. }
  19174. // create new face for all pairs around edge
  19175. i = 0;
  19176. var l = perimeter.length/2;
  19177. var f;
  19178. while( i < l ){
  19179. f = [ perimeter[i*2+1], apex, perimeter[i*2] ];
  19180. assignPoints( f, allPoints, points );
  19181. faces.push( f )
  19182. if( f.visiblePoints !== undefined )faceStack.push( f );
  19183. i++;
  19184. }
  19185. }
  19186. var distSqPointSegment = function(){
  19187. var ab = new THREE.Vector3(),
  19188. ac = new THREE.Vector3(),
  19189. bc = new THREE.Vector3();
  19190. return function( a, b, c ){
  19191. ab.subVectors( b, a );
  19192. ac.subVectors( c, a );
  19193. bc.subVectors( c, b );
  19194. var e = ac.dot(ab);
  19195. if (e < 0.0) return ac.dot( ac );
  19196. var f = ab.dot( ab );
  19197. if (e >= f) return bc.dot( bc );
  19198. return ac.dot( ac ) - e * e / f;
  19199. }
  19200. }();
  19201. return function( geometry ){
  19202. reset();
  19203. points = geometry.vertices;
  19204. faces = [],
  19205. faceStack = [],
  19206. i = NUM_POINTS = points.length,
  19207. extremes = points.slice( 0, 6 ),
  19208. max = 0;
  19209. /*
  19210. * FIND EXTREMETIES
  19211. */
  19212. while( i-- > 0 ){
  19213. if( points[i].x < extremes[0].x ) extremes[0] = points[i];
  19214. if( points[i].x > extremes[1].x ) extremes[1] = points[i];
  19215. if( points[i].y < extremes[2].y ) extremes[2] = points[i];
  19216. if( points[i].y < extremes[3].y ) extremes[3] = points[i];
  19217. if( points[i].z < extremes[4].z ) extremes[4] = points[i];
  19218. if( points[i].z < extremes[5].z ) extremes[5] = points[i];
  19219. }
  19220. /*
  19221. * Find the longest line between the extremeties
  19222. */
  19223. j = i = 6;
  19224. while( i-- > 0 ){
  19225. j = i - 1;
  19226. while( j-- > 0 ){
  19227. if( max < (dcur = extremes[i].distanceToSquared( extremes[j] )) ){
  19228. max = dcur;
  19229. v0 = extremes[ i ];
  19230. v1 = extremes[ j ];
  19231. }
  19232. }
  19233. }
  19234. // 3. Find the most distant point to the line segment, this creates a plane
  19235. i = 6;
  19236. max = 0;
  19237. while( i-- > 0 ){
  19238. dcur = distSqPointSegment( v0, v1, extremes[i]);
  19239. if( max < dcur ){
  19240. max = dcur;
  19241. v2 = extremes[ i ];
  19242. }
  19243. }
  19244. // 4. Find the most distant point to the plane.
  19245. N = norm(v0, v1, v2);
  19246. D = N.dot( v0 );
  19247. max = 0;
  19248. i = NUM_POINTS;
  19249. while( i-- > 0 ){
  19250. dcur = Math.abs( points[i].dot( N ) - D );
  19251. if( max < dcur ){
  19252. max = dcur;
  19253. v3 = points[i];
  19254. }
  19255. }
  19256. var v0Index = points.indexOf( v0 ),
  19257. v1Index = points.indexOf( v1 ),
  19258. v2Index = points.indexOf( v2 ),
  19259. v3Index = points.indexOf( v3 );
  19260. // We now have a tetrahedron as the base geometry.
  19261. // Now we must subdivide the
  19262. var tetrahedron =[
  19263. [ v2Index, v1Index, v0Index ],
  19264. [ v1Index, v3Index, v0Index ],
  19265. [ v2Index, v3Index, v1Index ],
  19266. [ v0Index, v3Index, v2Index ],
  19267. ];
  19268. subaA.subVectors( v1, v0 ).normalize();
  19269. subaB.subVectors( v2, v0 ).normalize();
  19270. subC.subVectors ( v3, v0 ).normalize();
  19271. var sign = subC.dot( new THREE.Vector3().crossVectors( subaB, subaA ));
  19272. // Reverse the winding if negative sign
  19273. if( sign < 0 ){
  19274. tetrahedron[0].reverse();
  19275. tetrahedron[1].reverse();
  19276. tetrahedron[2].reverse();
  19277. tetrahedron[3].reverse();
  19278. }
  19279. //One for each face of the pyramid
  19280. var pointsCloned = points.slice();
  19281. pointsCloned.splice( pointsCloned.indexOf( v0 ), 1 );
  19282. pointsCloned.splice( pointsCloned.indexOf( v1 ), 1 );
  19283. pointsCloned.splice( pointsCloned.indexOf( v2 ), 1 );
  19284. pointsCloned.splice( pointsCloned.indexOf( v3 ), 1 );
  19285. var i = tetrahedron.length;
  19286. while( i-- > 0 ){
  19287. assignPoints( tetrahedron[i], pointsCloned, points );
  19288. if( tetrahedron[i].visiblePoints !== undefined ){
  19289. faceStack.push( tetrahedron[i] );
  19290. }
  19291. faces.push( tetrahedron[i] );
  19292. }
  19293. process( points );
  19294. // Assign to our geometry object
  19295. var ll = faces.length;
  19296. while( ll-- > 0 ){
  19297. geometry.faces[ll] = new THREE.Face3( faces[ll][2], faces[ll][1], faces[ll][0], faces[ll].normal )
  19298. }
  19299. geometry.normalsNeedUpdate = true;
  19300. return geometry;
  19301. }
  19302. }())
  19303. },{}],86:[function(require,module,exports){
  19304. var EPS = 0.1;
  19305. module.exports = {
  19306. schema: {
  19307. enabled: {default: true},
  19308. mode: {default: 'teleport', oneOf: ['teleport', 'animate']},
  19309. animateSpeed: {default: 3.0}
  19310. },
  19311. init: function () {
  19312. this.active = true;
  19313. this.checkpoint = null;
  19314. this.offset = new THREE.Vector3();
  19315. this.position = new THREE.Vector3();
  19316. this.targetPosition = new THREE.Vector3();
  19317. },
  19318. play: function () { this.active = true; },
  19319. pause: function () { this.active = false; },
  19320. setCheckpoint: function (checkpoint) {
  19321. var el = this.el;
  19322. if (!this.active) return;
  19323. if (this.checkpoint === checkpoint) return;
  19324. if (this.checkpoint) {
  19325. el.emit('navigation-end', {checkpoint: this.checkpoint});
  19326. }
  19327. this.checkpoint = checkpoint;
  19328. this.sync();
  19329. // Ignore new checkpoint if we're already there.
  19330. if (this.position.distanceTo(this.targetPosition) < EPS) {
  19331. this.checkpoint = null;
  19332. return;
  19333. }
  19334. el.emit('navigation-start', {checkpoint: checkpoint});
  19335. if (this.data.mode === 'teleport') {
  19336. this.el.setAttribute('position', this.targetPosition);
  19337. this.checkpoint = null;
  19338. el.emit('navigation-end', {checkpoint: checkpoint});
  19339. }
  19340. },
  19341. isVelocityActive: function () {
  19342. return !!(this.active && this.checkpoint);
  19343. },
  19344. getVelocity: function () {
  19345. if (!this.active) return;
  19346. var data = this.data,
  19347. offset = this.offset,
  19348. position = this.position,
  19349. targetPosition = this.targetPosition,
  19350. checkpoint = this.checkpoint;
  19351. this.sync();
  19352. if (position.distanceTo(targetPosition) < EPS) {
  19353. this.checkpoint = null;
  19354. this.el.emit('navigation-end', {checkpoint: checkpoint});
  19355. return offset.set(0, 0, 0);
  19356. }
  19357. offset.setLength(data.animateSpeed);
  19358. return offset;
  19359. },
  19360. sync: function () {
  19361. var offset = this.offset,
  19362. position = this.position,
  19363. targetPosition = this.targetPosition;
  19364. position.copy(this.el.getAttribute('position'));
  19365. targetPosition.copy(this.checkpoint.object3D.getWorldPosition());
  19366. targetPosition.add(this.checkpoint.components.checkpoint.getOffset());
  19367. offset.copy(targetPosition).sub(position);
  19368. }
  19369. };
  19370. },{}],87:[function(require,module,exports){
  19371. /**
  19372. * Gamepad controls for A-Frame.
  19373. *
  19374. * Stripped-down version of: https://github.com/donmccurdy/aframe-gamepad-controls
  19375. *
  19376. * For more information about the Gamepad API, see:
  19377. * https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
  19378. */
  19379. var GamepadButton = require('../../lib/GamepadButton'),
  19380. GamepadButtonEvent = require('../../lib/GamepadButtonEvent');
  19381. var JOYSTICK_EPS = 0.2;
  19382. module.exports = {
  19383. /*******************************************************************
  19384. * Statics
  19385. */
  19386. GamepadButton: GamepadButton,
  19387. /*******************************************************************
  19388. * Schema
  19389. */
  19390. schema: {
  19391. // Controller 0-3
  19392. controller: { default: 0, oneOf: [0, 1, 2, 3] },
  19393. // Enable/disable features
  19394. enabled: { default: true },
  19395. // Debugging
  19396. debug: { default: false }
  19397. },
  19398. /*******************************************************************
  19399. * Core
  19400. */
  19401. /**
  19402. * Called once when component is attached. Generally for initial setup.
  19403. */
  19404. init: function () {
  19405. var scene = this.el.sceneEl;
  19406. this.prevTime = window.performance.now();
  19407. // Button state
  19408. this.buttons = {};
  19409. scene.addBehavior(this);
  19410. },
  19411. /**
  19412. * Called when component is attached and when component data changes.
  19413. * Generally modifies the entity based on the data.
  19414. */
  19415. update: function () { this.tick(); },
  19416. /**
  19417. * Called on each iteration of main render loop.
  19418. */
  19419. tick: function () {
  19420. this.updateButtonState();
  19421. },
  19422. /**
  19423. * Called when a component is removed (e.g., via removeAttribute).
  19424. * Generally undoes all modifications to the entity.
  19425. */
  19426. remove: function () { },
  19427. /*******************************************************************
  19428. * Universal controls - movement
  19429. */
  19430. isVelocityActive: function () {
  19431. if (!this.data.enabled || !this.isConnected()) return false;
  19432. var dpad = this.getDpad(),
  19433. joystick0 = this.getJoystick(0),
  19434. inputX = dpad.x || joystick0.x,
  19435. inputY = dpad.y || joystick0.y;
  19436. return Math.abs(inputX) > JOYSTICK_EPS || Math.abs(inputY) > JOYSTICK_EPS;
  19437. },
  19438. getVelocityDelta: function () {
  19439. var dpad = this.getDpad(),
  19440. joystick0 = this.getJoystick(0),
  19441. inputX = dpad.x || joystick0.x,
  19442. inputY = dpad.y || joystick0.y,
  19443. dVelocity = new THREE.Vector3();
  19444. if (Math.abs(inputX) > JOYSTICK_EPS) {
  19445. dVelocity.x += inputX;
  19446. }
  19447. if (Math.abs(inputY) > JOYSTICK_EPS) {
  19448. dVelocity.z += inputY;
  19449. }
  19450. return dVelocity;
  19451. },
  19452. /*******************************************************************
  19453. * Universal controls - rotation
  19454. */
  19455. isRotationActive: function () {
  19456. if (!this.data.enabled || !this.isConnected()) return false;
  19457. var joystick1 = this.getJoystick(1);
  19458. return Math.abs(joystick1.x) > JOYSTICK_EPS || Math.abs(joystick1.y) > JOYSTICK_EPS;
  19459. },
  19460. getRotationDelta: function () {
  19461. var lookVector = this.getJoystick(1);
  19462. if (Math.abs(lookVector.x) <= JOYSTICK_EPS) lookVector.x = 0;
  19463. if (Math.abs(lookVector.y) <= JOYSTICK_EPS) lookVector.y = 0;
  19464. return lookVector;
  19465. },
  19466. /*******************************************************************
  19467. * Button events
  19468. */
  19469. updateButtonState: function () {
  19470. var gamepad = this.getGamepad();
  19471. if (this.data.enabled && gamepad) {
  19472. // Fire DOM events for button state changes.
  19473. for (var i = 0; i < gamepad.buttons.length; i++) {
  19474. if (gamepad.buttons[i].pressed && !this.buttons[i]) {
  19475. this.emit(new GamepadButtonEvent('gamepadbuttondown', i, gamepad.buttons[i]));
  19476. } else if (!gamepad.buttons[i].pressed && this.buttons[i]) {
  19477. this.emit(new GamepadButtonEvent('gamepadbuttonup', i, gamepad.buttons[i]));
  19478. }
  19479. this.buttons[i] = gamepad.buttons[i].pressed;
  19480. }
  19481. } else if (Object.keys(this.buttons)) {
  19482. // Reset state if controls are disabled or controller is lost.
  19483. this.buttons = {};
  19484. }
  19485. },
  19486. emit: function (event) {
  19487. // Emit original event.
  19488. this.el.emit(event.type, event);
  19489. // Emit convenience event, identifying button index.
  19490. this.el.emit(
  19491. event.type + ':' + event.index,
  19492. new GamepadButtonEvent(event.type, event.index, event)
  19493. );
  19494. },
  19495. /*******************************************************************
  19496. * Gamepad state
  19497. */
  19498. /**
  19499. * Returns the Gamepad instance attached to the component. If connected,
  19500. * a proxy-controls component may provide access to Gamepad input from a
  19501. * remote device.
  19502. *
  19503. * @return {Gamepad}
  19504. */
  19505. getGamepad: function () {
  19506. var localGamepad = navigator.getGamepads
  19507. && navigator.getGamepads()[this.data.controller],
  19508. proxyControls = this.el.sceneEl.components['proxy-controls'],
  19509. proxyGamepad = proxyControls && proxyControls.isConnected()
  19510. && proxyControls.getGamepad(this.data.controller);
  19511. return proxyGamepad || localGamepad;
  19512. },
  19513. /**
  19514. * Returns the state of the given button.
  19515. * @param {number} index The button (0-N) for which to find state.
  19516. * @return {GamepadButton}
  19517. */
  19518. getButton: function (index) {
  19519. return this.getGamepad().buttons[index];
  19520. },
  19521. /**
  19522. * Returns state of the given axis. Axes are labelled 0-N, where 0-1 will
  19523. * represent X/Y on the first joystick, and 2-3 X/Y on the second.
  19524. * @param {number} index The axis (0-N) for which to find state.
  19525. * @return {number} On the interval [-1,1].
  19526. */
  19527. getAxis: function (index) {
  19528. return this.getGamepad().axes[index];
  19529. },
  19530. /**
  19531. * Returns the state of the given joystick (0 or 1) as a THREE.Vector2.
  19532. * @param {number} id The joystick (0, 1) for which to find state.
  19533. * @return {THREE.Vector2}
  19534. */
  19535. getJoystick: function (index) {
  19536. var gamepad = this.getGamepad();
  19537. switch (index) {
  19538. case 0: return new THREE.Vector2(gamepad.axes[0], gamepad.axes[1]);
  19539. case 1: return new THREE.Vector2(gamepad.axes[2], gamepad.axes[3]);
  19540. default: throw new Error('Unexpected joystick index "%d".', index);
  19541. }
  19542. },
  19543. /**
  19544. * Returns the state of the dpad as a THREE.Vector2.
  19545. * @return {THREE.Vector2}
  19546. */
  19547. getDpad: function () {
  19548. var gamepad = this.getGamepad();
  19549. if (!gamepad.buttons[GamepadButton.DPAD_RIGHT]) {
  19550. return new THREE.Vector2();
  19551. }
  19552. return new THREE.Vector2(
  19553. (gamepad.buttons[GamepadButton.DPAD_RIGHT].pressed ? 1 : 0)
  19554. + (gamepad.buttons[GamepadButton.DPAD_LEFT].pressed ? -1 : 0),
  19555. (gamepad.buttons[GamepadButton.DPAD_UP].pressed ? -1 : 0)
  19556. + (gamepad.buttons[GamepadButton.DPAD_DOWN].pressed ? 1 : 0)
  19557. );
  19558. },
  19559. /**
  19560. * Returns true if the gamepad is currently connected to the system.
  19561. * @return {boolean}
  19562. */
  19563. isConnected: function () {
  19564. var gamepad = this.getGamepad();
  19565. return !!(gamepad && gamepad.connected);
  19566. },
  19567. /**
  19568. * Returns a string containing some information about the controller. Result
  19569. * may vary across browsers, for a given controller.
  19570. * @return {string}
  19571. */
  19572. getID: function () {
  19573. return this.getGamepad().id;
  19574. }
  19575. };
  19576. },{"../../lib/GamepadButton":4,"../../lib/GamepadButtonEvent":5}],88:[function(require,module,exports){
  19577. var radToDeg = THREE.Math.radToDeg,
  19578. isMobile = AFRAME.utils.device.isMobile();
  19579. module.exports = {
  19580. schema: {
  19581. enabled: {default: true},
  19582. standing: {default: true}
  19583. },
  19584. init: function () {
  19585. this.isPositionCalibrated = false;
  19586. this.dolly = new THREE.Object3D();
  19587. this.hmdEuler = new THREE.Euler();
  19588. this.previousHMDPosition = new THREE.Vector3();
  19589. this.deltaHMDPosition = new THREE.Vector3();
  19590. this.vrControls = new THREE.VRControls(this.dolly);
  19591. this.rotation = new THREE.Vector3();
  19592. },
  19593. update: function () {
  19594. var data = this.data;
  19595. var vrControls = this.vrControls;
  19596. vrControls.standing = data.standing;
  19597. vrControls.update();
  19598. },
  19599. tick: function () {
  19600. this.vrControls.update();
  19601. },
  19602. remove: function () {
  19603. this.vrControls.dispose();
  19604. },
  19605. isRotationActive: function () {
  19606. var hmdEuler = this.hmdEuler;
  19607. if (!this.data.enabled || !(this.el.sceneEl.is('vr-mode') || isMobile)) {
  19608. return false;
  19609. }
  19610. hmdEuler.setFromQuaternion(this.dolly.quaternion, 'YXZ');
  19611. return !isNullVector(hmdEuler);
  19612. },
  19613. getRotation: function () {
  19614. var hmdEuler = this.hmdEuler;
  19615. return this.rotation.set(
  19616. radToDeg(hmdEuler.x),
  19617. radToDeg(hmdEuler.y),
  19618. radToDeg(hmdEuler.z)
  19619. );
  19620. },
  19621. isVelocityActive: function () {
  19622. var deltaHMDPosition = this.deltaHMDPosition;
  19623. var previousHMDPosition = this.previousHMDPosition;
  19624. var currentHMDPosition = this.calculateHMDPosition();
  19625. this.isPositionCalibrated = this.isPositionCalibrated || !isNullVector(previousHMDPosition);
  19626. if (!this.data.enabled || !this.el.sceneEl.is('vr-mode') || isMobile) {
  19627. return false;
  19628. }
  19629. deltaHMDPosition.copy(currentHMDPosition).sub(previousHMDPosition);
  19630. previousHMDPosition.copy(currentHMDPosition);
  19631. return this.isPositionCalibrated && !isNullVector(deltaHMDPosition);
  19632. },
  19633. getPositionDelta: function () {
  19634. return this.deltaHMDPosition;
  19635. },
  19636. calculateHMDPosition: function () {
  19637. var dolly = this.dolly;
  19638. var position = new THREE.Vector3();
  19639. dolly.updateMatrix();
  19640. position.setFromMatrixPosition(dolly.matrix);
  19641. return position;
  19642. }
  19643. };
  19644. function isNullVector (vector) {
  19645. return vector.x === 0 && vector.y === 0 && vector.z === 0;
  19646. }
  19647. },{}],89:[function(require,module,exports){
  19648. var physics = require('aframe-physics-system');
  19649. module.exports = {
  19650. 'checkpoint-controls': require('./checkpoint-controls'),
  19651. 'gamepad-controls': require('./gamepad-controls'),
  19652. 'hmd-controls': require('./hmd-controls'),
  19653. 'keyboard-controls': require('./keyboard-controls'),
  19654. 'mouse-controls': require('./mouse-controls'),
  19655. 'touch-controls': require('./touch-controls'),
  19656. 'universal-controls': require('./universal-controls'),
  19657. registerAll: function (AFRAME) {
  19658. if (this._registered) return;
  19659. AFRAME = AFRAME || window.AFRAME;
  19660. physics.registerAll();
  19661. if (!AFRAME.components['checkpoint-controls']) AFRAME.registerComponent('checkpoint-controls', this['checkpoint-controls']);
  19662. if (!AFRAME.components['gamepad-controls']) AFRAME.registerComponent('gamepad-controls', this['gamepad-controls']);
  19663. if (!AFRAME.components['hmd-controls']) AFRAME.registerComponent('hmd-controls', this['hmd-controls']);
  19664. if (!AFRAME.components['keyboard-controls']) AFRAME.registerComponent('keyboard-controls', this['keyboard-controls']);
  19665. if (!AFRAME.components['mouse-controls']) AFRAME.registerComponent('mouse-controls', this['mouse-controls']);
  19666. if (!AFRAME.components['touch-controls']) AFRAME.registerComponent('touch-controls', this['touch-controls']);
  19667. if (!AFRAME.components['universal-controls']) AFRAME.registerComponent('universal-controls', this['universal-controls']);
  19668. this._registered = true;
  19669. }
  19670. };
  19671. },{"./checkpoint-controls":86,"./gamepad-controls":87,"./hmd-controls":88,"./keyboard-controls":90,"./mouse-controls":91,"./touch-controls":92,"./universal-controls":93,"aframe-physics-system":11}],90:[function(require,module,exports){
  19672. require('../../lib/keyboard.polyfill');
  19673. var MAX_DELTA = 0.2,
  19674. PROXY_FLAG = '__keyboard-controls-proxy';
  19675. var KeyboardEvent = window.KeyboardEvent;
  19676. /**
  19677. * Keyboard Controls component.
  19678. *
  19679. * Stripped-down version of: https://github.com/donmccurdy/aframe-keyboard-controls
  19680. *
  19681. * Bind keyboard events to components, or control your entities with the WASD keys.
  19682. *
  19683. * Why use KeyboardEvent.code? "This is set to a string representing the key that was pressed to
  19684. * generate the KeyboardEvent, without taking the current keyboard layout (e.g., QWERTY vs.
  19685. * Dvorak), locale (e.g., English vs. French), or any modifier keys into account. This is useful
  19686. * when you care about which physical key was pressed, rather thanwhich character it corresponds
  19687. * to. For example, if you’re a writing a game, you might want a certain set of keys to move the
  19688. * player in different directions, and that mapping should ideally be independent of keyboard
  19689. * layout. See: https://developers.google.com/web/updates/2016/04/keyboardevent-keys-codes
  19690. *
  19691. * @namespace wasd-controls
  19692. * keys the entity moves and if you release it will stop. Easing simulates friction.
  19693. * to the entity when pressing the keys.
  19694. * @param {bool} [enabled=true] - To completely enable or disable the controls
  19695. */
  19696. module.exports = {
  19697. schema: {
  19698. enabled: { default: true },
  19699. debug: { default: false }
  19700. },
  19701. init: function () {
  19702. this.dVelocity = new THREE.Vector3();
  19703. this.localKeys = {};
  19704. this.listeners = {
  19705. keydown: this.onKeyDown.bind(this),
  19706. keyup: this.onKeyUp.bind(this),
  19707. blur: this.onBlur.bind(this)
  19708. };
  19709. this.attachEventListeners();
  19710. },
  19711. /*******************************************************************
  19712. * Movement
  19713. */
  19714. isVelocityActive: function () {
  19715. return this.data.enabled && !!Object.keys(this.getKeys()).length;
  19716. },
  19717. getVelocityDelta: function () {
  19718. var data = this.data,
  19719. keys = this.getKeys();
  19720. this.dVelocity.set(0, 0, 0);
  19721. if (data.enabled) {
  19722. if (keys.KeyW || keys.ArrowUp) { this.dVelocity.z -= 1; }
  19723. if (keys.KeyA || keys.ArrowLeft) { this.dVelocity.x -= 1; }
  19724. if (keys.KeyS || keys.ArrowDown) { this.dVelocity.z += 1; }
  19725. if (keys.KeyD || keys.ArrowRight) { this.dVelocity.x += 1; }
  19726. }
  19727. return this.dVelocity.clone();
  19728. },
  19729. /*******************************************************************
  19730. * Events
  19731. */
  19732. play: function () {
  19733. this.attachEventListeners();
  19734. },
  19735. pause: function () {
  19736. this.removeEventListeners();
  19737. },
  19738. remove: function () {
  19739. this.pause();
  19740. },
  19741. attachEventListeners: function () {
  19742. window.addEventListener('keydown', this.listeners.keydown, false);
  19743. window.addEventListener('keyup', this.listeners.keyup, false);
  19744. window.addEventListener('blur', this.listeners.blur, false);
  19745. },
  19746. removeEventListeners: function () {
  19747. window.removeEventListener('keydown', this.listeners.keydown);
  19748. window.removeEventListener('keyup', this.listeners.keyup);
  19749. window.removeEventListener('blur', this.listeners.blur);
  19750. },
  19751. onKeyDown: function (event) {
  19752. if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
  19753. this.localKeys[event.code] = true;
  19754. this.emit(event);
  19755. }
  19756. },
  19757. onKeyUp: function (event) {
  19758. if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
  19759. delete this.localKeys[event.code];
  19760. this.emit(event);
  19761. }
  19762. },
  19763. onBlur: function () {
  19764. for (var code in this.localKeys) {
  19765. if (this.localKeys.hasOwnProperty(code)) {
  19766. delete this.localKeys[code];
  19767. }
  19768. }
  19769. },
  19770. emit: function (event) {
  19771. // TODO - keydown only initially?
  19772. // TODO - where the f is the spacebar
  19773. // Emit original event.
  19774. if (PROXY_FLAG in event) {
  19775. // TODO - Method never triggered.
  19776. this.el.emit(event.type, event);
  19777. }
  19778. // Emit convenience event, identifying key.
  19779. this.el.emit(event.type + ':' + event.code, new KeyboardEvent(event.type, event));
  19780. if (this.data.debug) console.log(event.type + ':' + event.code);
  19781. },
  19782. /*******************************************************************
  19783. * Accessors
  19784. */
  19785. isPressed: function (code) {
  19786. return code in this.getKeys();
  19787. },
  19788. getKeys: function () {
  19789. if (this.isProxied()) {
  19790. return this.el.sceneEl.components['proxy-controls'].getKeyboard();
  19791. }
  19792. return this.localKeys;
  19793. },
  19794. isProxied: function () {
  19795. var proxyControls = this.el.sceneEl.components['proxy-controls'];
  19796. return proxyControls && proxyControls.isConnected();
  19797. }
  19798. };
  19799. },{"../../lib/keyboard.polyfill":10}],91:[function(require,module,exports){
  19800. document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
  19801. /**
  19802. * Mouse + Pointerlock controls.
  19803. *
  19804. * Based on: https://github.com/aframevr/aframe/pull/1056
  19805. */
  19806. module.exports = {
  19807. schema: {
  19808. enabled: { default: true },
  19809. pointerlockEnabled: { default: true },
  19810. sensitivity: { default: 1 / 25 }
  19811. },
  19812. init: function () {
  19813. this.mouseDown = false;
  19814. this.pointerLocked = false;
  19815. this.lookVector = new THREE.Vector2();
  19816. this.bindMethods();
  19817. },
  19818. update: function (previousData) {
  19819. var data = this.data;
  19820. if (previousData.pointerlockEnabled && !data.pointerlockEnabled && this.pointerLocked) {
  19821. document.exitPointerLock();
  19822. }
  19823. },
  19824. play: function () {
  19825. this.addEventListeners();
  19826. },
  19827. pause: function () {
  19828. this.removeEventListeners();
  19829. this.lookVector.set(0, 0);
  19830. },
  19831. remove: function () {
  19832. this.pause();
  19833. },
  19834. bindMethods: function () {
  19835. this.onMouseDown = this.onMouseDown.bind(this);
  19836. this.onMouseMove = this.onMouseMove.bind(this);
  19837. this.onMouseUp = this.onMouseUp.bind(this);
  19838. this.onMouseUp = this.onMouseUp.bind(this);
  19839. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  19840. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  19841. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  19842. },
  19843. addEventListeners: function () {
  19844. var sceneEl = this.el.sceneEl;
  19845. var canvasEl = sceneEl.canvas;
  19846. var data = this.data;
  19847. if (!canvasEl) {
  19848. sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
  19849. return;
  19850. }
  19851. canvasEl.addEventListener('mousedown', this.onMouseDown, false);
  19852. canvasEl.addEventListener('mousemove', this.onMouseMove, false);
  19853. canvasEl.addEventListener('mouseup', this.onMouseUp, false);
  19854. canvasEl.addEventListener('mouseout', this.onMouseUp, false);
  19855. if (data.pointerlockEnabled) {
  19856. document.addEventListener('pointerlockchange', this.onPointerLockChange, false);
  19857. document.addEventListener('mozpointerlockchange', this.onPointerLockChange, false);
  19858. document.addEventListener('pointerlockerror', this.onPointerLockError, false);
  19859. }
  19860. },
  19861. removeEventListeners: function () {
  19862. var canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
  19863. if (canvasEl) {
  19864. canvasEl.removeEventListener('mousedown', this.onMouseDown, false);
  19865. canvasEl.removeEventListener('mousemove', this.onMouseMove, false);
  19866. canvasEl.removeEventListener('mouseup', this.onMouseUp, false);
  19867. canvasEl.removeEventListener('mouseout', this.onMouseUp, false);
  19868. }
  19869. document.removeEventListener('pointerlockchange', this.onPointerLockChange, false);
  19870. document.removeEventListener('mozpointerlockchange', this.onPointerLockChange, false);
  19871. document.removeEventListener('pointerlockerror', this.onPointerLockError, false);
  19872. },
  19873. isRotationActive: function () {
  19874. return this.data.enabled && (this.mouseDown || this.pointerLocked);
  19875. },
  19876. /**
  19877. * Returns the sum of all mouse movement since last call.
  19878. */
  19879. getRotationDelta: function () {
  19880. var dRotation = this.lookVector.clone().multiplyScalar(this.data.sensitivity);
  19881. this.lookVector.set(0, 0);
  19882. return dRotation;
  19883. },
  19884. onMouseMove: function (event) {
  19885. var previousMouseEvent = this.previousMouseEvent;
  19886. if (!this.data.enabled || !(this.mouseDown || this.pointerLocked)) {
  19887. return;
  19888. }
  19889. var movementX = event.movementX || event.mozMovementX || 0;
  19890. var movementY = event.movementY || event.mozMovementY || 0;
  19891. if (!this.pointerLocked) {
  19892. movementX = event.screenX - previousMouseEvent.screenX;
  19893. movementY = event.screenY - previousMouseEvent.screenY;
  19894. }
  19895. this.lookVector.x += movementX;
  19896. this.lookVector.y += movementY;
  19897. this.previousMouseEvent = event;
  19898. },
  19899. onMouseDown: function (event) {
  19900. var canvasEl = this.el.sceneEl.canvas,
  19901. isEditing = (AFRAME.INSPECTOR || {}).opened;
  19902. this.mouseDown = true;
  19903. this.previousMouseEvent = event;
  19904. if (this.data.pointerlockEnabled && !this.pointerLocked && !isEditing) {
  19905. if (canvasEl.requestPointerLock) {
  19906. canvasEl.requestPointerLock();
  19907. } else if (canvasEl.mozRequestPointerLock) {
  19908. canvasEl.mozRequestPointerLock();
  19909. }
  19910. }
  19911. },
  19912. onMouseUp: function () {
  19913. this.mouseDown = false;
  19914. },
  19915. onPointerLockChange: function () {
  19916. this.pointerLocked = !!(document.pointerLockElement || document.mozPointerLockElement);
  19917. },
  19918. onPointerLockError: function () {
  19919. this.pointerLocked = false;
  19920. }
  19921. };
  19922. },{}],92:[function(require,module,exports){
  19923. module.exports = {
  19924. schema: {
  19925. enabled: { default: true }
  19926. },
  19927. init: function () {
  19928. this.dVelocity = new THREE.Vector3();
  19929. this.bindMethods();
  19930. },
  19931. play: function () {
  19932. this.addEventListeners();
  19933. },
  19934. pause: function () {
  19935. this.removeEventListeners();
  19936. this.dVelocity.set(0, 0, 0);
  19937. },
  19938. remove: function () {
  19939. this.pause();
  19940. },
  19941. addEventListeners: function () {
  19942. var sceneEl = this.el.sceneEl;
  19943. var canvasEl = sceneEl.canvas;
  19944. if (!canvasEl) {
  19945. sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
  19946. return;
  19947. }
  19948. canvasEl.addEventListener('touchstart', this.onTouchStart);
  19949. canvasEl.addEventListener('touchend', this.onTouchEnd);
  19950. },
  19951. removeEventListeners: function () {
  19952. var canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
  19953. if (!canvasEl) { return; }
  19954. canvasEl.removeEventListener('touchstart', this.onTouchStart);
  19955. canvasEl.removeEventListener('touchend', this.onTouchEnd);
  19956. },
  19957. isVelocityActive: function () {
  19958. return this.data.enabled && this.isMoving;
  19959. },
  19960. getVelocityDelta: function () {
  19961. this.dVelocity.z = this.isMoving ? -1 : 0;
  19962. return this.dVelocity.clone();
  19963. },
  19964. bindMethods: function () {
  19965. this.onTouchStart = this.onTouchStart.bind(this);
  19966. this.onTouchEnd = this.onTouchEnd.bind(this);
  19967. },
  19968. onTouchStart: function (e) {
  19969. this.isMoving = true;
  19970. e.preventDefault();
  19971. },
  19972. onTouchEnd: function (e) {
  19973. this.isMoving = false;
  19974. e.preventDefault();
  19975. }
  19976. };
  19977. },{}],93:[function(require,module,exports){
  19978. /**
  19979. * Universal Controls
  19980. *
  19981. * @author Don McCurdy <dm@donmccurdy.com>
  19982. */
  19983. var COMPONENT_SUFFIX = '-controls',
  19984. MAX_DELTA = 0.2, // ms
  19985. PI_2 = Math.PI / 2;
  19986. module.exports = {
  19987. /*******************************************************************
  19988. * Schema
  19989. */
  19990. dependencies: ['velocity', 'rotation'],
  19991. schema: {
  19992. enabled: { default: true },
  19993. movementEnabled: { default: true },
  19994. movementControls: { default: ['gamepad', 'keyboard', 'touch', 'hmd'] },
  19995. rotationEnabled: { default: true },
  19996. rotationControls: { default: ['hmd', 'gamepad', 'mouse'] },
  19997. movementSpeed: { default: 5 }, // m/s
  19998. movementEasing: { default: 15 }, // m/s2
  19999. movementEasingY: { default: 0 }, // m/s2
  20000. movementAcceleration: { default: 80 }, // m/s2
  20001. rotationSensitivity: { default: 0.05 }, // radians/frame, ish
  20002. fly: { default: false },
  20003. },
  20004. /*******************************************************************
  20005. * Lifecycle
  20006. */
  20007. init: function () {
  20008. var rotation = this.el.getAttribute('rotation');
  20009. if (this.el.hasAttribute('look-controls') && this.data.rotationEnabled) {
  20010. console.error('[universal-controls] The `universal-controls` component is a replacement '
  20011. + 'for `look-controls`, and cannot be used in combination with it.');
  20012. }
  20013. // Movement
  20014. this.velocity = new THREE.Vector3();
  20015. // Rotation
  20016. this.pitch = new THREE.Object3D();
  20017. this.pitch.rotation.x = THREE.Math.degToRad(rotation.x);
  20018. this.yaw = new THREE.Object3D();
  20019. this.yaw.position.y = 10;
  20020. this.yaw.rotation.y = THREE.Math.degToRad(rotation.y);
  20021. this.yaw.add(this.pitch);
  20022. this.heading = new THREE.Euler(0, 0, 0, 'YXZ');
  20023. if (this.el.sceneEl.hasLoaded) {
  20024. this.injectControls();
  20025. } else {
  20026. this.el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
  20027. }
  20028. },
  20029. update: function () {
  20030. if (this.el.sceneEl.hasLoaded) {
  20031. this.injectControls();
  20032. }
  20033. },
  20034. injectControls: function () {
  20035. var i, name,
  20036. data = this.data;
  20037. for (i = 0; i < data.movementControls.length; i++) {
  20038. name = data.movementControls[i] + COMPONENT_SUFFIX;
  20039. if (!this.el.components[name]) {
  20040. this.el.setAttribute(name, '');
  20041. }
  20042. }
  20043. for (i = 0; i < data.rotationControls.length; i++) {
  20044. name = data.rotationControls[i] + COMPONENT_SUFFIX;
  20045. if (!this.el.components[name]) {
  20046. this.el.setAttribute(name, '');
  20047. }
  20048. }
  20049. },
  20050. /*******************************************************************
  20051. * Tick
  20052. */
  20053. tick: function (t, dt) {
  20054. if (!dt) { return; }
  20055. // Update rotation.
  20056. if (this.data.rotationEnabled) this.updateRotation(dt);
  20057. // Update velocity. If FPS is too low, reset.
  20058. if (this.data.movementEnabled && dt / 1000 > MAX_DELTA) {
  20059. this.velocity.set(0, 0, 0);
  20060. this.el.setAttribute('velocity', this.velocity);
  20061. } else {
  20062. this.updateVelocity(dt);
  20063. }
  20064. },
  20065. /*******************************************************************
  20066. * Rotation
  20067. */
  20068. updateRotation: function (dt) {
  20069. var control, dRotation,
  20070. data = this.data;
  20071. for (var i = 0, l = data.rotationControls.length; i < l; i++) {
  20072. control = this.el.components[data.rotationControls[i] + COMPONENT_SUFFIX];
  20073. if (control && control.isRotationActive()) {
  20074. if (control.getRotationDelta) {
  20075. dRotation = control.getRotationDelta(dt);
  20076. dRotation.multiplyScalar(data.rotationSensitivity);
  20077. this.yaw.rotation.y -= dRotation.x;
  20078. this.pitch.rotation.x -= dRotation.y;
  20079. this.pitch.rotation.x = Math.max(-PI_2, Math.min(PI_2, this.pitch.rotation.x));
  20080. this.el.setAttribute('rotation', {
  20081. x: THREE.Math.radToDeg(this.pitch.rotation.x),
  20082. y: THREE.Math.radToDeg(this.yaw.rotation.y),
  20083. z: 0
  20084. });
  20085. } else if (control.getRotation) {
  20086. this.el.setAttribute('rotation', control.getRotation());
  20087. } else {
  20088. throw new Error('Incompatible rotation controls: %s', data.rotationControls[i]);
  20089. }
  20090. break;
  20091. }
  20092. }
  20093. },
  20094. /*******************************************************************
  20095. * Movement
  20096. */
  20097. updateVelocity: function (dt) {
  20098. var control, dVelocity,
  20099. velocity = this.velocity,
  20100. data = this.data;
  20101. if (data.movementEnabled) {
  20102. for (var i = 0, l = data.movementControls.length; i < l; i++) {
  20103. control = this.el.components[data.movementControls[i] + COMPONENT_SUFFIX];
  20104. if (control && control.isVelocityActive()) {
  20105. if (control.getVelocityDelta) {
  20106. dVelocity = control.getVelocityDelta(dt);
  20107. } else if (control.getVelocity) {
  20108. this.el.setAttribute('velocity', control.getVelocity());
  20109. return;
  20110. } else if (control.getPositionDelta) {
  20111. velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
  20112. this.el.setAttribute('velocity', velocity);
  20113. return;
  20114. } else {
  20115. throw new Error('Incompatible movement controls: ', data.movementControls[i]);
  20116. }
  20117. break;
  20118. }
  20119. }
  20120. }
  20121. velocity.copy(this.el.getAttribute('velocity'));
  20122. velocity.x -= velocity.x * data.movementEasing * dt / 1000;
  20123. velocity.y -= velocity.y * data.movementEasingY * dt / 1000;
  20124. velocity.z -= velocity.z * data.movementEasing * dt / 1000;
  20125. if (dVelocity && data.movementEnabled) {
  20126. // Set acceleration
  20127. if (dVelocity.length() > 1) {
  20128. dVelocity.setLength(this.data.movementAcceleration * dt / 1000);
  20129. } else {
  20130. dVelocity.multiplyScalar(this.data.movementAcceleration * dt / 1000);
  20131. }
  20132. // Rotate to heading
  20133. var rotation = this.el.getAttribute('rotation');
  20134. if (rotation) {
  20135. this.heading.set(
  20136. data.fly ? THREE.Math.degToRad(rotation.x) : 0,
  20137. THREE.Math.degToRad(rotation.y),
  20138. 0
  20139. );
  20140. dVelocity.applyEuler(this.heading);
  20141. }
  20142. velocity.add(dVelocity);
  20143. // TODO - Several issues here:
  20144. // (1) Interferes w/ gravity.
  20145. // (2) Interferes w/ jumping.
  20146. // (3) Likely to interfere w/ relative position to moving platform.
  20147. // if (velocity.length() > data.movementSpeed) {
  20148. // velocity.setLength(data.movementSpeed);
  20149. // }
  20150. }
  20151. this.el.setAttribute('velocity', velocity);
  20152. }
  20153. };
  20154. },{}],94:[function(require,module,exports){
  20155. var LoopMode = {
  20156. once: THREE.LoopOnce,
  20157. repeat: THREE.LoopRepeat,
  20158. pingpong: THREE.LoopPingPong
  20159. };
  20160. /**
  20161. * animation-mixer
  20162. *
  20163. * Player for animation clips. Intended to be compatible with any model format that supports
  20164. * skeletal or morph animations through THREE.AnimationMixer.
  20165. * See: https://threejs.org/docs/?q=animation#Reference/Animation/AnimationMixer
  20166. */
  20167. module.exports = {
  20168. schema: {
  20169. clip: {default: '*'},
  20170. duration: {default: 0},
  20171. crossFadeDuration: {default: 0},
  20172. loop: {default: 'repeat', oneOf: Object.keys(LoopMode)},
  20173. repetitions: {default: Infinity, min: 0}
  20174. },
  20175. init: function () {
  20176. /** @type {THREE.Mesh} */
  20177. this.model = null;
  20178. /** @type {THREE.AnimationMixer} */
  20179. this.mixer = null;
  20180. /** @type {Array<THREE.AnimationAction>} */
  20181. this.activeActions = [];
  20182. var model = this.el.getObject3D('mesh');
  20183. if (model) {
  20184. this.load(model);
  20185. } else {
  20186. this.el.addEventListener('model-loaded', function(e) {
  20187. this.load(e.detail.model);
  20188. }.bind(this));
  20189. }
  20190. },
  20191. load: function (model) {
  20192. var el = this.el;
  20193. this.model = model;
  20194. this.mixer = new THREE.AnimationMixer(model);
  20195. this.mixer.addEventListener('loop', function (e) {
  20196. el.emit('animation-loop', {action: e.action, loopDelta: e.loopDelta});
  20197. }.bind(this));
  20198. this.mixer.addEventListener('finished', function (e) {
  20199. el.emit('animation-finished', {action: e.action, direction: e.direction});
  20200. }.bind(this));
  20201. if (this.data.clip) this.update({});
  20202. },
  20203. remove: function () {
  20204. if (this.mixer) this.mixer.stopAllAction();
  20205. },
  20206. update: function (previousData) {
  20207. if (!previousData) return;
  20208. this.stopAction();
  20209. if (this.data.clip) {
  20210. this.playAction();
  20211. }
  20212. },
  20213. stopAction: function () {
  20214. var data = this.data;
  20215. for (var i = 0; i < this.activeActions.length; i++) {
  20216. data.crossFadeDuration
  20217. ? this.activeActions[i].fadeOut(data.crossFadeDuration)
  20218. : this.activeActions[i].stop();
  20219. }
  20220. this.activeActions.length = 0;
  20221. },
  20222. playAction: function () {
  20223. if (!this.mixer) return;
  20224. var model = this.model,
  20225. data = this.data,
  20226. clips = model.animations || (model.geometry || {}).animations || [];
  20227. if (!clips.length) return;
  20228. var re = wildcardToRegExp(data.clip);
  20229. for (var clip, i = 0; (clip = clips[i]); i++) {
  20230. if (clip.name.match(re)) {
  20231. var action = this.mixer.clipAction(clip, model);
  20232. action.enabled = true;
  20233. if (data.duration) action.setDuration(data.duration);
  20234. action
  20235. .setLoop(LoopMode[data.loop], data.repetitions)
  20236. .fadeIn(data.crossFadeDuration)
  20237. .play();
  20238. this.activeActions.push(action);
  20239. }
  20240. }
  20241. },
  20242. tick: function (t, dt) {
  20243. if (this.mixer && !isNaN(dt)) this.mixer.update(dt / 1000);
  20244. }
  20245. };
  20246. /**
  20247. * Creates a RegExp from the given string, converting asterisks to .* expressions,
  20248. * and escaping all other characters.
  20249. */
  20250. function wildcardToRegExp (s) {
  20251. return new RegExp('^' + s.split(/\*+/).map(regExpEscape).join('.*') + '$');
  20252. }
  20253. /**
  20254. * RegExp-escapes all characters in the given string.
  20255. */
  20256. function regExpEscape (s) {
  20257. return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
  20258. }
  20259. },{}],95:[function(require,module,exports){
  20260. THREE.FBXLoader = require('../../lib/FBXLoader');
  20261. /**
  20262. * fbx-model
  20263. *
  20264. * Loader for FBX format. Supports ASCII, but *not* binary, models.
  20265. */
  20266. module.exports = {
  20267. schema: {
  20268. src: { type: 'asset' },
  20269. crossorigin: { default: '' }
  20270. },
  20271. init: function () {
  20272. this.model = null;
  20273. },
  20274. update: function () {
  20275. var loader,
  20276. data = this.data;
  20277. if (!data.src) return;
  20278. this.remove();
  20279. loader = new THREE.FBXLoader();
  20280. if (data.crossorigin) loader.setCrossOrigin(data.crossorigin);
  20281. loader.load(data.src, this.load.bind(this));
  20282. },
  20283. load: function (model) {
  20284. this.model = model;
  20285. this.el.setObject3D('mesh', model);
  20286. this.el.emit('model-loaded', {format: 'fbx', model: model});
  20287. },
  20288. remove: function () {
  20289. if (this.model) this.el.removeObject3D('mesh');
  20290. }
  20291. };
  20292. },{"../../lib/FBXLoader":3}],96:[function(require,module,exports){
  20293. var fetchScript = require('../../lib/fetch-script')();
  20294. var LOADER_SRC = 'https://rawgit.com/mrdoob/three.js/r86/examples/js/loaders/GLTFLoader.js';
  20295. /**
  20296. * Legacy loader for glTF 1.0 models.
  20297. * Asynchronously loads THREE.GLTFLoader from rawgit.
  20298. */
  20299. module.exports = {
  20300. schema: {type: 'model'},
  20301. init: function () {
  20302. this.model = null;
  20303. this.loader = null;
  20304. this.loaderPromise = loadLoader().then(function () {
  20305. this.loader = new THREE.GLTFLoader();
  20306. this.loader.setCrossOrigin('Anonymous');
  20307. }.bind(this));
  20308. },
  20309. update: function () {
  20310. var self = this;
  20311. var el = this.el;
  20312. var src = this.data;
  20313. if (!src) { return; }
  20314. this.remove();
  20315. this.loaderPromise.then(function () {
  20316. this.loader.load(src, function gltfLoaded (gltfModel) {
  20317. self.model = gltfModel.scene;
  20318. self.model.animations = gltfModel.animations;
  20319. el.setObject3D('mesh', self.model);
  20320. el.emit('model-loaded', {format: 'gltf', model: self.model});
  20321. });
  20322. }.bind(this));
  20323. },
  20324. remove: function () {
  20325. if (!this.model) { return; }
  20326. this.el.removeObject3D('mesh');
  20327. }
  20328. };
  20329. var loadLoader = (function () {
  20330. var promise;
  20331. return function () {
  20332. promise = promise || fetchScript(LOADER_SRC);
  20333. return promise;
  20334. };
  20335. }());
  20336. },{"../../lib/fetch-script":8}],97:[function(require,module,exports){
  20337. module.exports = {
  20338. 'animation-mixer': require('./animation-mixer'),
  20339. 'fbx-model': require('./fbx-model'),
  20340. 'gltf-model-legacy': require('./gltf-model-legacy'),
  20341. 'json-model': require('./json-model'),
  20342. 'object-model': require('./object-model'),
  20343. 'ply-model': require('./ply-model'),
  20344. registerAll: function (AFRAME) {
  20345. if (this._registered) return;
  20346. AFRAME = AFRAME || window.AFRAME;
  20347. // THREE.AnimationMixer
  20348. if (!AFRAME.components['animation-mixer']) {
  20349. AFRAME.registerComponent('animation-mixer', this['animation-mixer']);
  20350. }
  20351. // THREE.PlyLoader
  20352. if (!AFRAME.systems['ply-model']) {
  20353. AFRAME.registerSystem('ply-model', this['ply-model'].System);
  20354. }
  20355. if (!AFRAME.components['ply-model']) {
  20356. AFRAME.registerComponent('ply-model', this['ply-model'].Component);
  20357. }
  20358. // THREE.FBXLoader
  20359. if (!AFRAME.components['fbx-model']) {
  20360. AFRAME.registerComponent('fbx-model', this['fbx-model']);
  20361. }
  20362. // THREE.GLTFLoader
  20363. if (!AFRAME.components['gltf-model-legacy']) {
  20364. AFRAME.registerComponent('gltf-model-legacy', this['gltf-model-legacy']);
  20365. }
  20366. // THREE.JsonLoader
  20367. if (!AFRAME.components['json-model']) {
  20368. AFRAME.registerComponent('json-model', this['json-model']);
  20369. }
  20370. // THREE.ObjectLoader
  20371. if (!AFRAME.components['object-model']) {
  20372. AFRAME.registerComponent('object-model', this['object-model']);
  20373. }
  20374. this._registered = true;
  20375. }
  20376. };
  20377. },{"./animation-mixer":94,"./fbx-model":95,"./gltf-model-legacy":96,"./json-model":98,"./object-model":99,"./ply-model":100}],98:[function(require,module,exports){
  20378. /**
  20379. * json-model
  20380. *
  20381. * Loader for THREE.js JSON format. Somewhat confusingly, there are two different THREE.js formats,
  20382. * both having the .json extension. This loader supports only THREE.JsonLoader, which typically
  20383. * includes only a single mesh.
  20384. *
  20385. * Check the console for errors, if in doubt. You may need to use `object-model` or
  20386. * `blend-character-model` for some .js and .json files.
  20387. *
  20388. * See: https://clara.io/learn/user-guide/data_exchange/threejs_export
  20389. */
  20390. module.exports = {
  20391. schema: {
  20392. src: { type: 'asset' },
  20393. crossorigin: { default: '' }
  20394. },
  20395. init: function () {
  20396. this.model = null;
  20397. },
  20398. update: function () {
  20399. var loader,
  20400. data = this.data;
  20401. if (!data.src) return;
  20402. this.remove();
  20403. loader = new THREE.JSONLoader();
  20404. if (data.crossorigin) loader.crossOrigin = data.crossorigin;
  20405. loader.load(data.src, function (geometry, materials) {
  20406. // Attempt to automatically detect common material options.
  20407. materials.forEach(function (mat) {
  20408. mat.vertexColors = (geometry.faces[0] || {}).color ? THREE.FaceColors : THREE.NoColors;
  20409. mat.skinning = !!(geometry.bones || []).length;
  20410. mat.morphTargets = !!(geometry.morphTargets || []).length;
  20411. mat.morphNormals = !!(geometry.morphNormals || []).length;
  20412. });
  20413. var model = (geometry.bones || []).length
  20414. ? new THREE.SkinnedMesh(geometry, new THREE.MultiMaterial(materials))
  20415. : new THREE.Mesh(geometry, new THREE.MultiMaterial(materials));
  20416. this.load(model);
  20417. }.bind(this));
  20418. },
  20419. load: function (model) {
  20420. this.model = model;
  20421. this.el.setObject3D('mesh', model);
  20422. this.el.emit('model-loaded', {format: 'json', model: model});
  20423. },
  20424. remove: function () {
  20425. if (this.model) this.el.removeObject3D('mesh');
  20426. }
  20427. };
  20428. },{}],99:[function(require,module,exports){
  20429. /**
  20430. * object-model
  20431. *
  20432. * Loader for THREE.js JSON format. Somewhat confusingly, there are two different THREE.js formats,
  20433. * both having the .json extension. This loader supports only THREE.ObjectLoader, which typically
  20434. * includes multiple meshes or an entire scene.
  20435. *
  20436. * Check the console for errors, if in doubt. You may need to use `json-model` or
  20437. * `blend-character-model` for some .js and .json files.
  20438. *
  20439. * See: https://clara.io/learn/user-guide/data_exchange/threejs_export
  20440. */
  20441. module.exports = {
  20442. schema: {
  20443. src: { type: 'asset' },
  20444. crossorigin: { default: '' }
  20445. },
  20446. init: function () {
  20447. this.model = null;
  20448. },
  20449. update: function () {
  20450. var loader,
  20451. data = this.data;
  20452. if (!data.src) return;
  20453. this.remove();
  20454. loader = new THREE.ObjectLoader();
  20455. if (data.crossorigin) loader.setCrossOrigin(data.crossorigin);
  20456. loader.load(data.src, function(object) {
  20457. // Enable skinning, if applicable.
  20458. object.traverse(function(o) {
  20459. if (o instanceof THREE.SkinnedMesh && o.material) {
  20460. o.material.skinning = !!((o.geometry && o.geometry.bones) || []).length;
  20461. }
  20462. });
  20463. this.load(object);
  20464. }.bind(this));
  20465. },
  20466. load: function (model) {
  20467. this.model = model;
  20468. this.el.setObject3D('mesh', model);
  20469. this.el.emit('model-loaded', {format: 'json', model: model});
  20470. },
  20471. remove: function () {
  20472. if (this.model) this.el.removeObject3D('mesh');
  20473. }
  20474. };
  20475. },{}],100:[function(require,module,exports){
  20476. /**
  20477. * ply-model
  20478. *
  20479. * Wraps THREE.PLYLoader.
  20480. */
  20481. THREE.PLYLoader = require('../../lib/PLYLoader');
  20482. /**
  20483. * Loads, caches, resolves geometries.
  20484. *
  20485. * @member cache - Promises that resolve geometries keyed by `src`.
  20486. */
  20487. module.exports.System = {
  20488. init: function () {
  20489. this.cache = {};
  20490. },
  20491. /**
  20492. * @returns {Promise}
  20493. */
  20494. getOrLoadGeometry: function (src, skipCache) {
  20495. var cache = this.cache;
  20496. var cacheItem = cache[src];
  20497. if (!skipCache && cacheItem) {
  20498. return cacheItem;
  20499. }
  20500. cache[src] = new Promise(function (resolve) {
  20501. var loader = new THREE.PLYLoader();
  20502. loader.load(src, function (geometry) {
  20503. resolve(geometry);
  20504. });
  20505. });
  20506. return cache[src];
  20507. },
  20508. };
  20509. module.exports.Component = {
  20510. schema: {
  20511. skipCache: {type: 'boolean', default: false},
  20512. src: {type: 'asset'}
  20513. },
  20514. init: function () {
  20515. this.model = null;
  20516. },
  20517. update: function () {
  20518. var data = this.data;
  20519. var el = this.el;
  20520. var loader;
  20521. if (!data.src) {
  20522. console.warn('[%s] `src` property is required.', this.name);
  20523. return;
  20524. }
  20525. // Get geometry from system, create and set mesh.
  20526. this.system.getOrLoadGeometry(data.src, data.skipCache).then(function (geometry) {
  20527. var model = createModel(geometry);
  20528. el.setObject3D('mesh', model);
  20529. el.emit('model-loaded', {format: 'ply', model: model});
  20530. });
  20531. },
  20532. remove: function () {
  20533. if (this.model) { this.el.removeObject3D('mesh'); }
  20534. }
  20535. };
  20536. function createModel (geometry) {
  20537. return new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({
  20538. color: 0xFFFFFF,
  20539. shading: THREE.FlatShading,
  20540. vertexColors: THREE.VertexColors,
  20541. shininess: 0
  20542. }));
  20543. }
  20544. },{"../../lib/PLYLoader":6}],101:[function(require,module,exports){
  20545. module.exports = {
  20546. schema: {
  20547. offset: {default: {x: 0, y: 0, z: 0}, type: 'vec3'}
  20548. },
  20549. init: function () {
  20550. this.active = false;
  20551. this.targetEl = null;
  20552. this.fire = this.fire.bind(this);
  20553. this.offset = new THREE.Vector3();
  20554. },
  20555. update: function () {
  20556. this.offset.copy(this.data.offset);
  20557. },
  20558. play: function () { this.el.addEventListener('click', this.fire); },
  20559. pause: function () { this.el.removeEventListener('click', this.fire); },
  20560. remove: function () { this.pause(); },
  20561. fire: function () {
  20562. var targetEl = this.el.sceneEl.querySelector('[checkpoint-controls]');
  20563. if (!targetEl) {
  20564. throw new Error('No `checkpoint-controls` component found.');
  20565. }
  20566. targetEl.components['checkpoint-controls'].setCheckpoint(this.el);
  20567. },
  20568. getOffset: function () {
  20569. return this.offset.copy(this.data.offset);
  20570. }
  20571. };
  20572. },{}],102:[function(require,module,exports){
  20573. /**
  20574. * Specifies an envMap on an entity, without replacing any existing material
  20575. * properties.
  20576. */
  20577. module.exports = {
  20578. schema: {
  20579. path: {default: ''},
  20580. extension: {default: 'jpg'},
  20581. format: {default: 'RGBFormat'},
  20582. enableBackground: {default: false}
  20583. },
  20584. init: function () {
  20585. var data = this.data;
  20586. this.texture = new THREE.CubeTextureLoader().load([
  20587. data.path + 'posx.' + data.extension, data.path + 'negx.' + data.extension,
  20588. data.path + 'posy.' + data.extension, data.path + 'negy.' + data.extension,
  20589. data.path + 'posz.' + data.extension, data.path + 'negz.' + data.extension
  20590. ]);
  20591. this.texture.format = THREE[data.format];
  20592. if (data.enableBackground) {
  20593. this.el.sceneEl.object3D.background = this.texture;
  20594. }
  20595. this.applyEnvMap();
  20596. this.el.addEventListener('object3dset', this.applyEnvMap.bind(this));
  20597. },
  20598. applyEnvMap: function () {
  20599. var mesh = this.el.getObject3D('mesh');
  20600. var envMap = this.texture;
  20601. if (!mesh) return;
  20602. mesh.traverse(function (node) {
  20603. if (node.material && 'envMap' in node.material) {
  20604. node.material.envMap = envMap;
  20605. node.material.needsUpdate = true;
  20606. }
  20607. });
  20608. }
  20609. };
  20610. },{}],103:[function(require,module,exports){
  20611. /**
  20612. * Based on aframe/examples/showcase/tracked-controls.
  20613. *
  20614. * Handles events coming from the hand-controls.
  20615. * Determines if the entity is grabbed or released.
  20616. * Updates its position to move along the controller.
  20617. */
  20618. module.exports = {
  20619. init: function () {
  20620. this.GRABBED_STATE = 'grabbed';
  20621. this.grabbing = false;
  20622. this.hitEl = /** @type {AFRAME.Element} */ null;
  20623. this.physics = /** @type {AFRAME.System} */ this.el.sceneEl.systems.physics;
  20624. this.constraint = /** @type {CANNON.Constraint} */ null;
  20625. // Bind event handlers
  20626. this.onHit = this.onHit.bind(this);
  20627. this.onGripOpen = this.onGripOpen.bind(this);
  20628. this.onGripClose = this.onGripClose.bind(this);
  20629. },
  20630. play: function () {
  20631. var el = this.el;
  20632. el.addEventListener('hit', this.onHit);
  20633. el.addEventListener('gripdown', this.onGripClose);
  20634. el.addEventListener('gripup', this.onGripOpen);
  20635. el.addEventListener('trackpaddown', this.onGripClose);
  20636. el.addEventListener('trackpadup', this.onGripOpen);
  20637. el.addEventListener('triggerdown', this.onGripClose);
  20638. el.addEventListener('triggerup', this.onGripOpen);
  20639. },
  20640. pause: function () {
  20641. var el = this.el;
  20642. el.removeEventListener('hit', this.onHit);
  20643. el.removeEventListener('gripdown', this.onGripClose);
  20644. el.removeEventListener('gripup', this.onGripOpen);
  20645. el.removeEventListener('trackpaddown', this.onGripClose);
  20646. el.removeEventListener('trackpadup', this.onGripOpen);
  20647. el.removeEventListener('triggerdown', this.onGripClose);
  20648. el.removeEventListener('triggerup', this.onGripOpen);
  20649. },
  20650. onGripClose: function (evt) {
  20651. this.grabbing = true;
  20652. },
  20653. onGripOpen: function (evt) {
  20654. var hitEl = this.hitEl;
  20655. this.grabbing = false;
  20656. if (!hitEl) { return; }
  20657. hitEl.removeState(this.GRABBED_STATE);
  20658. this.hitEl = undefined;
  20659. this.physics.world.removeConstraint(this.constraint);
  20660. this.constraint = null;
  20661. },
  20662. onHit: function (evt) {
  20663. var hitEl = evt.detail.el;
  20664. // If the element is already grabbed (it could be grabbed by another controller).
  20665. // If the hand is not grabbing the element does not stick.
  20666. // If we're already grabbing something you can't grab again.
  20667. if (!hitEl || hitEl.is(this.GRABBED_STATE) || !this.grabbing || this.hitEl) { return; }
  20668. hitEl.addState(this.GRABBED_STATE);
  20669. this.hitEl = hitEl;
  20670. this.constraint = new CANNON.LockConstraint(this.el.body, hitEl.body);
  20671. this.physics.world.addConstraint(this.constraint);
  20672. }
  20673. };
  20674. },{}],104:[function(require,module,exports){
  20675. var physics = require('aframe-physics-system');
  20676. module.exports = {
  20677. 'checkpoint': require('./checkpoint'),
  20678. 'cube-env-map': require('./cube-env-map'),
  20679. 'grab': require('./grab'),
  20680. 'jump-ability': require('./jump-ability'),
  20681. 'kinematic-body': require('./kinematic-body'),
  20682. 'mesh-smooth': require('./mesh-smooth'),
  20683. 'sphere-collider': require('./sphere-collider'),
  20684. 'toggle-velocity': require('./toggle-velocity'),
  20685. registerAll: function (AFRAME) {
  20686. if (this._registered) return;
  20687. AFRAME = AFRAME || window.AFRAME;
  20688. physics.registerAll();
  20689. if (!AFRAME.components['checkpoint']) AFRAME.registerComponent('checkpoint', this['checkpoint']);
  20690. if (!AFRAME.components['cube-env-map']) AFRAME.registerComponent('cube-env-map', this['cube-env-map']);
  20691. if (!AFRAME.components['grab']) AFRAME.registerComponent('grab', this['grab']);
  20692. if (!AFRAME.components['jump-ability']) AFRAME.registerComponent('jump-ability', this['jump-ability']);
  20693. if (!AFRAME.components['kinematic-body']) AFRAME.registerComponent('kinematic-body', this['kinematic-body']);
  20694. if (!AFRAME.components['mesh-smooth']) AFRAME.registerComponent('mesh-smooth', this['mesh-smooth']);
  20695. if (!AFRAME.components['sphere-collider']) AFRAME.registerComponent('sphere-collider', this['sphere-collider']);
  20696. if (!AFRAME.components['toggle-velocity']) AFRAME.registerComponent('toggle-velocity', this['toggle-velocity']);
  20697. this._registered = true;
  20698. }
  20699. };
  20700. },{"./checkpoint":101,"./cube-env-map":102,"./grab":103,"./jump-ability":105,"./kinematic-body":106,"./mesh-smooth":107,"./sphere-collider":108,"./toggle-velocity":109,"aframe-physics-system":11}],105:[function(require,module,exports){
  20701. var ACCEL_G = -9.8, // m/s^2
  20702. EASING = -15; // m/s^2
  20703. /**
  20704. * Jump ability.
  20705. */
  20706. module.exports = {
  20707. dependencies: ['velocity'],
  20708. /* Schema
  20709. ——————————————————————————————————————————————*/
  20710. schema: {
  20711. on: { default: 'keydown:Space gamepadbuttondown:0' },
  20712. playerHeight: { default: 1.764 },
  20713. maxJumps: { default: 1 },
  20714. distance: { default: 5 },
  20715. soundJump: { default: '' },
  20716. soundLand: { default: '' },
  20717. debug: { default: false }
  20718. },
  20719. init: function () {
  20720. this.velocity = 0;
  20721. this.numJumps = 0;
  20722. var beginJump = this.beginJump.bind(this),
  20723. events = this.data.on.split(' ');
  20724. this.bindings = {};
  20725. for (var i = 0; i < events.length; i++) {
  20726. this.bindings[events[i]] = beginJump;
  20727. this.el.addEventListener(events[i], beginJump);
  20728. }
  20729. this.bindings.collide = this.onCollide.bind(this);
  20730. this.el.addEventListener('collide', this.bindings.collide);
  20731. },
  20732. remove: function () {
  20733. for (var event in this.bindings) {
  20734. if (this.bindings.hasOwnProperty(event)) {
  20735. this.el.removeEventListener(event, this.bindings[event]);
  20736. delete this.bindings[event];
  20737. }
  20738. }
  20739. this.el.removeEventListener('collide', this.bindings.collide);
  20740. delete this.bindings.collide;
  20741. },
  20742. beginJump: function () {
  20743. if (this.numJumps < this.data.maxJumps) {
  20744. var data = this.data,
  20745. initialVelocity = Math.sqrt(-2 * data.distance * (ACCEL_G + EASING)),
  20746. v = this.el.getAttribute('velocity');
  20747. this.el.setAttribute('velocity', {x: v.x, y: initialVelocity, z: v.z});
  20748. this.numJumps++;
  20749. }
  20750. },
  20751. onCollide: function () {
  20752. this.numJumps = 0;
  20753. }
  20754. };
  20755. },{}],106:[function(require,module,exports){
  20756. /**
  20757. * Kinematic body.
  20758. *
  20759. * Managed dynamic body, which moves but is not affected (directly) by the
  20760. * physics engine. This is not a true kinematic body, in the sense that we are
  20761. * letting the physics engine _compute_ collisions against it and selectively
  20762. * applying those collisions to the object. The physics engine does not decide
  20763. * the position/velocity/rotation of the element.
  20764. *
  20765. * Used for the camera object, because full physics simulation would create
  20766. * movement that feels unnatural to the player. Bipedal movement does not
  20767. * translate nicely to rigid body physics.
  20768. *
  20769. * See: http://www.learn-cocos2d.com/2013/08/physics-engine-platformer-terrible-idea/
  20770. * And: http://oxleygamedev.blogspot.com/2011/04/player-physics-part-2.html
  20771. */
  20772. var CANNON = window.CANNON;
  20773. var EPS = 0.000001;
  20774. module.exports = {
  20775. dependencies: ['velocity'],
  20776. /*******************************************************************
  20777. * Schema
  20778. */
  20779. schema: {
  20780. mass: { default: 5 },
  20781. radius: { default: 1.3 },
  20782. height: { default: 1.764 },
  20783. linearDamping: { default: 0.05 },
  20784. enableSlopes: { default: true }
  20785. },
  20786. /*******************************************************************
  20787. * Lifecycle
  20788. */
  20789. init: function () {
  20790. this.system = this.el.sceneEl.systems.physics;
  20791. this.system.addBehavior(this, this.system.Phase.SIMULATE);
  20792. var el = this.el,
  20793. data = this.data,
  20794. position = (new CANNON.Vec3()).copy(el.getAttribute('position'));
  20795. this.body = new CANNON.Body({
  20796. material: this.system.material,
  20797. position: position,
  20798. mass: data.mass,
  20799. linearDamping: data.linearDamping,
  20800. fixedRotation: true
  20801. });
  20802. this.body.addShape(
  20803. new CANNON.Sphere(data.radius),
  20804. new CANNON.Vec3(0, data.radius - data.height, 0)
  20805. );
  20806. this.body.el = this.el;
  20807. this.el.body = this.body;
  20808. this.system.addBody(this.body);
  20809. },
  20810. remove: function () {
  20811. this.system.removeBody(this.body);
  20812. this.system.removeBehavior(this, this.system.Phase.SIMULATE);
  20813. delete this.el.body;
  20814. },
  20815. /*******************************************************************
  20816. * Tick
  20817. */
  20818. /**
  20819. * Checks CANNON.World for collisions and attempts to apply them to the
  20820. * element automatically, in a player-friendly way.
  20821. *
  20822. * There's extra logic for horizontal surfaces here. The basic requirements:
  20823. * (1) Only apply gravity when not in contact with _any_ horizontal surface.
  20824. * (2) When moving, project the velocity against exactly one ground surface.
  20825. * If in contact with two ground surfaces (e.g. ground + ramp), choose
  20826. * the one that collides with current velocity, if any.
  20827. */
  20828. step: (function () {
  20829. var velocity = new THREE.Vector3(),
  20830. normalizedVelocity = new THREE.Vector3(),
  20831. currentSurfaceNormal = new THREE.Vector3(),
  20832. groundNormal = new THREE.Vector3();
  20833. return function (t, dt) {
  20834. if (!dt) return;
  20835. var body = this.body,
  20836. data = this.data,
  20837. didCollide = false,
  20838. height, groundHeight = -Infinity,
  20839. groundBody;
  20840. dt = Math.min(dt, this.system.data.maxInterval * 1000);
  20841. groundNormal.set(0, 0, 0);
  20842. velocity.copy(this.el.getAttribute('velocity'));
  20843. body.velocity.copy(velocity);
  20844. body.position.copy(this.el.getAttribute('position'));
  20845. for (var i = 0, contact; (contact = this.system.world.contacts[i]); i++) {
  20846. // 1. Find any collisions involving this element. Get the contact
  20847. // normal, and make sure it's oriented _out_ of the other object and
  20848. // enabled (body.collisionReponse is true for both bodies)
  20849. if (!contact.enabled) { continue; }
  20850. if (body.id === contact.bi.id) {
  20851. contact.ni.negate(currentSurfaceNormal);
  20852. } else if (body.id === contact.bj.id) {
  20853. currentSurfaceNormal.copy(contact.ni);
  20854. } else {
  20855. continue;
  20856. }
  20857. didCollide = body.velocity.dot(currentSurfaceNormal) < -EPS;
  20858. if (didCollide && currentSurfaceNormal.y <= 0.5) {
  20859. // 2. If current trajectory attempts to move _through_ another
  20860. // object, project the velocity against the collision plane to
  20861. // prevent passing through.
  20862. velocity = velocity.projectOnPlane(currentSurfaceNormal);
  20863. } else if (currentSurfaceNormal.y > 0.5) {
  20864. // 3. If in contact with something roughly horizontal (+/- 45º) then
  20865. // consider that the current ground. Only the highest qualifying
  20866. // ground is retained.
  20867. height = body.id === contact.bi.id
  20868. ? Math.abs(contact.rj.y + contact.bj.position.y)
  20869. : Math.abs(contact.ri.y + contact.bi.position.y);
  20870. if (height > groundHeight) {
  20871. groundHeight = height;
  20872. groundNormal.copy(currentSurfaceNormal);
  20873. groundBody = body.id === contact.bi.id ? contact.bj : contact.bi;
  20874. }
  20875. }
  20876. }
  20877. normalizedVelocity.copy(velocity).normalize();
  20878. if (groundBody && normalizedVelocity.y < 0.5) {
  20879. if (!data.enableSlopes) {
  20880. groundNormal.set(0, 1, 0);
  20881. } else if (groundNormal.y < 1 - EPS) {
  20882. groundNormal.copy(this.raycastToGround(groundBody, groundNormal));
  20883. }
  20884. // 4. Project trajectory onto the top-most ground object, unless
  20885. // trajectory is > 45º.
  20886. velocity = velocity.projectOnPlane(groundNormal);
  20887. } else {
  20888. // 5. If not in contact with anything horizontal, apply world gravity.
  20889. // TODO - Why is the 4x scalar necessary.
  20890. velocity.add(this.system.world.gravity.scale(dt * 4.0 / 1000));
  20891. }
  20892. // 6. If the ground surface has a velocity, apply it directly to current
  20893. // position, not velocity, to preserve relative velocity.
  20894. if (groundBody && groundBody.el && groundBody.el.components.velocity) {
  20895. var groundVelocity = groundBody.el.getAttribute('velocity');
  20896. body.position.copy({
  20897. x: body.position.x + groundVelocity.x * dt / 1000,
  20898. y: body.position.y + groundVelocity.y * dt / 1000,
  20899. z: body.position.z + groundVelocity.z * dt / 1000
  20900. });
  20901. this.el.setAttribute('position', body.position);
  20902. }
  20903. body.velocity.copy(velocity);
  20904. this.el.setAttribute('velocity', velocity);
  20905. };
  20906. }()),
  20907. /**
  20908. * When walking on complex surfaces (trimeshes, borders between two shapes),
  20909. * the collision normals returned for the player sphere can be very
  20910. * inconsistent. To address this, raycast straight down, find the collision
  20911. * normal, and return whichever normal is more vertical.
  20912. * @param {CANNON.Body} groundBody
  20913. * @param {CANNON.Vec3} groundNormal
  20914. * @return {CANNON.Vec3}
  20915. */
  20916. raycastToGround: function (groundBody, groundNormal) {
  20917. var ray,
  20918. hitNormal,
  20919. vFrom = this.body.position,
  20920. vTo = this.body.position.clone();
  20921. vTo.y -= this.data.height;
  20922. ray = new CANNON.Ray(vFrom, vTo);
  20923. ray._updateDirection(); // TODO - Report bug.
  20924. ray.intersectBody(groundBody);
  20925. if (!ray.hasHit) return groundNormal;
  20926. // Compare ABS, in case we're projecting against the inside of the face.
  20927. hitNormal = ray.result.hitNormalWorld;
  20928. return Math.abs(hitNormal.y) > Math.abs(groundNormal.y) ? hitNormal : groundNormal;
  20929. }
  20930. };
  20931. },{}],107:[function(require,module,exports){
  20932. /**
  20933. * Apply this component to models that looks "blocky", to have Three.js compute
  20934. * vertex normals on the fly for a "smoother" look.
  20935. */
  20936. module.exports = {
  20937. init: function () {
  20938. this.el.addEventListener('model-loaded', function (e) {
  20939. e.detail.model.traverse(function (node) {
  20940. if (node.isMesh) node.geometry.computeVertexNormals();
  20941. });
  20942. })
  20943. }
  20944. }
  20945. },{}],108:[function(require,module,exports){
  20946. /**
  20947. * Based on aframe/examples/showcase/tracked-controls.
  20948. *
  20949. * Implement bounding sphere collision detection for entities with a mesh.
  20950. * Sets the specified state on the intersected entities.
  20951. *
  20952. * @property {string} objects - Selector of the entities to test for collision.
  20953. * @property {string} state - State to set on collided entities.
  20954. *
  20955. */
  20956. module.exports = {
  20957. schema: {
  20958. objects: {default: ''},
  20959. state: {default: 'collided'},
  20960. radius: {default: 0.05},
  20961. watch: {default: true}
  20962. },
  20963. init: function () {
  20964. /** @type {MutationObserver} */
  20965. this.observer = null;
  20966. /** @type {Array<Element>} Elements to watch for collisions. */
  20967. this.els = [];
  20968. /** @type {Array<Element>} Elements currently in collision state. */
  20969. this.collisions = [];
  20970. this.handleHit = this.handleHit.bind(this);
  20971. this.handleHitEnd = this.handleHitEnd.bind(this);
  20972. },
  20973. remove: function () {
  20974. this.pause();
  20975. },
  20976. play: function () {
  20977. var sceneEl = this.el.sceneEl;
  20978. if (this.data.watch) {
  20979. this.observer = new MutationObserver(this.update.bind(this, null));
  20980. this.observer.observe(sceneEl, {childList: true, subtree: true});
  20981. }
  20982. },
  20983. pause: function () {
  20984. if (this.observer) {
  20985. this.observer.disconnect();
  20986. this.observer = null;
  20987. }
  20988. },
  20989. /**
  20990. * Update list of entities to test for collision.
  20991. */
  20992. update: function () {
  20993. var data = this.data;
  20994. var objectEls;
  20995. // Push entities into list of els to intersect.
  20996. if (data.objects) {
  20997. objectEls = this.el.sceneEl.querySelectorAll(data.objects);
  20998. } else {
  20999. // If objects not defined, intersect with everything.
  21000. objectEls = this.el.sceneEl.children;
  21001. }
  21002. // Convert from NodeList to Array
  21003. this.els = Array.prototype.slice.call(objectEls);
  21004. },
  21005. tick: (function () {
  21006. var position = new THREE.Vector3(),
  21007. meshPosition = new THREE.Vector3(),
  21008. meshScale = new THREE.Vector3(),
  21009. colliderScale = new THREE.Vector3(),
  21010. distanceMap = new Map();
  21011. return function () {
  21012. var el = this.el,
  21013. data = this.data,
  21014. mesh = el.getObject3D('mesh'),
  21015. colliderRadius,
  21016. collisions = [];
  21017. if (!mesh) { return; }
  21018. distanceMap.clear();
  21019. position.copy(el.object3D.getWorldPosition());
  21020. el.object3D.getWorldScale(colliderScale);
  21021. colliderRadius = data.radius * scaleFactor(colliderScale);
  21022. // Update collision list.
  21023. this.els.forEach(intersect);
  21024. // Emit events and add collision states, in order of distance.
  21025. collisions
  21026. .sort(function (a, b) {
  21027. return distanceMap.get(a) > distanceMap.get(b) ? 1 : -1;
  21028. })
  21029. .forEach(this.handleHit);
  21030. // Remove collision state from current element.
  21031. if (collisions.length === 0) { el.emit('hit', {el: null}); }
  21032. // Remove collision state from other elements.
  21033. this.collisions.filter(function (el) {
  21034. return !distanceMap.has(el);
  21035. }).forEach(this.handleHitEnd);
  21036. // Store new collisions
  21037. this.collisions = collisions;
  21038. // Bounding sphere collision detection
  21039. function intersect (el) {
  21040. var radius, mesh, distance, box, extent, size;
  21041. if (!el.isEntity) { return; }
  21042. mesh = el.getObject3D('mesh');
  21043. if (!mesh) { return; }
  21044. box = new THREE.Box3().setFromObject(mesh);
  21045. size = box.getSize();
  21046. extent = Math.max(size.x, size.y, size.z) / 2;
  21047. radius = Math.sqrt(2 * extent * extent);
  21048. box.getCenter(meshPosition);
  21049. if (!radius) { return; }
  21050. distance = position.distanceTo(meshPosition);
  21051. if (distance < radius + colliderRadius) {
  21052. collisions.push(el);
  21053. distanceMap.set(el, distance);
  21054. }
  21055. }
  21056. // use max of scale factors to maintain bounding sphere collision
  21057. function scaleFactor (scaleVec) {
  21058. return Math.max.apply(null, scaleVec.toArray());
  21059. }
  21060. };
  21061. })(),
  21062. handleHit: function (targetEl) {
  21063. targetEl.emit('hit');
  21064. targetEl.addState(this.data.state);
  21065. this.el.emit('hit', {el: targetEl});
  21066. },
  21067. handleHitEnd: function (targetEl) {
  21068. targetEl.emit('hitend');
  21069. targetEl.removeState(this.data.state);
  21070. this.el.emit('hitend', {el: targetEl});
  21071. }
  21072. };
  21073. },{}],109:[function(require,module,exports){
  21074. /**
  21075. * Toggle velocity.
  21076. *
  21077. * Moves an object back and forth along an axis, within a min/max extent.
  21078. */
  21079. module.exports = {
  21080. dependencies: ['velocity'],
  21081. schema: {
  21082. axis: { default: 'x', oneOf: ['x', 'y', 'z'] },
  21083. min: { default: 0 },
  21084. max: { default: 0 },
  21085. speed: { default: 1 }
  21086. },
  21087. init: function () {
  21088. var velocity = {x: 0, y: 0, z: 0};
  21089. velocity[this.data.axis] = this.data.speed;
  21090. this.el.setAttribute('velocity', velocity);
  21091. if (this.el.sceneEl.addBehavior) this.el.sceneEl.addBehavior(this);
  21092. },
  21093. remove: function () {},
  21094. update: function () { this.tick(); },
  21095. tick: function () {
  21096. var data = this.data,
  21097. velocity = this.el.getAttribute('velocity'),
  21098. position = this.el.getAttribute('position');
  21099. if (velocity[data.axis] > 0 && position[data.axis] > data.max) {
  21100. velocity[data.axis] = -data.speed;
  21101. this.el.setAttribute('velocity', velocity);
  21102. } else if (velocity[data.axis] < 0 && position[data.axis] < data.min) {
  21103. velocity[data.axis] = data.speed;
  21104. this.el.setAttribute('velocity', velocity);
  21105. }
  21106. },
  21107. };
  21108. },{}],110:[function(require,module,exports){
  21109. module.exports = {
  21110. 'nav-mesh': require('./nav-mesh'),
  21111. 'nav-controller': require('./nav-controller'),
  21112. 'system': require('./system'),
  21113. registerAll: function (AFRAME) {
  21114. if (this._registered) return;
  21115. AFRAME = AFRAME || window.AFRAME;
  21116. if (!AFRAME.components['nav-mesh']) {
  21117. AFRAME.registerComponent('nav-mesh', this['nav-mesh']);
  21118. }
  21119. if (!AFRAME.components['nav-controller']) {
  21120. AFRAME.registerComponent('nav-controller', this['nav-controller']);
  21121. }
  21122. if (!AFRAME.systems.nav) {
  21123. AFRAME.registerSystem('nav', this.system);
  21124. }
  21125. this._registered = true;
  21126. }
  21127. };
  21128. },{"./nav-controller":111,"./nav-mesh":112,"./system":113}],111:[function(require,module,exports){
  21129. module.exports = {
  21130. schema: {
  21131. destination: {type: 'vec3'},
  21132. active: {default: false},
  21133. speed: {default: 2}
  21134. },
  21135. init: function () {
  21136. this.system = this.el.sceneEl.systems.nav;
  21137. this.system.addController(this);
  21138. this.path = [];
  21139. this.raycaster = new THREE.Raycaster();
  21140. },
  21141. remove: function () {
  21142. this.system.removeController(this);
  21143. },
  21144. update: function () {
  21145. this.path.length = 0;
  21146. },
  21147. tick: (function () {
  21148. var vDest = new THREE.Vector3();
  21149. var vDelta = new THREE.Vector3();
  21150. var vNext = new THREE.Vector3();
  21151. return function (t, dt) {
  21152. var el = this.el;
  21153. var data = this.data;
  21154. var raycaster = this.raycaster;
  21155. var speed = data.speed * dt / 1000;
  21156. if (!data.active) return;
  21157. // Use PatrolJS pathfinding system to get shortest path to target.
  21158. if (!this.path.length) {
  21159. this.path = this.system.getPath(this.el.object3D, vDest.copy(data.destination));
  21160. this.path = this.path || [];
  21161. el.emit('nav-start');
  21162. }
  21163. // If no path is found, exit.
  21164. if (!this.path.length) {
  21165. console.warn('[nav] Unable to find path to %o.', data.destination);
  21166. this.el.setAttribute('nav-controller', {active: false});
  21167. el.emit('nav-end');
  21168. return;
  21169. }
  21170. // Current segment is a vector from current position to next waypoint.
  21171. var vCurrent = el.object3D.position;
  21172. var vWaypoint = this.path[0];
  21173. vDelta.subVectors(vWaypoint, vCurrent);
  21174. var distance = vDelta.length();
  21175. var gazeTarget;
  21176. if (distance < speed) {
  21177. // If <1 step from current waypoint, discard it and move toward next.
  21178. this.path.shift();
  21179. // After discarding the last waypoint, exit pathfinding.
  21180. if (!this.path.length) {
  21181. this.el.setAttribute('nav-controller', {active: false});
  21182. el.emit('nav-end');
  21183. return;
  21184. } else {
  21185. gazeTarget = this.path[0];
  21186. }
  21187. } else {
  21188. // If still far away from next waypoint, find next position for
  21189. // the current frame.
  21190. vNext.copy(vDelta.setLength(speed)).add(vCurrent);
  21191. gazeTarget = vWaypoint;
  21192. }
  21193. // Look at the next waypoint.
  21194. gazeTarget.y = vCurrent.y;
  21195. el.object3D.lookAt(gazeTarget);
  21196. // Raycast against the nav mesh, to keep the controller moving along the
  21197. // ground, not traveling in a straight line from higher to lower waypoints.
  21198. raycaster.ray.origin.copy(vNext);
  21199. raycaster.ray.origin.y += 1.5;
  21200. raycaster.ray.direction.y = -1;
  21201. var intersections = raycaster.intersectObject(this.system.getNavMesh());
  21202. if (!intersections.length) {
  21203. // Raycasting failed. Step toward the waypoint and hope for the best.
  21204. vCurrent.copy(vNext);
  21205. } else {
  21206. // Re-project next position onto nav mesh.
  21207. vDelta.subVectors(intersections[0].point, vCurrent);
  21208. vCurrent.add(vDelta.setLength(speed));
  21209. }
  21210. };
  21211. }())
  21212. };
  21213. },{}],112:[function(require,module,exports){
  21214. /**
  21215. * nav-mesh
  21216. *
  21217. * Waits for a mesh to be loaded on the current entity, then sets it as the
  21218. * nav mesh in the pathfinding system.
  21219. */
  21220. module.exports = {
  21221. init: function () {
  21222. this.system = this.el.sceneEl.systems.nav;
  21223. this.loadNavMesh();
  21224. this.el.addEventListener('model-loaded', this.loadNavMesh.bind(this));
  21225. },
  21226. loadNavMesh: function () {
  21227. var object = this.el.getObject3D('mesh');
  21228. if (!object) return;
  21229. var navMesh;
  21230. object.traverse(function (node) {
  21231. if (node.isMesh) navMesh = node;
  21232. });
  21233. if (!navMesh) return;
  21234. this.system.setNavMesh(navMesh);
  21235. }
  21236. };
  21237. },{}],113:[function(require,module,exports){
  21238. var Path = require('three-pathfinding');
  21239. /**
  21240. * nav
  21241. *
  21242. * Pathfinding system, using PatrolJS.
  21243. */
  21244. module.exports = {
  21245. init: function () {
  21246. this.navMesh = null;
  21247. this.nodes = null;
  21248. this.controllers = new Set();
  21249. },
  21250. /**
  21251. * @param {THREE.Mesh} mesh
  21252. */
  21253. setNavMesh: function (mesh) {
  21254. var geometry = mesh.geometry.isBufferGeometry
  21255. ? new THREE.Geometry().fromBufferGeometry(mesh.geometry)
  21256. : mesh.geometry;
  21257. this.navMesh = new THREE.Mesh(geometry);
  21258. this.nodes = Path.buildNodes(this.navMesh.geometry);
  21259. Path.setZoneData('level', this.nodes);
  21260. },
  21261. /**
  21262. * @return {THREE.Mesh}
  21263. */
  21264. getNavMesh: function () {
  21265. return this.navMesh;
  21266. },
  21267. /**
  21268. * @param {NavController} ctrl
  21269. */
  21270. addController: function (ctrl) {
  21271. this.controllers.add(ctrl);
  21272. },
  21273. /**
  21274. * @param {NavController} ctrl
  21275. */
  21276. removeController: function (ctrl) {
  21277. this.controllers.remove(ctrl);
  21278. },
  21279. /**
  21280. * @param {NavController} ctrl
  21281. * @param {THREE.Vector3} target
  21282. * @return {Array<THREE.Vector3>}
  21283. */
  21284. getPath: function (ctrl, target) {
  21285. var start = ctrl.el.object3D.position;
  21286. // TODO(donmccurdy): Current group should be cached.
  21287. var group = Path.getGroup('level', start);
  21288. return Path.findPath(start, target, 'level', group);
  21289. }
  21290. };
  21291. },{"three-pathfinding":82}],114:[function(require,module,exports){
  21292. /**
  21293. * Flat grid.
  21294. *
  21295. * Defaults to 75x75.
  21296. */
  21297. var Primitive = module.exports = {
  21298. defaultComponents: {
  21299. geometry: {
  21300. primitive: 'plane',
  21301. width: 75,
  21302. height: 75
  21303. },
  21304. rotation: {x: -90, y: 0, z: 0},
  21305. material: {
  21306. src: 'url(https://cdn.rawgit.com/donmccurdy/aframe-extras/v1.16.3/assets/grid.png)',
  21307. repeat: '75 75'
  21308. }
  21309. },
  21310. mappings: {
  21311. width: 'geometry.width',
  21312. height: 'geometry.height',
  21313. src: 'material.src'
  21314. }
  21315. };
  21316. module.exports.registerAll = (function () {
  21317. var registered = false;
  21318. return function (AFRAME) {
  21319. if (registered) return;
  21320. AFRAME = AFRAME || window.AFRAME;
  21321. AFRAME.registerPrimitive('a-grid', Primitive);
  21322. registered = true;
  21323. };
  21324. }());
  21325. },{}],115:[function(require,module,exports){
  21326. var vg = require('../../lib/hex-grid.min.js');
  21327. var defaultHexGrid = require('../../lib/default-hex-grid.json');
  21328. /**
  21329. * Hex grid.
  21330. */
  21331. var Primitive = module.exports.Primitive = {
  21332. defaultComponents: {
  21333. 'hexgrid': {}
  21334. },
  21335. mappings: {
  21336. src: 'hexgrid.src'
  21337. }
  21338. };
  21339. var Component = module.exports.Component = {
  21340. dependencies: ['material'],
  21341. schema: {
  21342. src: {type: 'asset'}
  21343. },
  21344. init: function () {
  21345. var data = this.data;
  21346. if (data.src) {
  21347. fetch(data.src)
  21348. .then(function (response) { response.json(); })
  21349. .then(function (json) { this.addMesh(json); });
  21350. } else {
  21351. this.addMesh(defaultHexGrid);
  21352. }
  21353. },
  21354. addMesh: function (json) {
  21355. var grid = new vg.HexGrid();
  21356. grid.fromJSON(json);
  21357. var board = new vg.Board(grid);
  21358. board.generateTilemap();
  21359. this.el.setObject3D('mesh', board.group);
  21360. this.addMaterial();
  21361. },
  21362. addMaterial: function () {
  21363. var materialComponent = this.el.components.material;
  21364. var material = (materialComponent || {}).material;
  21365. if (!material) return;
  21366. this.el.object3D.traverse(function (node) {
  21367. if (node.isMesh) {
  21368. node.material = material;
  21369. }
  21370. });
  21371. },
  21372. remove: function () {
  21373. this.el.removeObject3D('mesh');
  21374. }
  21375. };
  21376. module.exports.registerAll = (function () {
  21377. var registered = false;
  21378. return function (AFRAME) {
  21379. if (registered) return;
  21380. AFRAME = AFRAME || window.AFRAME;
  21381. AFRAME.registerComponent('hexgrid', Component);
  21382. AFRAME.registerPrimitive('a-hexgrid', Primitive);
  21383. registered = true;
  21384. };
  21385. }());
  21386. },{"../../lib/default-hex-grid.json":7,"../../lib/hex-grid.min.js":9}],116:[function(require,module,exports){
  21387. /**
  21388. * Flat-shaded ocean primitive.
  21389. *
  21390. * Based on a Codrops tutorial:
  21391. * http://tympanus.net/codrops/2016/04/26/the-aviator-animating-basic-3d-scene-threejs/
  21392. */
  21393. var Primitive = module.exports.Primitive = {
  21394. defaultComponents: {
  21395. ocean: {},
  21396. rotation: {x: -90, y: 0, z: 0}
  21397. },
  21398. mappings: {
  21399. width: 'ocean.width',
  21400. depth: 'ocean.depth',
  21401. density: 'ocean.density',
  21402. color: 'ocean.color',
  21403. opacity: 'ocean.opacity'
  21404. }
  21405. };
  21406. var Component = module.exports.Component = {
  21407. schema: {
  21408. // Dimensions of the ocean area.
  21409. width: {default: 10, min: 0},
  21410. depth: {default: 10, min: 0},
  21411. // Density of waves.
  21412. density: {default: 10},
  21413. // Wave amplitude and variance.
  21414. amplitude: {default: 0.1},
  21415. amplitudeVariance: {default: 0.3},
  21416. // Wave speed and variance.
  21417. speed: {default: 1},
  21418. speedVariance: {default: 2},
  21419. // Material.
  21420. color: {default: '#7AD2F7', type: 'color'},
  21421. opacity: {default: 0.8}
  21422. },
  21423. /**
  21424. * Use play() instead of init(), because component mappings – unavailable as dependencies – are
  21425. * not guaranteed to have parsed when this component is initialized.
  21426. */
  21427. play: function () {
  21428. var el = this.el,
  21429. data = this.data,
  21430. material = el.components.material;
  21431. var geometry = new THREE.PlaneGeometry(data.width, data.depth, data.density, data.density);
  21432. geometry.mergeVertices();
  21433. this.waves = [];
  21434. for (var v, i = 0, l = geometry.vertices.length; i < l; i++) {
  21435. v = geometry.vertices[i];
  21436. this.waves.push({
  21437. z: v.z,
  21438. ang: Math.random() * Math.PI * 2,
  21439. amp: data.amplitude + Math.random() * data.amplitudeVariance,
  21440. speed: (data.speed + Math.random() * data.speedVariance) / 1000 // radians / frame
  21441. });
  21442. }
  21443. if (!material) {
  21444. material = {};
  21445. material.material = new THREE.MeshPhongMaterial({
  21446. color: data.color,
  21447. transparent: data.opacity < 1,
  21448. opacity: data.opacity,
  21449. shading: THREE.FlatShading,
  21450. });
  21451. }
  21452. this.mesh = new THREE.Mesh(geometry, material.material);
  21453. el.setObject3D('mesh', this.mesh);
  21454. },
  21455. remove: function () {
  21456. this.el.removeObject3D('mesh');
  21457. },
  21458. tick: function (t, dt) {
  21459. if (!dt) return;
  21460. var verts = this.mesh.geometry.vertices;
  21461. for (var v, vprops, i = 0; (v = verts[i]); i++){
  21462. vprops = this.waves[i];
  21463. v.z = vprops.z + Math.sin(vprops.ang) * vprops.amp;
  21464. vprops.ang += vprops.speed * dt;
  21465. }
  21466. this.mesh.geometry.verticesNeedUpdate = true;
  21467. }
  21468. };
  21469. module.exports.registerAll = (function () {
  21470. var registered = false;
  21471. return function (AFRAME) {
  21472. if (registered) return;
  21473. AFRAME = AFRAME || window.AFRAME;
  21474. AFRAME.registerComponent('ocean', Component);
  21475. AFRAME.registerPrimitive('a-ocean', Primitive);
  21476. registered = true;
  21477. };
  21478. }());
  21479. },{}],117:[function(require,module,exports){
  21480. /**
  21481. * Tube following a custom path.
  21482. *
  21483. * Usage:
  21484. *
  21485. * ```html
  21486. * <a-tube path="5 0 5, 5 0 -5, -5 0 -5" radius="0.5"></a-tube>
  21487. * ```
  21488. */
  21489. var Primitive = module.exports.Primitive = {
  21490. defaultComponents: {
  21491. tube: {},
  21492. },
  21493. mappings: {
  21494. path: 'tube.path',
  21495. segments: 'tube.segments',
  21496. radius: 'tube.radius',
  21497. radialSegments: 'tube.radialSegments',
  21498. closed: 'tube.closed'
  21499. }
  21500. };
  21501. var Component = module.exports.Component = {
  21502. schema: {
  21503. path: {default: []},
  21504. segments: {default: 64},
  21505. radius: {default: 1},
  21506. radialSegments: {default: 8},
  21507. closed: {default: false}
  21508. },
  21509. init: function () {
  21510. var el = this.el,
  21511. data = this.data,
  21512. material = el.components.material;
  21513. if (!data.path.length) {
  21514. console.error('[a-tube] `path` property expected but not found.');
  21515. return;
  21516. }
  21517. var curve = new THREE.CatmullRomCurve3(data.path.map(function (point) {
  21518. point = point.split(' ');
  21519. return new THREE.Vector3(Number(point[0]), Number(point[1]), Number(point[2]));
  21520. }));
  21521. var geometry = new THREE.TubeGeometry(
  21522. curve, data.segments, data.radius, data.radialSegments, data.closed
  21523. );
  21524. if (!material) {
  21525. material = {};
  21526. material.material = new THREE.MeshPhongMaterial();
  21527. }
  21528. this.mesh = new THREE.Mesh(geometry, material.material);
  21529. this.el.setObject3D('mesh', this.mesh);
  21530. },
  21531. remove: function () {
  21532. if (this.mesh) this.el.removeObject3D('mesh');
  21533. }
  21534. };
  21535. module.exports.registerAll = (function () {
  21536. var registered = false;
  21537. return function (AFRAME) {
  21538. if (registered) return;
  21539. AFRAME = AFRAME || window.AFRAME;
  21540. AFRAME.registerComponent('tube', Component);
  21541. AFRAME.registerPrimitive('a-tube', Primitive);
  21542. registered = true;
  21543. };
  21544. }());
  21545. },{}],118:[function(require,module,exports){
  21546. module.exports = {
  21547. 'a-grid': require('./a-grid'),
  21548. 'a-hexgrid': require('./a-hexgrid'),
  21549. 'a-ocean': require('./a-ocean'),
  21550. 'a-tube': require('./a-tube'),
  21551. registerAll: function (AFRAME) {
  21552. if (this._registered) return;
  21553. AFRAME = AFRAME || window.AFRAME;
  21554. this['a-grid'].registerAll(AFRAME);
  21555. this['a-hexgrid'].registerAll(AFRAME);
  21556. this['a-ocean'].registerAll(AFRAME);
  21557. this['a-tube'].registerAll(AFRAME);
  21558. this._registered = true;
  21559. }
  21560. };
  21561. },{"./a-grid":114,"./a-hexgrid":115,"./a-ocean":116,"./a-tube":117}]},{},[1]);