llviewerwindow.cpp 155 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081
  1. /**
  2. * @file llviewerwindow.cpp
  3. * @brief Implementation of the LLViewerWindow class.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. // system library includes
  34. #include <stdio.h>
  35. #include <iostream>
  36. #include <fstream>
  37. #if LL_WINDOWS
  38. #include <tchar.h> // For Unicode conversion methods
  39. #endif
  40. #include "llviewerwindow.h"
  41. #include "llapp.h"
  42. #include "llaudioengine.h" // gAudiop
  43. #include "llconsole.h"
  44. #include "llcubemaparray.h"
  45. #include "lldir.h"
  46. #include "llfontfreetype.h"
  47. #include "llimagebmp.h"
  48. #include "llimagedecodethread.h"
  49. #include "llimagegl.h"
  50. #include "llimagej2c.h"
  51. #include "llmenugl.h"
  52. #include "llmemory.h"
  53. #include "llmodaldialog.h"
  54. #include "llmousehandler.h"
  55. #include "llrender.h"
  56. #include "llrenderutils.h" // For gBox, gSphere
  57. #include "lltextbox.h"
  58. #include "lltrans.h"
  59. #include "lluictrlfactory.h"
  60. #include "llmessage.h"
  61. #include "llraytrace.h"
  62. #include "llagent.h"
  63. #include "llappviewer.h"
  64. #include "llchatbar.h"
  65. #include "lldebugview.h"
  66. #include "lldrawable.h"
  67. #include "lldrawpoolalpha.h"
  68. #include "lldrawpoolbump.h"
  69. #include "lldrawpoolwater.h"
  70. #include "llface.h"
  71. #include "llfeaturemanager.h"
  72. #include "llfloaterchat.h"
  73. #include "llfloaterchatterbox.h"
  74. #include "llfloatercustomize.h"
  75. #include "llfloatereditui.h" // HACK for UI editor
  76. #include "llfloaternotificationsconsole.h"
  77. #include "llfloatersnapshot.h"
  78. #include "hbfloaterteleporthistory.h"
  79. #include "llfloatertools.h"
  80. #include "llfloaterworldmap.h"
  81. #include "llgesturemgr.h"
  82. #include "llhoverview.h"
  83. #include "llhudtext.h"
  84. #include "llhudview.h"
  85. #include "llimmgr.h"
  86. #include "llmaniptranslate.h"
  87. #include "llmeshrepository.h"
  88. #include "llmorphview.h"
  89. #include "llnotify.h"
  90. #include "lloverlaybar.h"
  91. #include "llpanellogin.h"
  92. #include "llpanelworldmap.h"
  93. #include "llpipeline.h"
  94. #include "llpreviewnotecard.h" // refreshCachedSettings()
  95. #include "llpreviewscript.h" // refreshCachedSettings()
  96. #include "llprogressview.h"
  97. //MK
  98. #include "mkrlinterface.h"
  99. //mk
  100. #include "llselectmgr.h"
  101. #include "llsky.h" // gSky
  102. #include "llstartup.h"
  103. #include "llstatusbar.h"
  104. #include "llsurface.h"
  105. #include "lltexturecache.h"
  106. #include "lltexturefetch.h"
  107. #include "lltoolbar.h"
  108. #include "lltoolcomp.h"
  109. #include "lltooldraganddrop.h"
  110. #if LL_DARWIN
  111. # include "lltoolfocus.h"
  112. #endif
  113. #include "lltoolmgr.h"
  114. #include "lltoolpie.h"
  115. #include "llurldispatcher.h" // SLURL from other app instance
  116. #include "llvelocitybar.h"
  117. #include "llvieweraudio.h" // audio_update_volume()
  118. #include "hbviewerautomation.h"
  119. #include "llviewercamera.h"
  120. #include "llviewercontrol.h"
  121. #include "llviewerdisplay.h"
  122. #include "llviewergesture.h" // gGestureList
  123. #include "llviewerkeyboard.h"
  124. #include "llviewerjoystick.h"
  125. #include "llviewermediafocus.h"
  126. #include "llviewermenu.h"
  127. #include "llviewermessage.h" // send_sound_trigger()
  128. #include "llviewerobjectlist.h"
  129. #include "llviewerparcelmgr.h"
  130. #include "llviewerregion.h"
  131. #include "llviewershadermgr.h"
  132. #include "llviewerstats.h"
  133. #include "llviewertexturelist.h"
  134. #include "llvisualparamhint.h"
  135. #include "llvoavatarself.h"
  136. #include "llvoiceclient.h"
  137. #include "llvopartgroup.h"
  138. #include "llvovolume.h"
  139. #include "llwearablelist.h"
  140. #include "llworld.h"
  141. //
  142. // Globals
  143. //
  144. LLBottomPanel* gBottomPanelp = NULL;
  145. LLViewerWindow* gViewerWindowp = NULL;
  146. LLFrameTimer gMouseIdleTimer;
  147. LLFrameTimer gAwayTimer;
  148. LLFrameTimer gAwayTriggerTimer;
  149. LLFrameTimer gAlphaFadeTimer;
  150. LLViewerObject* gDebugRaycastObject = NULL;
  151. LLVOPartGroup* gDebugRaycastParticle = NULL;
  152. LLVector4a gDebugRaycastParticleIntersection;
  153. LLVector4a gDebugRaycastIntersection;
  154. LLVector2 gDebugRaycastTexCoord;
  155. LLVector4a gDebugRaycastNormal;
  156. LLVector4a gDebugRaycastTangent;
  157. S32 gDebugRaycastFaceHit = -1;
  158. S32 gDebugRaycastGLTFNodeHit = -1;
  159. S32 gDebugRaycastGLTFPrimHit = -1;
  160. LLVector4a gDebugRaycastStart;
  161. LLVector4a gDebugRaycastEnd;
  162. // HUD display lines in lower right
  163. bool gDisplayWindInfo = false;
  164. bool gDisplayCameraPos = false;
  165. bool gDisplayFOV = false;
  166. bool gSnapshotNoPost = false;
  167. constexpr U8 NO_FACE = 255;
  168. bool gQuietSnapshot = false;
  169. // Minimum time after setting away state before coming back:
  170. constexpr F32 MIN_AFK_TIME = 2.f;
  171. constexpr F32 MIN_DISPLAY_SCALE = 0.75f;
  172. // Static members
  173. LLStat LLViewerWindow::sMouseVelocityStat;
  174. std::string LLViewerWindow::sSnapshotBaseName;
  175. std::string LLViewerWindow::sSnapshotDir;
  176. std::string LLViewerWindow::sMovieBaseName;
  177. ////////////////////////////////////////////////////////////////////////////
  178. // *HACK: easy way for console.cpp to retrieve the window size...
  179. S32 viewer_window_width()
  180. {
  181. return gViewerWindowp ? gViewerWindowp->getWindowWidth() : 100;
  182. }
  183. S32 viewer_window_height()
  184. {
  185. return gViewerWindowp ? gViewerWindowp->getWindowHeight() : 100;
  186. }
  187. // *HACK: prevent double handling of accelerator keys...
  188. static KEY sLastAcceleratorKey = 0;
  189. ////////////////////////////////////////////////////////////////////////////
  190. // LLDebugText class
  191. ////////////////////////////////////////////////////////////////////////////
  192. class LLDebugText
  193. {
  194. public:
  195. LLDebugText()
  196. : mFont(LLFontGL::getFontMonospace()),
  197. // Draw the statistics in a light gray and in a thin font
  198. mTextColor(LLColor4(0.86f, 0.86f, 0.86f, 1.f)),
  199. mMinX(U32_MAX)
  200. {
  201. mLineHeight = mFont->getLineHeight();
  202. mIncY = 16 * mLineHeight / 10 + 1;
  203. mMaginX = 16 * mFont->getWidth(std::string("0")) / 10 + 1;
  204. }
  205. LL_INLINE void addText(U32 x, U32 y, const std::string& text)
  206. {
  207. mLineList.emplace_back(text, x, y);
  208. if (x < mMinX)
  209. {
  210. mMinX = x;
  211. }
  212. }
  213. void update()
  214. {
  215. if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
  216. {
  217. // Do not display debug info when not rendering UI (important for
  218. // the "snapshot to disk" feature).
  219. return;
  220. }
  221. // Draw stuff growing up from right lower corner of screen
  222. U32 xpos = 0;
  223. U32 window_width = gViewerWindowp->getWindowWidth();
  224. static LLCachedControl<U32> hud_right_margin(gSavedSettings,
  225. "HUDInfoRightMargin");
  226. U32 right_margin = llmax((U32)hud_right_margin, 256U);
  227. if (window_width > right_margin)
  228. {
  229. xpos = window_width - right_margin;
  230. }
  231. mMaxX = window_width - mMaginX;
  232. U32 ypos = 20;
  233. if (gToolBarp && gToolBarp->getVisible())
  234. {
  235. ypos += TOOL_BAR_HEIGHT;
  236. }
  237. if (gChatBarp && gChatBarp->getVisible())
  238. {
  239. ypos += CHAT_BAR_HEIGHT;
  240. }
  241. if (gOverlayBarp && gOverlayBarp->getVisible())
  242. {
  243. ypos += OVERLAY_BAR_HEIGHT;
  244. }
  245. mMinY = ypos - mLineHeight - 4;
  246. static LLCachedControl<bool> debug_show_size(gSavedSettings,
  247. "DebugShowResizing");
  248. S32 size_x = 0;
  249. S32 size_y = 0;
  250. if (debug_show_size && LLFloater::resizing(size_x, size_y))
  251. {
  252. addText(window_width - 168, ypos,
  253. llformat("Floater size: %d x %d", size_x, size_y));
  254. ypos += mIncY;
  255. }
  256. static LLCachedControl<bool> debug_show_fps(gSavedSettings,
  257. "DebugShowFPS");
  258. if (debug_show_fps)
  259. {
  260. addText(window_width - 60, ypos,
  261. llformat("%d fps",
  262. (S32)(gViewerStats.mFPSStat.getMeanPerSec() +
  263. 0.5f)));
  264. ypos += mIncY;
  265. }
  266. // Avoid text collision with the velocity bar...
  267. mVelocityBarShown = gVelocityBarp && gVelocityBarp->getVisible();
  268. if (mVelocityBarShown)
  269. {
  270. ypos = VELOCITY_TOP;
  271. }
  272. static LLCachedControl<bool> debug_show_time(gSavedSettings,
  273. "DebugShowTime");
  274. if (debug_show_time)
  275. {
  276. F32 time = gTextureTimer.getElapsedTimeF32();
  277. S32 thours = (S32)(time / 3600);
  278. S32 tmins = (S32)((time - thours * 3600) / 60);
  279. S32 tsecs = (S32)(time - thours * 3600 - tmins * 60);
  280. time = gFrameTimeSeconds;
  281. S32 hours = (S32)(time / 3600);
  282. S32 mins = (S32)((time - hours * 3600) / 60);
  283. S32 secs = (S32)(time - hours * 3600 - mins * 60);
  284. addText(xpos, ypos,
  285. llformat("Online time: %d:%02d:%02d - Texture fecthing time: %d:%02d:%02d",
  286. hours, mins, secs, thours, tmins, tsecs));
  287. ypos += mIncY;
  288. }
  289. static LLCachedControl<bool> debug_poll_age(gSavedSettings,
  290. "DebugShowPollRequestAge");
  291. if (debug_poll_age)
  292. {
  293. LLViewerRegion* regionp = gAgent.getRegion();
  294. if (regionp)
  295. {
  296. mTempStr = llformat("Poll request age: %.1fs",
  297. regionp->getEventPollRequestAge());
  298. if (!regionp->isEventPollInFlight())
  299. {
  300. mTempStr.append(" *");
  301. }
  302. addText(window_width - 172, ypos, mTempStr);
  303. ypos += mIncY;
  304. }
  305. }
  306. if (gDisplayCameraPos)
  307. {
  308. // Update camera center, camera view, wind info every other frame
  309. LLVector3d tvector = gAgent.getPositionGlobal();
  310. mTempStr = llformat("AgentCenter %f %f %f",
  311. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  312. (F32)tvector.mdV[VZ]);
  313. addText(xpos, ypos, mTempStr);
  314. ypos += mIncY;
  315. if (isAgentAvatarValid())
  316. {
  317. tvector =
  318. gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
  319. mTempStr = llformat("AgentRootCenter %f %f %f",
  320. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  321. (F32)tvector.mdV[VZ]);
  322. }
  323. else
  324. {
  325. mTempStr = "---";
  326. }
  327. addText(xpos, ypos, mTempStr);
  328. ypos += mIncY;
  329. tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
  330. mTempStr = llformat("AgentAtAxis %f %f %f",
  331. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  332. (F32)tvector.mdV[VZ]);
  333. addText(xpos, ypos, mTempStr);
  334. ypos += mIncY;
  335. tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
  336. mTempStr = llformat("AgentLeftAxis %f %f %f",
  337. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  338. (F32)tvector.mdV[VZ]);
  339. addText(xpos, ypos, mTempStr);
  340. ypos += mIncY;
  341. tvector = gAgent.getCameraPositionGlobal();
  342. mTempStr = llformat("CameraCenter %f %f %f",
  343. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  344. (F32)tvector.mdV[VZ]);
  345. addText(xpos, ypos, mTempStr);
  346. ypos += mIncY;
  347. tvector = LLVector4(gViewerCamera.getAtAxis());
  348. mTempStr = llformat("CameraAtAxis %f %f %f",
  349. (F32)tvector.mdV[VX], (F32)tvector.mdV[VY],
  350. (F32)tvector.mdV[VZ]);
  351. addText(xpos, ypos, mTempStr);
  352. ypos += mIncY;
  353. mTempStr = llformat("Near clip: %f - Far clip: %f",
  354. gViewerCamera.getNear(),
  355. gViewerCamera.getFar());
  356. addText(xpos, ypos, mTempStr);
  357. ypos += mIncY;
  358. mTempStr = "Camera mode: ";
  359. #define SETENUM(E) case E: mTempStr += #E; break
  360. switch (gAgent.getCameraMode())
  361. {
  362. SETENUM(CAMERA_MODE_THIRD_PERSON);
  363. SETENUM(CAMERA_MODE_MOUSELOOK);
  364. SETENUM(CAMERA_MODE_CUSTOMIZE_AVATAR);
  365. SETENUM(CAMERA_MODE_FOLLOW);
  366. default:
  367. mTempStr += llformat("%d", gAgent.getCameraMode());
  368. }
  369. #undef SETENUM
  370. addText(xpos, ypos, mTempStr);
  371. ypos += mIncY;
  372. }
  373. if (gDisplayWindInfo)
  374. {
  375. mTempStr = llformat("Wind velocity %.2f m/s", gWindVec.length());
  376. addText(xpos, ypos, mTempStr);
  377. ypos += mIncY;
  378. mTempStr = llformat("Wind vector %.2f %.2f %.2f",
  379. gWindVec.mV[0], gWindVec.mV[1],
  380. gWindVec.mV[2]);
  381. addText(xpos, ypos, mTempStr);
  382. ypos += mIncY;
  383. mTempStr = llformat("RWind vel %.2f m/s",
  384. gRelativeWindVec.length());
  385. addText(xpos, ypos, mTempStr);
  386. ypos += mIncY;
  387. mTempStr = llformat("RWind vec %.2f %.2f %.2f",
  388. gRelativeWindVec.mV[0], gRelativeWindVec.mV[1],
  389. gRelativeWindVec.mV[2]);
  390. addText(xpos, ypos, mTempStr);
  391. ypos += mIncY;
  392. if (gAudiop)
  393. {
  394. mTempStr = llformat("Audio for wind: %d",
  395. gAudiop->isWindEnabled());
  396. }
  397. addText(xpos, ypos, mTempStr);
  398. ypos += mIncY;
  399. }
  400. if (gDisplayFOV)
  401. {
  402. addText(xpos, ypos,
  403. llformat("FOV: %2.1f deg",
  404. RAD_TO_DEG * gViewerCamera.getView()));
  405. ypos += mIncY;
  406. }
  407. #if 0
  408. if (LLViewerJoystick::getInstance()->getOverrideCamera())
  409. {
  410. addText(xpos + 250, ypos, "Flycam");
  411. ypos += mIncY;
  412. }
  413. #endif
  414. static LLCachedControl<bool> debug_show_render_info(gSavedSettings,
  415. "DebugShowRenderInfo");
  416. if (debug_show_render_info)
  417. {
  418. if (!gPipeline.canUseShaders())
  419. {
  420. addText(xpos, ypos, "Shaders disabled");
  421. ypos += mIncY;
  422. }
  423. if (gGLManager.mHasATIMemInfo)
  424. {
  425. S32 meminfo[4];
  426. glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
  427. addText(xpos, ypos, llformat("%.2f MB texture memory free",
  428. meminfo[0] / 1024.f));
  429. ypos += mIncY;
  430. glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, meminfo);
  431. addText(xpos, ypos, llformat("%.2f MB VBO memory free",
  432. meminfo[0] / 1024.f));
  433. ypos += mIncY;
  434. }
  435. else if (gGLManager.mHasNVXMemInfo)
  436. {
  437. S32 free_memory;
  438. glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX,
  439. &free_memory);
  440. addText(xpos, ypos, llformat("%.2f MB video memory free",
  441. free_memory / 1024.f));
  442. ypos += mIncY;
  443. }
  444. // Show streaming cost/triangle count of known prims in current
  445. // region OR selection
  446. {
  447. F32 cost = 0.f;
  448. S32 count = 0;
  449. S32 vcount = 0;
  450. S32 object_count = 0;
  451. S32 total_bytes = 0;
  452. S32 visible_bytes = 0;
  453. LLObjectSelectionHandle selected_objects =
  454. gSelectMgr.getSelection();
  455. if (selected_objects->getObjectCount() == 0)
  456. {
  457. LLViewerRegion* regionp = gAgent.getRegion();
  458. if (regionp)
  459. {
  460. for (U32 i = 0, count = gObjectList.getNumObjects();
  461. i < count; ++i)
  462. {
  463. LLViewerObject* objectp = gObjectList.getObject(i);
  464. if (objectp && objectp->getRegion() == regionp &&
  465. objectp->getVolume())
  466. {
  467. ++object_count;
  468. S32 bytes = 0;
  469. S32 visible = 0;
  470. cost += objectp->getStreamingCost(&bytes,
  471. &visible);
  472. S32 vt = 0;
  473. count += objectp->getTriangleCount(&vt);
  474. vcount += vt;
  475. total_bytes += bytes;
  476. visible_bytes += visible;
  477. }
  478. }
  479. }
  480. addText(xpos, ypos,
  481. llformat("Region streaming cost: %.1f", cost));
  482. }
  483. else
  484. {
  485. cost =
  486. selected_objects->getSelectedObjectStreamingCost(&total_bytes,
  487. &visible_bytes);
  488. count =
  489. selected_objects->getSelectedObjectTriangleCount(&vcount);
  490. object_count = selected_objects->getObjectCount();
  491. addText(xpos, ypos,
  492. llformat("Selection streaming cost: %.1f", cost));
  493. }
  494. ypos += mIncY;
  495. addText(xpos, ypos,
  496. llformat("%.1f KTris, %.3f KVerts, %.1f/%.1f KB, %d objects",
  497. count / 1000.f, vcount / 1000.f,
  498. visible_bytes / 1024.f, total_bytes / 1024.f,
  499. object_count));
  500. ypos += mIncY;
  501. }
  502. addText(xpos, ypos,
  503. llformat("%d vertex buffers",
  504. LLVertexBuffer::getGLCount()));
  505. ypos += mIncY;
  506. addText(xpos, ypos,
  507. llformat("%d vertex buffer binds",
  508. LLVertexBuffer::getBindCount()));
  509. ypos += mIncY;
  510. addText(xpos, ypos,
  511. llformat("%d vertex buffer sets",
  512. LLVertexBuffer::getSetCount()));
  513. ypos += mIncY;
  514. addText(xpos, ypos,
  515. llformat("%d texture binds", LLImageGL::sBindCount));
  516. ypos += mIncY;
  517. addText(xpos, ypos,
  518. llformat("%d unique textures", LLImageGL::sUniqueCount));
  519. ypos += mIncY;
  520. addText(xpos, ypos,
  521. llformat("%d render calls", gPipeline.mBatchCount));
  522. ypos += mIncY;
  523. addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d",
  524. gPipeline.mMinBatchSize,
  525. gPipeline.mMaxBatchSize,
  526. gPipeline.mTrianglesDrawn /
  527. gPipeline.mBatchCount));
  528. ypos += mIncY;
  529. gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize = 0;
  530. gPipeline.mBatchCount = 0;
  531. addText(xpos, ypos,
  532. llformat("%d/%d objects active",
  533. gObjectList.getNumActiveObjects(),
  534. gObjectList.getNumObjects()));
  535. ypos += mIncY;
  536. addText(xpos, ypos,
  537. llformat("%d matrix ops", gPipeline.mMatrixOpCount));
  538. ypos += mIncY;
  539. gPipeline.mMatrixOpCount = 0;
  540. addText(xpos, ypos,
  541. llformat("%d texture matrix ops",
  542. gPipeline.mTextureMatrixOps));
  543. ypos += mIncY;
  544. gPipeline.mTextureMatrixOps = 0;
  545. addText(xpos, ypos,
  546. llformat("%d/%d nodes visible", gPipeline.mNumVisibleNodes,
  547. LLSpatialGroup::sNodeCount));
  548. ypos += mIncY;
  549. addText(xpos, ypos,
  550. llformat("%d avatars visible",
  551. LLVOAvatar::sNumVisibleAvatars));
  552. ypos += mIncY;
  553. addText(xpos, ypos,
  554. llformat("%d lights visible",
  555. LLPipeline::sVisibleLightCount));
  556. ypos += mIncY;
  557. if (gMeshRepo.meshRezEnabled())
  558. {
  559. constexpr F32 MEGABYTE = 1048576.f;
  560. addText(xpos, ypos,
  561. llformat("%.3f MB mesh data received",
  562. LLMeshRepository::sBytesReceived / MEGABYTE));
  563. ypos += mIncY;
  564. addText(xpos, ypos,
  565. llformat("%d/%d mesh HTTP requests/retries",
  566. LLMeshRepository::sHTTPRequestCount,
  567. LLMeshRepository::sHTTPRetryCount));
  568. ypos += mIncY;
  569. addText(xpos, ypos,
  570. llformat("%d/%d mesh LOD pending/processing",
  571. (S32)LLMeshRepository::sLODPending,
  572. (S32)LLMeshRepository::sLODProcessing));
  573. ypos += mIncY;
  574. addText(xpos, ypos,
  575. llformat("%.3f/%.3f MB mesh cache read/write ",
  576. LLMeshRepository::sCacheBytesRead / MEGABYTE,
  577. LLMeshRepository::sCacheBytesWritten / MEGABYTE));
  578. ypos += mIncY;
  579. }
  580. // Reset per-frame statistics.
  581. LLVertexBuffer::resetPerFrameStats();
  582. LLImageGL::sBindCount = LLImageGL::sUniqueCount =
  583. gPipeline.mNumVisibleNodes =
  584. LLPipeline::sVisibleLightCount = 0;
  585. }
  586. static LLCachedControl<bool> debug_show_avatars_info(gSavedSettings,
  587. "DebugShowAvatarRenderInfo");
  588. if (debug_show_avatars_info)
  589. {
  590. std::map<std::string, LLVOAvatar*> sorted_avs;
  591. for (S32 i = 0, count = LLCharacter::sInstances.size(); i < count;
  592. ++i)
  593. {
  594. LLVOAvatar* avatarp = (LLVOAvatar*)LLCharacter::sInstances[i];
  595. if (avatarp && !avatarp->isDead() && !avatarp->mIsDummy &&
  596. !avatarp->isOrphaned() && avatarp->isFullyLoaded(true))
  597. {
  598. sorted_avs[avatarp->getFullname(true)] = avatarp;
  599. }
  600. }
  601. //MK
  602. bool hide_names = gRLenabled && gRLInterface.mContainsShownames;
  603. if (hide_names)
  604. {
  605. mTempStr = "(Hidden)";
  606. }
  607. //mk
  608. for (std::map<std::string, LLVOAvatar*>::reverse_iterator
  609. rit = sorted_avs.rbegin(), rend = sorted_avs.rend();
  610. rit != rend; ++rit)
  611. {
  612. //MK
  613. if (!hide_names)
  614. //mk
  615. {
  616. mTempStr = utf8str_truncate(rit->first, 16);
  617. }
  618. LLVOAvatar* avatarp = rit->second;
  619. addText(xpos, ypos,
  620. llformat("%s: complexity %d, %d m2, %.1f MB",
  621. mTempStr.c_str(),
  622. avatarp->getVisualComplexity(),
  623. (S32)avatarp->getAttachmentSurfaceArea(),
  624. (F32)avatarp->getAttachmentSurfaceBytes() /
  625. 1048576.f));
  626. ypos += mIncY;
  627. }
  628. }
  629. static LLCachedControl<bool> debug_show_render_matrices(gSavedSettings,
  630. "DebugShowRenderMatrices");
  631. if (debug_show_render_matrices)
  632. {
  633. F32* m = gGLProjection.getF32ptr();
  634. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  635. m[12], m[13], m[14], m[15]));
  636. ypos += mIncY;
  637. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  638. m[8], m[9], m[10], m[11]));
  639. ypos += mIncY;
  640. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  641. m[4], m[5], m[6], m[7]));
  642. ypos += mIncY;
  643. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  644. m[0], m[1], m[2], m[3]));
  645. ypos += mIncY;
  646. m = gGLModelView.getF32ptr();
  647. addText(xpos, ypos, "Projection matrix");
  648. ypos += mIncY;
  649. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  650. m[12], m[13], m[14], m[15]));
  651. ypos += mIncY;
  652. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  653. m[8], m[9], m[10], m[11]));
  654. ypos += mIncY;
  655. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  656. m[4], m[5], m[6], m[7]));
  657. ypos += mIncY;
  658. addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f",
  659. m[0], m[1], m[2], m[3]));
  660. ypos += mIncY;
  661. addText(xpos, ypos, "View Matrix");
  662. ypos += mIncY;
  663. }
  664. static LLCachedControl<bool> debug_show_color(gSavedSettings,
  665. "DebugShowColor");
  666. if (debug_show_color)
  667. {
  668. static U8 color[4];
  669. LLCoordGL coord = gViewerWindowp->getCurrentMouse();
  670. const LLVector2& scaler = gViewerWindowp->getDisplayScale();
  671. S32 x = ll_round((F32)coord.mX * scaler.mV[VX]);
  672. S32 y = ll_round((F32)coord.mY * scaler.mV[VY]);
  673. glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
  674. addText(xpos, ypos, llformat("Pixel <%1d, %1d> R:%d G:%d B:%d A:%d",
  675. x, y, color[0], color[1], color[2],
  676. color[3]));
  677. ypos += mIncY;
  678. }
  679. // Only display these messages if we are actually rendering beacons at
  680. // this moment
  681. static LLCachedControl<bool> beacons_always_on(gSavedSettings,
  682. "BeaconAlwaysOn");
  683. if (LLPipeline::sRenderBeacons &&
  684. //MK
  685. !(gRLenabled && gRLInterface.mContainsEdit) &&
  686. //mk
  687. (LLPipeline::sRenderBeaconsFloaterOpen || beacons_always_on))
  688. {
  689. if (LLPipeline::sRenderScriptedBeacons)
  690. {
  691. addText(xpos, ypos, "Viewing scripted object beacons (red)");
  692. ypos += mIncY;
  693. }
  694. else if (LLPipeline::sRenderScriptedTouchBeacons)
  695. {
  696. addText(xpos, ypos,
  697. "Viewing scripted object with touch function beacons (red)");
  698. ypos += mIncY;
  699. }
  700. if (LLPipeline::sRenderPhysicalBeacons)
  701. {
  702. addText(xpos, ypos, "Viewing physical object beacons (green)");
  703. ypos += mIncY;
  704. }
  705. if (LLPipeline::sRenderPermanentBeacons)
  706. {
  707. addText(xpos, ypos,
  708. "Viewing navmesh affecting object beacons (cyan)");
  709. ypos += mIncY;
  710. }
  711. if (LLPipeline::sRenderCharacterBeacons)
  712. {
  713. addText(xpos, ypos,
  714. "Viewing pathfinding character object beacons (grey)");
  715. ypos += mIncY;
  716. }
  717. if (LLPipeline::sRenderSoundBeacons)
  718. {
  719. addText(xpos, ypos, "Viewing sound beacons (yellow)");
  720. ypos += mIncY;
  721. }
  722. if (LLPipeline::sRenderParticleBeacons)
  723. {
  724. addText(xpos, ypos, "Viewing particle beacons (light blue)");
  725. ypos += mIncY;
  726. if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
  727. {
  728. addText(xpos, ypos, " (note: particles hidden)");
  729. ypos += mIncY;
  730. }
  731. }
  732. if (LLPipeline::sRenderMOAPBeacons)
  733. {
  734. addText(xpos, ypos, "Viewing shared media beacons (white)");
  735. ypos += mIncY;
  736. }
  737. }
  738. static LLCachedControl<bool> sun_beacon(gSavedSettings, "sunbeacon");
  739. if (sun_beacon)
  740. {
  741. addText(xpos, ypos, "Viewing Sun direction beacon (orange)");
  742. ypos += mIncY;
  743. }
  744. static LLCachedControl<bool> moon_beacon(gSavedSettings, "moonbeacon");
  745. if (moon_beacon)
  746. {
  747. addText(xpos, ypos, "Viewing Moon direction beacon (purple)");
  748. ypos += mIncY;
  749. }
  750. static LLCachedControl<bool> debug_show_mesh_queue(gSavedSettings,
  751. "DebugShowMeshQueue");
  752. if (debug_show_mesh_queue)
  753. {
  754. if (!gMeshRepo.mUploads.empty())
  755. {
  756. for (std::vector<LLMeshUploadThread*>::iterator
  757. iter = gMeshRepo.mUploads.begin(),
  758. end = gMeshRepo.mUploads.end();
  759. iter != end; ++iter)
  760. {
  761. LLMeshUploadThread* thread = *iter;
  762. addText(xpos, ypos,
  763. llformat("Mesh uploads: %d",
  764. thread->mPendingUploads));
  765. ypos += mIncY;
  766. }
  767. }
  768. S32 pending = 0;
  769. S32 delayed = 0;
  770. S32 header = 0;
  771. S32 lod = 0;
  772. S32 ahead = 0;
  773. S32 alod = 0;
  774. LLMeshRepoThread* mthread = gMeshRepo.mThread;
  775. if (mthread)
  776. {
  777. // Note: no need to lock the mesh repository mutexes here: we
  778. // do not care if the (fast changing) numbers are inaccurate
  779. // once in a blue moon... HB
  780. pending = gMeshRepo.mPendingRequests.size();
  781. #if !LL_PENDING_MESH_REQUEST_SORTING
  782. delayed = gMeshRepo.mDelayedPendingRequests.size();
  783. #endif
  784. header = mthread->mHeaderReqQ.size();
  785. lod = mthread->mLODReqQ.size();
  786. ahead = LLMeshRepoThread::sActiveHeaderRequests;
  787. alod = LLMeshRepoThread::sActiveLODRequests;
  788. }
  789. if (delayed)
  790. {
  791. addText(xpos, ypos,
  792. llformat("Mesh queue: %d pending + %d delayed (%d:%d header | %d:%d LOD)",
  793. pending, delayed, ahead, header, alod, lod));
  794. }
  795. else if (pending || header || lod || ahead || alod)
  796. {
  797. addText(xpos, ypos,
  798. llformat("Mesh queue: %d pending (%d:%d header | %d:%d LOD)",
  799. pending, ahead, header, alod, lod));
  800. ypos += mIncY;
  801. }
  802. }
  803. mMaxY = ypos + 4 - mIncY;
  804. }
  805. void draw()
  806. {
  807. if (mLineList.empty())
  808. {
  809. return;
  810. }
  811. // Note: do not show the background while the velocity bar is shown
  812. static LLCachedControl<bool> hud_info_bg(gSavedSettings,
  813. "HUDInfoBackground");
  814. if (!mVelocityBarShown && hud_info_bg)
  815. {
  816. mMinX -= mMaginX;
  817. LLUIImage::sRoundedSquare->drawSolid(mMinX, mMinY,
  818. mMaxX - mMinX, mMaxY - mMinY,
  819. LLConsole::getBackground());
  820. }
  821. for (line_list_t::iterator iter = mLineList.begin(),
  822. end = mLineList.end();
  823. iter != end; ++iter)
  824. {
  825. const Line& line = *iter;
  826. mFont->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y,
  827. mTextColor, LLFontGL::LEFT, LLFontGL::TOP,
  828. LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, false);
  829. }
  830. mLineList.clear();
  831. mMinX = S32_MAX;
  832. }
  833. private:
  834. LLFontGL* mFont;
  835. LLColor4 mTextColor;
  836. U32 mLineHeight;
  837. U32 mMaginX;
  838. U32 mIncY;
  839. U32 mMinX;
  840. U32 mMaxX;
  841. U32 mMinY;
  842. U32 mMaxY;
  843. std::string mTempStr;
  844. struct Line
  845. {
  846. Line(const std::string& in_text, U32 in_x, U32 in_y)
  847. : text(in_text),
  848. x(in_x),
  849. y(in_y)
  850. {
  851. }
  852. U32 x;
  853. U32 y;
  854. std::string text;
  855. };
  856. typedef std::vector<Line> line_list_t;
  857. line_list_t mLineList;
  858. bool mVelocityBarShown;
  859. };
  860. ////////////////////////////////////////////////////////////////////////////
  861. // LLViewerWindow class
  862. ////////////////////////////////////////////////////////////////////////////
  863. LLViewerWindow::LLViewerWindow(const std::string& title, S32 x, S32 y,
  864. U32 width, U32 height, bool fullscreen)
  865. : mActive(true),
  866. mWindowRect(0, height, width, 0),
  867. mVirtualWindowRect(0, height, width, 0),
  868. mLeftMouseDown(false),
  869. mMiddleMouseDown(false),
  870. mRightMouseDown(false),
  871. #if LL_DARWIN
  872. mAllowMouseDragging(true),
  873. #endif
  874. mDebugText(NULL),
  875. mToolTip(NULL),
  876. mToolTipBlocked(false),
  877. mMouseInWindow(false),
  878. mLastMask(MASK_NONE),
  879. mToolStored(NULL),
  880. mSuppressToolbox(false),
  881. mCursorHidden(false),
  882. mIgnoreActivate(false),
  883. mHoverPick(),
  884. mResDirty(false),
  885. mStatesDirty(false),
  886. mCurrResolutionIndex(0)
  887. {
  888. gNotifications.initClass();
  889. LLNotificationChannel::buildChannel("VW_alerts", "Visible",
  890. LLNotificationFilters::filterBy<std::string>(&LLNotification::getType,
  891. "alert"));
  892. LLNotificationChannel::buildChannel("VW_alertmodal", "Visible",
  893. LLNotificationFilters::filterBy<std::string>(&LLNotification::getType,
  894. "alertmodal"));
  895. gNotifications.getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert);
  896. gNotifications.getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert);
  897. // Default to application directory.
  898. LLViewerWindow::sSnapshotBaseName = "Snapshot";
  899. LLViewerWindow::sMovieBaseName = "SLmovie";
  900. resetSnapshotLoc();
  901. // Create window
  902. LLWindow::createWindow(title, x, y, width, height, 0, fullscreen,
  903. gSavedSettings.getBool("DisableVerticalSync"),
  904. gSavedSettings.getU32("RenderFSAASamples"));
  905. if (!gAppViewerp->restoreErrorTrap())
  906. {
  907. llwarns << " Someone took over my signal/exception handler !"
  908. << llendl;
  909. }
  910. if (!gWindowp)
  911. {
  912. llwarns << "Unable to create window, be sure screen is set at 32 bits color."
  913. << llendl;
  914. gAppViewerp->forceExit();
  915. }
  916. #if LL_DEBUG || LL_NO_FORCE_INLINE
  917. gWindowp->setWindowTitle(title + " [DEVEL]");
  918. #endif
  919. // Immediately create the shader manager.
  920. LLViewerShaderMgr::createInstance();
  921. // Get the real window rect the window was created with (since there are
  922. // various OS-dependent reasons why the size of a window or fullscreen
  923. // context may have been adjusted slightly...)
  924. F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor") *
  925. gWindowp->getSystemUISize();
  926. // HiDPI scaling can be 4x. UI scaling in prefs is up to 2x, so max is 8x
  927. ui_scale_factor = llclamp(ui_scale_factor, 0.75f, 8.f);
  928. mDisplayScale.set(llmax(1.f / gWindowp->getPixelAspectRatio(), 1.f),
  929. llmax(gWindowp->getPixelAspectRatio(), 1.f));
  930. mDisplayScale *= ui_scale_factor;
  931. F32 divisor_x = 1.f / mDisplayScale.mV[VX];
  932. F32 divisor_y = 1.f / mDisplayScale.mV[VY];
  933. mDisplayScaleDivisor.set(divisor_x, divisor_y);
  934. LLUI::sGLScaleFactor = mDisplayScale;
  935. LLCoordWindow size;
  936. gWindowp->getSize(&size);
  937. mWindowRect.set(0, size.mY, size.mX, 0);
  938. mVirtualWindowRect.set(0, ll_roundp((F32)size.mY * divisor_y),
  939. ll_roundp((F32)size.mX * divisor_x), 0);
  940. LLFontManager::initClass();
  941. // We want to set this stuff up BEFORE we initialize the pipeline, so we
  942. // can turn off stuff like AGP if we think that it will crash the viewer.
  943. LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
  944. gFeatureManager.init();
  945. // Initialize OpenGL Renderer
  946. LLVertexBuffer::initClass();
  947. llinfos << "LLVertexBuffer initialization done." << llendl;
  948. gGL.init();
  949. if (gFeatureManager.isSafe() ||
  950. gSavedSettings.getS32("LastFeatureVersion") != gFeatureManager.getVersion() ||
  951. gSavedSettings.getBool("ProbeHardwareOnStartup"))
  952. {
  953. gFeatureManager.applyRecommendedSettings();
  954. gSavedSettings.setBool("ProbeHardwareOnStartup", false);
  955. }
  956. // If we crashed while initializing GL stuff last time, disable certain
  957. // features.
  958. if (gSavedSettings.getBool("RenderInitError"))
  959. {
  960. mInitAlert = "DisplaySettingsNoShaders";
  961. gFeatureManager.setGraphicsLevel(0, false);
  962. gSavedSettings.setU32("RenderQualityPerformance", 0);
  963. gSavedSettings.setBool("RenderUsePBR", false);
  964. }
  965. // Set callbacks
  966. gWindowp->setCallbacks(this);
  967. LLImageGL::initThread(gWindowp, gSavedSettings.getS32("GLWorkerThreads"));
  968. // Init the image list. Must happen after GL is initialized and before the
  969. // images that LLViewerWindow needs are requested.
  970. gTextureList.init();
  971. LLViewerTextureManager::init();
  972. // Init default fonts
  973. initFonts();
  974. // Create container for all sub-views
  975. mRootView = new LLRootView("root", mVirtualWindowRect, false);
  976. // Make avatar head look forward at start
  977. mCurrentMousePoint.mX = getWindowWidth() / 2;
  978. mCurrentMousePoint.mY = getWindowHeight() / 2;
  979. // Sync the keyboard setting with the saved setting
  980. gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
  981. mDebugText = new LLDebugText();
  982. }
  983. void LLViewerWindow::initGLDefaults()
  984. {
  985. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  986. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  987. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  988. gGL.setAmbientLightColor(LLColor4::black);
  989. glCullFace(GL_BACK);
  990. // RN: need this for translation and stretch manip.
  991. gBox.prerender();
  992. }
  993. void LLViewerWindow::initBase()
  994. {
  995. // Set the gamma
  996. F32 gamma = gSavedSettings.getF32("DisplayGamma");
  997. if (!gWindowp->setGamma(gamma))
  998. {
  999. llwarns << "Failed to set the display gamma to " << gamma
  1000. << ". Restoring the default gamma." << llendl;
  1001. gWindowp->restoreGamma();
  1002. }
  1003. // Create global views
  1004. // Create the floater view at the start so that other views can add
  1005. // children to it (but wait to add it as a child of the root view so that
  1006. // it will be in front of the other views).
  1007. // Constrain floaters to inside the menu and status bar regions.
  1008. S32 height = getWindowHeight();
  1009. S32 width = getWindowWidth();
  1010. LLRect full_window(0, height, width, 0);
  1011. LLRect floater_view_rect = full_window;
  1012. // Make space for the menu bar...
  1013. floater_view_rect.mTop -= gMenuBarHeight;
  1014. // ... and for the tool bar, the chat bar and the overlay bar...
  1015. if (gSavedSettings.getBool("ShowToolBar"))
  1016. {
  1017. floater_view_rect.mBottom += TOOL_BAR_HEIGHT;
  1018. }
  1019. if (gSavedSettings.getBool("ChatVisible"))
  1020. {
  1021. floater_view_rect.mBottom += CHAT_BAR_HEIGHT;
  1022. }
  1023. floater_view_rect.mBottom += OVERLAY_BAR_HEIGHT;
  1024. // Check for non-first startup
  1025. S32 floater_view_bottom = gSavedSettings.getS32("FloaterViewBottom");
  1026. if (floater_view_bottom >= 0)
  1027. {
  1028. floater_view_rect.mBottom = floater_view_bottom;
  1029. }
  1030. gFloaterViewp = new LLFloaterView("Floater View", floater_view_rect);
  1031. gFloaterViewp->setVisible(true);
  1032. gSnapshotFloaterViewp = new LLSnapshotFloaterView("Snapshot Floater View",
  1033. full_window);
  1034. // Snapshot floater must start invisible otherwise it eats all the tooltips
  1035. gSnapshotFloaterViewp->setVisible(false);
  1036. // Console
  1037. llassert(!gConsolep);
  1038. gConsolep = new LLConsole("console", getChatConsoleRect(),
  1039. gSavedSettings.getS32("ChatFontSize"),
  1040. gSavedSettings.getU32("ChatConsoleMaxLines"),
  1041. gSavedSettings.getF32("ChatPersistTime"));
  1042. gConsolep->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
  1043. mRootView->addChild(gConsolep);
  1044. // Debug view over the console
  1045. gDebugViewp = new LLDebugView("gDebugViewp", full_window);
  1046. gDebugViewp->setFollowsAll();
  1047. gDebugViewp->setVisible(true);
  1048. mRootView->addChild(gDebugViewp);
  1049. // HUD elements just below floaters
  1050. LLRect hud_rect = full_window;
  1051. hud_rect.mTop -= 24;
  1052. hud_rect.mBottom += gStatusBarHeight;
  1053. gHUDViewp = new LLHUDView("hud_view", hud_rect);
  1054. gHUDViewp->setFollowsAll();
  1055. mRootView->addChild(gHUDViewp);
  1056. // Add floater view at the end so it will be on top, and give it tab
  1057. // priority over others
  1058. mRootView->addChild(gFloaterViewp, -1);
  1059. mRootView->addChild(gSnapshotFloaterViewp);
  1060. // Notify above floaters !
  1061. LLRect notify_rect = full_window;
  1062. #if 0
  1063. notify_rect.mTop -= 24;
  1064. #endif
  1065. notify_rect.mBottom += gStatusBarHeight;
  1066. gNotifyBoxViewp = new LLNotifyBoxView("notify_container", notify_rect,
  1067. false, FOLLOWS_ALL);
  1068. mRootView->addChild(gNotifyBoxViewp, -2);
  1069. // Tooltips go above floaters
  1070. mToolTip = new LLTextBox(std::string("tool tip"), LLRect(0, 1, 1, 0));
  1071. mToolTip->setHPad(4);
  1072. mToolTip->setVPad(2);
  1073. mToolTip->setColor(gColors.getColor("ToolTipTextColor"));
  1074. mToolTip->setBorderColor(gColors.getColor("ToolTipBorderColor"));
  1075. mToolTip->setBorderVisible(false);
  1076. mToolTip->setBackgroundColor(gColors.getColor("ToolTipBgColor"));
  1077. mToolTip->setBackgroundVisible(true);
  1078. mToolTip->setFontStyle(LLFontGL::NORMAL);
  1079. mToolTip->setBorderDropshadowVisible(true);
  1080. mToolTip->setVisible(false);
  1081. // Add the progress bar view (startup view), which overrides everything
  1082. mProgressView = new LLProgressView("ProgressView", full_window);
  1083. mRootView->addChild(mProgressView);
  1084. setShowProgress(false);
  1085. setProgressCancelButtonVisible(false);
  1086. #if LL_DARWIN
  1087. // *HACK: to get a redraw and take into account Retina mode (or not)...
  1088. mResDirty = true;
  1089. #endif
  1090. }
  1091. void adjust_rect_top_left(const char* control, const LLRect& view)
  1092. {
  1093. LLRect r = gSavedSettings.getRect(control);
  1094. if (r.mLeft || r.mBottom)
  1095. {
  1096. return;
  1097. }
  1098. r.setLeftTopAndSize(0, view.getHeight(), r.getWidth(), r.getHeight());
  1099. gSavedSettings.setRect(control, r);
  1100. }
  1101. void adjust_rect_top_center(const char* control, const LLRect& view)
  1102. {
  1103. LLRect r = gSavedSettings.getRect(control);
  1104. if (r.mLeft || r.mBottom)
  1105. {
  1106. return;
  1107. }
  1108. r.setLeftTopAndSize((view.getWidth() - r.getWidth()) / 2, view.getHeight(),
  1109. r.getWidth(), r.getHeight());
  1110. gSavedSettings.setRect(control, r);
  1111. }
  1112. void adjust_rect_top_right(const char* control, const LLRect& view,
  1113. S32 delta_y = 0)
  1114. {
  1115. LLRect r = gSavedSettings.getRect(control);
  1116. if (r.mLeft || r.mBottom)
  1117. {
  1118. return;
  1119. }
  1120. r.setLeftTopAndSize(view.getWidth() - r.getWidth(),
  1121. view.getHeight() - delta_y,
  1122. r.getWidth(), r.getHeight());
  1123. gSavedSettings.setRect(control, r);
  1124. }
  1125. void adjust_rect_center(const char* control, const LLRect& view)
  1126. {
  1127. LLRect r = gSavedSettings.getRect(control);
  1128. if (r.mLeft || r.mBottom)
  1129. {
  1130. return;
  1131. }
  1132. r.setLeftTopAndSize((view.getWidth() - r.getWidth()) / 2,
  1133. view.getHeight() -
  1134. (view.getHeight() - r.getHeight()) / 2,
  1135. r.getWidth(), r.getHeight());
  1136. gSavedSettings.setRect(control, r);
  1137. }
  1138. void adjust_rect_left_center(const char* control, const LLRect& view)
  1139. {
  1140. LLRect r = gSavedSettings.getRect(control);
  1141. if (r.mLeft || r.mBottom)
  1142. {
  1143. return;
  1144. }
  1145. r.setLeftTopAndSize(0,
  1146. view.getHeight() -
  1147. (view.getHeight() - r.getHeight()) / 2,
  1148. r.getWidth(), r.getHeight());
  1149. gSavedSettings.setRect(control, r);
  1150. }
  1151. void adjust_rect_right_center(const char* control, const LLRect& view)
  1152. {
  1153. LLRect r = gSavedSettings.getRect(control);
  1154. if (r.mLeft || r.mBottom)
  1155. {
  1156. return;
  1157. }
  1158. r.setLeftTopAndSize(view.getWidth() - r.getWidth(),
  1159. view.getHeight() -
  1160. (view.getHeight() - r.getHeight()) / 2,
  1161. r.getWidth(), r.getHeight());
  1162. gSavedSettings.setRect(control, r);
  1163. }
  1164. void adjust_rect_bottom_left(const char* control, const LLRect& view)
  1165. {
  1166. LLRect r = gSavedSettings.getRect(control);
  1167. if (r.mLeft || r.mBottom)
  1168. {
  1169. return;
  1170. }
  1171. r.setOriginAndSize(0, view.mBottom, r.getWidth(), r.getHeight());
  1172. gSavedSettings.setRect(control, r);
  1173. }
  1174. void adjust_rect_bottom_center(const char* control, const LLRect& view)
  1175. {
  1176. LLRect r = gSavedSettings.getRect(control);
  1177. if (r.mLeft || r.mBottom)
  1178. {
  1179. return;
  1180. }
  1181. r.setOriginAndSize((view.getWidth() - r.getWidth()) / 2, view.mBottom,
  1182. r.getWidth(), r.getHeight());
  1183. gSavedSettings.setRect(control, r);
  1184. }
  1185. void adjust_rect_bottom_right(const char* control, const LLRect& view)
  1186. {
  1187. LLRect r = gSavedSettings.getRect(control);
  1188. if (r.mLeft || r.mBottom)
  1189. {
  1190. return;
  1191. }
  1192. r.setOriginAndSize(view.getWidth() - r.getWidth(), view.mBottom,
  1193. r.getWidth(), r.getHeight());
  1194. gSavedSettings.setRect(control, r);
  1195. }
  1196. // Many rectangles cannot be placed until we know the screen size. These
  1197. // rectangles have their bottom-left corner as 0,0 in the default settings.
  1198. void LLViewerWindow::adjustRectanglesForFirstUse()
  1199. {
  1200. if (!gFloaterViewp) return;
  1201. const LLRect& view_rect = gFloaterViewp->getRect();
  1202. // *NOTE: the width and height of non-resizable floaters must be identical
  1203. // in settings.xml and their relevant floater.xml files, otherwise the
  1204. // adjustment will not work properly.
  1205. // The camera controls floater goes at the top right corner...
  1206. adjust_rect_top_right("FloaterCameraRect3a", view_rect);
  1207. // ... then, just under, the movements controls floater...
  1208. LLRect r = gSavedSettings.getRect("FloaterCameraRect3a");
  1209. S32 delta_y = r.getHeight();
  1210. adjust_rect_top_right("FloaterMoveRect2", view_rect, delta_y);
  1211. // ... then, yet under, the mini-map...
  1212. r = gSavedSettings.getRect("FloaterMoveRect2");
  1213. delta_y += r.getHeight();
  1214. adjust_rect_top_right("FloaterMiniMapRect", view_rect, delta_y);
  1215. // ... finally, under the mini-map, all three friends list, groups list
  1216. // and radar floaters, at the same level...
  1217. r = gSavedSettings.getRect("FloaterMiniMapRect");
  1218. delta_y += r.getHeight();
  1219. adjust_rect_top_right("FloaterFriendsRect", view_rect, delta_y);
  1220. adjust_rect_top_right("FloaterGroupsRect", view_rect, delta_y);
  1221. adjust_rect_top_right("FloaterRadarRect", view_rect, delta_y);
  1222. // The inventory floater goes at the bottom right
  1223. adjust_rect_bottom_right("FloaterInventoryRect", view_rect);
  1224. // Chat history at the bottom left (replaces the console when opened)
  1225. adjust_rect_bottom_left("FloaterChatRect", view_rect);
  1226. // Communicate window at the top left (keeps the console visible while
  1227. // IMing)
  1228. adjust_rect_top_left("ChatterboxRect", view_rect);
  1229. // Chat and IM text input editor
  1230. adjust_rect_bottom_center("ChatInputEditorRect", view_rect);
  1231. adjust_rect_top_center("IMInputEditorRect", view_rect);
  1232. // Active speakers at the bottom right, above the voice controls
  1233. adjust_rect_bottom_right("FloaterActiveSpeakersRect", view_rect);
  1234. // Audio volume at the bottom right, above the master volume toggle
  1235. adjust_rect_bottom_right("FloaterAudioVolumeRect", view_rect);
  1236. // Same thing for the nearby media floater, above the media controls...
  1237. adjust_rect_bottom_right("FloaterNearbyMediaRect", view_rect);
  1238. adjust_rect_right_center("FloaterStatisticsRect", view_rect);
  1239. adjust_rect_right_center("FloaterPostcardRect", view_rect);
  1240. adjust_rect_bottom_right("FloaterLagMeter", view_rect);
  1241. // Build floater, top left
  1242. adjust_rect_top_left("ToolboxRect", view_rect);
  1243. // Script queue floater, top left
  1244. adjust_rect_top_left("CompileOutputRect", view_rect);
  1245. adjust_rect_top_left("FloaterCustomizeAppearanceRect", view_rect);
  1246. // Land/region/parcel related floaters go on top centre, below the status
  1247. // bar that shows the region and parcel names
  1248. adjust_rect_top_center("FloaterLandRect5", view_rect);
  1249. adjust_rect_top_center("FloaterRegionInfoRect", view_rect);
  1250. adjust_rect_top_left("FloaterLandHoldingsRect", view_rect);
  1251. adjust_rect_top_center("FloaterRegionDebugConsoleRect", view_rect);
  1252. adjust_rect_top_center("FloaterDebugTagsRect", view_rect);
  1253. adjust_rect_top_center("FloaterBumpRect", view_rect);
  1254. adjust_rect_top_center("FloaterWindlightRect", view_rect);
  1255. adjust_rect_top_center("FloaterObjectBackuptRect", view_rect);
  1256. adjust_rect_top_center("FloaterTeleportHistoryRect", view_rect);
  1257. adjust_rect_top_center("FloaterInspectAvatarRect", view_rect);
  1258. adjust_rect_top_center("FloaterInspectRect", view_rect);
  1259. adjust_rect_top_left("FloaterRLVRect", view_rect);
  1260. adjust_rect_top_left("FloaterDebugSettingsRect", view_rect);
  1261. adjust_rect_center("FloaterFindRect2", view_rect);
  1262. adjust_rect_center("FloaterLocalEnvEditorRect", view_rect);
  1263. adjust_rect_top_left("FloaterExperienceProfileRect", view_rect);
  1264. adjust_rect_center("FloaterExperiencesRect", view_rect);
  1265. adjust_rect_center("FloaterAreaSearchRect", view_rect);
  1266. adjust_rect_center("FloaterWorldMapRect2", view_rect);
  1267. adjust_rect_center("FloaterGroupTitlesRect", view_rect);
  1268. adjust_rect_center("MediaFilterRect", view_rect);
  1269. adjust_rect_center("FloaterSoundsListRect", view_rect);
  1270. adjust_rect_center("DirSelectorRect", view_rect);
  1271. adjust_rect_center("FileSelectorRect", view_rect);
  1272. adjust_rect_center("FloaterMarketplaceAssociationRect", view_rect);
  1273. adjust_rect_center("FloaterMarketplaceValidationRect", view_rect);
  1274. adjust_rect_left_center("FloaterAvatarProfileRect", view_rect);
  1275. adjust_rect_left_center("FloaterBeaconsRect", view_rect);
  1276. adjust_rect_left_center("FloaterMuteRect3", view_rect);
  1277. adjust_rect_left_center("FloaterGestureRect2", view_rect);
  1278. adjust_rect_center("PathFindingCharactersRect", view_rect);
  1279. adjust_rect_center("PathFindingLinksetsRect", view_rect);
  1280. adjust_rect_center("FloaterLuaDialogRect", view_rect);
  1281. }
  1282. void LLViewerWindow::initWorldUI()
  1283. {
  1284. pre_init_menus();
  1285. S32 height = mRootView->getRect().getHeight();
  1286. S32 width = mRootView->getRect().getWidth();
  1287. LLRect full_window(0, height, width, 0);
  1288. if (!gToolBarp) // Do not re-enter if objects are alreay created
  1289. {
  1290. if (gAudiop)
  1291. {
  1292. // Do not play the floaters opening sound
  1293. gAudiop->setMuted(true);
  1294. }
  1295. LLRect bar_rect(-1, gStatusBarHeight, width + 1, -1);
  1296. new LLToolBar(bar_rect);
  1297. LLRect chat_bar_rect(-1, CHAT_BAR_HEIGHT, width + 1, -1);
  1298. chat_bar_rect.translate(0, gStatusBarHeight - 1);
  1299. gChatBarp = new LLChatBar("chat", chat_bar_rect);
  1300. bar_rect.translate(0, gStatusBarHeight - 1);
  1301. bar_rect.translate(0, CHAT_BAR_HEIGHT - 1);
  1302. new LLOverlayBar(bar_rect);
  1303. // Panel containing chatbar, toolbar, and overlay, over floaters
  1304. LLRect bottom_rect(-1, 2 * gStatusBarHeight + CHAT_BAR_HEIGHT,
  1305. width + 1, -1);
  1306. gBottomPanelp = new LLBottomPanel(bottom_rect);
  1307. // The order here is important
  1308. gBottomPanelp->addChild(gChatBarp);
  1309. gBottomPanelp->addChild(gToolBarp);
  1310. gBottomPanelp->addChild(gOverlayBarp);
  1311. mRootView->addChild(gBottomPanelp);
  1312. mRootView->addChild(new HBLuaSideBar());
  1313. mRootView->sendChildToBack(gLuaSideBarp);
  1314. // View for hover information
  1315. gHoverViewp = new LLHoverView(full_window);
  1316. gHoverViewp->setVisible(true);
  1317. mRootView->addChild(gHoverViewp);
  1318. new LLIMMgr();
  1319. LLRect morph_view_rect = full_window;
  1320. morph_view_rect.stretch(-gStatusBarHeight);
  1321. morph_view_rect.mTop = full_window.mTop - 32;
  1322. gMorphViewp = new LLMorphView(morph_view_rect);
  1323. mRootView->addChild(gMorphViewp);
  1324. gMorphViewp->setVisible(false);
  1325. LLPanelWorldMap::initClass();
  1326. gFloaterWorldMapp = new LLFloaterWorldMap();
  1327. // Open teleport history floater and hide it initially
  1328. gFloaterTeleportHistoryp = new HBFloaterTeleportHistory();
  1329. //
  1330. // Tools for building
  1331. //
  1332. // Toolbox floater
  1333. init_menus();
  1334. gFloaterToolsp = new LLFloaterTools();
  1335. // Status bar
  1336. S32 menu_bar_height = gMenuBarViewp->getRect().getHeight();
  1337. LLRect root_rect = mRootView->getRect();
  1338. LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(),
  1339. root_rect.getHeight() - menu_bar_height);
  1340. gStatusBarp = new LLStatusBar(status_rect);
  1341. gStatusBarp->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP);
  1342. gStatusBarp->reshape(root_rect.getWidth(),
  1343. gStatusBarp->getRect().getHeight(), true);
  1344. gStatusBarp->translate(0,
  1345. root_rect.getHeight() -
  1346. gStatusBarp->getRect().getHeight());
  1347. // Sync bg color with menu bar
  1348. gStatusBarp->setBackgroundColor(gMenuBarViewp->getBackgroundColor());
  1349. LLFloaterChatterBox::createInstance(LLSD());
  1350. mRootView->addChild(gStatusBarp);
  1351. // Menu holder must be a child of the root view as well
  1352. mRootView->addChild(gMenuHolderp);
  1353. // Menu holder appears on top to get first pass at all mouse events
  1354. mRootView->sendChildToFront(gMenuHolderp);
  1355. if (gAudiop)
  1356. {
  1357. gAudiop->setMuted(false);
  1358. }
  1359. }
  1360. }
  1361. // Destroy the UI
  1362. void LLViewerWindow::shutdownViews()
  1363. {
  1364. gSavedSettings.setS32("FloaterViewBottom",
  1365. gFloaterViewp->getRect().mBottom);
  1366. gFocusMgr.unlockFocus();
  1367. gFocusMgr.setMouseCapture(NULL);
  1368. gFocusMgr.setKeyboardFocus(NULL);
  1369. gFocusMgr.setTopCtrl(NULL);
  1370. if (gWindowp)
  1371. {
  1372. gWindowp->allowLanguageTextInput(NULL, false);
  1373. }
  1374. // Cleanup global views
  1375. if (gMorphViewp)
  1376. {
  1377. gMorphViewp->setVisible(false);
  1378. }
  1379. // DEV-40930: clear sModalStack. Otherwise, any LLModalDialog left open
  1380. // will crump with llerrs.
  1381. LLModalDialog::shutdownModals();
  1382. llinfos << "LLModalDialog shut down." << llendl;
  1383. cleanup_menus();
  1384. llinfos << "Menus destroyed" << llendl;
  1385. delete gFloaterTeleportHistoryp;
  1386. delete gFloaterWorldMapp;
  1387. delete gFloaterToolsp;
  1388. // Delete all child views.
  1389. if (mRootView)
  1390. {
  1391. delete mRootView;
  1392. mRootView = NULL;
  1393. // Automatically deleted as children of mRootView:
  1394. mProgressView = NULL;
  1395. gFloaterViewp = NULL;
  1396. gSnapshotFloaterViewp = NULL;
  1397. gConsolep = NULL;
  1398. gChatBarp = NULL;
  1399. llinfos << "Root view and children destroyed." << llendl;
  1400. }
  1401. else
  1402. {
  1403. llwarns << "Root view was already destroyed." << llendl;
  1404. }
  1405. llinfos << "Destroying IM manager." << llendl;
  1406. delete gIMMgrp;
  1407. }
  1408. // Shuts down GL cleanly. Order is very important here.
  1409. void LLViewerWindow::shutdownGL()
  1410. {
  1411. stop_glerror();
  1412. LLFontGL::destroyDefaultFonts();
  1413. LLFontManager::cleanupClass();
  1414. llinfos << "Fonts destroyed" << llendl;
  1415. gSky.cleanup();
  1416. stop_glerror();
  1417. llinfos << "Sky cleaned up" << llendl;
  1418. gPipeline.cleanup();
  1419. stop_glerror();
  1420. llinfos << "Pipeline cleaned up" << llendl;
  1421. // MUST clean up pipeline before cleaning up wearables
  1422. LLWearableList::getInstance()->cleanup();
  1423. llinfos << "Wearables cleaned up" << llendl;
  1424. gTextureList.shutdown();
  1425. stop_glerror();
  1426. llinfos << "Texture list shut down" << llendl;
  1427. gBumpImageList.destroyGL();
  1428. stop_glerror();
  1429. llinfos << "Cleaned up bump map images" << llendl;
  1430. LLViewerTextureManager::cleanup();
  1431. llinfos << "Cleaned up textures and GL images" << llendl;
  1432. gSelectMgr.cleanup();
  1433. llinfos << "Cleaned up select manager" << llendl;
  1434. llinfos << "Stopping GL during shutdown" << llendl;
  1435. stopGL(false);
  1436. gGL.shutdown();
  1437. llinfos << "GL shutdown" << llendl;
  1438. LLVertexBuffer::cleanupClass();
  1439. llinfos << "LLVertexBuffer cleaned up." << llendl;
  1440. stop_glerror();
  1441. }
  1442. // Note: shutdownViews() and shutdownGL() need to be called first
  1443. LLViewerWindow::~LLViewerWindow()
  1444. {
  1445. llinfos << "Destroying Window" << llendl;
  1446. destroyWindow();
  1447. if (mDebugText)
  1448. {
  1449. delete mDebugText;
  1450. mDebugText = NULL;
  1451. llinfos << "Debug text deleted." << llendl;
  1452. }
  1453. if (mToolTip)
  1454. {
  1455. delete mToolTip;
  1456. mToolTip = NULL;
  1457. llinfos << "Tool tip deleted." << llendl;
  1458. }
  1459. LLViewerShaderMgr::releaseInstance();
  1460. llinfos << "LLViewerShaderMgr instance released." << llendl;
  1461. LLImageGL::stopThread();
  1462. }
  1463. void LLViewerWindow::setCursor(ECursorType c)
  1464. {
  1465. gWindowp->setCursor(c);
  1466. }
  1467. void LLViewerWindow::showCursor()
  1468. {
  1469. gWindowp->showCursor();
  1470. mCursorHidden = false;
  1471. }
  1472. void LLViewerWindow::hideCursor()
  1473. {
  1474. // Hide tooltips
  1475. if (mToolTip)
  1476. {
  1477. mToolTip->setVisible(false);
  1478. }
  1479. // Also hide hover info
  1480. if (gHoverViewp)
  1481. {
  1482. gHoverViewp->cancelHover();
  1483. }
  1484. // And hide the cursor
  1485. gWindowp->hideCursor();
  1486. mCursorHidden = true;
  1487. }
  1488. void LLViewerWindow::sendShapeToSim()
  1489. {
  1490. LLMessageSystem* msg = gMessageSystemp;
  1491. if (!msg) return;
  1492. msg->newMessageFast(_PREHASH_AgentHeightWidth);
  1493. msg->nextBlockFast(_PREHASH_AgentData);
  1494. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1495. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1496. msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
  1497. msg->nextBlockFast(_PREHASH_HeightWidthBlock);
  1498. msg->addU32Fast(_PREHASH_GenCounter, 0);
  1499. U16 height16 = (U16)mWindowRect.getHeight();
  1500. U16 width16 = (U16)mWindowRect.getWidth();
  1501. msg->addU16Fast(_PREHASH_Height, height16);
  1502. msg->addU16Fast(_PREHASH_Width, width16);
  1503. gAgent.sendReliableMessage();
  1504. }
  1505. // Must be called after the window is created to set up agent camera variables
  1506. // and UI variables.
  1507. void LLViewerWindow::reshape(S32 width, S32 height)
  1508. {
  1509. // Destroying the window at quit time generates spurious reshape messages.
  1510. // We do not care about these, and we do not want to send messages because
  1511. // the message system may have been destructed.
  1512. if (!LLApp::isExiting())
  1513. {
  1514. if (gMenuHolderp)
  1515. {
  1516. gMenuHolderp->hideMenus();
  1517. }
  1518. glViewport(0, 0, width, height);
  1519. if (height > 0)
  1520. {
  1521. gViewerCamera.setViewHeightInPixels(height);
  1522. if (gWindowp->getFullscreen())
  1523. {
  1524. // Force to 4:3 aspect for odd resolutions
  1525. gViewerCamera.setAspect(getDisplayAspectRatio());
  1526. }
  1527. else
  1528. {
  1529. gViewerCamera.setAspect(width / (F32) height);
  1530. }
  1531. }
  1532. // Update our window rectangle
  1533. mWindowRect.mRight = mWindowRect.mLeft + width;
  1534. mWindowRect.mTop = mWindowRect.mBottom + height;
  1535. calcDisplayScale();
  1536. bool display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
  1537. LLUI::sGLScaleFactor = mDisplayScale;
  1538. // Update our window rectangle
  1539. F32 divisor_x = mDisplayScaleDivisor.mV[VX];
  1540. F32 divisor_y = mDisplayScaleDivisor.mV[VY];
  1541. mVirtualWindowRect.mRight = mVirtualWindowRect.mLeft +
  1542. ll_roundp((F32)width * divisor_x);
  1543. mVirtualWindowRect.mTop = mVirtualWindowRect.mBottom +
  1544. ll_roundp((F32)height * divisor_y);
  1545. setupViewport();
  1546. // Inform lower views of the change; round up when converting
  1547. // coordinates to make sure there are no gaps at edge of window.
  1548. LLView::sForceReshape = display_scale_changed;
  1549. mRootView->reshape(llceil((F32)width * divisor_x),
  1550. llceil((F32)height * divisor_y));
  1551. LLView::sForceReshape = false;
  1552. // Clear font width caches
  1553. if (display_scale_changed)
  1554. {
  1555. LLHUDText::reshape();
  1556. }
  1557. sendShapeToSim();
  1558. // Store new settings for the mode we are in, regardless
  1559. if (!gWindowp->getFullscreen())
  1560. {
  1561. // Only save size if not maximized
  1562. bool maximized = gWindowp->getMaximized();
  1563. gSavedSettings.setBool("WindowMaximized", maximized);
  1564. LLCoordScreen window_size;
  1565. if (!maximized && gWindowp->getSize(&window_size))
  1566. {
  1567. gSavedSettings.setS32("WindowWidth", window_size.mX);
  1568. gSavedSettings.setS32("WindowHeight", window_size.mY);
  1569. }
  1570. }
  1571. gViewerStats.setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
  1572. gViewerStats.setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
  1573. gResizeScreenTexture = gScreenIsDirty = true;
  1574. }
  1575. }
  1576. // Hide normal UI when a logon fails
  1577. void LLViewerWindow::setNormalControlsVisible(bool visible)
  1578. {
  1579. if (gBottomPanelp)
  1580. {
  1581. gBottomPanelp->setVisible(visible);
  1582. gBottomPanelp->setEnabled(visible);
  1583. }
  1584. if (gMenuBarViewp)
  1585. {
  1586. gMenuBarViewp->setVisible(visible);
  1587. gMenuBarViewp->setEnabled(visible);
  1588. // ...and set the menu color appropriately.
  1589. setMenuBackgroundColor();
  1590. }
  1591. if (gStatusBarp)
  1592. {
  1593. gStatusBarp->setVisible(visible);
  1594. gStatusBarp->setEnabled(visible);
  1595. }
  1596. }
  1597. void LLViewerWindow::setMenuBackgroundColor()
  1598. {
  1599. LLColor4 new_bg_color;
  1600. if (gAgent.getGodLevel() > GOD_NOT)
  1601. {
  1602. if (gIsInProductionGrid)
  1603. {
  1604. new_bg_color = gColors.getColor("MenuBarGodBgColor");
  1605. }
  1606. else
  1607. {
  1608. new_bg_color = gColors.getColor("MenuNonProductionGodBgColor");
  1609. }
  1610. }
  1611. else if (gIsInProductionGrid)
  1612. {
  1613. new_bg_color = gColors.getColor("MenuBarBgColor");
  1614. }
  1615. else
  1616. {
  1617. new_bg_color = gColors.getColor("MenuNonProductionBgColor");
  1618. }
  1619. if (gMenuBarViewp)
  1620. {
  1621. gMenuBarViewp->setBackgroundColor(new_bg_color);
  1622. }
  1623. if (gStatusBarp)
  1624. {
  1625. gStatusBarp->setBackgroundColor(new_bg_color);
  1626. }
  1627. }
  1628. void LLViewerWindow::updateDebugText()
  1629. {
  1630. if (mDebugText)
  1631. {
  1632. mDebugText->update();
  1633. }
  1634. }
  1635. void LLViewerWindow::drawDebugText()
  1636. {
  1637. gUIProgram.bind();
  1638. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  1639. gGL.pushMatrix();
  1640. gGL.pushUIMatrix();
  1641. // Scale view by UI global scale factor and aspect ratio correction factor
  1642. gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
  1643. if (mDebugText)
  1644. {
  1645. mDebugText->draw();
  1646. }
  1647. gGL.popUIMatrix();
  1648. gGL.popMatrix();
  1649. gGL.flush();
  1650. gUIProgram.unbind();
  1651. }
  1652. void LLViewerWindow::draw()
  1653. {
  1654. if (!mRootView) return;
  1655. LLUI::setLineWidth(1.f);
  1656. LLUI::setLineWidth(1.f);
  1657. // Reset any left-over transforms
  1658. gGL.matrixMode(LLRender::MM_MODELVIEW);
  1659. gGL.loadIdentity();
  1660. // *HACK: for timecode debugging
  1661. static LLCachedControl<bool> display_timecode(gSavedSettings,
  1662. "DisplayTimecode");
  1663. if (display_timecode)
  1664. {
  1665. // Draw timecode block
  1666. std::string text;
  1667. gGL.loadIdentity();
  1668. microsecondsToTimecodeString(gFrameTime,text);
  1669. static const LLFontGL* font = LLFontGL::getFontSansSerif();
  1670. font->renderUTF8(text, 0,
  1671. ll_roundp(getWindowWidth() / 2 - 100.f),
  1672. ll_roundp(getWindowHeight() - 60.f),
  1673. LLColor4(1.f, 1.f, 1.f, 1.f),
  1674. LLFontGL::LEFT, LLFontGL::TOP);
  1675. }
  1676. // Draw all nested UI views.
  1677. // No translation needed, this view is glued to 0,0
  1678. gUIProgram.bind();
  1679. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  1680. gGL.pushMatrix();
  1681. LLUI::pushMatrix();
  1682. {
  1683. // Scale view by UI global scale factor and aspect ratio correction
  1684. // factor
  1685. gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
  1686. LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
  1687. // Apply camera zoom transform (for high res screenshots)
  1688. F32 zoom_factor = gViewerCamera.getZoomFactor();
  1689. S16 sub_region = gViewerCamera.getZoomSubRegion();
  1690. if (zoom_factor > 1.f)
  1691. {
  1692. // Decompose subregion number to x and y values
  1693. S32 pos_y = sub_region / llceil(zoom_factor);
  1694. S32 pos_x = sub_region - pos_y * llceil(zoom_factor);
  1695. // offset for this tile
  1696. gGL.translatef((F32)getWindowWidth() * -(F32)pos_x,
  1697. (F32)getWindowHeight() * -(F32)pos_y, 0.f);
  1698. gGL.scalef(zoom_factor, zoom_factor, 1.f);
  1699. LLUI::sGLScaleFactor *= zoom_factor;
  1700. }
  1701. // Draw tool specific overlay on world
  1702. gToolMgr.getCurrentTool()->draw();
  1703. if (gAgent.cameraMouselook())
  1704. {
  1705. drawMouselookInstructions();
  1706. }
  1707. // Draw all nested UI views.
  1708. // No translation needed, this view is glued to 0,0
  1709. mRootView->draw();
  1710. // Draw optional on-top-of-everyone view
  1711. LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
  1712. if (top_ctrl && top_ctrl->getVisible())
  1713. {
  1714. S32 screen_x, screen_y;
  1715. top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
  1716. gGL.matrixMode(LLRender::MM_MODELVIEW);
  1717. LLUI::pushMatrix();
  1718. LLUI::translate((F32) screen_x, (F32) screen_y, 0.f);
  1719. top_ctrl->draw();
  1720. LLUI::popMatrix();
  1721. }
  1722. // Draw tooltips; adjust their rectangle so they do not go off the top
  1723. // or bottom of the screen.
  1724. if (mToolTip && mToolTip->getVisible() && !mToolTipBlocked)
  1725. {
  1726. gGL.matrixMode(LLRender::MM_MODELVIEW);
  1727. LLUI::pushMatrix();
  1728. {
  1729. S32 tip_height = mToolTip->getRect().getHeight();
  1730. S32 screen_x, screen_y;
  1731. mToolTip->localPointToScreen(0, -24 - tip_height,
  1732. &screen_x, &screen_y);
  1733. // If tooltip would draw off the bottom of the screen, show it
  1734. // from the cursor tip position.
  1735. if (screen_y < tip_height)
  1736. {
  1737. mToolTip->localPointToScreen(0, 0, &screen_x, &screen_y);
  1738. }
  1739. LLUI::translate((F32) screen_x, (F32) screen_y, 0);
  1740. mToolTip->draw();
  1741. }
  1742. LLUI::popMatrix();
  1743. }
  1744. LLUI::sGLScaleFactor = old_scale_factor;
  1745. }
  1746. LLUI::popMatrix();
  1747. gGL.popMatrix();
  1748. gUIProgram.unbind();
  1749. stop_glerror();
  1750. }
  1751. static bool focus_chatbar_if_needed()
  1752. {
  1753. if (!gChatBarp || gFocusMgr.childHasKeyboardFocus(gChatBarp) ||
  1754. gAgent.cameraMouselook() || !gSavedSettings.getBool("AutoFocusChat"))
  1755. {
  1756. return false;
  1757. }
  1758. if (gChatBarp->getVisible() || LLFloaterChat::isFocused())
  1759. {
  1760. if (LLView::sDebugKeys)
  1761. {
  1762. llinfos << "Printable character detected, focusing chat bar"
  1763. << llendl;
  1764. }
  1765. LLChatBar::startChat(NULL);
  1766. return gFocusMgr.childHasKeyboardFocus(gChatBarp);
  1767. }
  1768. return false;
  1769. }
  1770. // Takes a single keydown event, usually when UI is visible
  1771. //virtual
  1772. bool LLViewerWindow::handleKey(KEY key, MASK mask)
  1773. {
  1774. sLastAcceleratorKey = 0;
  1775. if (LLView::sDebugKeys)
  1776. {
  1777. llinfos << "key = " << std::hex << (U32)key << std::dec << " - mask = "
  1778. << mask << llendl;
  1779. }
  1780. // Hide tooltips on keypress. Block until next time mouse is moved.
  1781. mToolTipBlocked = true;
  1782. // Also hide hover info on keypress
  1783. if (gHoverViewp)
  1784. {
  1785. gHoverViewp->cancelHover();
  1786. gHoverViewp->setTyping(true);
  1787. }
  1788. LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
  1789. if (keyboard_focus && !(mask & (MASK_CONTROL | MASK_ALT)) &&
  1790. !gFocusMgr.getKeystrokesOnly())
  1791. {
  1792. if (keyboard_focus->wantsKeyUpKeyDown()) // Media element
  1793. {
  1794. if (LLView::sDebugKeys)
  1795. {
  1796. llinfos << "Key handling passed to the focused media element"
  1797. << llendl;
  1798. }
  1799. return keyboard_focus->handleKey(key, mask, false);
  1800. }
  1801. if (key < 0x80)
  1802. {
  1803. // We have keyboard focus, and it is not an accelerator neither a
  1804. // special key, so likely (we hope) to generate a character. Let it
  1805. // fall through to character handler first.
  1806. if (LLView::sDebugKeys)
  1807. {
  1808. llinfos << "Key handling passed to the keyboard character handler"
  1809. << llendl;
  1810. }
  1811. return true;
  1812. }
  1813. }
  1814. // *HACK: look for UI editing keys
  1815. if (LLView::sEditingUI && LLFloaterEditUI::processKeystroke(key, mask))
  1816. {
  1817. if (LLView::sDebugKeys)
  1818. {
  1819. llinfos << "Key handled by the UI editor" << llendl;
  1820. }
  1821. return true;
  1822. }
  1823. // Handle shift-escape key (reset camera view)
  1824. if (key == KEY_ESCAPE && mask == MASK_SHIFT)
  1825. {
  1826. if (LLView::sDebugKeys)
  1827. {
  1828. llinfos << "Key handling for SHIFT ESC: resetting view" << llendl;
  1829. }
  1830. handle_reset_view();
  1831. return true;
  1832. }
  1833. // Let menus handle navigation keys
  1834. if (gLoginMenuBarViewp && gLoginMenuBarViewp->handleKey(key, mask, true))
  1835. {
  1836. if (LLView::sDebugKeys)
  1837. {
  1838. llinfos << "Key handled by the login menu bar" << llendl;
  1839. }
  1840. sLastAcceleratorKey = key;
  1841. return true;
  1842. }
  1843. if (gMenuBarViewp && gMenuBarViewp->handleKey(key, mask, true))
  1844. {
  1845. if (LLView::sDebugKeys)
  1846. {
  1847. llinfos << "Key handled by the menu bar" << llendl;
  1848. }
  1849. sLastAcceleratorKey = key;
  1850. return true;
  1851. }
  1852. // Traverses up the hierarchy
  1853. if (keyboard_focus)
  1854. {
  1855. // Arrow keys move avatar while chatting hack
  1856. if (gChatBarp && gChatBarp->inputEditorHasFocus())
  1857. {
  1858. if (gChatBarp->hasTextEditor() ||
  1859. gChatBarp->getCurrentChat().empty() ||
  1860. gSavedSettings.getBool("ArrowKeysMoveAvatar"))
  1861. {
  1862. switch (key)
  1863. {
  1864. case KEY_LEFT:
  1865. case KEY_RIGHT:
  1866. case KEY_UP:
  1867. case KEY_DOWN:
  1868. // Let CTRL-key pass through for chat line history
  1869. if (MASK_CONTROL == mask)
  1870. {
  1871. break;
  1872. }
  1873. case KEY_PAGE_UP:
  1874. case KEY_PAGE_DOWN:
  1875. case KEY_HOME:
  1876. // When chatbar is empty or ArrowKeysMoveAvatar set,
  1877. // pass arrow keys on to avatar...
  1878. if (LLView::sDebugKeys)
  1879. {
  1880. llinfos << "Key handling aborted as per ArrowKeysMoveAvatar"
  1881. << llendl;
  1882. }
  1883. return false;
  1884. default:
  1885. break;
  1886. }
  1887. }
  1888. }
  1889. if (keyboard_focus->handleKey(key, mask, false))
  1890. {
  1891. if (LLView::sDebugKeys)
  1892. {
  1893. llinfos << "Key handled by the keyboard focus holder"
  1894. << llendl;
  1895. }
  1896. return true;
  1897. }
  1898. }
  1899. if (gToolMgr.getCurrentTool()->handleKey(key, mask))
  1900. {
  1901. if (LLView::sDebugKeys)
  1902. {
  1903. llinfos << "Key handled by the tool manager" << llendl;
  1904. }
  1905. return true;
  1906. }
  1907. // Try for a new-format gesture
  1908. if (gGestureManager.triggerGesture(key, mask))
  1909. {
  1910. if (LLView::sDebugKeys)
  1911. {
  1912. llinfos << "Key handled by the gesture manager (1)" << llendl;
  1913. }
  1914. return true;
  1915. }
  1916. // See if this is a gesture trigger. If so, eat the key and do not pass it
  1917. // down to the menus.
  1918. if (gGestureList.trigger(key, mask))
  1919. {
  1920. if (LLView::sDebugKeys)
  1921. {
  1922. llinfos << "Key handled by the gesture manager (2)" << llendl;
  1923. }
  1924. return true;
  1925. }
  1926. // Give floaters first chance to handle TAB key so that frontmost floater
  1927. // gets focus. If nothing has focus, go to first or last UI element as
  1928. // appropriate.
  1929. if (key == KEY_TAB && ((mask & MASK_CONTROL) || !keyboard_focus))
  1930. {
  1931. if (LLView::sDebugKeys)
  1932. {
  1933. llinfos << "Key handling of the TAB key for focus cycling"
  1934. << llendl;
  1935. }
  1936. if (gMenuHolderp)
  1937. {
  1938. gMenuHolderp->hideMenus();
  1939. }
  1940. // If CTRL-tabbing (and not just TAB with no focus), go into window
  1941. // cycle mode
  1942. if (gFloaterViewp)
  1943. {
  1944. gFloaterViewp->setCycleMode((mask & MASK_CONTROL) != 0);
  1945. }
  1946. // Do CTRL-TAB and CTRL-SHIFT-TAB logic
  1947. if (mRootView)
  1948. {
  1949. if (mask & MASK_SHIFT)
  1950. {
  1951. mRootView->focusPrevRoot();
  1952. }
  1953. else
  1954. {
  1955. mRootView->focusNextRoot();
  1956. }
  1957. return true;
  1958. }
  1959. }
  1960. // Give menus a chance to handle accelerator keys
  1961. if (gLoginMenuBarViewp &&
  1962. gLoginMenuBarViewp->handleAcceleratorKey(key, mask))
  1963. {
  1964. if (LLView::sDebugKeys)
  1965. {
  1966. llinfos << "Key handled by the login menu accelerators" << llendl;
  1967. }
  1968. sLastAcceleratorKey = key;
  1969. return true;
  1970. }
  1971. if (gMenuBarViewp && gMenuBarViewp->handleAcceleratorKey(key, mask))
  1972. {
  1973. if (LLView::sDebugKeys)
  1974. {
  1975. llinfos << "Key handled by the menu accelerators" << llendl;
  1976. }
  1977. sLastAcceleratorKey = key;
  1978. return true;
  1979. }
  1980. // See if chat bar needs to be auto-focused.
  1981. if (key > 31 && key < 127 && (mask == MASK_NONE || mask == MASK_SHIFT))
  1982. {
  1983. if (focus_chatbar_if_needed())
  1984. {
  1985. keyboard_focus = gFocusMgr.getKeyboardFocus();
  1986. if (keyboard_focus->handleKey(key, mask, false))
  1987. {
  1988. if (LLView::sDebugKeys)
  1989. {
  1990. llinfos << "Key handled by the chat bar"<< llendl;
  1991. }
  1992. return true;
  1993. }
  1994. }
  1995. }
  1996. // Do not pass keys on to world when something in UI has focus
  1997. return gFocusMgr.childHasKeyboardFocus(mRootView) ||
  1998. LLMenuGL::getKeyboardMode() ||
  1999. (gMenuBarViewp && gMenuBarViewp->getHighlightedItem() &&
  2000. gMenuBarViewp->getHighlightedItem()->isActive());
  2001. }
  2002. //virtual
  2003. bool LLViewerWindow::handleKeyUp(KEY key, MASK mask)
  2004. {
  2005. LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
  2006. if (keyboard_focus && !(mask & (MASK_CONTROL | MASK_ALT)) &&
  2007. !gFocusMgr.getKeystrokesOnly())
  2008. {
  2009. if (keyboard_focus->wantsKeyUpKeyDown())
  2010. {
  2011. if (LLView::sDebugKeys)
  2012. {
  2013. llinfos << "Key Up handling passed to the media plugin"
  2014. << llendl;
  2015. }
  2016. return keyboard_focus->handleKeyUp(key, mask, false);
  2017. }
  2018. if (key < 0x80)
  2019. {
  2020. // We have keyboard focus, and it is not an accelerator neither a
  2021. // special key, so likely (we hope) to generate a character. Let it
  2022. // fall through to character handler first.
  2023. if (LLView::sDebugKeys)
  2024. {
  2025. llinfos << "Key Up handling passed to the keyboard character handler"
  2026. << llendl;
  2027. }
  2028. return true;
  2029. }
  2030. }
  2031. if (keyboard_focus)
  2032. {
  2033. if (keyboard_focus->handleKeyUp(key, mask, false))
  2034. {
  2035. if (LLView::sDebugKeys)
  2036. {
  2037. llinfos << "Key Up handled by the keyboard focus holder"
  2038. << llendl;
  2039. }
  2040. return true;
  2041. }
  2042. }
  2043. // Do not pass keys on to world when something in UI has focus
  2044. return gFocusMgr.childHasKeyboardFocus(mRootView) ||
  2045. LLMenuGL::getKeyboardMode() ||
  2046. (gMenuBarViewp && gMenuBarViewp->getHighlightedItem() &&
  2047. gMenuBarViewp->getHighlightedItem()->isActive());
  2048. }
  2049. //virtual
  2050. bool LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
  2051. {
  2052. if (!gKeyboardp) return true;
  2053. if (LLView::sDebugKeys)
  2054. {
  2055. llinfos << "key = " << std::hex << (U32)uni_char << std::dec
  2056. << " - mask = " << mask << " - Last accelerator key = "
  2057. << std::hex << (U32)sLastAcceleratorKey << std::dec << llendl;
  2058. }
  2059. // Do not eat-up accelerator keys: give menus a chance to handle keys.
  2060. if (mask & (MASK_CONTROL | MASK_ALT))
  2061. {
  2062. // *HACK: do not process twice the same key, when it was already
  2063. // accounted for as an accelerator key in handleKey()... HB
  2064. if (sLastAcceleratorKey)
  2065. {
  2066. if (LLView::sDebugKeys)
  2067. {
  2068. llinfos << "Key already handled by the menu accelerators in handleKey(), ignoring..."
  2069. << llendl;
  2070. }
  2071. sLastAcceleratorKey = 0;
  2072. return true;
  2073. }
  2074. if (gLoginMenuBarViewp)
  2075. {
  2076. KEY key = uni_char & 0xFFFF;
  2077. if (gLoginMenuBarViewp->handleAcceleratorKey(key, mask))
  2078. {
  2079. if (LLView::sDebugKeys)
  2080. {
  2081. llinfos << "Key handled by the login menu accelerators"
  2082. << llendl;
  2083. }
  2084. sLastAcceleratorKey = 0;
  2085. return true;
  2086. }
  2087. if (gLoginMenuBarViewp->handleUnicodeChar(uni_char, true))
  2088. {
  2089. if (LLView::sDebugKeys)
  2090. {
  2091. llinfos << "Key handled as a login menu jump key"
  2092. << llendl;
  2093. }
  2094. sLastAcceleratorKey = 0;
  2095. return true;
  2096. }
  2097. }
  2098. if (gMenuBarViewp)
  2099. {
  2100. KEY key = uni_char & 0xFFFF;
  2101. if (gMenuBarViewp->handleAcceleratorKey(key, mask))
  2102. {
  2103. if (LLView::sDebugKeys)
  2104. {
  2105. llinfos << "Key handled by the menu accelerators" << llendl;
  2106. }
  2107. sLastAcceleratorKey = 0;
  2108. return true;
  2109. }
  2110. if (gMenuBarViewp->handleUnicodeChar(uni_char, true))
  2111. {
  2112. if (LLView::sDebugKeys)
  2113. {
  2114. llinfos << "Key handled as a menu jump key" << llendl;
  2115. }
  2116. sLastAcceleratorKey = 0;
  2117. return true;
  2118. }
  2119. }
  2120. }
  2121. sLastAcceleratorKey = 0;
  2122. // *HACK: We delay processing of return keys until they arrive as a Unicode
  2123. // char, so that if you are typing chat text at low frame rate, we do not
  2124. // send the chat until all keystrokes have been entered. JC
  2125. // *HACK: Numeric keypad <enter> on Mac is Unicode 3
  2126. // *HACK: Control-M on Windows is Unicode 13
  2127. if ((uni_char == 13 && mask != MASK_CONTROL) ||
  2128. (uni_char == 3 && mask == MASK_NONE))
  2129. {
  2130. return gViewerKeyboard.handleKey(KEY_RETURN, mask,
  2131. gKeyboardp->getKeyRepeated(KEY_RETURN));
  2132. }
  2133. // Traverse up the hierarchy
  2134. LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
  2135. if (keyboard_focus)
  2136. {
  2137. if (LLView::sDebugKeys)
  2138. {
  2139. llinfos << "Traversing up the focused view hierarchy..." << llendl;
  2140. }
  2141. if (keyboard_focus->handleUnicodeChar(uni_char, false))
  2142. {
  2143. if (LLView::sDebugKeys)
  2144. {
  2145. llinfos << "Key got handled up in the hierarchy." << llendl;
  2146. }
  2147. return true;
  2148. }
  2149. else if (LLView::sDebugKeys)
  2150. {
  2151. llinfos << "Key was not handled up in the hierarchy." << llendl;
  2152. }
  2153. }
  2154. // See if the chat bar needs to be auto-focused. HB
  2155. bool is_media = keyboard_focus && keyboard_focus->wantsKeyUpKeyDown();
  2156. if (!is_media && uni_char > 31 && uni_char < 256 && uni_char != 127 &&
  2157. (mask == MASK_NONE || mask == MASK_SHIFT))
  2158. {
  2159. if (focus_chatbar_if_needed())
  2160. {
  2161. keyboard_focus = gFocusMgr.getKeyboardFocus();
  2162. if (keyboard_focus->handleUnicodeChar(uni_char, false))
  2163. {
  2164. if (LLView::sDebugKeys)
  2165. {
  2166. llinfos << "Key handled by the chat bar" << llendl;
  2167. }
  2168. return true;
  2169. }
  2170. }
  2171. }
  2172. return false;
  2173. }
  2174. //virtual
  2175. void LLViewerWindow::handleScrollWheel(S32 clicks)
  2176. {
  2177. LLView::sMouseHandlerMessage.clear();
  2178. gMouseIdleTimer.reset();
  2179. // Hide tooltips
  2180. if (mToolTip)
  2181. {
  2182. mToolTip->setVisible(false);
  2183. }
  2184. LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
  2185. if (mouse_captor)
  2186. {
  2187. S32 local_x;
  2188. S32 local_y;
  2189. mouse_captor->screenPointToLocal(mCurrentMousePoint.mX,
  2190. mCurrentMousePoint.mY,
  2191. &local_x, &local_y);
  2192. mouse_captor->handleScrollWheel(local_x, local_y, clicks);
  2193. if (LLView::sDebugMouseHandling)
  2194. {
  2195. llinfos << "Scroll wheel handled by captor "
  2196. << mouse_captor->getName() << llendl;
  2197. }
  2198. return;
  2199. }
  2200. LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
  2201. if (top_ctrl)
  2202. {
  2203. S32 local_x;
  2204. S32 local_y;
  2205. top_ctrl->screenPointToLocal(mCurrentMousePoint.mX,
  2206. mCurrentMousePoint.mY,
  2207. &local_x, &local_y);
  2208. if (top_ctrl->handleScrollWheel(local_x, local_y, clicks))
  2209. {
  2210. return;
  2211. }
  2212. }
  2213. if (mRootView->handleScrollWheel(mCurrentMousePoint.mX,
  2214. mCurrentMousePoint.mY, clicks))
  2215. {
  2216. if (LLView::sDebugMouseHandling)
  2217. {
  2218. llinfos << "Scroll wheel" << LLView::sMouseHandlerMessage
  2219. << llendl;
  2220. }
  2221. return;
  2222. }
  2223. if (LLView::sDebugMouseHandling)
  2224. {
  2225. llinfos << "Scroll wheel not handled by view" << llendl;
  2226. }
  2227. // Zoom the camera in and out behavior
  2228. gAgent.handleScrollWheel(clicks);
  2229. }
  2230. void LLViewerWindow::moveCursorToCenter()
  2231. {
  2232. S32 x = mVirtualWindowRect.getWidth() / 2;
  2233. S32 y = mVirtualWindowRect.getHeight() / 2;
  2234. // On a forced move, all deltas get zeroed out to prevent jumping
  2235. mCurrentMousePoint.set(x, y);
  2236. mLastMousePoint.set(x, y);
  2237. mCurrentMouseDelta.set(0, 0);
  2238. LLUI::setCursorPositionScreen(x, y);
  2239. }
  2240. bool LLViewerWindow::shouldShowToolTipFor(LLMouseHandler* mh)
  2241. {
  2242. if (mToolTip && mh)
  2243. {
  2244. LLMouseHandler::EShowToolTip showlevel = mh->getShowToolTip();
  2245. return (showlevel == LLMouseHandler::SHOW_ALWAYS ||
  2246. (showlevel == LLMouseHandler::SHOW_IF_NOT_BLOCKED &&
  2247. !mToolTipBlocked));
  2248. }
  2249. return false;
  2250. }
  2251. //virtual
  2252. bool LLViewerWindow::handleAnyMouseClick(LLWindow* window, LLCoordGL pos,
  2253. MASK mask,
  2254. LLMouseHandler::EClickType clicktype,
  2255. bool down)
  2256. {
  2257. std::string buttonname;
  2258. std::string buttonstatestr = down ? "down" : "up";
  2259. bool handled = false;
  2260. S32 x = pos.mX;
  2261. S32 y = pos.mY;
  2262. x = ll_round((F32)x * mDisplayScaleDivisor.mV[VX]);
  2263. y = ll_round((F32)y * mDisplayScaleDivisor.mV[VY]);
  2264. switch (clicktype)
  2265. {
  2266. case LLMouseHandler::CLICK_LEFT:
  2267. {
  2268. mLeftMouseDown = down;
  2269. buttonname = "Left";
  2270. break;
  2271. }
  2272. case LLMouseHandler::CLICK_RIGHT:
  2273. {
  2274. mRightMouseDown = down;
  2275. buttonname = "Right";
  2276. break;
  2277. }
  2278. case LLMouseHandler::CLICK_MIDDLE:
  2279. {
  2280. mMiddleMouseDown = down;
  2281. buttonname = "Middle";
  2282. break;
  2283. }
  2284. case LLMouseHandler::CLICK_DOUBLELEFT:
  2285. {
  2286. mLeftMouseDown = down;
  2287. buttonname = "Left Double Click";
  2288. }
  2289. }
  2290. LLView::sMouseHandlerMessage.clear();
  2291. if (gMenuBarViewp)
  2292. {
  2293. // Stop ALT-key access to menu
  2294. gMenuBarViewp->resetMenuTrigger();
  2295. }
  2296. if (gDebugClicks)
  2297. {
  2298. llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr
  2299. << " at " << x << "," << y << llendl;
  2300. }
  2301. // Make sure we get a corresponding mouse-up event, even if the mouse
  2302. // leaves the window
  2303. if (down)
  2304. {
  2305. gWindowp->captureMouse();
  2306. }
  2307. else
  2308. {
  2309. gWindowp->releaseMouse();
  2310. }
  2311. // Indicate mouse was active
  2312. gMouseIdleTimer.reset();
  2313. // Hide tooltips on mousedown
  2314. if (mToolTip && down)
  2315. {
  2316. mToolTipBlocked = true;
  2317. mToolTip->setVisible(false);
  2318. }
  2319. // Also hide hover info on mousedown/mouseup
  2320. if (gHoverViewp)
  2321. {
  2322. gHoverViewp->cancelHover();
  2323. }
  2324. // Do not let the user move the mouse out of the window until mouse up.
  2325. if (gToolMgr.getCurrentTool()->clipMouseWhenDown())
  2326. {
  2327. gWindowp->setMouseClipping(down);
  2328. }
  2329. LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
  2330. if (mouse_captor)
  2331. {
  2332. S32 local_x;
  2333. S32 local_y;
  2334. mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
  2335. if (LLView::sDebugMouseHandling)
  2336. {
  2337. llinfos << buttonname << " Mouse " << buttonstatestr
  2338. << " handled by captor " << mouse_captor->getName()
  2339. << llendl;
  2340. }
  2341. return mouse_captor->handleAnyMouseClick(local_x, local_y, mask,
  2342. clicktype, down);
  2343. }
  2344. // Topmost view gets a chance before the hierarchy
  2345. LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
  2346. if (top_ctrl)
  2347. {
  2348. S32 local_x, local_y;
  2349. top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
  2350. if (down)
  2351. {
  2352. if (top_ctrl->pointInView(local_x, local_y))
  2353. {
  2354. return top_ctrl->handleAnyMouseClick(local_x, local_y, mask,
  2355. clicktype, down);
  2356. }
  2357. else
  2358. {
  2359. gFocusMgr.setTopCtrl(NULL);
  2360. }
  2361. }
  2362. else
  2363. {
  2364. handled = top_ctrl->pointInView(local_x, local_y) &&
  2365. top_ctrl->handleMouseUp(local_x, local_y, mask);
  2366. }
  2367. }
  2368. // Give the UI views a chance to process the click
  2369. if (mRootView->handleAnyMouseClick(x, y, mask, clicktype, down))
  2370. {
  2371. if (LLView::sDebugMouseHandling)
  2372. {
  2373. llinfos << buttonname << " Mouse " << buttonstatestr << " "
  2374. << LLView::sMouseHandlerMessage << llendl;
  2375. }
  2376. return true;
  2377. }
  2378. else if (LLView::sDebugMouseHandling)
  2379. {
  2380. llinfos << buttonname << " Mouse " << buttonstatestr
  2381. << " not handled by view" << llendl;
  2382. }
  2383. if (down)
  2384. {
  2385. if (gDisconnected)
  2386. {
  2387. return false;
  2388. }
  2389. if (gToolMgr.getCurrentTool()->handleAnyMouseClick(x, y, mask,
  2390. clicktype, down))
  2391. {
  2392. // This is necessary to force clicks in the world to cause edit
  2393. // boxes that might have keyboard focus to relinquish it, and hence
  2394. // cause a commit to update their value. JC
  2395. gFocusMgr.setKeyboardFocus(NULL);
  2396. return true;
  2397. }
  2398. }
  2399. else
  2400. {
  2401. gWindowp->releaseMouse();
  2402. LLTool* tool = gToolMgr.getCurrentTool();
  2403. if (!handled)
  2404. {
  2405. handled = mRootView->handleAnyMouseClick(x, y, mask, clicktype, down);
  2406. }
  2407. if (!handled && tool)
  2408. {
  2409. handled = tool->handleAnyMouseClick(x, y, mask, clicktype, down);
  2410. }
  2411. }
  2412. return !down;
  2413. }
  2414. //virtual
  2415. bool LLViewerWindow::handleMouseDown(LLWindow* window, LLCoordGL pos,
  2416. MASK mask)
  2417. {
  2418. #if LL_DARWIN
  2419. mAllowMouseDragging = false;
  2420. if (!mMouseDownTimer.getStarted())
  2421. {
  2422. mMouseDownTimer.start();
  2423. }
  2424. else
  2425. {
  2426. mMouseDownTimer.reset();
  2427. }
  2428. #endif
  2429. return handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_LEFT,
  2430. true); // down
  2431. }
  2432. //virtual
  2433. bool LLViewerWindow::handleDoubleClick(LLWindow* window, LLCoordGL pos,
  2434. MASK mask)
  2435. {
  2436. // try handling as a double-click first, then a single-click if that wasn't
  2437. // handled.
  2438. return handleAnyMouseClick(window, pos, mask,
  2439. LLMouseHandler::CLICK_DOUBLELEFT, true) ||
  2440. handleMouseDown(window, pos, mask);
  2441. }
  2442. //virtual
  2443. bool LLViewerWindow::handleMouseUp(LLWindow* window, LLCoordGL pos, MASK mask)
  2444. {
  2445. #if LL_DARWIN
  2446. if (mMouseDownTimer.getStarted())
  2447. {
  2448. mMouseDownTimer.stop();
  2449. }
  2450. #endif
  2451. return handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_LEFT,
  2452. false); // up
  2453. }
  2454. //virtual
  2455. bool LLViewerWindow::handleRightMouseDown(LLWindow* window, LLCoordGL pos,
  2456. MASK mask)
  2457. {
  2458. S32 x = pos.mX;
  2459. S32 y = pos.mY;
  2460. x = ll_round((F32)x * mDisplayScaleDivisor.mV[VX]);
  2461. y = ll_round((F32)y * mDisplayScaleDivisor.mV[VY]);
  2462. LLView::sMouseHandlerMessage.clear();
  2463. if (handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_RIGHT,
  2464. true))
  2465. {
  2466. return true;
  2467. }
  2468. // *HACK: this should be rolled into the composite tool logic, not
  2469. // hardcoded at the top level.
  2470. if (gAgent.getCameraMode() != CAMERA_MODE_CUSTOMIZE_AVATAR &&
  2471. !gToolMgr.isCurrentTool(&gToolPie))
  2472. {
  2473. // If the current tool did not process the click, we should show the
  2474. // pie menu. This can be done by passing the event to the pie menu
  2475. // tool.
  2476. gToolPie.handleRightMouseDown(x, y, mask);
  2477. }
  2478. return true;
  2479. }
  2480. //virtual
  2481. bool LLViewerWindow::handleRightMouseUp(LLWindow* window, LLCoordGL pos,
  2482. MASK mask)
  2483. {
  2484. return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,
  2485. false); // Up
  2486. }
  2487. //virtual
  2488. bool LLViewerWindow::handleMiddleMouseDown(LLWindow* window, LLCoordGL pos,
  2489. MASK mask)
  2490. {
  2491. if (gVoiceClient.ready())
  2492. {
  2493. gVoiceClient.middleMouseState(true);
  2494. }
  2495. handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_MIDDLE, true);
  2496. // Always handled as far as the OS is concerned.
  2497. return true;
  2498. }
  2499. //virtual
  2500. bool LLViewerWindow::handleMiddleMouseUp(LLWindow* window, LLCoordGL pos,
  2501. MASK mask)
  2502. {
  2503. if (gVoiceClient.ready())
  2504. {
  2505. gVoiceClient.middleMouseState(false);
  2506. }
  2507. handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_MIDDLE,
  2508. false);
  2509. // Always handled as far as the OS is concerned.
  2510. return true;
  2511. }
  2512. // WARNING: this is potentially called multiple times per frame
  2513. //virtual
  2514. void LLViewerWindow::handleMouseMove(LLWindow* window, LLCoordGL pos,
  2515. MASK mask)
  2516. {
  2517. S32 x = pos.mX;
  2518. S32 y = pos.mY;
  2519. x = ll_round((F32)x * mDisplayScaleDivisor.mV[VX]);
  2520. y = ll_round((F32)y * mDisplayScaleDivisor.mV[VY]);
  2521. mMouseInWindow = true;
  2522. // Save mouse point for access during idle() and display()
  2523. LLCoordGL prev_saved_mouse_point = mCurrentMousePoint;
  2524. LLCoordGL mouse_point(x, y);
  2525. saveLastMouse(mouse_point);
  2526. bool actually_moved = // mouse is not currenty captured:
  2527. !gFocusMgr.getMouseCapture() &&
  2528. // mouse moved from last recorded position:
  2529. (prev_saved_mouse_point.mX != mCurrentMousePoint.mX ||
  2530. prev_saved_mouse_point.mY != mCurrentMousePoint.mY);
  2531. gMouseIdleTimer.reset();
  2532. gWindowp->showCursorFromMouseMove();
  2533. if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
  2534. {
  2535. gAgent.clearAFK();
  2536. }
  2537. if (actually_moved)
  2538. {
  2539. mToolTipBlocked = false;
  2540. }
  2541. // Activate the hover picker on mouse move.
  2542. if (gHoverViewp)
  2543. {
  2544. gHoverViewp->setTyping(false);
  2545. }
  2546. }
  2547. #if LL_DARWIN
  2548. //virtual
  2549. void LLViewerWindow::handleMouseDragged(LLWindow* window, LLCoordGL pos,
  2550. MASK mask)
  2551. {
  2552. if (mMouseDownTimer.getStarted())
  2553. {
  2554. if (mMouseDownTimer.getElapsedTimeF32() > 0.1)
  2555. {
  2556. mAllowMouseDragging = true;
  2557. mMouseDownTimer.stop();
  2558. }
  2559. }
  2560. if (mAllowMouseDragging || !gToolFocus.hasMouseCapture())
  2561. {
  2562. handleMouseMove(window, pos, mask);
  2563. }
  2564. }
  2565. #endif
  2566. //virtual
  2567. void LLViewerWindow::handleMouseLeave(LLWindow* window)
  2568. {
  2569. // Note: we would not get this if we had captured the mouse.
  2570. llassert(gFocusMgr.getMouseCapture() == NULL);
  2571. mMouseInWindow = false;
  2572. if (mToolTip)
  2573. {
  2574. mToolTip->setVisible(false);
  2575. }
  2576. }
  2577. //virtual
  2578. bool LLViewerWindow::handleCloseRequest(LLWindow* window)
  2579. {
  2580. // User has indicated they want to close, but we may need to ask about
  2581. // modified documents.
  2582. gAppViewerp->userQuit();
  2583. // Do not quit immediately
  2584. return false;
  2585. }
  2586. //virtual
  2587. void LLViewerWindow::handleQuit(LLWindow* window)
  2588. {
  2589. llinfos << "Quit window event received." << llendl;
  2590. gAppViewerp->forceQuit();
  2591. }
  2592. //virtual
  2593. void LLViewerWindow::handleResize(LLWindow* window, S32 width, S32 height)
  2594. {
  2595. reshape(width, height);
  2596. mResDirty = true;
  2597. }
  2598. // The top-level window has gained focus (e.g. via ALT-TAB)
  2599. //virtual
  2600. void LLViewerWindow::handleFocus(LLWindow* window)
  2601. {
  2602. gFocusMgr.setAppHasFocus(true);
  2603. LLModalDialog::onAppFocusGained();
  2604. gAgent.onAppFocusGained();
  2605. gToolMgr.onAppFocusGained();
  2606. gShowTextEditCursor = true;
  2607. // See if we are coming in with modifier keys held down
  2608. if (gKeyboardp)
  2609. {
  2610. gKeyboardp->resetMaskKeys();
  2611. }
  2612. }
  2613. // The top-level window has lost focus (e.g. via ALT-TAB)
  2614. //virtual
  2615. void LLViewerWindow::handleFocusLost(LLWindow* window)
  2616. {
  2617. gFocusMgr.setAppHasFocus(false);
  2618. gToolMgr.onAppFocusLost();
  2619. gFocusMgr.setMouseCapture(NULL);
  2620. if (gMenuBarViewp)
  2621. {
  2622. // Stop ALT-key access to menu
  2623. gMenuBarViewp->resetMenuTrigger();
  2624. }
  2625. // Restore mouse cursor
  2626. showCursor();
  2627. gWindowp->setMouseClipping(false);
  2628. gShowTextEditCursor = false;
  2629. // If losing focus while keys are down, reset them.
  2630. if (gKeyboardp)
  2631. {
  2632. gKeyboardp->resetKeys();
  2633. }
  2634. }
  2635. //virtual
  2636. bool LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, bool repeated)
  2637. {
  2638. // Let the voice chat code check for its PTT key. Note that this never
  2639. // affects event processing.
  2640. if (gVoiceClient.ready())
  2641. {
  2642. gVoiceClient.keyDown(key, mask);
  2643. }
  2644. if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
  2645. {
  2646. gAgent.clearAFK();
  2647. }
  2648. // *NOTE: we want to interpret KEY_RETURN later when it arrives as a
  2649. // Unicode char, not as a keydown. Otherwise when client frame rate is
  2650. // really low, hitting return sends your chat text before it is all
  2651. // entered/processed.
  2652. if (key == KEY_RETURN && mask == MASK_NONE)
  2653. {
  2654. // RIDER: although, at times some of the controls (in particular the
  2655. // CEF viewer would like to know about the KEYDOWN for an enter key...
  2656. // So ask and pass it along.
  2657. LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
  2658. if (!keyboard_focus || !keyboard_focus->wantsReturnKey())
  2659. {
  2660. return false;
  2661. }
  2662. }
  2663. return gViewerKeyboard.handleKey(key, mask, repeated);
  2664. }
  2665. //virtual
  2666. bool LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
  2667. {
  2668. // Let the voice chat code check for its PTT key. Note that this never
  2669. // affects event processing.
  2670. if (gVoiceClient.ready())
  2671. {
  2672. gVoiceClient.keyUp(key, mask);
  2673. }
  2674. return gViewerKeyboard.handleKeyUp(key, mask);
  2675. }
  2676. //virtual
  2677. void LLViewerWindow::handleScanKey(KEY key, bool key_down, bool key_up,
  2678. bool key_level)
  2679. {
  2680. LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
  2681. return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
  2682. }
  2683. //virtual
  2684. bool LLViewerWindow::handleActivate(LLWindow* window, bool activated)
  2685. {
  2686. if (activated)
  2687. {
  2688. mActive = true;
  2689. LLWorld::sendAgentResume();
  2690. gAgent.clearAFK();
  2691. if (gWindowp->getFullscreen() && !mIgnoreActivate)
  2692. {
  2693. if (!LLApp::isExiting())
  2694. {
  2695. if (LLStartUp::isLoggedIn())
  2696. {
  2697. // If we are in world, show a progress bar to hide
  2698. // reloading of textures
  2699. llinfos << "Restoring GL during activate" << llendl;
  2700. restoreGL("Restoring...");
  2701. }
  2702. else
  2703. {
  2704. // Otherwise restore immediately
  2705. restoreGL();
  2706. }
  2707. }
  2708. else
  2709. {
  2710. llwarns << "Activating while quitting" << llendl;
  2711. }
  2712. }
  2713. // Unmute audio
  2714. audio_update_volume();
  2715. }
  2716. else
  2717. {
  2718. mActive = false;
  2719. gAppViewerp->idleAFKCheck(true);
  2720. if (gAgent.cameraMouselook())
  2721. {
  2722. // Switch back to mouselook toolset
  2723. gToolMgr.setCurrentToolset(gMouselookToolset);
  2724. gSelectMgr.deselectAll();
  2725. gViewerWindowp->hideCursor();
  2726. gViewerWindowp->moveCursorToCenter();
  2727. }
  2728. LLWorld::sendAgentPause();
  2729. if (gWindowp->getFullscreen() && !mIgnoreActivate)
  2730. {
  2731. llinfos << "Stopping GL during deactivation" << llendl;
  2732. stopGL();
  2733. }
  2734. // Mute audio
  2735. audio_update_volume();
  2736. }
  2737. return true;
  2738. }
  2739. //virtual
  2740. bool LLViewerWindow::handleActivateApp(LLWindow* window, bool activating)
  2741. {
  2742. LLViewerJoystick::getInstance()->setNeedsReset(true);
  2743. return false;
  2744. }
  2745. //virtual
  2746. void LLViewerWindow::handleMenuSelect(LLWindow* window, S32 menu_item)
  2747. {
  2748. }
  2749. //virtual
  2750. bool LLViewerWindow::handlePaint(LLWindow* window, S32 x, S32 y, S32 width,
  2751. S32 height)
  2752. {
  2753. return false;
  2754. }
  2755. //virtual
  2756. void LLViewerWindow::handleScrollWheel(LLWindow* window, S32 clicks)
  2757. {
  2758. handleScrollWheel(clicks);
  2759. }
  2760. //virtual
  2761. void LLViewerWindow::handleWindowBlock(LLWindow* window)
  2762. {
  2763. LLWorld::sendAgentPause();
  2764. }
  2765. //virtual
  2766. void LLViewerWindow::handleWindowUnblock(LLWindow* window)
  2767. {
  2768. LLWorld::sendAgentResume();
  2769. }
  2770. //virtual
  2771. void LLViewerWindow::handleDataCopy(LLWindow*, S32 data_type, void* data)
  2772. {
  2773. constexpr S32 SLURL_MESSAGE_TYPE = 0;
  2774. if (data_type == SLURL_MESSAGE_TYPE)
  2775. {
  2776. // Received URL
  2777. std::string url = (const char*)data;
  2778. if (LLURLDispatcher::dispatch(url, "", NULL, false))
  2779. {
  2780. // Bring window to foreground, as it has just been "launched" from
  2781. // an URL.
  2782. gWindowp->bringToFront();
  2783. }
  2784. }
  2785. }
  2786. #if LL_WINDOWS
  2787. //virtual
  2788. bool LLViewerWindow::handleTimerEvent(LLWindow* window)
  2789. {
  2790. LLViewerJoystick* joystick = LLViewerJoystick::getInstance();
  2791. if (joystick->getOverrideCamera())
  2792. {
  2793. joystick->updateStatus();
  2794. return true;
  2795. }
  2796. return false;
  2797. }
  2798. //virtual
  2799. bool LLViewerWindow::handleDeviceChange(LLWindow* window)
  2800. {
  2801. // Give a chance to use a joystick after startup (hot-plugging)
  2802. LLViewerJoystick* joystick = LLViewerJoystick::getInstance();
  2803. if (!joystick->isJoystickInitialized())
  2804. {
  2805. joystick->init(true);
  2806. return true;
  2807. }
  2808. return false;
  2809. }
  2810. //virtual
  2811. bool LLViewerWindow::handleDPIChanged(LLWindow* window, F32 ui_scale_factor,
  2812. S32 window_width, S32 window_height)
  2813. {
  2814. if (LLApp::isExiting())
  2815. {
  2816. LL_DEBUGS("Window") << "Application is exiting, not reshaping the window."
  2817. << LL_ENDL;
  2818. return false;
  2819. }
  2820. // HiDPI scaling can be 4x. UI scaling in prefs is up to 2x, so max is 8x
  2821. if (ui_scale_factor < 0.75f || ui_scale_factor > 8.f)
  2822. {
  2823. llwarns << "DPI change caused UI scale to go out of bounds: "
  2824. << ui_scale_factor << ". Not reshaping window." << llendl;
  2825. return false;
  2826. }
  2827. LL_DEBUGS("Window") << "Reshaping the window..." << LL_ENDL;
  2828. reshape(window_width, window_height);
  2829. mResDirty = true;
  2830. return true;
  2831. }
  2832. #endif
  2833. //virtual
  2834. bool LLViewerWindow::handleWindowDidChangeScreen(LLWindow* window)
  2835. {
  2836. LLCoordScreen size;
  2837. gWindowp->getSize(&size);
  2838. reshape(size.mX, size.mY);
  2839. return true;
  2840. }
  2841. ///////////////////////////////////////////////////////////////////////////////
  2842. //
  2843. // Hover handlers
  2844. //
  2845. // Update UI based on stored mouse position from mouse-move event processing.
  2846. bool LLViewerWindow::handlePerFrameHover()
  2847. {
  2848. static std::string last_handle_msg;
  2849. LLView::sMouseHandlerMessage.clear();
  2850. if (!gFloaterViewp || !gKeyboardp) return true;
  2851. const S32 x = mCurrentMousePoint.mX;
  2852. const S32 y = mCurrentMousePoint.mY;
  2853. MASK mask = gKeyboardp->currentMask(true);
  2854. // RN: fix for asynchronous notification of mouse leaving window not
  2855. // working
  2856. LLCoordWindow mouse_pos;
  2857. gWindowp->getCursorPosition(&mouse_pos);
  2858. if (mouse_pos.mX < 0 || mouse_pos.mY < 0 ||
  2859. mouse_pos.mX > mWindowRect.getWidth() ||
  2860. mouse_pos.mY > mWindowRect.getHeight())
  2861. {
  2862. mMouseInWindow = false;
  2863. }
  2864. else
  2865. {
  2866. mMouseInWindow = true;
  2867. }
  2868. S32 dx = lltrunc((F32)(mCurrentMousePoint.mX - mLastMousePoint.mX) *
  2869. LLUI::sGLScaleFactor.mV[VX]);
  2870. S32 dy = lltrunc((F32)(mCurrentMousePoint.mY - mLastMousePoint.mY) *
  2871. LLUI::sGLScaleFactor.mV[VY]);
  2872. LLVector2 mouse_vel;
  2873. static LLCachedControl<bool> mouse_smooth(gSavedSettings, "MouseSmooth");
  2874. if (mouse_smooth)
  2875. {
  2876. static F32 fdx = 0.f;
  2877. static F32 fdy = 0.f;
  2878. F32 amount = llmin(gFrameIntervalSeconds * 16.f, 1.f);
  2879. fdx = fdx + ((F32)dx - fdx) * amount;
  2880. fdy = fdy + ((F32)dy - fdy) * amount;
  2881. mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy));
  2882. mouse_vel.set(fdx, fdy);
  2883. }
  2884. else
  2885. {
  2886. mCurrentMouseDelta.set(dx, dy);
  2887. mouse_vel.set((F32)dx, (F32)dy);
  2888. }
  2889. sMouseVelocityStat.addValue(mouse_vel.length());
  2890. // Clean up current focus
  2891. LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocusUICtrl();
  2892. if (cur_focus)
  2893. {
  2894. if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
  2895. {
  2896. gFocusMgr.releaseFocusIfNeeded(cur_focus);
  2897. LLUICtrl* parent = cur_focus->getParentUICtrl();
  2898. const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
  2899. while (parent)
  2900. {
  2901. if (parent->isCtrl() &&
  2902. (parent->hasTabStop() || parent == focus_root) &&
  2903. !parent->getIsChrome() &&
  2904. parent->isInVisibleChain() &&
  2905. parent->isInEnabledChain())
  2906. {
  2907. if (!parent->focusFirstItem())
  2908. {
  2909. parent->setFocus(true);
  2910. }
  2911. break;
  2912. }
  2913. parent = parent->getParentUICtrl();
  2914. }
  2915. }
  2916. else if (cur_focus->isFocusRoot())
  2917. {
  2918. // Focus roots keep trying to delegate focus to their first valid
  2919. // descendant; this assumes that focus roots are not valid focus
  2920. // holders on their own.
  2921. cur_focus->focusFirstItem();
  2922. }
  2923. }
  2924. bool handled = false;
  2925. bool handled_by_top_ctrl = false;
  2926. LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
  2927. LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
  2928. if (mouse_captor)
  2929. {
  2930. // Pass hover events to object capturing mouse events.
  2931. S32 local_x;
  2932. S32 local_y;
  2933. mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
  2934. handled = mouse_captor->handleHover(local_x, local_y, mask);
  2935. if (LLView::sDebugMouseHandling)
  2936. {
  2937. llinfos << "Hover handled by captor " << mouse_captor->getName()
  2938. << llendl;
  2939. }
  2940. if (!handled)
  2941. {
  2942. LL_DEBUGS("UserInput") << "hover not handled by mouse captor"
  2943. << LL_ENDL;
  2944. }
  2945. }
  2946. else
  2947. {
  2948. if (top_ctrl)
  2949. {
  2950. S32 local_x, local_y;
  2951. top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
  2952. handled = top_ctrl->pointInView(local_x, local_y) &&
  2953. top_ctrl->handleHover(local_x, local_y, mask);
  2954. handled_by_top_ctrl = true;
  2955. }
  2956. if (!handled)
  2957. {
  2958. // x and y are from last time mouse was in window
  2959. // mMouseInWindow tracks *actual* mouse location
  2960. if (mMouseInWindow && mRootView->handleHover(x, y, mask))
  2961. {
  2962. if (LLView::sDebugMouseHandling &&
  2963. LLView::sMouseHandlerMessage != last_handle_msg)
  2964. {
  2965. last_handle_msg = LLView::sMouseHandlerMessage;
  2966. llinfos << "Hover" << LLView::sMouseHandlerMessage
  2967. << llendl;
  2968. }
  2969. handled = true;
  2970. }
  2971. else if (LLView::sDebugMouseHandling)
  2972. {
  2973. if (last_handle_msg != LLStringUtil::null)
  2974. {
  2975. last_handle_msg.clear();
  2976. llinfos << "Hover not handled by view" << llendl;
  2977. }
  2978. }
  2979. }
  2980. if (!handled)
  2981. {
  2982. LL_DEBUGS("UserInput") << "hover not handled by top view or root"
  2983. << LL_ENDL;
  2984. }
  2985. }
  2986. LLToolPie* toolpie = &gToolPie;
  2987. // *NOTE: sometimes tools handle the mouse as a captor, so this logic is a
  2988. // little confusing
  2989. LLTool* tool = NULL;
  2990. if (gHoverViewp)
  2991. {
  2992. tool = gToolMgr.getCurrentTool();
  2993. if (!handled && tool)
  2994. {
  2995. handled = tool->handleHover(x, y, mask);
  2996. if (!gWindowp->isCursorHidden())
  2997. {
  2998. gHoverViewp->updateHover(tool);
  2999. }
  3000. }
  3001. else
  3002. {
  3003. // Cancel hovering if any UI element handled the event.
  3004. gHoverViewp->cancelHover();
  3005. }
  3006. // Suppress the toolbox view if our source tool was the pie tool and
  3007. // we have overridden to something else.
  3008. mSuppressToolbox = gToolMgr.getBaseTool() == toolpie &&
  3009. gToolMgr.getCurrentTool() != toolpie;
  3010. }
  3011. // Show a new tool tip (or update one that is alrady shown)
  3012. bool tool_tip_handled = false;
  3013. std::string tool_tip_msg;
  3014. static LLCachedControl<F32> normal_tool_tip_delay(gSavedSettings,
  3015. "ToolTipDelay");
  3016. static LLCachedControl<F32> dad_tool_tip_delay(gSavedSettings,
  3017. "DragAndDropToolTipDelay");
  3018. F32 tooltip_delay = normal_tool_tip_delay;
  3019. // *HACK: hack for tool-based tooltips which need to pop up more quickly
  3020. // Also for show xui names as tooltips debug mode
  3021. if ((mouse_captor && !mouse_captor->isView()) || LLUI::sShowXUINames)
  3022. {
  3023. tooltip_delay = dad_tool_tip_delay;
  3024. }
  3025. if (handled && !gWindowp->isCursorHidden() &&
  3026. gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay)
  3027. {
  3028. LLRect screen_sticky_rect;
  3029. LLMouseHandler *mh;
  3030. S32 local_x, local_y;
  3031. if (mouse_captor)
  3032. {
  3033. mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
  3034. mh = mouse_captor;
  3035. }
  3036. else if (handled_by_top_ctrl)
  3037. {
  3038. top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
  3039. mh = top_ctrl;
  3040. }
  3041. else
  3042. {
  3043. local_x = x; local_y = y;
  3044. mh = mRootView;
  3045. }
  3046. bool tooltip_vis = false;
  3047. if (shouldShowToolTipFor(mh))
  3048. {
  3049. tool_tip_handled = mh->handleToolTip(local_x, local_y,
  3050. tool_tip_msg,
  3051. &screen_sticky_rect);
  3052. if (mToolTip && tool_tip_handled && !tool_tip_msg.empty())
  3053. {
  3054. mToolTipStickyRect = screen_sticky_rect;
  3055. mToolTip->setWrappedText(tool_tip_msg, 200);
  3056. mToolTip->reshapeToFitText();
  3057. mToolTip->setOrigin(x, y);
  3058. LLRect virtual_window_rect(0, getWindowHeight(),
  3059. getWindowWidth(), 0);
  3060. mToolTip->translateIntoRect(virtual_window_rect, false);
  3061. tooltip_vis = true;
  3062. }
  3063. }
  3064. if (mToolTip)
  3065. {
  3066. mToolTip->setVisible(tooltip_vis);
  3067. }
  3068. }
  3069. if (gFloaterToolsp && tool && tool != gToolNull &&
  3070. tool != &gToolCompInspect && tool != &gToolDragAndDrop &&
  3071. !LLPipeline::sFreezeTime)
  3072. {
  3073. LLMouseHandler* captor = gFocusMgr.getMouseCapture();
  3074. // With the null, inspect, or drag and drop tool, do not muck with
  3075. // visibility.
  3076. if (gFloaterToolsp->isMinimized() ||
  3077. (tool != toolpie && // Not default tool
  3078. // Not coming out of mouselook
  3079. tool != &gToolCompGun &&
  3080. // Not override in third person
  3081. !mSuppressToolbox &&
  3082. // Not in a special mode
  3083. gToolMgr.getCurrentToolset() != gFaceEditToolset &&
  3084. gToolMgr.getCurrentToolset() != gMouselookToolset &&
  3085. // Not dragging
  3086. (!captor || captor->isView())))
  3087. {
  3088. // Force floater tools to be visible (unless minimized)
  3089. if (!LLFloaterTools::isVisible())
  3090. {
  3091. gFloaterToolsp->open();
  3092. }
  3093. // Update the location of the blue box tool popup
  3094. LLCoordGL select_center_screen;
  3095. gFloaterToolsp->updatePopup(select_center_screen, mask);
  3096. }
  3097. else
  3098. {
  3099. gFloaterToolsp->setVisible(false);
  3100. }
  3101. }
  3102. if (gToolBarp)
  3103. {
  3104. gToolBarp->refresh();
  3105. }
  3106. if (gChatBarp)
  3107. {
  3108. gChatBarp->refresh();
  3109. }
  3110. if (gOverlayBarp)
  3111. {
  3112. if (gOverlayBarp->getVisible())
  3113. {
  3114. if (gAgent.cameraMouselook())
  3115. {
  3116. // Turn off the whole bar in mouselook
  3117. gOverlayBarp->setVisible(false);
  3118. }
  3119. }
  3120. else if (!gAgent.cameraMouselook())
  3121. {
  3122. // Turn on the bar when no more in mouse-look
  3123. gOverlayBarp->setVisible(true);
  3124. }
  3125. }
  3126. if (gLuaSideBarp)
  3127. {
  3128. if (gLuaSideBarp->getVisible())
  3129. {
  3130. if (gAgent.cameraMouselook())
  3131. {
  3132. // Turn off the whole bar in mouselook
  3133. gLuaSideBarp->setVisible(false);
  3134. }
  3135. }
  3136. else if (!gAgent.cameraMouselook())
  3137. {
  3138. // Turn on the bar when no more in mouse-look
  3139. gLuaSideBarp->setVisible(true);
  3140. }
  3141. }
  3142. // Update rectangles for the various toolbars
  3143. if (gOverlayBarp && gNotifyBoxViewp && gFloaterViewp && gConsolep &&
  3144. gToolBarp && gChatBarp)
  3145. {
  3146. LLRect bar_rect(-1, gStatusBarHeight, getWindowWidth() + 1, -1);
  3147. if (gToolBarp->getVisible())
  3148. {
  3149. gToolBarp->setRect(bar_rect);
  3150. bar_rect.translate(0, gStatusBarHeight - 1);
  3151. }
  3152. if (gChatBarp->getVisible())
  3153. {
  3154. // Fix up the height
  3155. LLRect chat_bar_rect = bar_rect;
  3156. chat_bar_rect.mTop = chat_bar_rect.mBottom + CHAT_BAR_HEIGHT + 1;
  3157. gChatBarp->setRect(chat_bar_rect);
  3158. bar_rect.translate(0, CHAT_BAR_HEIGHT - 1);
  3159. }
  3160. LLRect notify_box_rect = gNotifyBoxViewp->getRect();
  3161. notify_box_rect.mBottom = bar_rect.mBottom;
  3162. gNotifyBoxViewp->reshape(notify_box_rect.getWidth(),
  3163. notify_box_rect.getHeight());
  3164. gNotifyBoxViewp->setRect(notify_box_rect);
  3165. // Make sure floaters snap to visible rect by adjusting floater view
  3166. // rect
  3167. LLRect floater_rect = gFloaterViewp->getRect();
  3168. if (floater_rect.mBottom != bar_rect.mBottom + 1)
  3169. {
  3170. floater_rect.mBottom = bar_rect.mBottom + 1;
  3171. // Don't bounce the floaters up and down.
  3172. gFloaterViewp->reshapeFloater(floater_rect.getWidth(),
  3173. floater_rect.getHeight(),
  3174. true, ADJUST_VERTICAL_NO);
  3175. gFloaterViewp->setRect(floater_rect);
  3176. }
  3177. if (gOverlayBarp->getVisible())
  3178. {
  3179. LLRect overlay_rect = bar_rect;
  3180. overlay_rect.mTop = overlay_rect.mBottom + OVERLAY_BAR_HEIGHT;
  3181. // Fitt's Law: push buttons flush with bottom of screen if nothing
  3182. // else visible.
  3183. if (!gToolBarp->getVisible() && !gChatBarp->getVisible())
  3184. {
  3185. // *NOTE: this is highly depenent on the XML describing the
  3186. // position of the buttons
  3187. overlay_rect.translate(0, 0);
  3188. }
  3189. gOverlayBarp->setRect(overlay_rect);
  3190. gOverlayBarp->updateBoundingRect();
  3191. bar_rect.translate(0, gOverlayBarp->getRect().getHeight());
  3192. gFloaterViewp->setSnapOffsetBottom(OVERLAY_BAR_HEIGHT);
  3193. }
  3194. else
  3195. {
  3196. gFloaterViewp->setSnapOffsetBottom(0);
  3197. }
  3198. // Fix rectangle of bottom panel focus indicator
  3199. if (gBottomPanelp && gBottomPanelp->getFocusIndicator())
  3200. {
  3201. LLRect focus_rect = gBottomPanelp->getFocusIndicator()->getRect();
  3202. focus_rect.mTop = (gToolBarp->getVisible() ? gStatusBarHeight : 0) +
  3203. (gChatBarp->getVisible() ? CHAT_BAR_HEIGHT : 0) - 2;
  3204. gBottomPanelp->getFocusIndicator()->setRect(focus_rect);
  3205. }
  3206. // Always update console
  3207. LLRect console_rect = getChatConsoleRect();
  3208. console_rect.mBottom = bar_rect.mBottom - 8;
  3209. gConsolep->reshape(console_rect.getWidth(), console_rect.getHeight());
  3210. gConsolep->setRect(console_rect);
  3211. }
  3212. mLastMousePoint = mCurrentMousePoint;
  3213. // Last ditch force of edit menu to selection manager
  3214. if (!gEditMenuHandlerp && gSelectMgr.getSelection()->getObjectCount())
  3215. {
  3216. gEditMenuHandlerp = &gSelectMgr;
  3217. }
  3218. if (gFloaterViewp->getCycleMode())
  3219. {
  3220. // sync all floaters with their focus state
  3221. gFloaterViewp->highlightFocusedFloater();
  3222. gSnapshotFloaterViewp->highlightFocusedFloater();
  3223. // When user is holding down CTRL, do not update tab order of floaters
  3224. if ((gKeyboardp->currentMask(true) & MASK_CONTROL) == 0)
  3225. {
  3226. // Control key no longer held down, finish cycle mode
  3227. gFloaterViewp->setCycleMode(false);
  3228. gFloaterViewp->syncFloaterTabOrder();
  3229. }
  3230. }
  3231. else
  3232. {
  3233. // Update focused floater
  3234. gFloaterViewp->highlightFocusedFloater();
  3235. gSnapshotFloaterViewp->highlightFocusedFloater();
  3236. // Make sure floater visible order is in sync with tab order
  3237. gFloaterViewp->syncFloaterTabOrder();
  3238. }
  3239. static LLCachedControl<bool> chat_bar_steals_focus(gSavedSettings,
  3240. "ChatBarStealsFocus");
  3241. if (chat_bar_steals_focus && gChatBarp &&
  3242. gFocusMgr.getKeyboardFocus() == NULL &&
  3243. gChatBarp->isInVisibleChain())
  3244. {
  3245. LLChatBar::startChat(NULL);
  3246. }
  3247. // Cleanup unused selections when no modal dialogs are open
  3248. if (LLModalDialog::activeCount() == 0)
  3249. {
  3250. gViewerParcelMgr.deselectUnused();
  3251. }
  3252. if (LLModalDialog::activeCount() == 0)
  3253. {
  3254. gSelectMgr.deselectUnused();
  3255. }
  3256. if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
  3257. {
  3258. gDebugRaycastFaceHit = gDebugRaycastGLTFNodeHit =
  3259. gDebugRaycastGLTFPrimHit = -1;
  3260. gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1,
  3261. false, false,
  3262. &gDebugRaycastFaceHit,
  3263. &gDebugRaycastGLTFNodeHit,
  3264. &gDebugRaycastGLTFPrimHit,
  3265. &gDebugRaycastIntersection,
  3266. &gDebugRaycastTexCoord,
  3267. &gDebugRaycastNormal,
  3268. &gDebugRaycastTangent,
  3269. &gDebugRaycastStart,
  3270. &gDebugRaycastEnd);
  3271. gDebugRaycastParticle =
  3272. gPipeline.lineSegmentIntersectParticle(gDebugRaycastStart,
  3273. gDebugRaycastEnd,
  3274. &gDebugRaycastParticleIntersection,
  3275. NULL);
  3276. }
  3277. // Per frame picking for tooltips and changing cursor over interactive
  3278. // objects
  3279. static S32 previous_x = -1;
  3280. static S32 previous_y = -1;
  3281. bool mouse_moved_since_pick = previous_x != x || previous_y != y;
  3282. bool do_pick = false;
  3283. static LLCachedControl<F32> picks_moving(gSavedSettings,
  3284. "PicksPerSecondMouseMoving");
  3285. if (mouse_moved_since_pick && picks_moving > 0.f &&
  3286. mPickTimer.getElapsedTimeF32() > 1.f / picks_moving)
  3287. {
  3288. do_pick = true;
  3289. }
  3290. static LLCachedControl<F32> picks_stationary(gSavedSettings,
  3291. "PicksPerSecondMouseStationary");
  3292. if (!mouse_moved_since_pick && picks_stationary > 0.f &&
  3293. mPickTimer.getElapsedTimeF32() > 1.f / picks_stationary)
  3294. {
  3295. do_pick = true;
  3296. }
  3297. if (getCursorHidden())
  3298. {
  3299. do_pick = false;
  3300. }
  3301. if (LLViewerMediaFocus::getInstance()->getFocus())
  3302. {
  3303. // When in-world media is in focus, pick every frame so that browser
  3304. // mouse-overs, dragging scrollbars, etc. work properly.
  3305. do_pick = true;
  3306. }
  3307. if (do_pick)
  3308. {
  3309. mPickTimer.reset();
  3310. static LLCachedControl<bool> pick_transparent(gSavedSettings,
  3311. "AllowPickTransparent");
  3312. pickAsync(x, y, mask, hoverPickCallback, pick_transparent,
  3313. false, false, true);
  3314. }
  3315. previous_x = x;
  3316. previous_y = y;
  3317. return handled;
  3318. }
  3319. //static
  3320. void LLViewerWindow::hoverPickCallback(const LLPickInfo& pick_info)
  3321. {
  3322. gViewerWindowp->mHoverPick = pick_info;
  3323. }
  3324. void LLViewerWindow::saveLastMouse(const LLCoordGL& point)
  3325. {
  3326. // Store last mouse location; if the mouse leaves the window, pretend last
  3327. // point was on edge of window.
  3328. if (point.mX < 0)
  3329. {
  3330. mCurrentMousePoint.mX = 0;
  3331. }
  3332. else if (point.mX > getWindowWidth())
  3333. {
  3334. mCurrentMousePoint.mX = getWindowWidth();
  3335. }
  3336. else
  3337. {
  3338. mCurrentMousePoint.mX = point.mX;
  3339. }
  3340. if (point.mY < 0)
  3341. {
  3342. mCurrentMousePoint.mY = 0;
  3343. }
  3344. else if (point.mY > getWindowHeight())
  3345. {
  3346. mCurrentMousePoint.mY = getWindowHeight();
  3347. }
  3348. else
  3349. {
  3350. mCurrentMousePoint.mY = point.mY;
  3351. }
  3352. }
  3353. // Draws the selection outlines for the currently selected objects. Must be
  3354. // called after displayObjects is called, which sets the mGLName parameter
  3355. // NOTE: This function gets called 3 times:
  3356. // render_ui_3d: false, false, true
  3357. // renderObjectsForSelect: true, pick_parcel_wall, false
  3358. // render_hud_elements: false, false, false
  3359. void LLViewerWindow::renderSelections(bool for_gl_pick, bool pick_parcel_walls,
  3360. bool for_hud)
  3361. {
  3362. if (!for_hud && !for_gl_pick)
  3363. {
  3364. // Call this once and only once
  3365. gSelectMgr.updateSilhouettes();
  3366. }
  3367. // Draw fence around land selections
  3368. if (for_gl_pick)
  3369. {
  3370. if (pick_parcel_walls)
  3371. {
  3372. gViewerParcelMgr.renderParcelCollision();
  3373. }
  3374. stop_glerror();
  3375. return;
  3376. }
  3377. LLObjectSelectionHandle selection = gSelectMgr.getSelection();
  3378. bool is_hud = selection->getSelectType() == SELECT_TYPE_HUD;
  3379. if (for_hud != is_hud)
  3380. {
  3381. return;
  3382. }
  3383. gSelectMgr.renderSilhouettes(for_hud);
  3384. bool in_edit = gToolMgr.inEdit();
  3385. // *FIXME: this is a total hack (borrowed from Firestorm, Beq's code). The
  3386. // proper fix to the 0 LOD on some edited mesh objects would be to find
  3387. // why in the first place that low LOD gets wrongly used. So far, I did not
  3388. // find where this happens. HB
  3389. static LLCachedControl<S32> edit_lod(gSavedSettings, "EditedMeshLOD");
  3390. if (in_edit && !is_hud && edit_lod >= 0)
  3391. {
  3392. struct LLFunctorApplyLOD : public LLSelectedObjectFunctor
  3393. {
  3394. LLFunctorApplyLOD(S32 lod)
  3395. : mLOD(lod)
  3396. {
  3397. }
  3398. bool apply(LLViewerObject* objectp) override
  3399. {
  3400. if (objectp && objectp->isMesh())
  3401. {
  3402. ((LLVOVolume*)objectp)->tempSetLOD(mLOD);
  3403. }
  3404. return true;
  3405. }
  3406. S32 mLOD;
  3407. };
  3408. LLFunctorApplyLOD func(llmin((S32)edit_lod, 3));
  3409. selection->applyToObjects(&func);
  3410. }
  3411. // Setup HUD render
  3412. if (for_hud && gSelectMgr.getSelection()->getObjectCount())
  3413. {
  3414. LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
  3415. // Set-up transform to encompass bounding box of HUD
  3416. gGL.matrixMode(LLRender::MM_PROJECTION);
  3417. gGL.pushMatrix();
  3418. gGL.loadIdentity();
  3419. F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
  3420. F32 aspect = gViewerCamera.getAspect();
  3421. gGL.ortho(-0.5f * aspect, 0.5f * aspect, -0.5f, 0.5f, 0.f, depth);
  3422. gGL.matrixMode(LLRender::MM_MODELVIEW);
  3423. gGL.pushMatrix();
  3424. gGL.loadIdentity();
  3425. // Load Cory's favorite reference frame
  3426. gGL.loadMatrix(OGL_TO_CFR_ROT4A);
  3427. gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + depth * 0.5f, 0.f,
  3428. 0.f);
  3429. }
  3430. // Render light for editing
  3431. if (in_edit && LLSelectMgr::sRenderLightRadius)
  3432. {
  3433. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  3434. LLGLEnable gls_blend(GL_BLEND);
  3435. LLGLEnable gls_cull(GL_CULL_FACE);
  3436. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  3437. gGL.matrixMode(LLRender::MM_MODELVIEW);
  3438. gGL.pushMatrix();
  3439. if (selection->getSelectType() == SELECT_TYPE_HUD)
  3440. {
  3441. F32 zoom = gAgent.mHUDCurZoom;
  3442. gGL.scalef(zoom, zoom, zoom);
  3443. }
  3444. struct f final : public LLSelectedObjectFunctor
  3445. {
  3446. bool apply(LLViewerObject* object) override
  3447. {
  3448. LLDrawable* drawable = object->mDrawable;
  3449. if (drawable && drawable->isLight())
  3450. {
  3451. LLVOVolume* vovolume = drawable->getVOVolume();
  3452. gGL.pushMatrix();
  3453. LLVector3 center = drawable->getPositionAgent();
  3454. gGL.translatef(center[0], center[1], center[2]);
  3455. F32 scale = vovolume->getLightRadius();
  3456. gGL.scalef(scale, scale, scale);
  3457. LLColor4 color(vovolume->getLightSRGBColor(), 0.5f);
  3458. gGL.color4fv(color.mV);
  3459. // Render Outside
  3460. gSphere.render();
  3461. // Render Inside
  3462. glCullFace(GL_FRONT);
  3463. gSphere.render();
  3464. glCullFace(GL_BACK);
  3465. gGL.popMatrix();
  3466. }
  3467. return true;
  3468. }
  3469. } func;
  3470. gSelectMgr.getSelection()->applyToObjects(&func);
  3471. gGL.popMatrix();
  3472. }
  3473. // NOTE: The average position for the axis arrows of the selected objects
  3474. // should not be recalculated at this time. If they are, then group
  3475. // rotations will break.
  3476. // Draw arrows at average center of all selected objects
  3477. LLTool* tool = gToolMgr.getCurrentTool();
  3478. if (!tool)
  3479. {
  3480. stop_glerror();
  3481. return;
  3482. }
  3483. if (tool->isAlwaysRendered())
  3484. {
  3485. tool->render();
  3486. }
  3487. else if (!gSelectMgr.getSelection()->isEmpty())
  3488. {
  3489. bool sel_can_move, sel_is_mod_ok;
  3490. // *TODO: This might be costly to do on each frame and when a lot of
  3491. // objects are selected. We might be better off with some kind of
  3492. // memory for selection and/or states: consider optimizing, perhaps
  3493. // even some kind of selection generation at level of LLSelectMgr to
  3494. // make whole viewer benefit.
  3495. gSelectMgr.selectGetEditMoveLinksetPermissions(sel_can_move,
  3496. sel_is_mod_ok);
  3497. bool draw_handles = true;
  3498. if (!sel_is_mod_ok && tool == &gToolCompScale)
  3499. {
  3500. draw_handles = false;
  3501. }
  3502. else if (!sel_can_move &&
  3503. (tool == &gToolCompTranslate || tool == &gToolCompRotate))
  3504. {
  3505. draw_handles = false;
  3506. }
  3507. if (draw_handles)
  3508. {
  3509. tool->render();
  3510. }
  3511. }
  3512. if (is_hud && selection->getObjectCount())
  3513. {
  3514. gGL.matrixMode(LLRender::MM_PROJECTION);
  3515. gGL.popMatrix();
  3516. gGL.matrixMode(LLRender::MM_MODELVIEW);
  3517. gGL.popMatrix();
  3518. }
  3519. stop_glerror();
  3520. }
  3521. // Return a point near the clicked object representative of the place the
  3522. // object was clicked.
  3523. LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot,
  3524. LLViewerObject* clicked_object) const
  3525. {
  3526. // Create a normalized vector pointing from the camera center into the
  3527. // world at the location of the mouse click
  3528. LLVector3 mouse_direction_global = mouseDirectionGlobal(x, y_from_bot);
  3529. LLVector3d relative_object = clicked_object->getPositionGlobal() -
  3530. gAgent.getCameraPositionGlobal();
  3531. // Make mouse vector as long as object vector, so it touchs a point near
  3532. // where the user clicked on the object
  3533. mouse_direction_global *= (F32) relative_object.length();
  3534. LLVector3d new_pos;
  3535. new_pos.set(mouse_direction_global);
  3536. // Transform mouse vector back to world coords
  3537. new_pos += gAgent.getCameraPositionGlobal();
  3538. return new_pos;
  3539. }
  3540. void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask,
  3541. void (*callback)(const LLPickInfo& info),
  3542. bool pick_transparent, bool pick_rigged,
  3543. bool pick_particle, bool get_surface_info)
  3544. {
  3545. // Push back pick info object
  3546. if (LLFloaterTools::isVisible() || LLDrawPoolAlpha::sShowDebugAlpha)
  3547. {
  3548. // Build mode allows interaction with all transparent objects
  3549. // "Show Debug Alpha" means no object actually transparent
  3550. pick_transparent = true;
  3551. }
  3552. LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent,
  3553. pick_rigged, pick_particle, get_surface_info,
  3554. callback);
  3555. schedulePick(pick_info);
  3556. }
  3557. void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
  3558. {
  3559. if (mPicks.size() >= 1024 || gWindowp->getMinimized())
  3560. {
  3561. // Something went wrong, picks are being scheduled but not processed
  3562. if (pick_info.mPickCallback)
  3563. {
  3564. pick_info.mPickCallback(pick_info);
  3565. }
  3566. return;
  3567. }
  3568. mPicks.emplace_back(pick_info);
  3569. // Delay further event processing until we receive results of pick
  3570. gWindowp->delayInputProcessing();
  3571. }
  3572. void LLViewerWindow::performPick()
  3573. {
  3574. if (!mPicks.empty())
  3575. {
  3576. for (pick_info_list_t::iterator it = mPicks.begin(),
  3577. end = mPicks.end();
  3578. it != end; ++it)
  3579. {
  3580. it->fetchResults();
  3581. }
  3582. mLastPick = mPicks.back();
  3583. mPicks.clear();
  3584. }
  3585. }
  3586. void LLViewerWindow::returnEmptyPicks()
  3587. {
  3588. for (pick_info_list_t::iterator it = mPicks.begin(), end = mPicks.end();
  3589. it != end; ++it)
  3590. {
  3591. mLastPick = *it;
  3592. // Just trigger callback with empty results
  3593. if (it->mPickCallback)
  3594. {
  3595. it->mPickCallback(*it);
  3596. }
  3597. }
  3598. mPicks.clear();
  3599. }
  3600. // Performs the GL object/land pick.
  3601. LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot,
  3602. bool pick_transparent)
  3603. {
  3604. if (LLFloaterTools::isVisible() || LLDrawPoolAlpha::sShowDebugAlpha)
  3605. {
  3606. // Build mode allows interaction with all transparent objects
  3607. // "Show Debug Alpha" means no object actually transparent
  3608. pick_transparent = true;
  3609. }
  3610. // Shortcut queueing in mPicks and just update mLastPick in place
  3611. MASK key_mask = gKeyboardp ? gKeyboardp->currentMask(true) : 0;
  3612. mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask,
  3613. pick_transparent, false, false, true, NULL);
  3614. mLastPick.fetchResults();
  3615. return mLastPick;
  3616. }
  3617. LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y,
  3618. F32 depth,
  3619. LLVector4a* intersection)
  3620. {
  3621. S32 x = mouse_x;
  3622. S32 y = mouse_y;
  3623. if (mouse_x == -1 && mouse_y == -1) // use current mouse position
  3624. {
  3625. x = getCurrentMouseX();
  3626. y = getCurrentMouseY();
  3627. }
  3628. // World coordinates of mouse
  3629. // *TODO: VECTORIZE THIS
  3630. LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
  3631. LLVector3 mouse_point_global = gViewerCamera.getOrigin();
  3632. LLVector3 mouse_world_start = mouse_point_global;
  3633. LLVector3 mouse_world_end = mouse_point_global +
  3634. mouse_direction_global * depth;
  3635. LLVector4a start, end;
  3636. start.load3(mouse_world_start.mV);
  3637. end.load3(mouse_world_end.mV);
  3638. return LLHUDIcon::lineSegmentIntersectAll(start, end, intersection);
  3639. }
  3640. LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y,
  3641. F32 depth,
  3642. LLViewerObject* this_object,
  3643. S32 this_face,
  3644. bool pick_transparent,
  3645. bool pick_rigged,
  3646. S32* face_hit,
  3647. S32* gltf_node_hit,
  3648. S32* gltf_prim_hit,
  3649. LLVector4a* intersection,
  3650. LLVector2* uv,
  3651. LLVector4a* normal,
  3652. LLVector4a* tangent,
  3653. LLVector4a* start,
  3654. LLVector4a* end)
  3655. {
  3656. S32 x = mouse_x;
  3657. S32 y = mouse_y;
  3658. if (mouse_x == -1 && mouse_y == -1) // use current mouse position
  3659. {
  3660. x = getCurrentMouseX();
  3661. y = getCurrentMouseY();
  3662. }
  3663. // HUD coordinates of mouse
  3664. LLVector3 mouse_point_hud = mousePointHUD(x, y);
  3665. LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
  3666. LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
  3667. // World coordinates of mouse
  3668. LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
  3669. LLVector3 mouse_point_global = gViewerCamera.getOrigin();
  3670. // Get near clip plane
  3671. LLVector3 n = gViewerCamera.getAtAxis();
  3672. LLVector3 p = mouse_point_global + n * gViewerCamera.getNear();
  3673. // Project mouse point onto plane
  3674. LLVector3 pos;
  3675. line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
  3676. mouse_point_global = pos;
  3677. LLVector3 mouse_world_start = mouse_point_global;
  3678. LLVector3 mouse_world_end = mouse_point_global +
  3679. mouse_direction_global * depth;
  3680. if (!LLViewerJoystick::getInstance()->getOverrideCamera())
  3681. {
  3682. // Always set raycast intersection to mouse_world_end unless flycam is
  3683. // on (for DoF effect)
  3684. gDebugRaycastIntersection.load3(mouse_world_end.mV);
  3685. }
  3686. LLVector4a mw_start;
  3687. mw_start.load3(mouse_world_start.mV);
  3688. LLVector4a mw_end;
  3689. mw_end.load3(mouse_world_end.mV);
  3690. LLVector4a mh_start;
  3691. mh_start.load3(mouse_hud_start.mV);
  3692. LLVector4a mh_end;
  3693. mh_end.load3(mouse_hud_end.mV);
  3694. if (start)
  3695. {
  3696. *start = mw_start;
  3697. }
  3698. if (end)
  3699. {
  3700. *end = mw_end;
  3701. }
  3702. LLViewerObject* found = NULL;
  3703. if (this_object) // Check only this object
  3704. {
  3705. if (this_object->isHUDAttachment()) // Is it a HUD object ?
  3706. {
  3707. if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face,
  3708. pick_transparent,
  3709. pick_rigged, face_hit,
  3710. intersection, uv, normal,
  3711. tangent))
  3712. {
  3713. found = this_object;
  3714. }
  3715. }
  3716. else // It is a world object
  3717. {
  3718. if (this_object->lineSegmentIntersect(mw_start, mw_end, this_face,
  3719. pick_transparent,
  3720. pick_rigged, face_hit,
  3721. intersection, uv, normal,
  3722. tangent))
  3723. {
  3724. found = this_object;
  3725. }
  3726. //MK
  3727. if (gRLenabled && gRLInterface.mContainsInteract)
  3728. {
  3729. found = NULL;
  3730. }
  3731. //mk
  3732. }
  3733. }
  3734. else // Check ALL objects
  3735. {
  3736. found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end,
  3737. pick_transparent,
  3738. face_hit, intersection,
  3739. uv, normal, tangent);
  3740. //MK
  3741. // *HACK: do not allow focusing on HUDs while we are right-clicking on
  3742. // something while not in mouse look: useful for "blinding" HUDs that
  3743. // cover the whole screen, even when transparent.
  3744. if (gRLenabled && !gAgent.cameraMouselook() &&
  3745. gRLInterface.mHasLockedHuds)
  3746. {
  3747. MASK mask = gKeyboardp ? gKeyboardp->currentMask(true) : 0;
  3748. if (mask & MASK_ALT)
  3749. {
  3750. found = NULL;
  3751. }
  3752. }
  3753. //mk
  3754. if (!found) // If not found in HUD, look in world:
  3755. {
  3756. found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end,
  3757. pick_transparent,
  3758. pick_rigged,
  3759. face_hit,
  3760. gltf_node_hit,
  3761. gltf_prim_hit,
  3762. intersection,
  3763. uv, normal, tangent);
  3764. if (found && !pick_transparent)
  3765. {
  3766. gDebugRaycastIntersection = *intersection;
  3767. }
  3768. }
  3769. }
  3770. return found;
  3771. }
  3772. // Returns unit vector relative to camera
  3773. // indicating direction of point on screen x,y
  3774. LLVector3 LLViewerWindow::mouseDirectionGlobal(S32 x, S32 y) const
  3775. {
  3776. // Find vertical field of view
  3777. F32 fov = gViewerCamera.getView();
  3778. // Find screen resolution
  3779. S32 height = getWindowHeight();
  3780. S32 width = getWindowWidth();
  3781. // Calculate pixel distance to screen
  3782. F32 t = 2.f * tanf(fov * 0.5f);
  3783. F32 distance = t == 0.f ? F32_MAX : height / t;
  3784. // Calculate click point relative to middle of screen
  3785. F32 click_x = x - width * 0.5f;
  3786. F32 click_y = y - height * 0.5f;
  3787. // Compute mouse vector
  3788. LLVector3 mouse_vector = distance * gViewerCamera.getAtAxis() -
  3789. click_x * gViewerCamera.getLeftAxis() +
  3790. click_y * gViewerCamera.getUpAxis();
  3791. mouse_vector.normalize();
  3792. return mouse_vector;
  3793. }
  3794. LLVector3 LLViewerWindow::mousePointHUD(S32 x, S32 y) const
  3795. {
  3796. // Find screen resolution
  3797. S32 height = getWindowHeight();
  3798. S32 width = getWindowWidth();
  3799. // Remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
  3800. F32 hud_x = -((F32)x - (F32)width * 0.5f) / height;
  3801. F32 hud_y = ((F32)y - (F32)height * 0.5f) / height;
  3802. return LLVector3(0.f, hud_x / gAgent.mHUDCurZoom,
  3803. hud_y / gAgent.mHUDCurZoom);
  3804. }
  3805. // Returns unit vector relative to camera in camera space indicating direction
  3806. // of point on screen x,y
  3807. LLVector3 LLViewerWindow::mouseDirectionCamera(S32 x, S32 y) const
  3808. {
  3809. // Find vertical field of view
  3810. F32 fov_height = gViewerCamera.getView();
  3811. F32 fov_width = fov_height * gViewerCamera.getAspect();
  3812. // Find screen resolution
  3813. S32 height = getWindowHeight();
  3814. S32 width = getWindowWidth();
  3815. // Calculate click point relative to middle of screen
  3816. F32 click_x = ((F32)x / (F32)width - 0.5f) * fov_width * -1.f;
  3817. F32 click_y = ((F32)y / (F32)height - 0.5f) * fov_height;
  3818. // compute mouse vector
  3819. LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
  3820. LLQuaternion mouse_rotate;
  3821. mouse_rotate.setEulerAngles(click_y, click_x, 0.f);
  3822. mouse_vector = mouse_vector * mouse_rotate;
  3823. // project to z = -1 plane;
  3824. mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
  3825. return mouse_vector;
  3826. }
  3827. bool LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, S32 x, S32 y,
  3828. const LLVector3d& plane_point_global,
  3829. const LLVector3& plane_normal_global)
  3830. {
  3831. LLVector3d mouse_direction_global_d;
  3832. mouse_direction_global_d.set(mouseDirectionGlobal(x, y));
  3833. LLVector3d plane_normal_global_d;
  3834. plane_normal_global_d.set(plane_normal_global);
  3835. F64 plane_mouse_dot = plane_normal_global_d * mouse_direction_global_d;
  3836. LLVector3d plane_origin_camera_rel = plane_point_global -
  3837. gAgent.getCameraPositionGlobal();
  3838. F64 mouse_look_at_scale = plane_normal_global_d * plane_origin_camera_rel /
  3839. plane_mouse_dot;
  3840. if (fabs(plane_mouse_dot) < 0.00001)
  3841. {
  3842. // If mouse is parallel to plane, return closest point on line through
  3843. // plane origin that is parallel to camera plane by scaling mouse
  3844. // direction vector by distance to plane origin, modulated by deviation
  3845. // of mouse direction from plane origin
  3846. LLVector3d plane_origin_dir = plane_origin_camera_rel;
  3847. plane_origin_dir.normalize();
  3848. mouse_look_at_scale = plane_origin_camera_rel.length() /
  3849. (plane_origin_dir * mouse_direction_global_d);
  3850. }
  3851. point = gAgent.getCameraPositionGlobal() +
  3852. mouse_look_at_scale * mouse_direction_global_d;
  3853. return mouse_look_at_scale > 0.0;
  3854. }
  3855. // Returns global position
  3856. bool LLViewerWindow::mousePointOnLandGlobal(S32 x, S32 y,
  3857. LLVector3d* land_position_global)
  3858. {
  3859. LLVector3 mouse_direction_global = mouseDirectionGlobal(x, y);
  3860. F32 mouse_dir_scale;
  3861. bool hit_land = false;
  3862. LLViewerRegion* regionp;
  3863. F32 land_z;
  3864. constexpr F32 FIRST_PASS_STEP = 1.f; // meters
  3865. constexpr F32 SECOND_PASS_STEP = 0.1f; // meters
  3866. LLVector3d camera_pos_global;
  3867. camera_pos_global = gAgent.getCameraPositionGlobal();
  3868. LLVector3d probe_point_global;
  3869. LLVector3 probe_point_region;
  3870. F32 max_distance = gAgent.noCameraConstraints() ? 1024.f
  3871. : gAgent.mDrawDistance;
  3872. // Walk forwards to find the point
  3873. for (mouse_dir_scale = FIRST_PASS_STEP;
  3874. mouse_dir_scale < max_distance;
  3875. mouse_dir_scale += FIRST_PASS_STEP)
  3876. {
  3877. LLVector3d mouse_direction_global_d;
  3878. mouse_direction_global_d.set(mouse_direction_global * mouse_dir_scale);
  3879. probe_point_global = camera_pos_global + mouse_direction_global_d;
  3880. regionp = gWorld.resolveRegionGlobal(probe_point_region,
  3881. probe_point_global);
  3882. if (!regionp)
  3883. {
  3884. // ...we are outside the world somehow
  3885. continue;
  3886. }
  3887. S32 i = (S32)(probe_point_region.mV[VX] /
  3888. regionp->getLand().getMetersPerGrid());
  3889. S32 j = (S32)(probe_point_region.mV[VY] /
  3890. regionp->getLand().getMetersPerGrid());
  3891. S32 grids_per_edge = (S32)regionp->getLand().mGridsPerEdge;
  3892. if (i >= grids_per_edge || j >= grids_per_edge)
  3893. {
  3894. continue;
  3895. }
  3896. land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
  3897. if (probe_point_region.mV[VZ] < land_z)
  3898. {
  3899. hit_land = true;
  3900. break;
  3901. }
  3902. }
  3903. if (hit_land)
  3904. {
  3905. // Do not go more than one step beyond where we stopped above. This
  3906. // cannot just be "mouse_vec_scale" because floating point error will
  3907. // stop the loop before the last increment...
  3908. // X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
  3909. F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
  3910. // Take a step backwards, then walk forwards again to refine position
  3911. for (mouse_dir_scale -= FIRST_PASS_STEP;
  3912. mouse_dir_scale <= stop_mouse_dir_scale;
  3913. mouse_dir_scale += SECOND_PASS_STEP)
  3914. {
  3915. LLVector3d mouse_direction_global_d;
  3916. mouse_direction_global_d.set(mouse_direction_global *
  3917. mouse_dir_scale);
  3918. probe_point_global = camera_pos_global + mouse_direction_global_d;
  3919. regionp = gWorld.resolveRegionGlobal(probe_point_region,
  3920. probe_point_global);
  3921. if (!regionp)
  3922. {
  3923. // ...we are outside the world somehow
  3924. continue;
  3925. }
  3926. #if 0
  3927. i = (S32)(local_probe_point.mV[VX] /
  3928. regionp->getLand().getMetersPerGrid());
  3929. j = (S32)(local_probe_point.mV[VY] /
  3930. regionp->getLand().getMetersPerGrid());
  3931. if (i >= regionp->getLand().mGridsPerEdge ||
  3932. j >= regionp->getLand().mGridsPerEdge)
  3933. {
  3934. llwarns << "probe_point is out of region" << llendl;
  3935. continue;
  3936. }
  3937. land_z =
  3938. regionp->getLand().mSurfaceZ[i + j *
  3939. (regionp->getLand().mGridsPerEdge)];
  3940. #endif
  3941. land_z =
  3942. regionp->getLand().resolveHeightRegion(probe_point_region);
  3943. if (probe_point_region.mV[VZ] < land_z)
  3944. {
  3945. // ...just went under land again
  3946. *land_position_global = probe_point_global;
  3947. return true;
  3948. }
  3949. }
  3950. }
  3951. return false;
  3952. }
  3953. void LLViewerWindow::setSnapshotLoc(std::string filepath)
  3954. {
  3955. LLViewerWindow::sSnapshotBaseName = gDirUtil.getBaseFileName(filepath,
  3956. true);
  3957. LLViewerWindow::sSnapshotDir = gDirUtil.getDirName(filepath);
  3958. }
  3959. // Saves an image to the harddrive as "SnapshotX" where X >= 1.
  3960. bool LLViewerWindow::saveImageNumbered(LLImageFormatted* image)
  3961. {
  3962. if (!image || !isSnapshotLocSet())
  3963. {
  3964. return false;
  3965. }
  3966. // Look for an unused file name
  3967. const std::string extension = "." + image->getExtension();
  3968. std::string filepath;
  3969. const std::string base_path = sSnapshotDir + LL_DIR_DELIM_STR +
  3970. sSnapshotBaseName;
  3971. S32 i = 1;
  3972. do
  3973. {
  3974. filepath = base_path + llformat("_%.3d", i++) + extension;
  3975. }
  3976. // Search until the file is not found
  3977. while (LLFile::isfile(filepath));
  3978. bool result = image->save(filepath);
  3979. if (result)
  3980. {
  3981. playSnapshotAnimAndSound();
  3982. }
  3983. return result;
  3984. }
  3985. void LLViewerWindow::resetSnapshotLoc()
  3986. {
  3987. sSnapshotDir.clear();
  3988. }
  3989. void LLViewerWindow::resizeWindow(S32 new_width, S32 new_height)
  3990. {
  3991. static S32 border_width = 0;
  3992. static S32 border_height = 0;
  3993. LLCoordScreen size;
  3994. gWindowp->getSize(&size);
  3995. if (size.mX != new_width + border_width ||
  3996. size.mY != new_height + border_height)
  3997. {
  3998. // Use the actual display dimensions, not the virtual UI dimensions
  3999. border_width = size.mX - getWindowDisplayWidth();
  4000. border_height = size.mY - getWindowDisplayHeight();
  4001. LLCoordScreen new_size(new_width + border_width,
  4002. new_height + border_height);
  4003. bool disable_sync = gSavedSettings.getBool("DisableVerticalSync");
  4004. if (gWindowp->getFullscreen())
  4005. {
  4006. changeDisplaySettings(new_size, disable_sync, true);
  4007. }
  4008. else
  4009. {
  4010. gWindowp->setSize(new_size);
  4011. }
  4012. }
  4013. mResDirty = true;
  4014. }
  4015. bool LLViewerWindow::saveSnapshot(const std::string& filepath,
  4016. S32 image_width, S32 image_height,
  4017. bool show_ui, bool do_rebuild,
  4018. U32 type)
  4019. {
  4020. llinfos << "Saving snapshot to: " << filepath << llendl;
  4021. LLPointer<LLImageRaw> raw = new LLImageRaw;
  4022. bool success = rawSnapshot(raw, image_width, image_height, true, false,
  4023. show_ui, do_rebuild);
  4024. if (success)
  4025. {
  4026. LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
  4027. success = bmp_image->encode(raw);
  4028. if (success)
  4029. {
  4030. success = bmp_image->save(filepath);
  4031. }
  4032. else
  4033. {
  4034. llwarns << "Unable to encode bmp snapshot" << llendl;
  4035. }
  4036. }
  4037. else
  4038. {
  4039. llwarns << "Unable to capture raw snapshot" << llendl;
  4040. }
  4041. return success;
  4042. }
  4043. void LLViewerWindow::playSnapshotAnimAndSound()
  4044. {
  4045. if (!gSavedSettings.getBool("QuietSnapshotsToDisk"))
  4046. {
  4047. gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
  4048. if (gSavedSettings.getBool("UISndSnapshotEnable"))
  4049. {
  4050. send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")),
  4051. 1.f);
  4052. }
  4053. }
  4054. }
  4055. bool LLViewerWindow::thumbnailSnapshot(LLImageRaw* raw, S32 preview_width,
  4056. S32 preview_height, bool show_ui,
  4057. bool do_rebuild, U32 type)
  4058. {
  4059. return rawSnapshot(raw, preview_width, preview_height, false, false,
  4060. show_ui, do_rebuild, type);
  4061. }
  4062. // Saves the image from the screen to the specified filename and path.
  4063. bool LLViewerWindow::rawSnapshot(LLImageRaw* raw,
  4064. S32 image_width, S32 image_height,
  4065. bool keep_window_aspect, bool is_texture,
  4066. bool show_ui, bool do_rebuild,
  4067. U32 type, S32 max_size)
  4068. {
  4069. if (!raw)
  4070. {
  4071. return false;
  4072. }
  4073. // Check if there is enough memory for the snapshot image
  4074. if (LLMemory::gotFailedAllocation())
  4075. {
  4076. llwarns << "Snapshots disabled due to past memory allocation falures."
  4077. << llendl;
  4078. return false;
  4079. }
  4080. #if LL_LINUX
  4081. // Avoids unrefreshed rectangles in screen shots when other applications
  4082. // windows are overlapping ours. HB
  4083. gWindowp->bringToFront();
  4084. // Let some time to the window manager to bring us back to front.
  4085. ms_sleep(100);
  4086. #endif
  4087. // PRE SNAPSHOT
  4088. gDisplaySwapBuffers = false;
  4089. if (gUsePBRShaders)
  4090. {
  4091. gSnapshotNoPost = gSavedSettings.getBool("RenderSnapshotNoPost");
  4092. glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  4093. }
  4094. else
  4095. {
  4096. glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT |
  4097. GL_STENCIL_BUFFER_BIT);
  4098. }
  4099. setCursor(UI_CURSOR_WAIT);
  4100. // Hide all the UI widgets first and draw a frame
  4101. bool prev_draw_ui =
  4102. gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
  4103. if (prev_draw_ui != show_ui)
  4104. {
  4105. LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
  4106. }
  4107. //MK
  4108. if (gRLenabled && gRLInterface.mHasLockedHuds)
  4109. {
  4110. gSavedSettings.setBool("RenderHUDInSnapshot", true);
  4111. }
  4112. //mk
  4113. bool hide_hud = LLPipeline::sShowHUDAttachments &&
  4114. !gSavedSettings.getBool("RenderHUDInSnapshot");
  4115. if (hide_hud)
  4116. {
  4117. LLPipeline::sShowHUDAttachments = false;
  4118. }
  4119. // Copy screen to a buffer; crop sides or top and bottom, if taking a
  4120. // snapshot of different aspect ratio from window
  4121. S32 snapshot_width = mWindowRect.getWidth();
  4122. S32 snapshot_height = mWindowRect.getHeight();
  4123. S32 window_width = mWindowRect.getWidth();
  4124. S32 window_height = mWindowRect.getHeight();
  4125. // Note: Scaling of the UI is currently *not* supported so we limit the
  4126. // output size if UI is requested
  4127. if (show_ui)
  4128. {
  4129. // If the user wants the UI, limit the output size to the available
  4130. // screen size
  4131. image_width = llmin(image_width, window_width);
  4132. image_height = llmin(image_height, window_height);
  4133. }
  4134. F32 scale_factor = 1.f;
  4135. S32 max_width = llmin(window_width, gGLManager.mGLMaxTextureSize);
  4136. S32 max_height = llmin(window_height, gGLManager.mGLMaxTextureSize);
  4137. if (!keep_window_aspect || image_width > max_width ||
  4138. image_height > max_height)
  4139. {
  4140. // If image cropping or need to enlarge the scene, compute a
  4141. // scale_factor
  4142. F32 ratio = llmin((F32)max_width / image_width ,
  4143. (F32)max_height / image_height);
  4144. snapshot_width = (S32)(ratio * image_width);
  4145. snapshot_height = (S32)(ratio * image_height);
  4146. scale_factor = llmax(1.f, 1.f / ratio);
  4147. }
  4148. if (show_ui && scale_factor > 1.f)
  4149. {
  4150. // Note: we should never get there...
  4151. llwarns << "Over scaling UI not supported." << llendl;
  4152. }
  4153. S32 buffer_x_offset = llfloor((window_width - snapshot_width) *
  4154. scale_factor * 0.5f);
  4155. S32 buffer_y_offset = llfloor((window_height - snapshot_height) *
  4156. scale_factor * 0.5f);
  4157. S32 image_buffer_x = llfloor(snapshot_width*scale_factor);
  4158. S32 image_buffer_y = llfloor(snapshot_height *scale_factor);
  4159. // Boundary check to avoid memory overflow
  4160. if (image_buffer_x > max_size || image_buffer_y > max_size)
  4161. {
  4162. scale_factor *= llmin((F32)max_size / image_buffer_x,
  4163. (F32)max_size / image_buffer_y);
  4164. image_buffer_x = llfloor(snapshot_width*scale_factor);
  4165. image_buffer_y = llfloor(snapshot_height *scale_factor);
  4166. }
  4167. if (image_buffer_x > 0 && image_buffer_y > 0)
  4168. {
  4169. raw->resize(image_buffer_x, image_buffer_y, 3);
  4170. }
  4171. else
  4172. {
  4173. gSnapshotNoPost = false;
  4174. return false;
  4175. }
  4176. if (raw->isBufferInvalid())
  4177. {
  4178. gSnapshotNoPost = false;
  4179. return false;
  4180. }
  4181. bool high_res = scale_factor > 1.f;
  4182. #if 0
  4183. if (high_res)
  4184. {
  4185. LLWorld::sendAgentPause();
  4186. if (show_ui || !hide_hud)
  4187. {
  4188. // Rescale fonts
  4189. initFonts(scale_factor);
  4190. LLHUDText::reshape();
  4191. }
  4192. }
  4193. #endif
  4194. S32 output_buffer_offset_y = 0;
  4195. F32 dnear = gViewerCamera.getNear();
  4196. F32 dfar = gViewerCamera.getFar();
  4197. F32 divisor = 2.f * dnear * dfar;
  4198. F32 depth_conv_factor_1 = (dfar + dnear) / divisor;
  4199. F32 depth_conv_factor_2 = (dfar - dnear) / divisor;
  4200. // Sub-images are in fact partial rendering of the final view. This happens
  4201. // when the final view is bigger than the screen. In most common cases,
  4202. // scale_factor is 1 and there is no more than 1 iteration on x and y
  4203. for (S32 subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
  4204. {
  4205. S32 subimage_y_offset =
  4206. llclamp(buffer_y_offset - subimage_y * window_height, 0,
  4207. window_height);
  4208. // Handle fractional columns
  4209. U32 read_height = llmax(0,
  4210. window_height - subimage_y_offset -
  4211. llmax(0,
  4212. window_height * (subimage_y + 1) -
  4213. buffer_y_offset - raw->getHeight()));
  4214. S32 output_buffer_offset_x = 0;
  4215. for (S32 subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
  4216. {
  4217. gDisplaySwapBuffers = false;
  4218. gDepthDirty = true;
  4219. S32 subimage_x_offset =
  4220. llclamp(buffer_x_offset - subimage_x * window_width, 0,
  4221. window_width);
  4222. // Handle fractional rows
  4223. U32 read_width =
  4224. llmax(0,
  4225. window_width - subimage_x_offset -
  4226. llmax(0,
  4227. window_width * (subimage_x + 1) -
  4228. buffer_x_offset - raw->getWidth()));
  4229. // Skip rendering and sampling altogether if either width or height
  4230. // is degenerated to 0 (common in cropping cases)
  4231. if (read_width && read_height)
  4232. {
  4233. const U32 subfield = subimage_x +
  4234. subimage_y * llceil(scale_factor);
  4235. display(do_rebuild, scale_factor, subfield, true);
  4236. if (!LLPipeline::sRenderDeferred)
  4237. {
  4238. // Required for showing the GUI in snapshots and performing
  4239. // bloom composite overlay. Call even if show_ui is false
  4240. render_ui(scale_factor);
  4241. }
  4242. glFinish(); // Ensure everything got drawn
  4243. for (U32 out_y = 0; out_y < read_height; ++out_y)
  4244. {
  4245. S32 output_buffer_offset =
  4246. raw->getComponents() *
  4247. // iterated y...
  4248. (out_y * raw->getWidth() +
  4249. // ...plus subimage start in x...
  4250. window_width * subimage_x +
  4251. // ...plus subimage start in y...
  4252. raw->getWidth() * window_height * subimage_y -
  4253. // ...minus buffer padding x...
  4254. output_buffer_offset_x -
  4255. // ...minus buffer padding y...
  4256. output_buffer_offset_y * raw->getWidth());
  4257. if (type == SNAPSHOT_TYPE_COLOR)
  4258. {
  4259. glReadPixels(subimage_x_offset,
  4260. out_y + subimage_y_offset, read_width, 1,
  4261. GL_RGB, GL_UNSIGNED_BYTE,
  4262. raw->getData() + output_buffer_offset);
  4263. }
  4264. else // SNAPSHOT_TYPE_DEPTH
  4265. {
  4266. LLPointer<LLImageRaw> depth_line_buffer;
  4267. depth_line_buffer = new LLImageRaw(read_width, 1,
  4268. // need to store floats
  4269. sizeof(GL_FLOAT));
  4270. glReadPixels(subimage_x_offset,
  4271. out_y + subimage_y_offset, read_width, 1,
  4272. GL_DEPTH_COMPONENT, GL_FLOAT,
  4273. // current output pixel is beginning
  4274. // of buffer
  4275. depth_line_buffer->getData());
  4276. for (S32 i = 0; i < (S32)read_width; ++i)
  4277. {
  4278. F32 depth_float =
  4279. *(F32*)(depth_line_buffer->getData() +
  4280. i * sizeof(F32));
  4281. F32 linear_depth_float =
  4282. 1.f / (depth_conv_factor_1 -
  4283. depth_float * depth_conv_factor_2);
  4284. U8 depth_byte = F32_to_U8(linear_depth_float,
  4285. dnear, dfar);
  4286. // Write converted scanline out to result image
  4287. for (S32 j = 0, count = raw->getComponents();
  4288. j < count; ++j)
  4289. {
  4290. *(raw->getData() + output_buffer_offset +
  4291. i * raw->getComponents() + j) = depth_byte;
  4292. }
  4293. }
  4294. }
  4295. }
  4296. }
  4297. output_buffer_offset_x += subimage_x_offset;
  4298. }
  4299. output_buffer_offset_y += subimage_y_offset;
  4300. }
  4301. gDisplaySwapBuffers = false;
  4302. gDepthDirty = true;
  4303. gSnapshotNoPost = false;
  4304. // Post snapshot
  4305. if (prev_draw_ui &&
  4306. !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
  4307. {
  4308. LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
  4309. }
  4310. if (hide_hud)
  4311. {
  4312. LLPipeline::sShowHUDAttachments = true;
  4313. }
  4314. #if 0
  4315. if (high_res)
  4316. {
  4317. initFonts(1.f);
  4318. LLHUDObject::reshapeAll();
  4319. }
  4320. #endif
  4321. // Pre-pad image to number of pixels such that the line length is a
  4322. // multiple of 4 bytes (for BMP encoding). Note: this formula depends on
  4323. // the number of components being 3. Not obvious, but it's correct.
  4324. image_width += (image_width * 3) % 4;
  4325. bool ret = true;
  4326. // Resize image
  4327. if (abs(image_width - image_buffer_x) > 4 ||
  4328. abs(image_height - image_buffer_y) > 4)
  4329. {
  4330. ret = raw->scale(image_width, image_height);
  4331. }
  4332. else if (image_width != image_buffer_x || image_height != image_buffer_y)
  4333. {
  4334. ret = raw->scale(image_width, image_height, false);
  4335. }
  4336. setCursor(UI_CURSOR_ARROW);
  4337. if (do_rebuild)
  4338. {
  4339. // If we had to do a rebuild, that means that the lists of drawables to
  4340. // be rendered was empty before we started. Need to reset these,
  4341. // otherwise we call state sort on it again when render gets called the
  4342. // next time and we stand a good chance of crashing on rebuild because
  4343. // the render drawable arrays have multiple copies of objects on them.
  4344. gPipeline.resetDrawOrders();
  4345. }
  4346. if (high_res)
  4347. {
  4348. LLWorld::sendAgentResume();
  4349. }
  4350. stop_glerror();
  4351. return ret;
  4352. }
  4353. void LLViewerWindow::cubeSnapshot(const LLVector3& origin,
  4354. LLCubeMapArray* cubemapp, S32 face,
  4355. F32 near_clip, bool dynamic_render)
  4356. {
  4357. if (!gUsePBRShaders)
  4358. {
  4359. return;
  4360. }
  4361. LLDisableOcclusionCulling no_occlusion;
  4362. // Store current projection/modelview matrix
  4363. const LLMatrix4a saved_proj = gGLProjection;
  4364. const LLMatrix4a saved_view = gGLModelView;
  4365. U32 res = gPipeline.mRT->mDeferredScreen.getWidth();
  4366. LLViewerCamera saved_camera = gViewerCamera;
  4367. // Camera constants for the square, cube map capture image
  4368. // We must set aspect ratio first to avoid undesirable clamping of vertical
  4369. // FoV.
  4370. gViewerCamera.setAspect(1.f);
  4371. gViewerCamera.setViewNoBroadcast(F_PI_BY_TWO);
  4372. gViewerCamera.yaw(0.f);
  4373. gViewerCamera.setOrigin(origin);
  4374. gViewerCamera.setNear(near_clip);
  4375. glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  4376. static const U32 dynamic_render_types[] =
  4377. {
  4378. LLPipeline::RENDER_TYPE_AVATAR,
  4379. LLPipeline::RENDER_TYPE_PUPPET,
  4380. LLPipeline::RENDER_TYPE_PARTICLES
  4381. };
  4382. static const U32 render_types_count = LL_ARRAY_SIZE(dynamic_render_types);
  4383. bool prev_dynamic_render_type[render_types_count];
  4384. if (!dynamic_render)
  4385. {
  4386. for (U32 i = 0; i < render_types_count; ++i)
  4387. {
  4388. bool enabled = gPipeline.hasRenderType(dynamic_render_types[i]);
  4389. prev_dynamic_render_type[i] = enabled;
  4390. if (enabled)
  4391. {
  4392. gPipeline.toggleRenderType(dynamic_render_types[i]);
  4393. }
  4394. }
  4395. }
  4396. constexpr U32 ui_mask = LLPipeline::RENDER_DEBUG_FEATURE_UI;
  4397. bool draw_ui = gPipeline.hasRenderDebugFeatureMask(ui_mask);
  4398. if (draw_ui)
  4399. {
  4400. LLPipeline::toggleRenderDebugFeature((void*)ui_mask);
  4401. }
  4402. bool show_huds = LLPipeline::sShowHUDAttachments;
  4403. if (show_huds)
  4404. {
  4405. LLPipeline::sShowHUDAttachments = false;
  4406. }
  4407. LLRect window_rect = mWindowRect;
  4408. mWindowRect.set(0, res, res, 0);
  4409. // See LLCubeMapArray::sTargets
  4410. static const LLVector3 look_dirs[6] =
  4411. {
  4412. LLVector3::x_axis,
  4413. LLVector3::x_axis_neg,
  4414. LLVector3::y_axis,
  4415. LLVector3::y_axis_neg,
  4416. LLVector3::z_axis,
  4417. LLVector3::z_axis_neg
  4418. };
  4419. static const LLVector3 look_upvecs[6] =
  4420. {
  4421. LLVector3::y_axis_neg,
  4422. LLVector3::y_axis_neg,
  4423. LLVector3::z_axis,
  4424. LLVector3::z_axis_neg,
  4425. LLVector3::y_axis_neg,
  4426. LLVector3::y_axis_neg
  4427. };
  4428. // Set up camera to look at the right direction
  4429. gViewerCamera.lookDir(look_dirs[face], look_upvecs[face]);
  4430. // Turning this flag off here prohibits the screen swap to present the new
  4431. // frame to the viewer: this avoids a black flash in between captures when
  4432. // the number of render passes is more than 1. We need to also set it here
  4433. // because code in llviewerdisplay.cpp resets it to true each time.
  4434. gDisplaySwapBuffers = false;
  4435. gCubeSnapshot = true;
  4436. display_cube_face();
  4437. gCubeSnapshot = false;
  4438. gDisplaySwapBuffers = true;
  4439. mWindowRect = window_rect;
  4440. setupViewport();
  4441. if (draw_ui && !gPipeline.hasRenderDebugFeatureMask(ui_mask))
  4442. {
  4443. LLPipeline::toggleRenderDebugFeature((void*)ui_mask);
  4444. }
  4445. if (!dynamic_render)
  4446. {
  4447. for (size_t i = 0; i < render_types_count; ++i)
  4448. {
  4449. if (prev_dynamic_render_type[i])
  4450. {
  4451. gPipeline.toggleRenderType(dynamic_render_types[i]);
  4452. }
  4453. }
  4454. }
  4455. if (show_huds)
  4456. {
  4457. LLPipeline::sShowHUDAttachments = true;
  4458. }
  4459. gPipeline.resetDrawOrders();
  4460. gViewerCamera = saved_camera;
  4461. gGLProjection = saved_proj;
  4462. gGLModelView = saved_view;
  4463. }
  4464. void LLViewerWindow::destroyWindow()
  4465. {
  4466. LLWindow::destroyWindow();
  4467. }
  4468. void LLViewerWindow::drawMouselookInstructions()
  4469. {
  4470. // Draw instructions for mouselook ("Press SHIFT ESC to leave Mouselook"
  4471. // in a box at the top of the screen).
  4472. static const LLWString instructions = LLTrans::getWString("mouselook");
  4473. static const LLFontGL* font = LLFontGL::getFontSansSerif();
  4474. constexpr S32 INSTRUCTIONS_PAD = 5;
  4475. static const S32 inst_width = font->getWidth(instructions.c_str()) +
  4476. 2 * INSTRUCTIONS_PAD;
  4477. static const S32 inst_height = font->getLineHeight() +
  4478. 2 * INSTRUCTIONS_PAD;
  4479. static LLCachedControl<U32> fade_ml_exit_tip(gSavedSettings,
  4480. "FadeMouselookExitTip");
  4481. F32 opaque_time = (F32)fade_ml_exit_tip;
  4482. if (opaque_time != 0.f && opaque_time < 5.f)
  4483. {
  4484. opaque_time = 5.f;
  4485. }
  4486. constexpr F32 INSTRUCTIONS_FADE_TIME = 5.f;
  4487. F32 timer = mMouselookTipFadeTimer.getElapsedTimeF32();
  4488. if (opaque_time && timer >= opaque_time + INSTRUCTIONS_FADE_TIME)
  4489. {
  4490. // Faded out already
  4491. return;
  4492. }
  4493. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  4494. F32 alpha = 1.f;
  4495. if (opaque_time && timer >= opaque_time)
  4496. {
  4497. // Instructions are fading
  4498. alpha = 1.f - (timer - opaque_time) / INSTRUCTIONS_FADE_TIME;
  4499. }
  4500. gGL.color4f(0.9f, 0.9f, 0.9f, alpha);
  4501. LLRect rect;
  4502. rect.setLeftTopAndSize(INSTRUCTIONS_PAD,
  4503. getWindowHeight() - INSTRUCTIONS_PAD,
  4504. inst_width, inst_height);
  4505. gl_rect_2d(rect);
  4506. font->render(instructions, 0,
  4507. rect.mLeft + INSTRUCTIONS_PAD, rect.mTop - INSTRUCTIONS_PAD,
  4508. LLColor4(0.f, 0.f, 0.f, alpha),
  4509. LLFontGL::LEFT, LLFontGL::TOP);
  4510. }
  4511. void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset)
  4512. {
  4513. #if 0 // mWindowRect.mLeft = mWindowRect.mBottom = 0
  4514. gGLViewport[0] = mWindowRect.mLeft + x_offset;
  4515. gGLViewport[1] = mWindowRect.mBottom + y_offset;
  4516. gGLViewport[2] = mWindowRect.getWidth();
  4517. gGLViewport[3] = mWindowRect.getHeight();
  4518. #else
  4519. gGLViewport[0] = x_offset;
  4520. gGLViewport[1] = y_offset;
  4521. gGLViewport[2] = mWindowRect.mRight;
  4522. gGLViewport[3] = mWindowRect.mTop;
  4523. #endif
  4524. glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
  4525. }
  4526. void LLViewerWindow::setup3DRender()
  4527. {
  4528. gViewerCamera.setPerspective(NOT_FOR_SELECTION, 0, 0,
  4529. mWindowRect.getWidth(),
  4530. mWindowRect.getHeight(), false,
  4531. gViewerCamera.getNear(), MAX_FAR_CLIP * 2.f);
  4532. #if 0 // Redundant
  4533. setupViewport();
  4534. #endif
  4535. }
  4536. void LLViewerWindow::setup2DRender()
  4537. {
  4538. gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight());
  4539. #if 0 // Redundant
  4540. setupViewport();
  4541. #endif
  4542. }
  4543. void LLViewerWindow::setShowProgress(bool show)
  4544. {
  4545. if (mProgressView)
  4546. {
  4547. mProgressView->setVisible(show);
  4548. }
  4549. }
  4550. void LLViewerWindow::moveProgressViewToFront()
  4551. {
  4552. if (mProgressView && mRootView)
  4553. {
  4554. mRootView->removeChild(mProgressView);
  4555. mRootView->addChild(mProgressView);
  4556. }
  4557. }
  4558. void LLViewerWindow::setProgressString(const std::string& string)
  4559. {
  4560. if (mProgressView)
  4561. {
  4562. mProgressView->setText(string);
  4563. }
  4564. }
  4565. void LLViewerWindow::setProgressMessage(const std::string& msg)
  4566. {
  4567. if (mProgressView)
  4568. {
  4569. mProgressView->setMessage(msg);
  4570. }
  4571. }
  4572. void LLViewerWindow::setProgressPercent(F32 percent)
  4573. {
  4574. if (mProgressView)
  4575. {
  4576. mProgressView->setPercent(percent);
  4577. }
  4578. }
  4579. void LLViewerWindow::setProgressCancelButtonVisible(bool show,
  4580. const std::string& label)
  4581. {
  4582. if (mProgressView)
  4583. {
  4584. mProgressView->setCancelButtonVisible(show, label);
  4585. }
  4586. }
  4587. void LLViewerWindow::dumpState()
  4588. {
  4589. llinfos << "LLViewerWindow active: " << (mActive ? "true": "false")
  4590. << " - gWindowp visible: "
  4591. << (gWindowp->getVisible() ? "true": "false")
  4592. << " - minimized: "
  4593. << (gWindowp->getMinimized() ? "true": "false") << llendl;
  4594. }
  4595. // Note: if not necessary, do not change the order of the function calls in
  4596. // this function. If you change something, make sure it will not break
  4597. // anything; be especially careful to put anything behind
  4598. // LLViewerTextureList::destroyGL(save_state)
  4599. void LLViewerWindow::stopGL(bool save_state)
  4600. {
  4601. if (!gGLManager.mIsDisabled)
  4602. {
  4603. llinfos << "Shutting down GL..." << llendl;
  4604. // *HACK: That flag *MUST* be set before stopping GL and can only be
  4605. // reset after GL is restarted. Else, you will crash because the GL
  4606. // textures will have their size set to weird numbers and/or will be
  4607. // recreated with GL stopped ! HB
  4608. LLImageGL::sPreserveDiscard = true;
  4609. // Pause texture decode threads (will get unpaused during main loop)
  4610. LLAppViewer::pauseTextureFetch();
  4611. gSky.destroyGL();
  4612. stop_glerror();
  4613. LLManipTranslate::destroyGL();
  4614. stop_glerror();
  4615. gBumpImageList.destroyGL();
  4616. stop_glerror();
  4617. LLFontGL::destroyAllGL();
  4618. stop_glerror();
  4619. LLVOAvatar::destroyGL();
  4620. stop_glerror();
  4621. if (gPipeline.isInit())
  4622. {
  4623. gPipeline.destroyGL();
  4624. }
  4625. gBox.cleanupGL();
  4626. LLViewerTextureList::destroyGL(save_state);
  4627. stop_glerror();
  4628. LLImageGL::stopThread();
  4629. gGLManager.mIsDisabled = true;
  4630. stop_glerror();
  4631. while (LLGLSLShader::sInstances.size())
  4632. {
  4633. LLGLSLShader* shader = *(LLGLSLShader::sInstances.begin());
  4634. shader->unload();
  4635. }
  4636. stop_glerror();
  4637. llinfos << "Remaining allocated texture memory: "
  4638. << LLImageGL::sGlobalTexMemBytes << " bytes." << llendl;
  4639. }
  4640. }
  4641. // Note: if not necessary, do not change the order of the function calls in
  4642. // this function. When changing something, make sure it will not break
  4643. // anything. Be especially careful when putting something before
  4644. // LLViewerTextureList::restoreGL()
  4645. void LLViewerWindow::restoreGL(const std::string& progress_message)
  4646. {
  4647. if (gGLManager.mIsDisabled)
  4648. {
  4649. llinfos << "Restoring GL..." << llendl;
  4650. gGLManager.mIsDisabled = false;
  4651. initGLDefaults();
  4652. LLGLState::restoreGL();
  4653. bool aniso = gSavedSettings.getBool("RenderAnisotropic");
  4654. if (LLImageGL::sGlobalUseAnisotropic != aniso)
  4655. {
  4656. LLImageGL::sGlobalUseAnisotropic = aniso;
  4657. LLImageGL::dirtyTexOptions();
  4658. }
  4659. LLImageGL::initThread(gWindowp,
  4660. gSavedSettings.getS32("GLWorkerThreads"));
  4661. LLViewerTextureList::restoreGL();
  4662. #if 0 // For future support of non-square pixels, and fonts that are properly
  4663. // stretched
  4664. LLFontGL::destroyDefaultFonts();
  4665. #endif
  4666. initFonts();
  4667. gPipeline.restoreGL();
  4668. gSky.restoreGL();
  4669. LLDrawPoolWater::restoreGL();
  4670. LLManipTranslate::restoreGL();
  4671. gBumpImageList.restoreGL();
  4672. LLVOAvatar::restoreGL();
  4673. gResizeScreenTexture = true;
  4674. if (LLFloaterCustomize::isVisible())
  4675. {
  4676. LLVisualParamHint::requestHintUpdates();
  4677. }
  4678. if (!progress_message.empty())
  4679. {
  4680. gRestoreGLTimer.reset();
  4681. gRestoreGL = true;
  4682. setShowProgress(true);
  4683. setProgressString(progress_message);
  4684. }
  4685. // *HACK: now that GL is restarted, we can reset that flag. HB
  4686. LLImageGL::sPreserveDiscard = false;
  4687. llinfos << "...Restoring GL done" << llendl;
  4688. if (!gAppViewerp->restoreErrorTrap())
  4689. {
  4690. llwarns << "Someone took over my signal/exception handler !"
  4691. << llendl;
  4692. }
  4693. }
  4694. }
  4695. void LLViewerWindow::initFonts(F32 zoom_factor)
  4696. {
  4697. LLFontGL::destroyAllGL();
  4698. // Initialize with possibly different zoom factor
  4699. LLFontManager::initClass();
  4700. LLFontGL::initClass(gSavedSettings.getF32("FontScreenDPI"),
  4701. mDisplayScale.mV[VX] * zoom_factor,
  4702. mDisplayScale.mV[VY] * zoom_factor,
  4703. LLUICtrlFactory::getXUIPaths());
  4704. // Force font reloads, which can be very slow
  4705. LLFontGL::loadDefaultFonts();
  4706. // Setup custom fonts.
  4707. LLPreviewNotecard::refreshCachedSettings();
  4708. LLPreviewScript::refreshCachedSettings();
  4709. }
  4710. void LLViewerWindow::getTargetWindow(bool full_screen, U32& width, U32& height)
  4711. {
  4712. // Sadly, width and height settings have been historically stored as signed
  4713. // integers, where it does not make any sense... HB
  4714. S32 signed_width, signed_height;
  4715. if (full_screen)
  4716. {
  4717. signed_width = gSavedSettings.getS32("FullScreenWidth");
  4718. signed_height = gSavedSettings.getS32("FullScreenHeight");
  4719. }
  4720. else
  4721. {
  4722. signed_width = gSavedSettings.getS32("WindowWidth");
  4723. signed_height = gSavedSettings.getS32("WindowHeight");
  4724. }
  4725. width = signed_width >= 0 ? (U32)signed_width : 800;
  4726. height = signed_height >= 0 ? (U32)signed_height : 600;
  4727. }
  4728. void LLViewerWindow::requestResolutionUpdate()
  4729. {
  4730. mResDirty = true;
  4731. }
  4732. bool LLViewerWindow::checkSettings()
  4733. {
  4734. if (mStatesDirty)
  4735. {
  4736. gGL.refreshState();
  4737. gViewerShaderMgrp->setShaders();
  4738. mStatesDirty = false;
  4739. }
  4740. // We want to update the resolution AFTER the states getting refreshed not
  4741. // before.
  4742. if (mResDirty)
  4743. {
  4744. if (gSavedSettings.getBool("FullScreenAutoDetectAspectRatio"))
  4745. {
  4746. gWindowp->setNativeAspectRatio(0.f);
  4747. }
  4748. else
  4749. {
  4750. gWindowp->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
  4751. }
  4752. reshape(getWindowDisplayWidth(), getWindowDisplayHeight());
  4753. // Force aspect ratio
  4754. if (gWindowp->getFullscreen())
  4755. {
  4756. gViewerCamera.setAspect(getDisplayAspectRatio());
  4757. }
  4758. mResDirty = false;
  4759. }
  4760. return false;
  4761. }
  4762. void LLViewerWindow::restartDisplay()
  4763. {
  4764. llinfos << "Restarting GL" << llendl;
  4765. stopGL();
  4766. if (LLStartUp::isLoggedIn())
  4767. {
  4768. restoreGL("Changing resolution...");
  4769. }
  4770. else
  4771. {
  4772. restoreGL();
  4773. if (LLPanelLogin::getInstance())
  4774. {
  4775. // Force a refresh of the fonts and GL images
  4776. LLPanelLogin::getInstance()->refresh();
  4777. }
  4778. }
  4779. }
  4780. bool LLViewerWindow::changeDisplaySettings(LLCoordScreen size,
  4781. bool disable_vsync,
  4782. bool show_progress_bar)
  4783. {
  4784. bool was_maximized = gSavedSettings.getBool("WindowMaximized");
  4785. bool fullscreen = gWindowp->getFullscreen();
  4786. gResizeScreenTexture = true;
  4787. U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
  4788. U32 old_fsaa = gWindowp->getFSAASamples();
  4789. if (!fullscreen)
  4790. {
  4791. // If not maximized, use the request size
  4792. if (!gWindowp->getMaximized())
  4793. {
  4794. gWindowp->setSize(size);
  4795. }
  4796. if (fsaa == old_fsaa)
  4797. {
  4798. return true;
  4799. }
  4800. }
  4801. // Close floaters that do not handle settings change
  4802. LLFloaterSnapshot::hide(NULL);
  4803. bool result_first_try = false;
  4804. bool result_second_try = false;
  4805. LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
  4806. LLWorld::sendAgentPause();
  4807. llinfos << "Stopping GL during changeDisplaySettings" << llendl;
  4808. stopGL();
  4809. mIgnoreActivate = true;
  4810. LLCoordScreen old_size;
  4811. gWindowp->getSize(&old_size);
  4812. gWindowp->setFSAASamples(fsaa);
  4813. result_first_try = gWindowp->switchContext(fullscreen, size,
  4814. disable_vsync);
  4815. if (!result_first_try)
  4816. {
  4817. // Try to switch back
  4818. gWindowp->setFSAASamples(old_fsaa);
  4819. result_second_try = gWindowp->switchContext(fullscreen, old_size,
  4820. disable_vsync);
  4821. if (!result_second_try)
  4822. {
  4823. // We are stuck... try once again with a minimal resolution ?
  4824. LLWorld::sendAgentResume();
  4825. mIgnoreActivate = false;
  4826. gFocusMgr.setKeyboardFocus(keyboard_focus);
  4827. return false;
  4828. }
  4829. }
  4830. LLWorld::sendAgentResume();
  4831. llinfos << "Restoring GL during resolution change" << llendl;
  4832. if (show_progress_bar)
  4833. {
  4834. restoreGL("Changing resolution...");
  4835. }
  4836. else
  4837. {
  4838. restoreGL();
  4839. }
  4840. if (!result_first_try)
  4841. {
  4842. LLSD args;
  4843. args["RESX"] = llformat("%d", size.mX);
  4844. args["RESY"] = llformat("%d", size.mY);
  4845. gNotifications.add("ResolutionSwitchFail", args);
  4846. size = old_size; // For reshape below
  4847. }
  4848. bool success = result_first_try || result_second_try;
  4849. if (success)
  4850. {
  4851. #if LL_WINDOWS
  4852. // Only trigger a reshape after switching to fullscreen; otherwise rely
  4853. // on the windows callback (otherwise size is wrong; this is the entire
  4854. // window size, reshape wants the visible window size)
  4855. if (fullscreen && result_first_try)
  4856. #endif
  4857. {
  4858. reshape(size.mX, size.mY);
  4859. }
  4860. }
  4861. if (!fullscreen && success)
  4862. {
  4863. // Maximize window if was maximized, else reposition
  4864. if (was_maximized)
  4865. {
  4866. gWindowp->maximize();
  4867. }
  4868. else
  4869. {
  4870. S32 window_x = gSavedSettings.getS32("WindowX");
  4871. S32 window_y = gSavedSettings.getS32("WindowY");
  4872. gWindowp->setPosition(LLCoordScreen(window_x, window_y));
  4873. }
  4874. }
  4875. mIgnoreActivate = false;
  4876. gFocusMgr.setKeyboardFocus(keyboard_focus);
  4877. return success;
  4878. }
  4879. F32 LLViewerWindow::getDisplayAspectRatio() const
  4880. {
  4881. if (gWindowp->getFullscreen())
  4882. {
  4883. if (gSavedSettings.getBool("FullScreenAutoDetectAspectRatio"))
  4884. {
  4885. return gWindowp->getNativeAspectRatio();
  4886. }
  4887. else
  4888. {
  4889. return gSavedSettings.getF32("FullScreenAspectRatio");
  4890. }
  4891. }
  4892. return gWindowp->getNativeAspectRatio();
  4893. }
  4894. void LLViewerWindow::calcDisplayScale()
  4895. {
  4896. F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor") *
  4897. gWindowp->getSystemUISize();
  4898. // HiDPI scaling can be 4x. UI scaling in prefs is up to 2x, so max is 8x
  4899. ui_scale_factor = llclamp(ui_scale_factor, 0.75f, 8.f);
  4900. LLVector2 display_scale;
  4901. display_scale.set(llmax(1.f / gWindowp->getPixelAspectRatio(), 1.f),
  4902. llmax(gWindowp->getPixelAspectRatio(), 1.f));
  4903. F32 height_normalization = 1.f;
  4904. if (gSavedSettings.getBool("UIAutoScale"))
  4905. {
  4906. height_normalization = (F32)mWindowRect.getHeight() /
  4907. display_scale.mV[VY] / 768.f;
  4908. }
  4909. if (gWindowp->getFullscreen())
  4910. {
  4911. display_scale *= (ui_scale_factor * height_normalization);
  4912. }
  4913. else
  4914. {
  4915. display_scale *= ui_scale_factor;
  4916. }
  4917. // Limit minimum display scale
  4918. if (display_scale.mV[VX] < MIN_DISPLAY_SCALE ||
  4919. display_scale.mV[VY] < MIN_DISPLAY_SCALE)
  4920. {
  4921. display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX],
  4922. display_scale.mV[VY]);
  4923. }
  4924. if (gWindowp->getFullscreen())
  4925. {
  4926. display_scale.mV[0] = ll_round(display_scale.mV[0],
  4927. 2.f / (F32)mWindowRect.getWidth());
  4928. display_scale.mV[1] = ll_round(display_scale.mV[1],
  4929. 2.f / (F32)mWindowRect.getHeight());
  4930. }
  4931. if (display_scale != mDisplayScale)
  4932. {
  4933. llinfos << "Setting display scale to " << display_scale << llendl;
  4934. mDisplayScale = display_scale;
  4935. mDisplayScaleDivisor.set(1.f / mDisplayScale.mV[VX],
  4936. 1.f / mDisplayScale.mV[VY]);
  4937. // Init default fonts
  4938. initFonts();
  4939. }
  4940. }
  4941. S32 LLViewerWindow::getChatConsoleBottomPad()
  4942. {
  4943. S32 offset = 0;
  4944. if (gToolBarp && gToolBarp->getVisible())
  4945. {
  4946. offset += TOOL_BAR_HEIGHT;
  4947. }
  4948. return offset;
  4949. }
  4950. LLRect LLViewerWindow::getChatConsoleRect()
  4951. {
  4952. LLRect full_window(0, getWindowHeight(), getWindowWidth(), 0);
  4953. LLRect console_rect = full_window;
  4954. constexpr S32 CONSOLE_PADDING_TOP = 24;
  4955. constexpr S32 CONSOLE_PADDING_BOTTOM = 24;
  4956. console_rect.mTop -= CONSOLE_PADDING_TOP;
  4957. console_rect.mBottom += getChatConsoleBottomPad() + CONSOLE_PADDING_BOTTOM;
  4958. console_rect.mLeft += CONSOLE_PADDING_LEFT;
  4959. static LLCachedControl<bool> chat_full_width(gSavedSettings,
  4960. "ChatFullWidth");
  4961. if (chat_full_width)
  4962. {
  4963. console_rect.mRight -= CONSOLE_PADDING_RIGHT;
  4964. }
  4965. else
  4966. {
  4967. // Make console rect somewhat narrow so having inventory open is
  4968. // less of a problem.
  4969. console_rect.mRight = console_rect.mLeft + 2 * getWindowWidth() / 3;
  4970. }
  4971. return console_rect;
  4972. }
  4973. //static
  4974. bool LLViewerWindow::onAlert(const LLSD& notify)
  4975. {
  4976. LLNotificationPtr notification =
  4977. gNotifications.find(notify["id"].asUUID());
  4978. // If we are in mouselook, the mouse is hidden and so the user cannot click
  4979. // the dialog buttons. In that case, change to First Person instead.
  4980. if (gAgent.cameraMouselook())
  4981. {
  4982. gAgent.changeCameraToDefault();
  4983. }
  4984. return false;
  4985. }
  4986. ////////////////////////////////////////////////////////////////////////////
  4987. LLBottomPanel::LLBottomPanel(const LLRect& rect)
  4988. : LLPanel("bottom panel", rect, false),
  4989. mIndicator(NULL)
  4990. {
  4991. // Bottom panel is focus root, so Tab moves through the toolbar and button
  4992. // bar, and overlay
  4993. setFocusRoot(true);
  4994. // Do not capture mouse clicks that do not hit a child
  4995. setMouseOpaque(false);
  4996. setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
  4997. // Flag this panel as chrome so buttons do not grab keyboard focus
  4998. setIsChrome(true);
  4999. }
  5000. LLBottomPanel::~LLBottomPanel()
  5001. {
  5002. gBottomPanelp = NULL;
  5003. }
  5004. void LLBottomPanel::setFocusIndicator(LLView* indicator)
  5005. {
  5006. mIndicator = indicator;
  5007. }
  5008. void LLBottomPanel::draw()
  5009. {
  5010. if (mIndicator)
  5011. {
  5012. bool hasFocus = gFocusMgr.childHasKeyboardFocus(this);
  5013. mIndicator->setVisible(hasFocus);
  5014. mIndicator->setEnabled(hasFocus);
  5015. }
  5016. LLPanel::draw();
  5017. }
  5018. //
  5019. // LLPickInfo
  5020. //
  5021. LLPickInfo::LLPickInfo()
  5022. : mKeyMask(MASK_NONE),
  5023. mPickCallback(NULL),
  5024. mPickType(PICK_INVALID),
  5025. mWantSurfaceInfo(false),
  5026. mObjectFace(-1),
  5027. mGLTFNodeIndex(-1),
  5028. mGLTFPrimIndex(-1),
  5029. mUVCoords(-1.f, -1.f),
  5030. mSTCoords(-1.f, -1.f),
  5031. mXYCoords(-1, -1),
  5032. mIntersection(),
  5033. mNormal(),
  5034. mTangent(),
  5035. mBinormal(),
  5036. mHUDIcon(NULL),
  5037. mPickTransparent(false),
  5038. mPickRigged(false),
  5039. mPickParticle(false)
  5040. {
  5041. }
  5042. LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
  5043. MASK keyboard_mask,
  5044. bool pick_transparent,
  5045. bool pick_rigged,
  5046. bool pick_particle,
  5047. bool pick_uv_coords,
  5048. void (*pick_callback)(const LLPickInfo&))
  5049. : mMousePt(mouse_pos),
  5050. mKeyMask(keyboard_mask),
  5051. mPickCallback(pick_callback),
  5052. mPickType(PICK_INVALID),
  5053. mWantSurfaceInfo(pick_uv_coords),
  5054. mObjectFace(-1),
  5055. mGLTFNodeIndex(-1),
  5056. mGLTFPrimIndex(-1),
  5057. mUVCoords(-1.f, -1.f),
  5058. mSTCoords(-1.f, -1.f),
  5059. mXYCoords(-1, -1),
  5060. mNormal(),
  5061. mTangent(),
  5062. mBinormal(),
  5063. mHUDIcon(NULL),
  5064. mPickTransparent(pick_transparent),
  5065. mPickRigged(pick_rigged),
  5066. mPickParticle(pick_particle)
  5067. {
  5068. }
  5069. void LLPickInfo::fetchResults()
  5070. {
  5071. static LLVector4a intersection;
  5072. LLHUDIcon* hit_icon =
  5073. gViewerWindowp->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f,
  5074. &intersection);
  5075. static LLVector4a origin;
  5076. origin.load3(gViewerCamera.getOrigin().mV);
  5077. static LLVector4a delta;
  5078. F32 icon_dist = 0.f;
  5079. if (hit_icon)
  5080. {
  5081. delta.setSub(intersection, origin);
  5082. icon_dist = delta.getLength3().getF32();
  5083. }
  5084. S32 face_hit = -1;
  5085. static LLVector4a normal;
  5086. static LLVector4a tangent;
  5087. static LLVector4a start;
  5088. static LLVector4a end;
  5089. static LLVector4a particle_end;
  5090. static LLVector2 uv;
  5091. LLViewerObject* objectp =
  5092. gViewerWindowp->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, NULL,
  5093. -1, mPickTransparent, mPickRigged,
  5094. &face_hit,
  5095. &gDebugRaycastGLTFNodeHit,
  5096. &gDebugRaycastGLTFPrimHit,
  5097. &intersection, &uv, &normal,
  5098. &tangent, &start, &end);
  5099. if (objectp && objectp->isDead())
  5100. {
  5101. return;
  5102. }
  5103. mPickPt = mMousePt;
  5104. U32 te_offset = face_hit > -1 ? face_hit : 0;
  5105. if (mPickParticle)
  5106. {
  5107. // Get the end point of line segment to use for particle raycast
  5108. if (objectp)
  5109. {
  5110. particle_end = intersection;
  5111. }
  5112. else
  5113. {
  5114. particle_end = end;
  5115. }
  5116. }
  5117. // Un-project relative clicked coordinate from window coordinate using GL
  5118. delta.setSub(origin, intersection);
  5119. if (hit_icon && (!objectp || icon_dist < delta.getLength3().getF32()))
  5120. {
  5121. // Was this name referring to a hud icon ?
  5122. mHUDIcon = hit_icon;
  5123. mPickType = PICK_ICON;
  5124. mPosGlobal = mHUDIcon->getPositionGlobal();
  5125. }
  5126. else if (objectp)
  5127. {
  5128. if (objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
  5129. {
  5130. // Hit land
  5131. mPickType = PICK_LAND;
  5132. mObjectID.setNull(); // land has no id
  5133. // put global position into land_pos
  5134. static LLVector3d land_pos;
  5135. if (!gViewerWindowp->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY,
  5136. &land_pos))
  5137. {
  5138. // The selected point is beyond the draw distance or is
  5139. // otherwise not selectable. Return before calling
  5140. // mPickCallback().
  5141. return;
  5142. }
  5143. // Fudge the land focus a little bit above ground.
  5144. mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
  5145. }
  5146. else
  5147. {
  5148. if (isFlora(objectp))
  5149. {
  5150. mPickType = PICK_FLORA;
  5151. }
  5152. else
  5153. {
  5154. mPickType = PICK_OBJECT;
  5155. }
  5156. LLVector3 v_intersection(intersection.getF32ptr());
  5157. mObjectOffset = gAgent.calcFocusOffset(objectp, v_intersection,
  5158. mPickPt.mX, mPickPt.mY);
  5159. mObjectID = objectp->mID;
  5160. mObjectFace = te_offset == NO_FACE ? -1 : (S32)te_offset;
  5161. mPosGlobal = gAgent.getPosGlobalFromAgent(v_intersection);
  5162. if (mWantSurfaceInfo)
  5163. {
  5164. getSurfaceInfo();
  5165. }
  5166. }
  5167. }
  5168. if (mPickParticle)
  5169. {
  5170. // Search for closest particle to click origin out to intersection
  5171. // point
  5172. S32 part_face = -1;
  5173. LLVOPartGroup* groupp =
  5174. gPipeline.lineSegmentIntersectParticle(start, particle_end, NULL,
  5175. &part_face);
  5176. if (groupp)
  5177. {
  5178. mParticleOwnerID = groupp->getPartOwner(part_face);
  5179. mParticleSourceID = groupp->getPartSource(part_face);
  5180. }
  5181. }
  5182. if (mPickCallback)
  5183. {
  5184. mPickCallback(*this);
  5185. }
  5186. }
  5187. LLPointer<LLViewerObject> LLPickInfo::getObject() const
  5188. {
  5189. return gObjectList.findObject(mObjectID);
  5190. }
  5191. void LLPickInfo::updateXYCoords()
  5192. {
  5193. if (mObjectFace > -1)
  5194. {
  5195. const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
  5196. if (!tep) return;
  5197. LLPointer<LLViewerTexture> imagep =
  5198. LLViewerTextureManager::getFetchedTexture(tep->getID());
  5199. if (imagep.notNull() && mUVCoords.mV[VX] >= 0.f &&
  5200. mUVCoords.mV[VY] >= 0.f)
  5201. {
  5202. mXYCoords.mX = ll_round(mUVCoords.mV[VX] *
  5203. (F32)imagep->getWidth());
  5204. mXYCoords.mY = ll_round((1.f - mUVCoords.mV[VY]) *
  5205. (F32)imagep->getHeight());
  5206. }
  5207. }
  5208. }
  5209. void LLPickInfo::getSurfaceInfo()
  5210. {
  5211. // Set values to uninitialized: this is what we return if no intersection
  5212. // is found
  5213. mObjectFace = -1;
  5214. mUVCoords = LLVector2(-1.f, -1.f);
  5215. mSTCoords = LLVector2(-1.f, -1.f);
  5216. mXYCoords = LLCoordScreen(-1.f, -1.f);
  5217. mIntersection.setZero();
  5218. mNormal.setZero();
  5219. mBinormal.setZero();
  5220. mTangent.setZero();
  5221. LLViewerObject* objectp = getObject();
  5222. if (!objectp) return;
  5223. static LLVector4a tangent;
  5224. static LLVector4a intersection;
  5225. static LLVector4a normal;
  5226. tangent.clear();
  5227. normal.clear();
  5228. intersection.clear();
  5229. if (gViewerWindowp->cursorIntersect(ll_round((F32)mMousePt.mX),
  5230. ll_round((F32)mMousePt.mY), 1024.f,
  5231. objectp, -1, mPickTransparent,
  5232. mPickRigged, &mObjectFace,
  5233. &mGLTFNodeIndex, &mGLTFPrimIndex,
  5234. &intersection, &mSTCoords, &normal,
  5235. &tangent))
  5236. {
  5237. // If we succeeded with the intersect above, compute the texture
  5238. // coordinates:
  5239. if (objectp->mDrawable.notNull() && mObjectFace > -1)
  5240. {
  5241. LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
  5242. if (facep)
  5243. {
  5244. mUVCoords = facep->surfaceToTexture(mSTCoords, intersection,
  5245. normal);
  5246. }
  5247. }
  5248. mIntersection.set(intersection.getF32ptr());
  5249. mNormal.set(normal.getF32ptr());
  5250. mTangent.set(tangent.getF32ptr());
  5251. // Extrapoloate binormal from normal and tangent
  5252. static LLVector4a binormal;
  5253. binormal.setCross3(normal, tangent);
  5254. binormal.mul(tangent.getF32ptr()[3]);
  5255. mBinormal.set(binormal.getF32ptr());
  5256. mBinormal.normalize();
  5257. mNormal.normalize();
  5258. mTangent.normalize();
  5259. // and XY coords:
  5260. updateXYCoords();
  5261. }
  5262. }
  5263. //static
  5264. bool LLPickInfo::isFlora(LLViewerObject* object)
  5265. {
  5266. if (!object) return false;
  5267. LLPCode pcode = object->getPCode();
  5268. return pcode == LL_PCODE_LEGACY_GRASS || pcode == LL_PCODE_LEGACY_TREE;
  5269. }
  5270. ///////////////////////////////////////////////////////////////////////////////
  5271. // HBTempWindowTitle class
  5272. ///////////////////////////////////////////////////////////////////////////////
  5273. HBTempWindowTitle::HBTempWindowTitle(const std::string& message)
  5274. {
  5275. if (gWindowp && !message.empty())
  5276. {
  5277. std::string title = gSecondLife + " - " + message;
  5278. LLStringUtil::truncate(title, 255);
  5279. gWindowp->setWindowTitle(title);
  5280. }
  5281. }
  5282. HBTempWindowTitle::~HBTempWindowTitle()
  5283. {
  5284. if (gWindowp)
  5285. {
  5286. gWindowp->setWindowTitle(gWindowTitle);
  5287. }
  5288. }