1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837 |
- /**
- * @file llviewerobject.cpp
- * @brief Base class for viewer objects
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include <sstream>
- #include <utility>
- #include "boost/lexical_cast.hpp"
- #include "llviewerobject.h"
- #include "imageids.h"
- #include "llaudioengine.h"
- #include "lldatapacker.h"
- #include "lldir.h"
- #include "lldispatcher.h"
- #include "llfasttimer.h"
- #include "llglslshader.h" // For gUsePBRShaders
- #include "llinventory.h"
- #include "llmaterialid.h"
- #include "llmaterialtable.h"
- #include "llnamevalue.h"
- #include "llprimitive.h"
- #include "llregionhandle.h"
- #include "llsdserialize.h"
- #include "llsdutil.h"
- #include "lltree_common.h"
- #include "llvolume.h"
- #include "llvolumemessage.h"
- #include "llxfermanager.h"
- #include "llmessage.h"
- #include "object_flags.h"
- #include "llagent.h"
- #include "llaudiosourcevo.h"
- #include "lldrawable.h"
- #include "llface.h"
- #include "llflexibleobject.h"
- #include "hbfloaterdebugtags.h"
- #include "llfloaterproperties.h"
- #include "llfloatertools.h"
- #include "llfollowcam.h"
- #include "llgltfmateriallist.h"
- #include "llgridmanager.h"
- #include "llhudtext.h"
- #include "llinventorymodel.h"
- #include "lllocalbitmaps.h"
- #include "llmanip.h"
- #include "llmutelist.h"
- #include "llpipeline.h"
- #include "llselectmgr.h"
- #include "lltooldraganddrop.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewertexturelist.h"
- #include "llviewerinventory.h"
- #include "llviewermessage.h" // For gGenericDispatcher;
- #include "llviewerobjectlist.h"
- #include "llviewerparceloverlay.h"
- #include "llviewerpartsim.h"
- #include "llviewerpartsource.h"
- #include "llviewerregion.h"
- #include "llviewertextureanim.h"
- #include "llvoavatarpuppet.h"
- #include "llvoavatarself.h"
- #include "llvocache.h"
- #include "llvoclouds.h"
- #include "llvograss.h"
- #include "llvopartgroup.h"
- #include "llvosky.h"
- #include "llvosurfacepatch.h"
- #include "llvotree.h"
- #include "llvovolume.h"
- #include "llvowater.h"
- #include "llvowlsky.h"
- #include "llworld.h"
- using namespace LLAvatarAppearanceDefines;
- // At 45 Hz collisions seem stable and objects seem to settle down at a
- // reasonable rate. JC 3/18/2003
- constexpr F32 PHYSICS_TIMESTEP = 1.f / 45.f;
- // Maximum number of unknown tokens in inventory files
- constexpr U32 MAX_INV_FILE_READ_FAILS = 25;
- //constexpr U8 LL_SOUND_FLAG_NONE = 0x0;
- constexpr U8 LL_SOUND_FLAG_LOOP = 1 << 0;
- constexpr U8 LL_SOUND_FLAG_SYNC_MASTER = 1 << 1;
- constexpr U8 LL_SOUND_FLAG_SYNC_SLAVE = 1 << 2;
- //constexpr U8 LL_SOUND_FLAG_SYNC_PENDING = 1 << 3;
- constexpr U8 LL_SOUND_FLAG_QUEUE = 1 << 4;
- constexpr U8 LL_SOUND_FLAG_STOP = 1 << 5;
- // The maximum size of an object extra parameters binary (packed) block
- #define MAX_OBJECT_PARAMS_SIZE 1024
- bool LLViewerObject::sVelocityInterpolate = true;
- bool LLViewerObject::sPingInterpolate = true;
- // For motion interpolation: after X seconds with no updates, don't predict
- // object motion. NOTE: sMaxUpdateInterpolationTime must be greater than
- // sPhaseOutUpdateInterpolationTime.
- F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0;
- // For motion interpolation: after Y seconds with no updates, taper off motion
- // prediction
- F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 1.0;
- // For motion interpolation: do not interpolate over this time on region
- // crossing
- F64 LLViewerObject::sMaxRegionCrossingInterpolationTime = 1.0;
- S32 LLViewerObject::sNumObjects = 0;
- bool LLViewerObject::sUseNewTargetOmegaCode = false;
- std::map<std::string, U32> LLViewerObject::sObjectDataMap;
- LLUUID LLViewerObject::sDebugObjectId;
- //static
- LLViewerObject* LLViewerObject::createObject(const LLUUID& id, LLPCode pcode,
- LLViewerRegion* regionp,
- S32 flags)
- {
- LL_FAST_TIMER(FTM_CREATE_OBJECT);
- switch (pcode)
- {
- case LL_PCODE_VOLUME:
- return (LLViewerObject*)new LLVOVolume(id, regionp);
- case LL_PCODE_LEGACY_AVATAR:
- {
- if (id == gAgentID)
- {
- if (!gAgentAvatarp)
- {
- gAgentAvatarp = new LLVOAvatarSelf(id, regionp);
- gAgentAvatarp->initInstance();
- }
- else if (isAgentAvatarValid())
- {
- gAgentAvatarp->updateRegion(regionp);
- }
- return gAgentAvatarp;
- }
- if (flags & CO_FLAG_UI_AVATAR)
- {
- LLVOAvatarUI* avatarp = new LLVOAvatarUI(id, regionp);
- avatarp->initInstance();
- return avatarp;
- }
- if (flags & CO_FLAG_PUPPET_AVATAR)
- {
- LLVOAvatarPuppet* avatarp = new LLVOAvatarPuppet(id, regionp);
- avatarp->initInstance();
- return avatarp;
- }
- LLVOAvatar* avatarp = new LLVOAvatar(id, regionp);
- avatarp->initInstance();
- return avatarp;
- }
- case LL_PCODE_LEGACY_GRASS:
- return new LLVOGrass(id, regionp);
- case LL_PCODE_LEGACY_TREE:
- return new LLVOTree(id, regionp);
- case LL_VO_CLOUDS:
- return new LLVOClouds(id, regionp);
- case LL_VO_SURFACE_PATCH:
- return new LLVOSurfacePatch(id, regionp);
- case LL_VO_SKY:
- return new LLVOSky(id, regionp);
- case LL_VO_VOID_WATER:
- return new LLVOVoidWater(id, regionp);
- case LL_VO_WATER:
- return new LLVOWater(id, regionp);
- case LL_VO_PART_GROUP:
- return new LLVOPartGroup(id, regionp);
- case LL_VO_HUD_PART_GROUP:
- return new LLVOHUDPartGroup(id, regionp);
- case LL_VO_WL_SKY:
- return new LLVOWLSky(id, regionp);
- default:
- llwarns_once << "Unknown or deperecated object pcode: "
- << (S32)pcode << llendl;
- }
- return NULL;
- }
- LLViewerObject::LLViewerObject(const LLUUID& id, LLPCode pcode,
- LLViewerRegion* regionp, bool is_global)
- : mID(id),
- mLocalID(0),
- mTotalCRC(0),
- mListIndex(-1),
- mCanSelect(true),
- mFlags(0),
- mFlagsLoaded(false),
- mPhysicsShapeType(0),
- mPhysicsGravity(0),
- mPhysicsFriction(0),
- mPhysicsDensity(0),
- mPhysicsRestitution(0),
- mCreateSelected(false),
- mIsReflectionProbe(false),
- mIsHeroProbe(false),
- mBestUpdatePrecision(0),
- mLastInterpUpdateSecs(LLFrameTimer::getElapsedSeconds()),
- mRegionCrossExpire(0.0),
- mLastMessageUpdateSecs(0.0),
- mLatestRecvPacketID(0),
- mData(NULL),
- mAudioSourcep(NULL),
- mAudioGain(1.f),
- mSoundCutOffRadius(0.f),
- mAppAngle(0.f),
- mPixelArea(1024.f),
- mInventory(NULL),
- mInventorySerialNum(0),
- mExpectedInventorySerialNum(0),
- mInvRequestState(INVENTORY_REQUEST_STOPPED),
- mInvRequestXFerId(0),
- mInventoryDirty(false),
- mRegionp(regionp),
- mDead(false),
- mOrphaned(false),
- mUserSelected(false),
- mOnActiveList(false),
- mOnMap(false),
- mStatic(false),
- mNumFaces(0),
- mRotTime(0.f),
- mAttachmentState(0),
- mMedia(NULL),
- mClickAction(0),
- mObjectCost(0.f),
- mLinksetCost(0.f),
- mPhysicsCost(0.f),
- mLinksetPhysicsCost(0.f),
- mCostStale(true),
- mShouldShrinkWrap(false),
- mPhysicsShapeUnknown(true),
- mAttachmentItemID(LLUUID::null),
- mLastUpdateType(OUT_UNKNOWN),
- mLastUpdateCached(false)
- {
- if (!is_global)
- {
- llassert(mRegionp);
- }
- setPCode(pcode);
- // Initialize the extra parameters data arrays to NULL pointers and false
- // 'in use' booleans.
- memset((void*)&mExtraParameters[0], 0,
- LL_EPARAMS_COUNT * sizeof(LLNetworkData*));
- memset((void*)&mExtraParameterInUse[0], (int)false,
- LL_EPARAMS_COUNT * sizeof(bool));
- mDebugUpdateMsg = id == sDebugObjectId;
- if (mDebugUpdateMsg)
- {
- llinfos << "Debugged object created with Id: " << id << llendl;
- }
- if (!is_global && mRegionp)
- {
- mPositionAgent = mRegionp->getOriginAgent();
- }
- if (sUseNewTargetOmegaCode)
- {
- resetRot();
- }
- ++sNumObjects;
- }
- LLViewerObject::~LLViewerObject()
- {
- if (!mDead) // Paranoia
- {
- llwarns << "Object " << std::hex << intptr_t(this) << std::dec
- << " destroyed while not yet marked dead." << llendl;
- llassert(false);
- markDead();
- }
- deleteTEImages();
- // Unhook from reflection probe manager
- if (mReflectionProbe.notNull())
- {
- mReflectionProbe->mViewerObject = NULL;
- mReflectionProbe = NULL;
- }
- if (mInventory)
- {
- mInventory->clear(); // Will de-reference and delete entries
- delete mInventory;
- mInventory = NULL;
- }
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- // Delete memory associated with extra parameters.
- for (S32 i = 0; i < LL_EPARAMS_COUNT; ++i)
- {
- LLNetworkData* param = mExtraParameters[i];
- if (param)
- {
- delete param;
- }
- }
- std::for_each(mNameValuePairs.begin(), mNameValuePairs.end(),
- DeletePairedPointer());
- mNameValuePairs.clear();
- mJointRiggingInfoTab.clear();
- delete[] mData;
- mData = NULL;
- delete mMedia;
- mMedia = NULL;
- --sNumObjects;
- llassert(mChildList.size() == 0);
- clearInventoryListeners();
- }
- void LLViewerObject::deleteTEImages()
- {
- mTEImages.clear();
- mTENormalMaps.clear();
- mTESpecularMaps.clear();
- }
- void LLViewerObject::markDead()
- {
- if (mDead)
- {
- return;
- }
- if (mUserSelected)
- {
- gSelectMgr.deselectObjectAndFamily(this);
- }
- // Do this before the following removeChild()...
- LLVOAvatar* av = getAvatar();
- // Root object of this hierarchy unlinks itself.
- if (getParent())
- {
- ((LLViewerObject*)getParent())->removeChild(this);
- }
- LLUUID mesh_id;
- if (av && LLVOAvatar::getRiggedMeshID(this, mesh_id))
- {
- // This case is needed for indirectly attached mesh objects.
- av->updateAttachmentOverrides();
- }
- LLVOInventoryListener::removeObjectFromListeners(this);
- // Mark itself as dead
- mDead = true;
- if (mRegionp)
- {
- mRegionp->removeFromCreatedList(getLocalID());
- }
- gObjectList.cleanupReferences(this);
- while (mChildList.size() > 0)
- {
- LLViewerObject* childp = mChildList.back();
- if (childp->isAvatar())
- {
- // Make sure avatar is no longer parented, so we can properly set
- // its position
- childp->setDrawableParent(NULL);
- LLVOAvatar* avatarp = (LLVOAvatar*)childp;
- if (avatarp->isSelf())
- {
- LL_DEBUGS("AgentSit") << "Unsitting agent from dead object"
- << LL_ENDL;
- }
- avatarp->getOffObject();
- childp->setParent(NULL);
- }
- else
- {
- childp->setParent(NULL);
- childp->markDead();
- }
- mChildList.pop_back();
- }
- if (mDrawable.notNull())
- {
- // Drawables are reference counted, mark as dead, then nuke the
- // pointer.
- mDrawable->markDead();
- mDrawable = NULL;
- }
- // Unhook from reflection probe manager
- if (mReflectionProbe.notNull())
- {
- mReflectionProbe->mViewerObject = NULL;
- mReflectionProbe = NULL;
- }
- // Free any reference to a GLTF asset. HB
- mGLTFAsset = NULL;
- if (mText)
- {
- mText->markDead();
- mText = NULL;
- }
- if (mIcon)
- {
- mIcon->markDead();
- mIcon = NULL;
- }
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- if (mAudioSourcep)
- {
- // Do some cleanup
- if (gAudiop)
- {
- gAudiop->cleanupAudioSource(mAudioSourcep);
- }
- mAudioSourcep = NULL;
- }
- if (flagAnimSource())
- {
- if (isAgentAvatarValid())
- {
- // Stop motions associated with this object
- gAgentAvatarp->stopMotionFromSource(mID);
- }
- }
- if (flagCameraSource())
- {
- LLFollowCamMgr::removeFollowCamParams(mID);
- }
- // Do this last, since this will destroy ourselves if we are the puppet
- // avatar object...
- if (av && av->isPuppetAvatar())
- {
- unlinkPuppetAvatar();
- }
- }
- void LLViewerObject::dump() const
- {
- llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl;
- llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl;
- llinfos << "Update Age: "
- << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs
- << llendl;
- llinfos << "Parent: " << getParent() << llendl;
- llinfos << "ID: " << mID << llendl;
- llinfos << "LocalID: " << mLocalID << llendl;
- llinfos << "PositionRegion: " << getPositionRegion() << llendl;
- llinfos << "PositionAgent: " << getPositionAgent() << llendl;
- llinfos << "PositionGlobal: " << getPositionGlobal() << llendl;
- llinfos << "Velocity: " << getVelocity() << llendl;
- llinfos << "Angular velocity: " << getAngularVelocity() << llendl;
- if (mDrawable.notNull() && mDrawable->getNumFaces() &&
- mDrawable->getFace(0))
- {
- LLFacePool* poolp = mDrawable->getFace(0)->getPool();
- if (poolp)
- {
- llinfos << "Pool: " << poolp << llendl;
- llinfos << "Pool reference count: " << poolp->mReferences.size()
- << llendl;
- }
- else
- {
- llinfos << "No pool for this object." << llendl;
- }
- }
- #if 0
- llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl;
- llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl;
- llinfos << "Velocity: " << getVelocity() << llendl;
- llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: "
- << permYouOwner() << " Edit: " << mPermEdit << llendl;
- llinfos << "UsePhysics: " << flagUsePhysics() << " CanSelect "
- << mCanSelect << " UserSelected " << mUserSelected << llendl;
- llinfos << "AppAngle: " << mAppAngle << llendl;
- llinfos << "PixelArea: " << mPixelArea << llendl;
- char buffer[1000];
- for (char* key = mNameValuePairs.getFirstKey(); key;
- key = mNameValuePairs.getNextKey())
- {
- mNameValuePairs[key]->printNameValue(buffer);
- llinfos << buffer << llendl;
- }
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); ++iter)
- {
- LLViewerObject* child = *iter;
- llinfos << " child " << child->mID << llendl;
- }
- #endif
- }
- void LLViewerObject::printNameValuePairs() const
- {
- for (name_value_map_t::const_iterator iter = mNameValuePairs.begin(),
- end = mNameValuePairs.end();
- iter != end; ++iter)
- {
- LLNameValue* nv = iter->second;
- llinfos << nv->printNameValue() << llendl;
- }
- }
- void LLViewerObject::initVOClasses()
- {
- sPingInterpolate = gSavedSettings.getBool("PingInterpolate");
- sVelocityInterpolate = gSavedSettings.getBool("VelocityInterpolate");
- setUpdateInterpolationTimes(gSavedSettings.getF32("InterpolationTime"),
- gSavedSettings.getF32("InterpolationPhaseOut"),
- gSavedSettings.getF32("RegionCrossingInterpolationTime"));
- sDebugObjectId.set(gSavedSettings.getString("DebugObjectId"), false);
- if (sDebugObjectId.notNull())
- {
- llinfos << "Debugging enabled on object Id: " << sDebugObjectId
- << llendl;
- }
- // New, experimental code paths toggles (get rid of them once confirmed):
- sUseNewTargetOmegaCode = gSavedSettings.getBool("UseNewTargetOmegaCode");
- // Initialized shared class stuff first.
- LLVOAvatar::initClass();
- LLVOTree::initClass();
- llinfos << "LLViewerObject size: " << sizeof(LLViewerObject) << llendl;
- LLVOGrass::initClass();
- LLVOWater::initClass();
- LLVOVolume::initClass();
- LLVOWLSky::initClass();
- LLVolumeImplFlexible::sUpdateFactor =
- gSavedSettings.getF32("RenderFlexTimeFactor");
- LLVOCacheEntry::updateSettings();
- initObjectDataMap();
- }
- void LLViewerObject::cleanupVOClasses()
- {
- LLVOWLSky::cleanupClass();
- LLVOGrass::cleanupClass();
- LLVOWater::cleanupClass();
- LLVOTree::cleanupClass();
- LLVOAvatar::cleanupClass();
- LLVOVolume::cleanupClass();
- sObjectDataMap.clear();
- }
- void LLViewerObject::toggleDebugUpdateMsg()
- {
- mDebugUpdateMsg = !mDebugUpdateMsg;
- llinfos << "Debugging " << (mDebugUpdateMsg ? "enabled" : "disabled")
- << " on object Id: " << mID << llendl;
- }
- void LLViewerObject::setlocalID(U32 local_id)
- {
- if (mLocalID != local_id)
- {
- mLocalID = local_id;
- if (sDebugObjectId == mID)
- {
- llinfos << "Received local Id " << local_id << " for object "
- << mID << llendl;
- }
- }
- }
- //static
- void LLViewerObject::setDebugObjectId(const LLUUID& id)
- {
- if (id == sDebugObjectId)
- {
- return;
- }
- if (sDebugObjectId.notNull())
- {
- LLViewerObject* objectp = gObjectList.findObject(sDebugObjectId);
- if (objectp)
- {
- objectp->mDebugUpdateMsg = false;
- }
- }
- sDebugObjectId = id;
- if (id.isNull())
- {
- return;
- }
- LLViewerObject* objectp = gObjectList.findObject(sDebugObjectId);
- if (objectp)
- {
- objectp->mDebugUpdateMsg = true;
- llinfos << "Debugging enabled on object Id: " << id << llendl;
- }
- }
- // Object data map for compressed && !OUT_TERSE_IMPROVED
- //static
- void LLViewerObject::initObjectDataMap()
- {
- U32 count = 0;
- sObjectDataMap["ID"] = count;
- count += sizeof(LLUUID);
- sObjectDataMap["LocalID"] = count;
- count += sizeof(U32);
- sObjectDataMap["PCode"] = count;
- count += sizeof(U8);
- sObjectDataMap["State"] = count;
- count += sizeof(U8);
- sObjectDataMap["CRC"] = count;
- count += sizeof(U32);
- sObjectDataMap["Material"] = count;
- count += sizeof(U8);
- sObjectDataMap["ClickAction"] = count;
- count += sizeof(U8);
- sObjectDataMap["Scale"] = count;
- count += sizeof(LLVector3);
- sObjectDataMap["Pos"] = count;
- count += sizeof(LLVector3);
- sObjectDataMap["Rot"] = count;
- count += sizeof(LLVector3);
- sObjectDataMap["SpecialCode"] = count;
- count += sizeof(U32);
- sObjectDataMap["Owner"] = count;
- count += sizeof(LLUUID);
- // LLVector3, when SpecialCode & 0x80 is set
- sObjectDataMap["Omega"] = count;
- count += sizeof(LLVector3);
- // ParentID is after Omega if there is Omega, otherwise is after Owner.
- // U32, when SpecialCode & 0x20 is set
- sObjectDataMap["ParentID"] = count;
- count += sizeof(U32);
- // The rest items are not included here
- }
- //static
- void LLViewerObject::unpackVector3(LLDataPackerBinaryBuffer* dp,
- LLVector3& value, std::string name)
- {
- dp->shift(sObjectDataMap[name]);
- dp->unpackVector3(value, name.c_str());
- dp->reset();
- }
- //static
- void LLViewerObject::unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value,
- std::string name)
- {
- dp->shift(sObjectDataMap[name]);
- dp->unpackUUID(value, name.c_str());
- dp->reset();
- }
- //static
- void LLViewerObject::unpackU32(LLDataPackerBinaryBuffer* dp, U32& value,
- std::string name)
- {
- dp->shift(sObjectDataMap[name]);
- dp->unpackU32(value, name.c_str());
- dp->reset();
- }
- //static
- void LLViewerObject::unpackU8(LLDataPackerBinaryBuffer* dp, U8& value,
- std::string name)
- {
- dp->shift(sObjectDataMap[name]);
- dp->unpackU8(value, name.c_str());
- dp->reset();
- }
- //static
- U32 LLViewerObject::unpackParentID(LLDataPackerBinaryBuffer* dp,
- U32& parent_id)
- {
- dp->shift(sObjectDataMap["SpecialCode"]);
- U32 value;
- dp->unpackU32(value, "SpecialCode");
- parent_id = 0;
- if (value & 0x20)
- {
- S32 offset = sObjectDataMap["ParentID"];
- if (!(value & 0x80))
- {
- offset -= sizeof(LLVector3);
- }
- dp->shift(offset);
- dp->unpackU32(parent_id, "ParentID");
- }
- dp->reset();
- return parent_id;
- }
- // Replaces all name value pairs with data from \n delimited list. Does not
- // update the server.
- void LLViewerObject::setNameValueList(const std::string& name_value_list)
- {
- // Clear out the old
- for_each(mNameValuePairs.begin(), mNameValuePairs.end(),
- DeletePairedPointer());
- mNameValuePairs.clear();
- // Bring in the new
- std::string::size_type length = name_value_list.length();
- std::string::size_type start = 0;
- std::string::size_type end;
- while (start < length)
- {
- end = name_value_list.find_first_of("\n", start);
- if (end == std::string::npos)
- {
- end = length;
- }
- if (end > start)
- {
- std::string tok = name_value_list.substr(start, end - start);
- addNVPair(tok);
- }
- start = end + 1;
- }
- }
- // This method returns true if the object is over land owned by the agent.
- bool LLViewerObject::isReturnable()
- {
- if (isAttachment())
- {
- return false;
- }
- std::vector<LLBBox> boxes;
- boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(),
- getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (!child) return false; // Paranoia
- boxes.push_back(LLBBox(child->getPositionRegion(),
- child->getRotationRegion(),
- child->getScale() * -0.5f,
- child->getScale() * 0.5f).getAxisAligned());
- }
- bool result = mRegionp && mRegionp->objectIsReturnable(getPositionRegion(),
- boxes);
- if (!result)
- {
- // Get list of neighboring regions relative to this VO's region
- std::vector<LLViewerRegion*> unique_regions;
- mRegionp->getNeighboringRegions(unique_regions);
- // Build AABB's for root and all children
- returnable_vec_t returnables;
- for (std::vector<LLViewerRegion*>::iterator
- reg_it = unique_regions.begin(),
- reg_end = unique_regions.end();
- reg_it != reg_end; ++reg_it)
- {
- LLViewerRegion* target_regionp = *reg_it;
- // Add the root vo as there may be no children and we still want
- // to test for any edge overlap
- buildReturnablesForChildrenVO(returnables, this, target_regionp);
- // Add its children
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* childp = *iter;
- buildReturnablesForChildrenVO(returnables, childp,
- target_regionp);
- }
- }
- // TBD: eventually create a region -> box list map
- for (returnable_vec_t::iterator it = returnables.begin(),
- end = returnables.end();
- it != end; ++it)
- {
- boxes.clear();
- LLViewerRegion* regionp = it->region;
- boxes.push_back(it->box);
- if (regionp && regionp->childrenObjectReturnable(boxes) &&
- regionp->canManageEstate())
- {
- result = true;
- break;
- }
- }
- }
- return result;
- }
- void LLViewerObject::buildReturnablesForChildrenVO(returnable_vec_t& returnables,
- LLViewerObject* childp,
- LLViewerRegion* target_regionp)
- {
- if (!childp)
- {
- llerrs << "Child viewerobject is NULL" << llendl;
- }
- constructAndAddReturnable(returnables, childp, target_regionp);
- // We want to handle any children VO's as well
- for (child_list_t::iterator iter = childp->mChildList.begin(),
- end = childp->mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* obj = *iter;
- buildReturnablesForChildrenVO(returnables, obj, target_regionp);
- }
- }
- void LLViewerObject::constructAndAddReturnable(returnable_vec_t& returnables,
- LLViewerObject* childp,
- LLViewerRegion* target_regionp)
- {
- LLVector3 target_region_pos;
- target_region_pos.set(childp->getPositionGlobal());
- LLBBox child_bbox = LLBBox(target_region_pos, childp->getRotationRegion(),
- childp->getScale() * -0.5f,
- childp->getScale() * 0.5f).getAxisAligned();
- LLVector3 edge_a = target_region_pos + child_bbox.getMinLocal();
- LLVector3 edge_b = target_region_pos + child_bbox.getMaxLocal();
- LLVector3d edge_a_3d, edge_b_3d;
- edge_a_3d.set(edge_a);
- edge_b_3d.set(edge_b);
- // Only add the box when either of the extents are in a neighboring region
- if (target_regionp->pointInRegionGlobal(edge_a_3d) ||
- target_regionp->pointInRegionGlobal(edge_b_3d))
- {
- PotentialReturnableObject returnable_obj;
- returnable_obj.box = child_bbox;
- returnable_obj.region = target_regionp;
- returnables.push_back(returnable_obj);
- }
- }
- bool LLViewerObject::setParent(LLViewerObject* parent)
- {
- if (mParent != parent)
- {
- LLViewerObject* old_parent = (LLViewerObject*)mParent;
- bool ret = LLPrimitive::setParent(parent);
- if (ret && old_parent && parent)
- {
- old_parent->removeChild(this);
- }
- return ret;
- }
- return false;
- }
- void LLViewerObject::addChild(LLViewerObject* childp)
- {
- for (child_list_t::iterator i = mChildList.begin(), end = mChildList.end();
- i != end; ++i)
- {
- if (*i == childp)
- {
- // Already has child
- return;
- }
- }
- if (!isAvatar())
- {
- // Propagate selection properties
- childp->mCanSelect = mCanSelect;
- }
- if (childp->setParent(this))
- {
- mChildList.push_back(childp);
- childp->afterReparent();
- }
- }
- void LLViewerObject::removeChild(LLViewerObject* childp)
- {
- if (!childp) return;
- for (child_list_t::iterator i = mChildList.begin(), end = mChildList.end();
- i != end; ++i)
- {
- if (*i == childp)
- {
- if (!childp->isAvatar() && mDrawable.notNull() &&
- mDrawable->isActive() && childp->mDrawable.notNull() &&
- !isAvatar())
- {
- gPipeline.markRebuild(childp->mDrawable,
- LLDrawable::REBUILD_VOLUME);
- }
- mChildList.erase(i);
- if (childp->getParent() == this)
- {
- childp->setParent(NULL);
- }
- break;
- }
- }
- if (childp->mUserSelected)
- {
- gSelectMgr.deselectObjectAndFamily(childp);
- gSelectMgr.selectObjectAndFamily(childp, true);
- }
- }
- void LLViewerObject::addThisAndAllChildren(std::vector<LLViewerObject*>& objects)
- {
- objects.push_back(this);
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child && !child->isAvatar())
- {
- child->addThisAndAllChildren(objects);
- }
- }
- }
- void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects)
- {
- objects.push_back(this);
- // Do not add any attachments when temporarily selecting avatar
- if (isAvatar())
- {
- return;
- }
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child && !child->isAvatar())
- {
- child->addThisAndNonJointChildren(objects);
- }
- }
- }
- bool LLViewerObject::isChild(LLViewerObject* childp) const
- {
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* testchild = *iter;
- if (testchild == childp)
- {
- return true;
- }
- }
- return false;
- }
- bool LLViewerObject::isSeat() const
- {
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child && child->isAvatar())
- {
- return true;
- }
- }
- return false;
- }
- bool LLViewerObject::isAgentSeat() const
- {
- if (!isAgentAvatarValid() || !gAgentAvatarp->mIsSitting)
- {
- // Agent is not even sitting, so do not bother to check further
- return false;
- }
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child && child == (LLViewerObject*)gAgentAvatarp)
- {
- return true;
- }
- }
- return false;
- }
- bool LLViewerObject::setDrawableParent(LLDrawable* parentp)
- {
- if (mDrawable.isNull())
- {
- return false;
- }
- bool ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
- if (!ret)
- {
- return false;
- }
- LLDrawable* old_parent = mDrawable->mParent;
- mDrawable->mParent = parentp;
- if (parentp && mDrawable->isActive())
- {
- parentp->makeActive();
- parentp->setState(LLDrawable::ACTIVE_CHILD);
- }
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME);
- if ((old_parent != parentp && old_parent) ||
- (parentp && parentp->isActive()))
- {
- // *TODO: we should not be relying on setDrawable parent to call
- // markMoved()
- gPipeline.markMoved(mDrawable, false);
- }
- else if (!mDrawable->isAvatar())
- {
- mDrawable->updateXform(true);
- #if 0
- if (!mDrawable->getSpatialGroup())
- {
- mDrawable->movePartition();
- }
- #endif
- }
- return ret;
- }
- // Show or hide particles, icon and HUD
- void LLViewerObject::hideExtraDisplayItems(bool hidden)
- {
- if (mPartSourcep.notNull())
- {
- LLViewerPartSourceScript* ps = mPartSourcep.get();
- ps->setSuspended(hidden);
- }
- if (mText.notNull())
- {
- LLHUDText* hudtext = mText.get();
- hudtext->setHidden(hidden);
- }
- if (mIcon.notNull())
- {
- LLHUDIcon* hudicon = mIcon.get();
- hudicon->setHidden(hidden);
- }
- }
- U32 LLViewerObject::checkMediaURL(const std::string& media_url)
- {
- U32 retval = 0;
- if (!mMedia && !media_url.empty())
- {
- retval |= MEDIA_URL_ADDED;
- mMedia = new LLViewerObjectMedia;
- mMedia->mMediaURL = media_url;
- mMedia->mMediaType = LLViewerObject::MEDIA_SET;
- mMedia->mPassedWhitelist = false;
- }
- else if (mMedia)
- {
- if (media_url.empty())
- {
- retval |= MEDIA_URL_REMOVED;
- delete mMedia;
- mMedia = NULL;
- }
- else if (mMedia->mMediaURL != media_url)
- {
- // We just added or changed a media.
- retval |= MEDIA_URL_UPDATED;
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = false;
- }
- }
- return retval;
- }
- // Extracts spatial information from object update message. Return parent_id.
- //static
- U32 LLViewerObject::extractSpatialExtents(LLDataPackerBinaryBuffer* dp,
- LLVector3& pos, LLVector3& scale,
- LLQuaternion& rot)
- {
- U32 parent_id = 0;
- LLViewerObject::unpackParentID(dp, parent_id);
- LLViewerObject::unpackVector3(dp, scale, "Scale");
- LLViewerObject::unpackVector3(dp, pos, "Pos");
- LLVector3 vec;
- LLViewerObject::unpackVector3(dp, vec, "Rot");
- rot.unpackFromVector3(vec);
- return parent_id;
- }
- U32 LLViewerObject::processUpdateMessage(LLMessageSystem* mesgsys,
- void** user_data, U32 block_num,
- EObjectUpdateType update_type,
- LLDataPacker* dp)
- {
- U32 retval = 0x0;
- // If region is removed from the list it is also deleted.
- if (!gWorld.isRegionListed(mRegionp))
- {
- llwarns << "Updating object in an invalid region" << llendl;
- return retval;
- }
- // Coordinates of objects on simulators are region-local.
- U64 region_handle;
- if (mesgsys)
- {
- mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle,
- region_handle);
- LLViewerRegion* regionp = gWorld.getRegionFromHandle(region_handle);
- if (regionp != mRegionp && regionp && mRegionp) // region cross
- {
- // This is the redundant position and region update, but it is
- // necessary in case the viewer misses the following position and
- // region update messages from sim. This redundant update should
- // not cause any problems.
- LLVector3 delta_pos = mRegionp->getOriginAgent() -
- regionp->getOriginAgent();
- // Update to the new region position immediately:
- setPositionParent(getPosition() + delta_pos);
- // Change the region:
- setRegion(regionp);
- }
- else if (regionp != mRegionp)
- {
- if (mRegionp)
- {
- mRegionp->removeFromCreatedList(getLocalID());
- }
- if (regionp)
- {
- regionp->addToCreatedList(getLocalID());
- }
- mRegionp = regionp;
- }
- }
- if (!mRegionp)
- {
- U32 x, y;
- from_region_handle(region_handle, &x, &y);
- llerrs << "Object has invalid region " << x << ":" << y << llendl;
- return retval;
- }
- if (mesgsys)
- {
- U16 time_dilation16;
- mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation,
- time_dilation16);
- F32 time_dilation = ((F32)time_dilation16) / 65535.f;
- mRegionp->setTimeDilation(time_dilation);
- }
- // This will be used to determine if we have really changed position. Use
- // getPosition, not getPositionRegion, since this is what we're comparing
- // directly against.
- LLVector3 test_pos_parent = getPosition();
- // This needs to match the largest size below.
- constexpr S32 MAX_DATA_SIZE = 60 + 16;
- static U8 data[MAX_DATA_SIZE];
- #if LL_BIG_ENDIAN
- U16 valswizzle[4];
- #endif
- U16* val;
- constexpr F32 MAX_HEIGHT = MAX_OBJECT_Z;
- // Variable region size support:
- const F32 size = mRegionp->getWidth();
- const F32 min_height = -size;
- S32 length, count;
- S32 this_update_precision = 32; // in bits
- // Temporaries, because we need to compare with previous to set dirty flags
- LLVector3 new_pos_parent, new_vel, new_acc, new_angv;
- LLVector3 new_scale = getScale();
- LLVector3 old_angv = getAngularVelocity();
- LLQuaternion new_rot;
- U8 material = 0;
- U8 click_action = 0;
- U32 crc = 0;
- U32 parent_id = 0;
- LLViewerObject* cur_parentp = (LLViewerObject*)getParent();
- if (cur_parentp)
- {
- parent_id = cur_parentp->mLocalID;
- }
- // If needed, enable the "UpdateType" debug tag for this method call with
- // this debugged LLViewerObject instance. HB
- bool set_debug_tag = mDebugUpdateMsg &&
- !HBFloaterDebugTags::debugTagActive("UpdateType");
- if (set_debug_tag)
- {
- HBFloaterDebugTags::setTag("UpdateType", true);
- }
- if (!dp)
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Update message received for object " << mID << ":"
- << llendl;
- }
- switch (update_type)
- {
- case OUT_FULL:
- {
- LL_DEBUGS("UpdateType") << "Full: " << mID << LL_ENDL;
- // Clear cost and linkset cost
- setObjectCostStale();
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc,
- block_num);
- mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ParentID,
- parent_id, block_num);
- LLUUID audio_uuid;
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound,
- audio_uuid, block_num);
- // *HACK: Owner Id only valid if non-null sound Id or particle
- // system and if audio_uuid or particle system is not null:
- LLUUID owner_id;
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID,
- owner_id, block_num);
- F32 gain;
- mesgsys->getF32Fast(_PREHASH_ObjectData, _PREHASH_Gain, gain,
- block_num);
- F32 cutoff;
- mesgsys->getF32Fast(_PREHASH_ObjectData, _PREHASH_Radius,
- cutoff, block_num);
- U8 sound_flags;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_Flags,
- sound_flags, block_num);
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_Material,
- material, block_num);
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_ClickAction,
- click_action, block_num);
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale,
- new_scale, block_num);
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num,
- _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData,
- _PREHASH_ObjectData, data, length,
- block_num, MAX_DATA_SIZE);
- mTotalCRC = crc;
- // Might need to update mSourceMuted here to properly pick up
- // the new cutoff radius.
- mSoundCutOffRadius = cutoff;
- // Owner Id used for sound muting or particle system muting
- mOwnerID = owner_id;
- setAttachedSound(audio_uuid, owner_id, gain, sound_flags);
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, false); // Undamped
- }
- }
- setClickAction(click_action);
- count = 0;
- LLVector4 collision_plane;
- switch (length)
- {
- case (60 + 16):
- // Pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4,
- sizeof(LLVector4));
- if (isAvatar())
- {
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- count += sizeof(LLVector4);
- // Fall through
- case 60:
- {
- this_update_precision = 32;
- // This is a terse update
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- count += sizeof(LLVector3);
- htonmemcpy((void*)getVelocity().mV, &data[count],
- MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- htonmemcpy((void*)getAcceleration().mV, &data[count],
- MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // Theta
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- count += sizeof(LLVector3);
- // Target omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- resetRot();
- }
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (1): " << new_angv << llendl;
- }
- #if LL_DARWIN // Why is that ??? HB
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
- #endif
- break;
- }
- case (32 + 16):
- // Pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4,
- sizeof(LLVector4));
- if (isAvatar())
- {
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- count += sizeof(LLVector4);
- // Fall through
- case 32:
- this_update_precision = 16;
- test_pos_parent.quantize16(-0.5f * size, 1.5f * size,
- min_height, MAX_HEIGHT);
- // This is a terse 16 update, so treat data as an array of U16's.
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], min_height,
- MAX_HEIGHT);
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- setVelocity(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size)));
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size,
- size)));
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- new_angv.set(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- if (new_angv.isExactlyZero())
- {
- resetRot();
- }
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (2): " << new_angv << llendl;
- }
- break;
- case 16:
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f * size, 1.5f * size,
- min_height, MAX_HEIGHT);
- // This is a terse 8 update
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], min_height,
- MAX_HEIGHT);
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size));
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size));
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
- new_angv.set(U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size));
- if (new_angv.isExactlyZero())
- {
- resetRot();
- }
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (3): " << new_angv << llendl;
- }
- break;
- }
- ////////////////////////////////////////////////////
- // Here we handle data specific to the full message.
- U32 flags;
- mesgsys->getU32Fast(_PREHASH_ObjectData,
- _PREHASH_UpdateFlags, flags, block_num);
- // Clear all but local flags
- mFlags &= FLAGS_LOCAL;
- mFlags |= flags;
- mFlagsLoaded = true;
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state,
- block_num);
- mAttachmentState = state;
- // ...new objects that should come in selected need to be added
- // to the selected list
- mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
- // Set all name value pairs
- S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData,
- block_num,
- _PREHASH_NameValue);
- if (nv_size > 0)
- {
- std::string name_value_list;
- mesgsys->getStringFast(_PREHASH_ObjectData,
- _PREHASH_NameValue, name_value_list,
- block_num);
- setNameValueList(name_value_list);
- }
- // Clear out any existing generic data
- if (mData)
- {
- delete[] mData;
- }
- // Check for appended generic data
- S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData,
- block_num, _PREHASH_Data);
- if (data_size <= 0)
- {
- mData = NULL;
- }
- else
- {
- // ...has generic data
- mData = new U8[data_size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData,
- _PREHASH_Data, mData, data_size,
- block_num);
- }
- // Reset the cached values used for debug info display toggle.
- mHudTextString.clear();
- mHudTextColor = LLColor4U::white;
- S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData,
- block_num, _PREHASH_Text);
- if (text_size > 1)
- {
- // Setup object text
- if (!mText)
- {
- mText = (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1);
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text,
- mHudTextString, block_num);
- LLColor4U coloru;
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData,
- _PREHASH_TextColor, coloru.mV,
- 4, block_num);
- // Alpha was flipped so that it zero encoded better
- coloru.mV[3] = 255 - coloru.mV[3];
- mHudTextColor = LLColor4(coloru);
- // Fading is disabled only when the hovetext is being
- // overridden by debug text.
- if (mText->getDoFade())
- {
- mText->setColor(mHudTextColor);
- mText->setStringUTF8(mHudTextString);
- }
- //MK
- mText->mLastMessageText = mHudTextString;
- //mk
- setChanged(MOVED | SILHOUETTE);
- }
- else if (mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
- std::string media_url;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL,
- media_url, block_num);
- retval |= checkMediaURL(media_url);
- //
- // Unpack particle system data
- //
- unpackParticleSource(block_num, owner_id);
- // Mark all extra parameters not used
- for (S32 i = 0; i < LL_EPARAMS_COUNT; ++i)
- {
- mExtraParameterInUse[i] = false;
- }
- // Unpack extra parameters
- S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num,
- _PREHASH_ExtraParams);
- if (size > 0)
- {
- U8* buffer = new U8[size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData,
- _PREHASH_ExtraParams,
- buffer, size, block_num);
- LLDataPackerBinaryBuffer dp(buffer, size);
- U8 num_parameters;
- dp.unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param = 0; param < num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp.unpackU16(param_type, "param_type");
- dp.unpackBinaryData(param_block, param_size,
- "param_data");
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
- delete[] buffer;
- }
- for (S32 i = 0; i < LL_EPARAMS_COUNT; ++i)
- {
- if (!mExtraParameterInUse[i])
- {
- parameterChanged(LL_EPARAM_TYPE(i),
- mExtraParameters[i], false, false);
- }
- }
- break;
- }
- case OUT_TERSE_IMPROVED:
- {
- LL_DEBUGS("UpdateType") << "TI:" << mID << LL_ENDL;
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num,
- _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData,
- _PREHASH_ObjectData, data, length,
- block_num, MAX_DATA_SIZE);
- count = 0;
- LLVector4 collision_plane;
- switch (length)
- {
- case (60 + 16):
- // Pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4,
- sizeof(LLVector4));
- if (isAvatar())
- {
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- count += sizeof(LLVector4);
- // Fall through
- case 60:
- {
- // This is a terse 32 update
- this_update_precision = 32;
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- count += sizeof(LLVector3);
- htonmemcpy((void*)getVelocity().mV, &data[count],
- MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- htonmemcpy((void*)getAcceleration().mV, &data[count],
- MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // Theta
- {
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- }
- count += sizeof(LLVector3);
- // Target omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3,
- sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- resetRot();
- }
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (4): " << new_angv << llendl;
- }
- #if LL_DARWIN // Why is that ??? HB
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
- #endif
- break;
- }
- case (32 + 16):
- // Pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4,
- sizeof(LLVector4));
- if (isAvatar())
- {
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- count += sizeof(LLVector4);
- // fall through
- case 32:
- // This is a terse 16 update
- this_update_precision = 16;
- test_pos_parent.quantize16(-0.5f * size, 1.5f * size,
- min_height, MAX_HEIGHT);
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], min_height,
- MAX_HEIGHT);
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- setVelocity(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 3;
- setAcceleration(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- count += sizeof(U16) * 4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
- #if LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16*)&data[count];
- #endif
- new_angv.set(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (5): " << new_angv << llendl;
- }
- break;
- case 16:
- // This is a terse 8 update
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f * size, 1.5f * size,
- min_height, MAX_HEIGHT);
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f * size,
- 1.5f * size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], min_height,
- MAX_HEIGHT);
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size));
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size));
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
- new_angv.set(U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size));
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (6): " << new_angv << llendl;
- }
- break;
- }
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state,
- block_num);
- mAttachmentState = state;
- break;
- }
- default:
- break;
- }
- }
- else
- {
- // Handle the compressed case
- LLUUID sound_uuid, owner_id;
- F32 gain = 0;
- U8 sound_flags = 0;
- F32 cutoff = 0;
- U16 val[4];
- U8 state;
- dp->unpackU8(state, "State");
- mAttachmentState = state;
- switch (update_type)
- {
- case OUT_TERSE_IMPROVED:
- {
- LL_DEBUGS("UpdateType") << "CompTI:" << mID << LL_ENDL;
- U8 value;
- dp->unpackU8(value, "agent");
- if (value)
- {
- LLVector4 collision_plane;
- dp->unpackVector4(collision_plane, "Plane");
- if (isAvatar())
- {
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- }
- test_pos_parent = getPosition();
- dp->unpackVector3(new_pos_parent, "Pos");
- dp->unpackU16(val[VX], "VelX");
- dp->unpackU16(val[VY], "VelY");
- dp->unpackU16(val[VZ], "VelZ");
- setVelocity(U16_to_F32(val[VX], -128.f, 128.f),
- U16_to_F32(val[VY], -128.f, 128.f),
- U16_to_F32(val[VZ], -128.f, 128.f));
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- setAcceleration(U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
- dp->unpackU16(val[VX], "ThetaX");
- dp->unpackU16(val[VY], "ThetaY");
- dp->unpackU16(val[VZ], "ThetaZ");
- dp->unpackU16(val[VS], "ThetaS");
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f);
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- new_angv.set(U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (7): " << new_angv << llendl;
- }
- break;
- }
- case OUT_FULL_COMPRESSED:
- case OUT_FULL_CACHED:
- {
- LL_DEBUGS("UpdateType") << "CompFull:" << mID << LL_ENDL;
- setObjectCostStale();
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- dp->unpackU32(crc, "CRC");
- mTotalCRC = crc;
- dp->unpackU8(material, "Material");
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, false); // undamped
- }
- }
- dp->unpackU8(click_action, "ClickAction");
- setClickAction(click_action);
- dp->unpackVector3(new_scale, "Scale");
- dp->unpackVector3(new_pos_parent, "Pos");
- LLVector3 vec;
- dp->unpackVector3(vec, "Rot");
- new_rot.unpackFromVector3(vec);
- setAcceleration(LLVector3::zero);
- U32 value;
- dp->unpackU32(value, "SpecialCode");
- dp->setPassFlags(value);
- dp->unpackUUID(owner_id, "Owner");
- mOwnerID = owner_id;
- if (value & 0x80)
- {
- dp->unpackVector3(new_angv, "Omega");
- setAngularVelocity(new_angv);
- if (mDebugUpdateMsg)
- {
- llinfos << "Angular velocity (8): " << new_angv
- << llendl;
- }
- }
- if (value & 0x20)
- {
- dp->unpackU32(parent_id, "ParentID");
- }
- else
- {
- parent_id = 0;
- }
- S32 sp_size;
- U32 size;
- if (value & 0x2)
- {
- sp_size = 1;
- delete[] mData;
- mData = new U8[1];
- dp->unpackU8(((U8*)mData)[0], "TreeData");
- }
- else if (value & 0x1)
- {
- dp->unpackU32(size, "ScratchPadSize");
- delete[] mData;
- mData = new U8[size];
- dp->unpackBinaryData((U8 *)mData, sp_size, "PartData");
- }
- else
- {
- mData = NULL;
- }
- // Reset the cached values used for debug info display toggle.
- mHudTextString.clear();
- mHudTextColor = LLColor4U::white;
- // Setup object text
- if (!mText && (value & 0x4))
- {
- mText = (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1); // Set to match current agni behavior.
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
- if (value & 0x4)
- {
- dp->unpackString(mHudTextString, "Text");
- LLColor4U coloru;
- dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
- coloru.mV[3] = 255 - coloru.mV[3];
- mHudTextColor = LLColor4(coloru);
- // Fading is disabled only when the hovetext is being
- // overridden by debug text.
- if (mText->getDoFade())
- {
- mText->setColor(mHudTextColor);
- mText->setStringUTF8(mHudTextString);
- }
- //MK
- mText->mLastMessageText = mHudTextString;
- //mk
- setChanged(TEXTURE);
- }
- else if (mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
- std::string media_url;
- if (value & 0x200)
- {
- dp->unpackString(media_url, "MediaURL");
- }
- retval |= checkMediaURL(media_url);
- //
- // Unpack particle system data (legacy)
- //
- if (value & 0x8)
- {
- unpackParticleSource(*dp, owner_id, true);
- }
- else if (!(value & 0x400))
- {
- deleteParticleSource();
- }
- // Mark all extra parameters not used
- for (S32 i = 0; i < LL_EPARAMS_COUNT; ++i)
- {
- mExtraParameterInUse[i] = false;
- }
- // Unpack extra params
- U8 num_parameters;
- dp->unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param = 0; param < num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp->unpackU16(param_type, "param_type");
- dp->unpackBinaryData(param_block, param_size,
- "param_data");
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
- for (S32 i = 0; i < LL_EPARAMS_COUNT; ++i)
- {
- if (!mExtraParameterInUse[i])
- {
- parameterChanged(LL_EPARAM_TYPE(i),
- mExtraParameters[i], false, false);
- }
- }
- if (value & 0x10)
- {
- dp->unpackUUID(sound_uuid, "SoundUUID");
- dp->unpackF32(gain, "SoundGain");
- dp->unpackU8(sound_flags, "SoundFlags");
- dp->unpackF32(cutoff, "SoundRadius");
- }
- if (value & 0x100)
- {
- std::string name_value_list;
- dp->unpackString(name_value_list, "NV");
- setNameValueList(name_value_list);
- }
- mTotalCRC = crc;
- mSoundCutOffRadius = cutoff;
- setAttachedSound(sound_uuid, owner_id, gain, sound_flags);
- // Only get these flags on updates from sim, not cached ones.
- // Preload these five flags for every object. Finer shades
- // require the object to be selected, and the selection manager
- // stores the extended permission info.
- if (mesgsys)
- {
- U32 flags;
- mesgsys->getU32Fast(_PREHASH_ObjectData,
- _PREHASH_UpdateFlags,
- flags, block_num);
- loadFlags(flags);
- }
- break;
- }
- default:
- break;
- }
- }
- if (set_debug_tag)
- {
- HBFloaterDebugTags::setTag("UpdateType", false);
- }
- //
- // Fix object parenting.
- //
- bool b_changed_status = false;
- // We only need to update parenting on full updates, terse updates
- // do not send parenting information.
- if (update_type != OUT_TERSE_IMPROVED)
- {
- U32 ip, port;
- if (mesgsys)
- {
- ip = mesgsys->getSenderIP();
- port = mesgsys->getSenderPort();
- }
- else
- {
- const LLHost& host = mRegionp->getHost();
- ip = host.getAddress();
- port = host.getPort();
- }
- LLViewerObject* sent_parentp = NULL;
- if (parent_id)
- {
- LLUUID parent_uuid;
- gObjectList.getUUIDFromLocal(parent_uuid, parent_id, ip, port);
- sent_parentp = gObjectList.findObject(parent_uuid);
- }
- if (!cur_parentp)
- {
- if (parent_id)
- {
- // No parent now, new parent in message -> attach to that
- // parent if possible
- // Check to see if we have the corresponding viewer object for
- // the parent.
- if (sent_parentp && sent_parentp->getParent() == this)
- {
- // Try to recover if we attempt to attach a parent to its
- // child
- llwarns << "Attempt to attach a parent to its child: "
- << mID << " to " << sent_parentp->mID
- << llendl;
- removeChild(sent_parentp);
- sent_parentp->setDrawableParent(NULL);
- }
- if (sent_parentp && sent_parentp != this &&
- !sent_parentp->isDead())
- {
- // We have a viewer object for the parent, and it is not
- // dead. Do the actual reparenting here.
- b_changed_status = true;
- // ...no current parent, so do not try to remove child
- if (mDrawable.notNull())
- {
- if (mDrawable->isDead() || !mDrawable->getVObj())
- {
- llwarns << "Drawable is dead or no VObj !"
- << llendl;
- sent_parentp->addChild(this);
- }
- else
- {
- // LLViewerObject::processUpdateMessage 1
- if (!setDrawableParent(sent_parentp->mDrawable))
- {
- // Bad, we got a cycle somehow. Kill both the
- // parent and the child, and set cache misses
- // for both of them.
- llwarns << "Attempting to recover from parenting cycle ! Killing "
- << sent_parentp->mID << " and "
- << mID << " and adding them to the cache miss list."
- << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- sent_parentp->addChild(this);
- // Make sure this object gets a non-damped update
- if (sent_parentp->mDrawable.notNull())
- {
- gPipeline.markMoved(sent_parentp->mDrawable,
- // undamped
- false);
- }
- }
- }
- else
- {
- sent_parentp->addChild(this);
- }
- // Show particles, icon and HUD
- hideExtraDisplayItems(false);
- setChanged(MOVED | SILHOUETTE);
- }
- else
- {
- // No corresponding viewer object for the parent: put the
- // various pieces on the orphan list.
- gObjectList.orphanize(this, parent_id, ip, port);
- // Hide particles, icon and HUD
- hideExtraDisplayItems(true);
- }
- }
- }
- else
- {
- if (parent_id && !sent_parentp)
- {
- if (isAvatar())
- {
- // This logic is meant to handle the case where a
- // sitting avatar has reached a new sim ahead of the
- // object it was sitting on (which is common as objects
- // are transfered through a slower route than agents).
- // In this case, the local id for the object will not
- // be valid, since the viewer has not received a full
- // update for the object from that sim yet, so we
- // assume that the agent is still sitting where she was
- // originally. --RN
- sent_parentp = cur_parentp;
- }
- else
- {
- // Switching parents, but we do not know the new
- // parent. We are an orphan, flag things appropriately.
- gObjectList.orphanize(this, parent_id, ip, port);
- }
- }
- // Reparent if possible.
- if (sent_parentp && sent_parentp != cur_parentp &&
- sent_parentp != this)
- {
- // New parent is valid, detach and reattach
- b_changed_status = true;
- if (mDrawable.notNull())
- {
- // LLViewerObject::processUpdateMessage 2
- if (!setDrawableParent(sent_parentp->mDrawable))
- {
- // Bad, we got a cycle somehow. Kill both the parent
- // and the child, and set cache misses for both of them
- llwarns << "Attempting to recover from parenting cycle ! Killing "
- << sent_parentp->mID << " and "
- << mID << " and adding them to cache miss list."
- << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- // Make sure this object gets a non-damped update
- }
- cur_parentp->removeChild(this);
- sent_parentp->addChild(this);
- setChanged(MOVED | SILHOUETTE);
- sent_parentp->setChanged(MOVED | SILHOUETTE);
- if (sent_parentp->mDrawable.notNull())
- {
- // false = undamped
- gPipeline.markMoved(sent_parentp->mDrawable, false);
- }
- }
- else if (!sent_parentp)
- {
- bool remove_parent = true;
- // No new parent, or the parent that we sent does not exist on
- // the viewer.
- LLViewerObject* parentp = (LLViewerObject*)getParent();
- if (parentp && parentp->getRegion() != getRegion())
- {
- // This is probably an object flying across a region
- // boundary, the object probably ISN'T being reparented,
- // but just got an object update out of order (child
- // update before parent).
- remove_parent = false;
- }
- if (remove_parent)
- {
- if (parentp && parentp == gAgentAvatarp)
- {
- LL_DEBUGS("Attachment") << "Detaching object " << mID
- << LL_ENDL;
- }
- b_changed_status = true;
- if (mDrawable.notNull())
- {
- // Clear parent so that removeChild can put the
- // drawable on the damped list
- // LLViewerObject::processUpdateMessage 3
- setDrawableParent(NULL);
- }
- cur_parentp->removeChild(this);
- setChanged(MOVED | SILHOUETTE);
- if (mDrawable.notNull())
- {
- // Make sure this object gets a non-damped update
- gPipeline.markMoved(mDrawable, false); // undamped
- }
- }
- }
- }
- }
- new_rot.normalize();
- if (sPingInterpolate && mesgsys)
- {
- LLCircuitData* cdp =
- mesgsys->mCircuitInfo.findCircuit(mesgsys->getSender());
- if (cdp)
- {
- F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.f;
- F32 ping_delay = 0.5f * time_dilation *
- ((F32)cdp->getPingDelay() * 0.001f +
- gFrameDT);
- LLVector3 diff = getVelocity() * ping_delay;
- new_pos_parent += diff;
- }
- else
- {
- llwarns << "findCircuit() returned NULL; skipping interpolation"
- << llendl;
- }
- }
- //////////////////////////
- //
- // Set the generic change flags...
- //
- // If we are going to skip this message, why are we doing all the
- // parenting, etc above ?
- if (mesgsys)
- {
- U32 packet_id = mesgsys->getCurrentRecvPacketID();
- if (packet_id < mLatestRecvPacketID &&
- mLatestRecvPacketID - packet_id < 65536)
- {
- // Skip application of this message, it is old
- return retval;
- }
- mLatestRecvPacketID = packet_id;
- }
- // Set the change flags for scale
- if (new_scale != getScale())
- {
- setChanged(SCALED | SILHOUETTE);
- setScale(new_scale); // Must follow setting permYouOwner()
- }
- // Add to mini-map objects if not yet in them and of interest; this is
- // particularly important for scripted objects which may change their
- // path-finding or physical status.
- if (!mOnMap && getPCode() == LL_PCODE_VOLUME && !isDead() &&
- (flagUsePhysics() || flagCharacter()) && !isAttachment() && isRoot())
- {
- gObjectList.addToMap(this);
- mOnMap = true;
- }
- // First, let's see if the new position is actually a change
- F32 vel_mag_sq = getVelocity().lengthSquared();
- F32 accel_mag_sq = getAcceleration().lengthSquared();
- if (b_changed_status || test_pos_parent != new_pos_parent ||
- (!mUserSelected &&
- (vel_mag_sq != 0.f || accel_mag_sq != 0.f ||
- this_update_precision > mBestUpdatePrecision)))
- {
- mBestUpdatePrecision = this_update_precision;
- LLVector3 diff = new_pos_parent - test_pos_parent;
- F32 mag_sqr = diff.lengthSquared();
- if (llfinite(mag_sqr))
- {
- setPositionParent(new_pos_parent);
- }
- else
- {
- llwarns << "Cannot move the object/avatar to an infinite location !"
- << llendl;
- retval |= INVALID_UPDATE;
- }
- if (mParent && mParent->isAvatar())
- {
- // We have changed the position of an attachment, so we need to
- // clamp it
- ((LLVOAvatar*)mParent)->clampAttachmentPositions();
- }
- }
- if (sUseNewTargetOmegaCode)
- {
- // New, experimental code
- bool is_new_rot = new_rot.isNotEqualEps(getRotation(), F_ALMOST_ZERO);
- if (mDebugUpdateMsg)
- {
- llinfos << "Rotation changed: " << (is_new_rot ? "yes" : "no")
- << " - Angular velocity changed: "
- << (new_angv != old_angv ? "yes" : "no") << llendl;
- }
- if (is_new_rot || new_angv != old_angv)
- {
- if (new_angv != old_angv)
- {
- if (new_rot != mPreviousRotation || flagUsePhysics())
- {
- resetRot();
- }
- else
- {
- mRotTime = 0.f;
- }
- }
- // Remember the last rotation value
- mPreviousRotation = new_rot;
- // Set the rotation of the object followed by adjusting for the
- // accumulated angular velocity (llSetTargetOmega)
- setRotation(new_rot * mAngularVelocityRot);
- setChanged(ROTATED | SILHOUETTE);
- }
- }
- else
- {
- // Old code
- bool is_new_rot = new_rot.isNotEqualEps(mPreviousRotation,
- F_ALMOST_ZERO);
- if (mDebugUpdateMsg)
- {
- llinfos << "Rotation changed: " << (is_new_rot ? "yes" : "no")
- << " - Angular velocity changed: "
- << (new_angv != old_angv ? "yes" : "no") << llendl;
- }
- if (is_new_rot || new_angv != old_angv)
- {
- if (is_new_rot)
- {
- mPreviousRotation = new_rot;
- setRotation(new_rot);
- }
- mRotTime = 0.f;
- setChanged(ROTATED | SILHOUETTE);
- }
- }
- if (gShowObjectUpdates)
- {
- LLColor4 color;
- if (update_type == OUT_TERSE_IMPROVED)
- {
- color.set(0.f, 0.f, 1.f, 1.f);
- }
- else
- {
- color.set(1.f, 0.f, 0.f, 1.f);
- }
- gPipeline.addDebugBlip(getPositionAgent(), color);
- }
- constexpr F32 MAG_CUTOFF = F_APPROXIMATELY_ZERO;
- mStatic = vel_mag_sq <= MAG_CUTOFF && accel_mag_sq <= MAG_CUTOFF &&
- getAngularVelocity().lengthSquared() <= MAG_CUTOFF;
- // *BUG: This code leads to problems during group rotate and any scale
- // operation. Small discepencies between the simulator and viewer
- // representations cause the selection center to creep, leading to objects
- // moving around the wrong center.
- //
- // Removing this, however, means that if someone else drags an object you
- // have selected, your selection center and dialog boxes will be wrong. It
- // also means that higher precision information on selected objects will be
- // ignored.
- //
- // I believe the group rotation problem is fixed. JNC 1.21.2002
- // Additionally, if any child is selected, need to update the dialogs and
- // selection center.
- bool needs_refresh = mUserSelected;
- if (!needs_refresh)
- {
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child && child->mUserSelected)
- {
- needs_refresh = true;
- break;
- }
- }
- }
- if (needs_refresh)
- {
- gSelectMgr.updateSelectionCenter();
- dialog_refresh_all();
- }
- // Mark update time as approx. now, with the ping delay. Ping delay is off
- // because it is not set for velocity interpolation, causing much jumping
- // and hopping around...
- #if 0
- U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay();
- #endif
- mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
- mLastMessageUpdateSecs = mLastInterpUpdateSecs;
- if (mDrawable.notNull())
- {
- // Do not clear invisibility flag on update if still orphaned !
- if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned)
- {
- LL_DEBUGS("ViewerObject") << "Clearing force invisible: " << mID
- << " : " << getPCodeString() << " : "
- << getPositionAgent() << LL_ENDL;
- mDrawable->clearState(LLDrawable::FORCE_INVISIBLE);
- gPipeline.markRebuild(mDrawable);
- }
- }
- return retval;
- }
- // Load flags from cache or from message
- void LLViewerObject::loadFlags(U32 flags)
- {
- if (flags == 0xffffffff)
- {
- LL_DEBUGS("ObjectCache") << "Invalid flags for object "
- << mID << "; ignoring." << LL_ENDL;
- return; // invalid
- }
- LL_DEBUGS("ObjectCacheSpam") << "Flags for object " << mID << " set to: "
- << flags << LL_ENDL;
- // Keep local flags and overwrite remote-controlled flags
- mFlags = (mFlags & FLAGS_LOCAL) | flags;
- mFlagsLoaded = true;
- // ...new objects that should come in selected need to be added to the
- // selected list
- mCreateSelected = (flags & FLAGS_CREATE_SELECTED) != 0;
- }
- void LLViewerObject::idleUpdate(F64 time)
- {
- if (!mDead)
- {
- if (!mStatic && sVelocityInterpolate && !mUserSelected)
- {
- // Calculate dt from last update
- F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.f;
- F32 dt = time_dilation * (F32)(time - mLastInterpUpdateSecs);
- applyAngularVelocity(dt);
- if (isAttachment())
- {
- mLastInterpUpdateSecs = time;
- return;
- }
- // Move object based on its velocity and rotation
- interpolateLinearMotion(time, dt);
- }
- updateDrawable(false);
- }
- }
- // Moves an object due to idle-time viewer side updates by iterpolating motion
- void LLViewerObject::interpolateLinearMotion(F64 time, F32 dt)
- {
- // Linear motion
- // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity
- // in object updates represents the average velocity of the last timestep,
- // rather than the final velocity. The time dilation above should guarantee
- // that dt is never less than PHYSICS_TIMESTEP, theoretically...
- // *TODO: should also wrap linear accel/velocity in check to see if object
- // is selected, instead of explicitly zeroing it out
- F64 time_since_last_update = time - mLastMessageUpdateSecs;
- if (time_since_last_update <= 0.0 || dt <= 0.f)
- {
- return;
- }
- LLVector3 accel = getAcceleration();
- LLVector3 vel = getVelocity();
- if (sMaxUpdateInterpolationTime <= 0.0)
- {
- // Old code path... unbounded, simple interpolation.
- if (!accel.isExactlyZero() || !vel.isExactlyZero())
- {
- LLVector3 pos = (vel + 0.5f * (dt - PHYSICS_TIMESTEP) * accel) * dt;
- // Region local
- setPositionRegion(pos + getPositionRegion());
- setVelocity(vel + accel * dt);
- // For objects that are spinning but not translating, make sure to
- // flag them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
- }
- else if (!accel.isExactlyZero() || !vel.isExactlyZero())
- {
- // Object is moving, and has not been too long since we got an update
- // from the server.
- // Calculate predicted position and velocity
- LLVector3 new_pos = (vel + 0.5f * (dt - PHYSICS_TIMESTEP) * accel) * dt;
- LLVector3 new_v = accel * dt;
- if (time_since_last_update > sPhaseOutUpdateInterpolationTime &&
- sPhaseOutUpdateInterpolationTime > 0.0)
- {
- // Have not seen a viewer update in a while, check to see if the
- // ciruit is still active
- if (mRegionp)
- {
- // The simulator will NOT send updates if the object continues
- // normally on the path predicted by the velocity and the
- // acceleration (often gravity) sent to the viewer. So check to
- // see if the circuit is blocked, which means the sim is likely
- // in a long lag.
- LLCircuitData* cdp =
- gMessageSystemp->mCircuitInfo.findCircuit(mRegionp->getHost());
- if (cdp)
- {
- // Find out how many seconds since last packet arrived on
- // the circuit
- F64 time_since_last_packet =
- LLMessageSystem::getMessageTimeSeconds() -
- cdp->getLastPacketInTime();
- if (!cdp->isAlive() || // Circuit is dead or blocked
- cdp->isBlocked() || // or doesn't seem to be getting any packets
- time_since_last_packet > sPhaseOutUpdateInterpolationTime)
- {
- // Start to reduce motion interpolation since we
- // haven't seen a server update in a while
- F64 time_since_last_interpolation = time - mLastInterpUpdateSecs;
- F64 phase_out = 1.0;
- if (time_since_last_update > sMaxUpdateInterpolationTime)
- {
- // Past the time limit, so stop the object
- phase_out = 0.0;
- LL_DEBUGS("MotionInterpolate") << "Motion phase out to zero"
- << LL_ENDL;
- #if 0 // Not adding this due to paranoia about stopping
- // rotation for/ TargetOmega objects and not having
- // it restart
- setAngularVelocity(LLVector3::zero);
- #endif
- }
- else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs >
- sPhaseOutUpdateInterpolationTime)
- {
- // Last update was already phased out a bit
- phase_out = (sMaxUpdateInterpolationTime -
- time_since_last_update) /
- (sMaxUpdateInterpolationTime -
- time_since_last_interpolation);
- LL_DEBUGS("MotionInterpolate") << "Continuing motion phase out of "
- << (F32)phase_out
- << LL_ENDL;
- }
- else
- {
- // Phase out from full value
- phase_out = (sMaxUpdateInterpolationTime -
- time_since_last_update) /
- (sMaxUpdateInterpolationTime -
- sPhaseOutUpdateInterpolationTime);
- LL_DEBUGS("MotionInterpolate") << "Starting motion phase out of "
- << (F32)phase_out
- << LL_ENDL;
- }
- phase_out = llclamp(phase_out, 0.0, 1.0);
- new_pos = new_pos * (F32)phase_out;
- new_v = new_v * (F32)phase_out;
- }
- }
- }
- }
- new_pos = new_pos + getPositionRegion();
- new_v = new_v + vel;
- // Clamp interpolated position to minimum underground and maximum
- // region height
- LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos);
- F32 min_height;
- if (isAvatar())
- {
- // Make a better guess about AVs not going underground
- min_height = gWorld.resolveLandHeightGlobal(new_pos_global);
- min_height += 0.5f * getScale().mV[VZ];
- }
- else
- {
- // This will put the object underground, but we cannot tell if it
- // will stop at ground level or not
- min_height = gWorld.getMinAllowedZ(this, new_pos_global);
- // Cap maximum height
- new_pos.mV[VZ] = llmin(MAX_OBJECT_Z, new_pos.mV[VZ]);
- }
- new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]);
- // Check to see if it is going off the region
- LLVector3 temp(new_pos.mV[VX], new_pos.mV[VY], 0.f);
- // Frame time we detected region crossing in + wait time
- if (temp.clamp(0.f, mRegionp->getWidth()))
- {
- // Going off this region, so see if we might end up on another
- // region
- LLVector3d old_pos_global =
- mRegionp->getPosGlobalFromRegion(getPositionRegion());
- // Re-fetch in case it got clipped above
- new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos);
- // Clip the positions to known regions
- LLVector3d clip_pos_global =
- gWorld.clipToVisibleRegions(old_pos_global, new_pos_global);
- if (clip_pos_global != new_pos_global)
- {
- // Was clipped, so this means we hit a edge where there is no
- // region to enter
- LL_DEBUGS("MotionInterpolate") << "Hit empty region edge, clipped predicted position to "
- << mRegionp->getPosRegionFromGlobal(clip_pos_global)
- << " from " << new_pos
- << LL_ENDL;
- new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
- // Stop motion and get server update for bouncing on the edge
- new_v.clear();
- setAcceleration(LLVector3::zero);
- }
- else if (mRegionCrossExpire == 0.0)
- {
- // Workaround: we cannot accurately figure out time when we
- // cross border so just write down time "after the fact".
- // It is far from optimal in case of lag, but then
- // sMaxUpdateInterpolationTime will kick in first.
- LL_DEBUGS("MotionInterpolate") << "Predicted region crossing, new position"
- << new_pos << LL_ENDL;
- mRegionCrossExpire = time + sMaxRegionCrossingInterpolationTime;
- }
- else if (time > mRegionCrossExpire)
- {
- // Predicting crossing over 1s, stop motion
- LL_DEBUGS("MotionInterpolate") << "Predicting region crossing for too long, stopping at "
- << new_pos << LL_ENDL;
- new_v.clear();
- setAcceleration(LLVector3::zero);
- mRegionCrossExpire = 0.0;
- }
- }
- else
- {
- mRegionCrossExpire = 0.0;
- }
- // Set new position and velocity
- setPositionRegion(new_pos);
- setVelocity(new_v);
- // For objects that are spinning but not translating, make sure to flag
- // them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
- // Update the last time we did anything
- mLastInterpUpdateSecs = time;
- }
- bool LLViewerObject::setData(const U8* datap, U32 data_size)
- {
- delete[] mData;
- if (datap)
- {
- mData = new U8[data_size];
- if (!mData)
- {
- return false;
- }
- memcpy(mData, datap, data_size);
- }
- return true;
- }
- // Delete an item in the inventory, but do not tell the server. This is used
- // internally by remove, update, and savescript. This will only delete the
- // first item with an item_id in the list.
- void LLViewerObject::deleteInventoryItem(const LLUUID& item_id)
- {
- if (mInventory)
- {
- for (LLInventoryObject::object_list_t::iterator
- it = mInventory->begin(), end = mInventory->end();
- it != end; ++it)
- {
- LLInventoryObject* obj = *it;
- if (obj && obj->getUUID() == item_id)
- {
- // This is safe only because we return immediatly.
- mInventory->erase(it); // will deref and delete it
- return;
- }
- }
- doInventoryCallback();
- }
- }
- void LLViewerObject::doUpdateInventory(LLPointer<LLViewerInventoryItem>& itemp,
- bool is_new)
- {
- if (is_new)
- {
- ++mExpectedInventorySerialNum;
- return;
- }
- if (!mInventory)
- {
- return;
- }
- LLUUID item_id;
- LLUUID new_owner;
- LLUUID new_group;
- bool group_owned = false;
- LLViewerInventoryItem* old_itemp =
- (LLViewerInventoryItem*)getInventoryObject(itemp->getUUID());
- if (old_itemp)
- {
- item_id = old_itemp->getUUID();
- new_owner = old_itemp->getPermissions().getOwner();
- new_group = old_itemp->getPermissions().getGroup();
- group_owned = old_itemp->getPermissions().isGroupOwned();
- }
- else
- {
- item_id = itemp->getUUID();
- }
- // Attempt to update the local inventory. If we can get the object
- // permissions, we have perfect visibility, so we want the serial number to
- // match. Otherwise, take our best guess and make sure that the serial
- // number does not match.
- deleteInventoryItem(item_id);
- LLPermissions perm(itemp->getPermissions());
- LLPermissions* obj_permp = gSelectMgr.findObjectPermissions(this);
- bool is_atomic = itemp->getType() != (S32)LLAssetType::AT_OBJECT;
- if (obj_permp)
- {
- perm.setOwnerAndGroup(LLUUID::null, obj_permp->getOwner(),
- obj_permp->getGroup(), is_atomic);
- }
- else if (group_owned)
- {
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- else if (new_owner.notNull())
- {
- // The object used to be in inventory, so we can assume the owner and
- // group will match what they are there.
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- // *FIXME: could make an even better guess by using the mPermGroup flags
- else if (permYouOwner())
- {
- // Best guess.
- perm.setOwnerAndGroup(LLUUID::null, gAgentID,
- itemp->getPermissions().getGroup(), is_atomic);
- --mExpectedInventorySerialNum;
- }
- else
- {
- // Dummy it up.
- perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null,
- is_atomic);
- --mExpectedInventorySerialNum;
- }
- LLViewerInventoryItem* new_itemp = new LLViewerInventoryItem(itemp.get());
- new_itemp->setPermissions(perm);
- mInventory->emplace_front(new_itemp);
- doInventoryCallback();
- ++mExpectedInventorySerialNum;
- }
- // Saves a script, which involves removing the old one, and rezzing in the new
- // one. This method should be called with the asset id of the new and old
- // script AFTER the bytecode has been saved.
- void LLViewerObject::saveScript(const LLViewerInventoryItem* item, bool active,
- bool is_new)
- {
- /*
- * XXXPAM Investigate not making this copy. Seems unecessary, but I am
- * unsure about the interaction with doUpdateInventory() called below.
- */
- LL_DEBUGS("ViewerObject") << "Saving script for object: " << mID
- << ". Inventory item Id: " << item->getUUID()
- << ". Asset Id: " << item->getAssetUUID()
- << LL_ENDL;
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
- item->getAssetUUID(), item->getType(),
- item->getInventoryType(),
- item->getName(), item->getDescription(),
- item->getSaleInfo(), item->getFlags(),
- item->getCreationDate());
- task_item->setTransactionID(item->getTransactionID());
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RezScript);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- msg->nextBlockFast(_PREHASH_UpdateBlock);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- msg->addBoolFast(_PREHASH_Enabled, active);
- msg->nextBlockFast(_PREHASH_InventoryBlock);
- task_item->packMessage(msg);
- msg->sendReliable(mRegionp->getHost());
- // Do the internal logic
- doUpdateInventory(task_item, is_new);
- }
- void LLViewerObject::moveInventory(const LLUUID& folder_id,
- const LLUUID& item_id)
- {
- LL_DEBUGS("ViewerObject") << "Moving inventory item " << item_id
- << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_MoveTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addUUIDFast(_PREHASH_FolderID, folder_id);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->sendReliable(mRegionp->getHost());
- LLInventoryObject* inv_obj = getInventoryObject(item_id);
- if (inv_obj)
- {
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj;
- if (!item->getPermissions().allowCopyBy(gAgentID))
- {
- deleteInventoryItem(item_id);
- ++mExpectedInventorySerialNum;
- }
- }
- }
- void LLViewerObject::dirtyInventory()
- {
- // If there is no LLVOInventoryListener, we will not be able to update our
- // mInventory when it comes back from the simulator, so we should not clear
- // the inventory either.
- if (mInventory && !mInventoryCallbacks.empty())
- {
- mInventory->clear(); // will deref and delete entries
- delete mInventory;
- mInventory = NULL;
- }
- mInventoryDirty = true;
- }
- void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener,
- void* user_data)
- {
- LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo;
- info->mObject = this;
- info->mListener = listener;
- info->mInventoryData = user_data;
- mInventoryCallbacks.push_front(info);
- }
- void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
- {
- if (!listener) return;
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info && info->mListener == listener)
- {
- delete info;
- mInventoryCallbacks.erase(curiter);
- break;
- }
- }
- }
- void LLViewerObject::clearInventoryListeners()
- {
- for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(),
- DeletePointer());
- mInventoryCallbacks.clear();
- }
- void LLViewerObject::requestInventory()
- {
- if (mInventoryDirty && mInventory && !mInventoryCallbacks.empty())
- {
- mInventory->clear(); // Will deref and delete it
- delete mInventory;
- mInventory = NULL;
- }
- if (mInventory)
- {
- // Inventory is either up to date or does not have a listener if it is
- // dirty, leave it this way in case we gain a listener.
- doInventoryCallback();
- }
- else
- {
- // Since we are going to request it now.
- mInventoryDirty = false;
- // Throw away duplicate requests.
- fetchInventoryFromServer();
- }
- }
- void LLViewerObject::fetchInventoryFromServer()
- {
- if (!isInventoryPending())
- {
- delete mInventory;
- mInventory = NULL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RequestTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->sendReliable(mRegionp->getHost());
- // this will get reset by dirtyInventory or doInventoryCallback
- mInvRequestState = INVENTORY_REQUEST_PENDING;
- }
- }
- LLVOAvatarPuppet* LLViewerObject::getPuppetAvatar()
- {
- return getRootEdit()->mPuppetAvatar.get();
- }
- LLVOAvatarPuppet* LLViewerObject::getPuppetAvatar() const
- {
- return getRootEdit()->mPuppetAvatar.get();
- }
- void LLViewerObject::linkPuppetAvatar()
- {
- LLVOAvatarPuppet* puppet = getPuppetAvatar();
- if (!puppet && isRootEdit())
- {
- LLVOVolume* volp = asVolume();
- if (!volp)
- {
- llwarns << "Called with null or non-volume object" << llendl;
- return;
- }
- puppet = mPuppetAvatar = LLVOAvatarPuppet::createAvatarPuppet(volp);
- }
- if (puppet)
- {
- puppet->updateAttachmentOverrides();
- if (!puppet->mPlaying)
- {
- puppet->mPlaying = true;
- #if 0
- if (!puppet->mRootVolp->isAnySelected())
- #endif
- {
- puppet->updateVolumeGeom();
- puppet->mRootVolp->recursiveMarkForUpdate();
- }
- }
- }
- else
- {
- llwarns << "No puppet avatar found !" << llendl;
- }
- }
- void LLViewerObject::unlinkPuppetAvatar()
- {
- LLVOAvatarPuppet* puppet = getPuppetAvatar();
- if (puppet)
- {
- puppet->updateAttachmentOverrides();
- if (isRootEdit())
- {
- // This will remove the entire linkset from the puppet avatar.
- // Note: mPuppetAvatar == puppet for root edit, so it is not NULL
- // here.
- mPuppetAvatar->markForDeath();
- mPuppetAvatar = NULL;
- }
- // For non-root prims, removing from the linkset will automatically
- // remove the puppet avatar connection.
- }
- }
- void LLViewerObject::updatePuppetAvatar()
- {
- LLViewerObject* root = getRootEdit();
- bool animated = root->isAnimatedObject();
- LLVOAvatarPuppet* puppet = root->mPuppetAvatar.get();
- bool no_puppet = puppet == NULL;
- if (no_puppet && !animated)
- {
- return;
- }
- bool is_rigged_mesh = false;
- if (animated)
- {
- is_rigged_mesh = root->isRiggedMesh();
- if (!is_rigged_mesh)
- {
- const_child_list_t& child_list = root->getChildren();
- for (const_child_list_t::const_iterator iter = child_list.begin(),
- end = child_list.end();
- iter != end; ++iter)
- {
- const LLViewerObject* child = *iter;
- if (child && child->isRiggedMesh())
- {
- is_rigged_mesh = true;
- break;
- }
- }
- }
- }
- if (animated && is_rigged_mesh)
- {
- if (no_puppet)
- {
- root->linkPuppetAvatar();
- }
- }
- else if (!no_puppet)
- {
- root->unlinkPuppetAvatar();
- }
- if (puppet)
- {
- puppet->updateAnimations();
- if (mUserSelected)
- {
- gSelectMgr.pauseAssociatedAvatars();
- }
- }
- }
- struct LLFilenameAndTask
- {
- LL_INLINE LLFilenameAndTask(const LLUUID& id, const std::string& fname,
- S16 serial)
- : mTaskID(id),
- mFilename(fname),
- mSerial(serial)
- {
- }
- LLUUID mTaskID;
- std::string mFilename;
- S16 mSerial; // For sequencing in case of multiple updates
- };
- //static
- void LLViewerObject::processTaskInv(LLMessageSystem* msg, void**)
- {
- LLUUID task_id;
- msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
- LLViewerObject* object = gObjectList.findObject(task_id);
- if (!object)
- {
- llwarns << "Object " << task_id << " does not exist." << llendl;
- return;
- }
- // Note: we can receive multiple task updates simultaneously, make sure we
- // will not rewrite newer with older update
- S16 serial;
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial);
- if (serial == object->mInventorySerialNum &&
- serial < object->mExpectedInventorySerialNum)
- {
- // Loop protection. We received same serial twice. Viewer did some
- // changes to inventory that could not be saved yet or something went
- // wrong to cause serial to be out of sync...
- // ... but only warn if inventory has already been received once (else
- // it simply means we are still waiting for initial data: seen while
- // inspecting avatars attachments).
- if (serial)
- {
- llwarns << "Task inventory serial might be out of sync, server serial: "
- << serial << " - Client expected serial: "
- << object->mExpectedInventorySerialNum << llendl;
- }
- object->mExpectedInventorySerialNum = serial;
- }
- if (serial < object->mExpectedInventorySerialNum)
- {
- // Out of date message; record to current serial for loop protection,
- // but do not load it: just drop xfer to restart on idle.
- if (serial < object->mInventorySerialNum)
- {
- llwarns << "Task inventory serial has decreased: out of order packet ? Server serial: "
- << serial << " - Client expected serial: "
- << object->mExpectedInventorySerialNum << llendl;
- }
- object->mInventorySerialNum = serial;
- object->mInvRequestXFerId = 0;
- object->mInvRequestState = INVENTORY_REQUEST_STOPPED;
- return;
- }
- object->mInventorySerialNum = object->mExpectedInventorySerialNum = serial;
- std::string filename;
- msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, filename);
- filename = LLDir::getScrubbedFileName(filename);
- if (filename.empty())
- {
- LL_DEBUGS("ViewerObject") << "Task has no inventory" << LL_ENDL;
- // Mock up some inventory to make a drop target.
- if (object->mInventory)
- {
- object->mInventory->clear(); // Will deref and delete it
- }
- else
- {
- object->mInventory = new LLInventoryObject::object_list_t();
- }
- object->mInventory->emplace_front(new LLInventoryObject(object->mID,
- LLUUID::null,
- LLAssetType::AT_CATEGORY,
- "Contents"));
- object->doInventoryCallback();
- return;
- }
- if (!gXferManagerp)
- {
- llwarns << "Transfer manager gone. Aborted." << llendl;
- return;
- }
- LLFilenameAndTask* ft = new LLFilenameAndTask(task_id, filename, serial);
- U64 new_id =
- gXferManagerp->requestFile(gDirUtil.getFullPath(LL_PATH_CACHE,
- filename),
- filename, LL_PATH_CACHE,
- object->mRegionp->getHost(), true,
- processTaskInvFile, (void**)ft,
- LLXferManager::HIGH_PRIORITY);
- if (object->mInvRequestState == INVENTORY_XFER)
- {
- if (new_id && new_id != object->mInvRequestXFerId)
- {
- // We started a new download. Abort the old one.
- gXferManagerp->abortRequestById(object->mInvRequestXFerId, -1);
- object->mInvRequestXFerId = new_id;
- }
- }
- else
- {
- object->mInvRequestState = INVENTORY_XFER;
- object->mInvRequestXFerId = new_id;
- }
- }
- void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code,
- LLExtStat ext_status)
- {
- LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
- LLViewerObject* objectp;
- if (ft && error_code == 0 &&
- (objectp = gObjectList.findObject(ft->mTaskID)) &&
- ft->mSerial >= objectp->mInventorySerialNum)
- {
- objectp->mInventorySerialNum = ft->mSerial;
- LL_DEBUGS("ViewerObject") << "Receiving inventory task file for serial: "
- << objectp->mInventorySerialNum
- << " - Expected serial: "
- << objectp->mExpectedInventorySerialNum
- << " - Task Id: " << ft->mTaskID << LL_ENDL;
- if (objectp->loadTaskInvFile(ft->mFilename))
- {
- uuid_list_t& pending = objectp->mPendingInventoryItemsIDs;
- for (LLInventoryObject::object_list_t::iterator
- it = objectp->mInventory->begin(),
- end = objectp->mInventory->end();
- it != end && !pending.empty(); ++it)
- {
- LLViewerInventoryItem* itemp =
- it->get()->asViewerInventoryItem();
- if (itemp && itemp->getType() != LLAssetType::AT_CATEGORY)
- {
- // Erase if present. No-op when absent.
- pending.erase(itemp->getAssetUUID());
- }
- }
- }
- }
- else
- {
- // This occurs when two requests were made, and the first one has
- // already handled it.
- LL_DEBUGS("ViewerObject") << "Problem loading task inventory. Return code: "
- << error_code << LL_ENDL;
- }
- if (ft)
- {
- delete ft;
- }
- }
- bool LLViewerObject::loadTaskInvFile(const std::string& filename)
- {
- std::string full_path = gDirUtil.getFullPath(LL_PATH_CACHE, filename);
- llifstream ifs(full_path.c_str());
- if (!ifs.good())
- {
- llwarns << "Unable to load task inventory: " << full_path << llendl;
- return false;
- }
- if (mInventory)
- {
- mInventory->clear(); // Will deref and delete it
- }
- else
- {
- mInventory = new LLInventoryObject::object_list_t;
- }
- char buffer[MAX_STRING];
- // *NOTE: This buffer size is hard coded into scanf() below.
- char keyword[MAX_STRING];
- U32 failed = 0;
- while (ifs.good())
- {
- ifs.getline(buffer, MAX_STRING);
- if (sscanf(buffer, " %254s", keyword) < 1)
- {
- continue; // Ignore empty lines. HB
- }
- if (strcmp("inv_item", keyword) == 0)
- {
- LLPointer<LLInventoryObject> inv_objp = new LLViewerInventoryItem;
- inv_objp->importLegacyStream(ifs);
- mInventory->emplace_front(std::move(inv_objp));
- }
- else if (strcmp("inv_object", keyword) == 0)
- {
- LLPointer<LLInventoryObject> inv_objp = new LLInventoryObject;
- inv_objp->importLegacyStream(ifs);
- mInventory->emplace_front(std::move(inv_objp));
- }
- else if (++failed > MAX_INV_FILE_READ_FAILS)
- {
- llwarns << "Too many unknown token in inventory file: " << filename
- << ". Aborting." << llendl;
- break;
- }
- else
- {
- llwarns << "Unknown token '" << keyword << "' in inventory file: "
- << filename << llendl;
- }
- }
- ifs.close();
- LLFile::remove(full_path);
- doInventoryCallback();
- return true;
- }
- void LLViewerObject::doInventoryCallback()
- {
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info && info->mListener)
- {
- info->mListener->inventoryChanged(this, mInventory,
- mInventorySerialNum,
- info->mInventoryData);
- }
- else
- {
- llinfos << "Deleting bad listener entry." << llendl;
- delete info;
- mInventoryCallbacks.erase(curiter);
- }
- }
- // Release inventory loading state
- mInvRequestXFerId = 0;
- mInvRequestState = INVENTORY_REQUEST_STOPPED;
- }
- void LLViewerObject::removeInventory(const LLUUID& item_id)
- {
- // close any associated floater properties
- LLFloaterProperties::closeByID(item_id, mID);
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RemoveTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->sendReliable(mRegionp->getHost());
- deleteInventoryItem(item_id);
- ++mExpectedInventorySerialNum;
- }
- bool LLViewerObject::isAssetInInventory(LLViewerInventoryItem* itemp,
- LLAssetType::EType type)
- {
- if (!itemp)
- {
- return false;
- }
- // Note: for now mPendingInventoryItemsIDs only stores textures and
- // GLTF materials, but if it gets to store more types, it will need to
- // verify type as well since null can be a shared default UUID and it is
- // fine to need a null script and a null material simultaneously.
- const LLUUID& asset_id = itemp->getAssetUUID();
- return mPendingInventoryItemsIDs.count(asset_id) > 0 ||
- getInventoryItemByAsset(asset_id, type) != NULL;
- }
- void LLViewerObject::updateInventory(LLViewerInventoryItem* itemp, bool is_new)
- {
- if (!itemp) // Paranoia
- {
- return;
- }
- if (is_new)
- {
- LLAssetType::EType type = itemp->getType();
- if (type == LLAssetType::AT_TEXTURE ||
- type == LLAssetType::AT_MATERIAL)
- {
- if (isAssetInInventory(itemp, type))
- {
- return; // Already here
- }
- mPendingInventoryItemsIDs.emplace(itemp->getAssetUUID());
- }
- }
- // This slices the object into what we are concerned about on the viewer.
- // The simulator will take the permissions and transfer ownership.
- LLPointer<LLViewerInventoryItem> task_itemp =
- new LLViewerInventoryItem(itemp->getUUID(), mID,
- itemp->getPermissions(),
- itemp->getAssetUUID(), itemp->getType(),
- itemp->getInventoryType(), itemp->getName(),
- itemp->getDescription(),
- itemp->getSaleInfo(), itemp->getFlags(),
- itemp->getCreationDate());
- task_itemp->setTransactionID(itemp->getTransactionID());
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_UpdateData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addU8Fast(_PREHASH_Key, TASK_INVENTORY_ITEM_KEY);
- msg->nextBlockFast(_PREHASH_InventoryData);
- task_itemp->packMessage(msg);
- msg->sendReliable(mRegionp->getHost());
- // Do the internal logic
- doUpdateInventory(task_itemp, is_new);
- }
- LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id)
- {
- LLInventoryObject* rv = NULL;
- if (mInventory && item_id.notNull())
- {
- for (LLInventoryObject::object_list_t::const_iterator
- it = mInventory->begin(), end = mInventory->end();
- it != end; ++it)
- {
- LLInventoryObject* obj = *it;
- if (obj && obj->getUUID() == item_id)
- {
- rv = *it;
- break;
- }
- }
- }
- return rv;
- }
- LLInventoryItem* LLViewerObject::getInventoryItem(const LLUUID& item_id)
- {
- LLInventoryObject* invobjp = getInventoryObject(item_id);
- if (invobjp && invobjp->getType() != LLAssetType::AT_CATEGORY)
- {
- return dynamic_cast<LLInventoryItem*>(invobjp);
- }
- return NULL;
- }
- void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects)
- {
- if (mInventory)
- {
- for (LLInventoryObject::object_list_t::const_iterator
- it = mInventory->begin(), end = mInventory->end();
- it != end; ++it)
- {
- LLInventoryObject* obj = *it;
- if (obj && obj->getType() != LLAssetType::AT_CATEGORY)
- {
- objects.push_back(obj);
- }
- }
- }
- }
- LLInventoryObject* LLViewerObject::getInventoryRoot()
- {
- return mInventory && !mInventory->empty() ? mInventory->back().get()
- : NULL;
- }
- LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id,
- LLAssetType::EType type)
- {
- if (mInventoryDirty)
- {
- // This is rather common (and harmless), now, while editing PBR objects
- // (since a check is done for the PBR material permissions/presence in
- // the edited primitive), so made it a LL_DEBUGS to avoid spamming the
- // log uselessly. HB
- LL_DEBUGS("ViewerObject") << "Performing inventory lookup for object "
- << mID << " that has dirty inventory."
- << LL_ENDL;
- }
- if (type == LLAssetType::AT_CATEGORY)
- {
- llwarns << "Attempted to get an inventory asset for category Id: "
- << asset_id << llendl;
- // Whatever called this should not be trying to get a folder by asset,
- // since categories do not have any asset !
- llassert(false);
- return NULL;
- }
- if (mInventory)
- {
- for (LLInventoryObject::object_list_t::const_iterator
- it = mInventory->begin(), end = mInventory->end();
- it != end; ++it)
- {
- LLInventoryObject* objp = *it;
- if (!objp) continue;
- LLAssetType::EType atype = objp->getType();
- if (atype != LLAssetType::AT_CATEGORY &&
- atype != LLAssetType::AT_NONE)
- {
- LLViewerInventoryItem* itemp = objp->asViewerInventoryItem();
- if (itemp && itemp->getAssetUUID() == asset_id)
- {
- if (type == LLAssetType::AT_NONE || type == atype)
- {
- return itemp;
- }
- }
- }
- }
- }
- return NULL;
- }
- void LLViewerObject::updateViewerInventoryAsset(const LLViewerInventoryItem* item,
- const LLUUID& new_asset)
- {
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item);
- task_item->setAssetUUID(new_asset);
- // Do the internal logic
- doUpdateInventory(task_item, false);
- }
- void LLViewerObject::setPixelAreaAndAngle()
- {
- if (getVolume())
- {
- // Volumes calculate pixel area and angle per face
- return;
- }
- LLVector3 viewer_pos_agent = gAgent.getCameraPositionAgent();
- LLVector3 pos_agent = getRenderPosition();
- F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX];
- F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY];
- F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ];
- F32 max_scale = getMaxScale();
- F32 mid_scale = getMidScale();
- F32 min_scale = getMinScale();
- // IW: estimate, when close to large objects, computing range based on
- // distance from center is no good to try to get a min distance from face,
- // subtract min_scale/2 from the range. This means we will load too much
- // detail sometimes, but that is better than not enough. I do not think
- // there is a better way to do this without calculating distance per-poly.
- F32 range = sqrtf(dx * dx + dy * dy + dz * dz) - 0.5f * min_scale;
- if (range < 0.001f || isHUDAttachment()) // range == zero
- {
- mAppAngle = 180.f;
- mPixelArea = (F32)gViewerCamera.getScreenPixelArea();
- }
- else
- {
- mAppAngle = atan2f(max_scale, range) * RAD_TO_DEG;
- F32 pixels_per_meter = gViewerCamera.getPixelMeterRatio() / range;
- mPixelArea = (pixels_per_meter * max_scale) *
- (pixels_per_meter * mid_scale);
- if (mPixelArea > gViewerCamera.getScreenPixelArea())
- {
- mAppAngle = 180.f;
- mPixelArea = (F32)gViewerCamera.getScreenPixelArea();
- }
- }
- }
- void LLViewerObject::setScale(const LLVector3& scale, bool damped)
- {
- LLPrimitive::setScale(scale);
- if (mDrawable.notNull())
- {
- // Encompass completely sheared objects by taking the most extreme
- // point possible (<1,1,0.5>)
- mDrawable->setRadius(LLVector3(1.f, 1.f, 0.5f).scaleVec(scale).length());
- updateDrawable(damped);
- }
- if (getPCode() == LL_PCODE_VOLUME && !isDead() && !isAttachment())
- {
- bool plottable = (flagCharacter() || flagUsePhysics()) && isRoot();
- if (plottable || permYouOwner() || scale.lengthSquared() > 7.5f * 7.5f)
- {
- if (!mOnMap)
- {
- gObjectList.addToMap(this);
- mOnMap = true;
- }
- }
- else if (mOnMap)
- {
- gObjectList.removeFromMap(this);
- mOnMap = false;
- }
- }
- }
- void LLViewerObject::setObjectCostStale()
- {
- mCostStale = true;
- // Note: this is harmlessly redundant for Blinn-Phong material updates,
- // since the root prim currently gets set stale anyway due to other
- // property updates. But it is needed for PBR material Id updates.
- LLViewerObject* rootp = getRootEdit();
- if (rootp && rootp != this)
- {
- rootp->mCostStale = true;
- }
- }
- void LLViewerObject::setObjectCost(F32 cost)
- {
- mObjectCost = cost;
- mCostStale = false;
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- }
- void LLViewerObject::setLinksetCost(F32 cost)
- {
- mLinksetCost = cost;
- mCostStale = false;
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- }
- void LLViewerObject::setPhysicsCost(F32 cost)
- {
- mPhysicsCost = cost;
- mCostStale = false;
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- }
- void LLViewerObject::setLinksetPhysicsCost(F32 cost)
- {
- mLinksetPhysicsCost = cost;
- mCostStale = false;
- if (gFloaterToolsp && mUserSelected)
- {
- gFloaterToolsp->dirty();
- }
- }
- F32 LLViewerObject::getObjectCost()
- {
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
- return mObjectCost;
- }
- F32 LLViewerObject::getLinksetCost()
- {
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
- return mLinksetCost;
- }
- F32 LLViewerObject::getPhysicsCost()
- {
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
- return mPhysicsCost;
- }
- F32 LLViewerObject::getLinksetPhysicsCost()
- {
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
- return mLinksetPhysicsCost;
- }
- F32 LLViewerObject::recursiveGetEstTrianglesMax() const
- {
- F32 est_tris = getEstTrianglesMax();
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- const LLViewerObject* childp = *iter;
- if (childp && !childp->isAvatar())
- {
- est_tris += childp->recursiveGetEstTrianglesMax();
- }
- }
- return est_tris;
- }
- U32 LLViewerObject::recursiveGetTriangleCount(S32* vcountp) const
- {
- S32 total_tris = getTriangleCount(vcountp);
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- const LLViewerObject* childp = *iter;
- if (childp)
- {
- total_tris += childp->getTriangleCount(vcountp);
- }
- }
- return total_tris;
- }
- S32 LLViewerObject::getAnimatedObjectMaxTris() const
- {
- S32 res = 0;
- LLViewerRegion* regionp = gAgent.getRegion();
- if (regionp)
- {
- const LLSD& info = regionp->getSimulatorFeatures();
- if (info.has("AnimatedObjects"))
- {
- res = info["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger();
- }
- }
- return res;
- }
- void LLViewerObject::updateSpatialExtents(LLVector4a& new_min,
- LLVector4a& new_max)
- {
- if (mDrawable.notNull())
- {
- LLVector4a center;
- center.load3(getRenderPosition().mV);
- LLVector4a size;
- size.load3(getScale().mV);
- new_min.setSub(center, size);
- new_max.setAdd(center, size);
- mDrawable->setPositionGroup(center);
- }
- else
- {
- llwarns << "Call done for an object with NULL mDrawable" << llendl;
- }
- }
- F32 LLViewerObject::getBinRadius()
- {
- if (mDrawable.notNull())
- {
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- LLVector4a diff;
- diff.setSub(ext[1], ext[0]);
- return diff.getLength3().getF32();
- }
- return getScale().length();
- }
- F32 LLViewerObject::getMaxScale() const
- {
- return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]);
- }
- F32 LLViewerObject::getMinScale() const
- {
- return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]);
- }
- F32 LLViewerObject::getMidScale() const
- {
- if (getScale().mV[VX] < getScale().mV[VY])
- {
- if (getScale().mV[VY] < getScale().mV[VZ])
- {
- return getScale().mV[VY];
- }
- else if (getScale().mV[VX] < getScale().mV[VZ])
- {
- return getScale().mV[VZ];
- }
- else
- {
- return getScale().mV[VX];
- }
- }
- else if (getScale().mV[VX] < getScale().mV[VZ])
- {
- return getScale().mV[VX];
- }
- else if (getScale().mV[VY] < getScale().mV[VZ])
- {
- return getScale().mV[VZ];
- }
- else
- {
- return getScale().mV[VY];
- }
- }
- void LLViewerObject::boostTexturePriority(bool boost_children)
- {
- if (isDead())
- {
- return;
- }
- for (S32 i = 0, count = getNumTEs(); i < count; ++i)
- {
- LLViewerTexture* texp = getTEImage(i);
- if (texp)
- {
- texp->setBoostLevel(LLGLTexture::BOOST_SELECTED);
- }
- }
- if (isSculpted() && !isMesh())
- {
- const LLSculptParams* sculpt_params = getSculptParams();
- const LLUUID& sculpt_id = sculpt_params->getSculptTexture();
- LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, true,
- LLGLTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED);
- }
- if (boost_children)
- {
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child) // Paranoia
- {
- child->boostTexturePriority();
- }
- }
- }
- }
- void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
- {
- if (window_width < 700)
- {
- LLUI::setLineWidth(2.f);
- }
- else if (window_width < 1100)
- {
- LLUI::setLineWidth(3.f);
- }
- else if (window_width < 2000)
- {
- LLUI::setLineWidth(4.f);
- }
- else
- {
- LLUI::setLineWidth(5.f);
- }
- }
- // Culled from newsim LLTask::addNVPair
- void LLViewerObject::addNVPair(const std::string& data)
- {
- LLNameValue* nv = new LLNameValue(data.c_str());
- name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName);
- if (iter != mNameValuePairs.end())
- {
- LLNameValue* foundnv = iter->second;
- if (foundnv->mClass != NVC_READ_ONLY)
- {
- delete foundnv;
- mNameValuePairs.erase(iter);
- }
- else
- {
- delete nv;
- return;
- }
- }
- mNameValuePairs[nv->mName] = nv;
- }
- bool LLViewerObject::removeNVPair(const std::string& name)
- {
- char* canonical_name = gNVNameTable.addString(name);
- LL_DEBUGS("ViewerObject") << "Removing: " << name << LL_ENDL;
- name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name);
- if (iter != mNameValuePairs.end())
- {
- if (mRegionp)
- {
- LLNameValue* nv = iter->second;
- #if 0
- std::string buffer = nv->printNameValue();
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RemoveNameValuePair);
- msg->nextBlockFast(_PREHASH_TaskData);
- msg->addUUIDFast(_PREHASH_ID, mID);
- msg->nextBlockFast(_PREHASH_NameValueData);
- msg->addStringFast(_PREHASH_NVPair, buffer);
- msg->sendReliable(mRegionp->getHost());
- #endif
- // Remove the NV pair from the local list.
- delete nv;
- mNameValuePairs.erase(iter);
- return true;
- }
- else
- {
- LL_DEBUGS("ViewerObject") << "No region for object" << LL_ENDL;
- }
- }
- return false;
- }
- LLNameValue* LLViewerObject::getNVPair(const std::string& name) const
- {
- char* canonical_name = gNVNameTable.addString(name);
- if (!canonical_name)
- {
- return NULL;
- }
- // If you access a map with a name that is not in it, it will add the name
- // and a null pointer. So first check if the data is in the map.
- name_value_map_t::const_iterator it = mNameValuePairs.find(canonical_name);
- if (it != mNameValuePairs.end())
- {
- return it->second;
- }
- return NULL;
- }
- void LLViewerObject::updatePositionCaches() const
- {
- // If region is removed from the list it is also deleted.
- if (mRegionp && gWorld.isRegionListed(mRegionp))
- {
- if (!isRoot())
- {
- LLViewerObject* parent = (LLViewerObject*)getParent();
- if (!parent)
- {
- llwarns_once << "No parent for child object " << mID << llendl;
- llassert(false);
- return;
- }
- mPositionRegion = parent->getPositionRegion() +
- getPosition() * parent->getRotation();
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- else
- {
- mPositionRegion = getPosition();
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- }
- }
- const LLVector3d LLViewerObject::getPositionGlobal() const
- {
- LLVector3d pos_global;
- // If region is removed from the list it is also deleted.
- if (mRegionp && gWorld.isRegionListed(mRegionp))
- {
- if (isAttachment())
- {
- pos_global = gAgent.getPosGlobalFromAgent(getRenderPosition());
- }
- else
- {
- pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
- }
- }
- else
- {
- pos_global.set(getPosition());
- }
- return pos_global;
- }
- const LLVector3& LLViewerObject::getPositionAgent() const
- {
- // If region is removed from the list it is also deleted.
- if (mRegionp && gWorld.isRegionListed(mRegionp))
- {
- if (mDrawable.notNull() && !mDrawable->isRoot() && getParent())
- {
- // Do not return cached position if you have a parent, recalculate
- // until all dirtying is done correctly.
- LLVector3 position_region =
- ((LLViewerObject*)getParent())->getPositionRegion() +
- getPosition() * getParent()->getRotation();
- mPositionAgent = mRegionp->getPosAgentFromRegion(position_region);
- }
- else
- {
- mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition());
- }
- }
- return mPositionAgent;
- }
- const LLVector3& LLViewerObject::getPositionRegion() const
- {
- if (!isRoot())
- {
- LLViewerObject* parent = (LLViewerObject*)getParent();
- mPositionRegion = parent->getPositionRegion() +
- getPosition() * parent->getRotation();
- }
- else
- {
- mPositionRegion = getPosition();
- }
- return mPositionRegion;
- }
- const LLVector3 LLViewerObject::getPositionEdit() const
- {
- if (isRootEdit())
- {
- return getPosition();
- }
- else
- {
- LLViewerObject* parent = (LLViewerObject*)getParent();
- LLVector3 position_edit = parent->getPositionEdit() +
- getPosition() * parent->getRotationEdit();
- return position_edit;
- }
- }
- const LLVector3 LLViewerObject::getRenderPosition() const
- {
- if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
- {
- if (isRoot())
- {
- LLVOAvatarPuppet* puppet = getPuppetAvatar();
- if (puppet)
- {
- F32 fixup;
- if (puppet->hasPelvisFixup(fixup))
- {
- LLVector3 pos = mDrawable->getPositionAgent();
- pos[VZ] += fixup;
- return pos;
- }
- }
- }
- LLVOAvatar* avatar = getAvatar();
- #if 0
- if (avatar && !avatar->isPuppetAvatar())
- {
- return avatar->getRenderPosition();
- }
- #else
- if (avatar && !getPuppetAvatar())
- {
- return avatar->getPositionAgent();
- }
- #endif
- }
- if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
- {
- return getPositionAgent();
- }
- return mDrawable->getPositionAgent();
- }
- LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const
- {
- LLMatrix4 root;
- root.initScale(getScale());
- root.rotate(getRenderRotation());
- root.translate(getPositionAgent());
- LLMatrix4a mat;
- mat.loadu(root.getF32ptr());
- return mat;
- }
- LLVector3 LLViewerObject::getGLTFNodePositionAgent(S32 node_index) const
- {
- LLVector3 ret;
- getGLTFNodeTransformAgent(node_index, &ret, NULL, NULL);
- return ret;
- }
- LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const
- {
- LLVector3 scale = getScale();
- scale.mV[0] = 1.f / scale.mV[0];
- scale.mV[1] = 1.f / scale.mV[1];
- scale.mV[2] = 1.f / scale.mV[2];
- LLMatrix4 scale_mat;
- scale_mat.initScale(scale);
- LLMatrix4 root;
- root.translate(-getPositionAgent());
- root.rotate(~getRenderRotation());
- root *= scale_mat;
- LLMatrix4a mat;
- mat.loadu(root.getF32ptr());
- return mat;
- }
- LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
- {
- LLMatrix4a mat;
- if (mGLTFAsset.notNull() && node_index >= 0 &&
- node_index < (S32)mGLTFAsset->mNodes.size())
- {
- auto& node = mGLTFAsset->mNodes[node_index];
- mat.matMul(node.mAssetMatrix, getGLTFAssetToAgentTransform());
- }
- else
- {
- mat.setIdentity();
- }
- return mat;
- }
- void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* posp,
- LLQuaternion* rotp,
- LLVector3* scalep) const
- {
- LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index);
- if (posp)
- {
- LLVector4a p = node_to_agent.getTranslation();
- posp->set(p.getF32ptr());
- }
- if (rotp)
- {
- rotp->set(node_to_agent.asMatrix4());
- }
- if (scalep)
- {
- scalep->mV[0] = node_to_agent.mMatrix[0].getLength3().getF32();
- scalep->mV[1] = node_to_agent.mMatrix[1].getLength3().getF32();
- scalep->mV[2] = node_to_agent.mMatrix[2].getLength3().getF32();
- }
- }
- static void decompose_mat(const LLMatrix4a& mat, LLVector3& position,
- LLQuaternion& rotation, LLVector3& scale)
- {
- LLVector4a p = mat.getTranslation();
- position.set(p.getF32ptr());
- rotation.set(mat.asMatrix4());
- scale.mV[0] = mat.mMatrix[0].getLength3().getF32();
- scale.mV[1] = mat.mMatrix[1].getLength3().getF32();
- scale.mV[2] = mat.mMatrix[2].getLength3().getF32();
- }
- void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index,
- const LLQuaternion& rotation)
- {
- if (mGLTFAsset.isNull() || node_index < 0 ||
- node_index >= (S32)mGLTFAsset->mNodes.size())
- {
- return;
- }
- auto& node = mGLTFAsset->mNodes[node_index];
- LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
- LLMatrix4a agent_to_node = agent_to_asset;
- if (node.mParent != -1)
- {
- auto& parent = mGLTFAsset->mNodes[node.mParent];
- agent_to_node.matMul(agent_to_asset, parent.mAssetMatrixInv);
- }
- LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4());
- LLQuaternion new_rot = rotation * agent_to_node_rot;
- new_rot.normalize();
- LLVector3 pos, scale;
- LLQuaternion rot;
- decompose_mat(node.mMatrix, pos, rot, scale);
- node.mMatrix.asMatrix4().initAll(scale, new_rot, pos);
- mGLTFAsset->updateTransforms();
- }
- void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
- {
- if (mGLTFAsset.isNull() || node_index < 0 ||
- node_index >= (S32)mGLTFAsset->mNodes.size())
- {
- return;
- }
- auto& node = mGLTFAsset->mNodes[node_index];
- LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
- LLMatrix4a agent_to_node;
- agent_to_node.matMul(agent_to_asset, node.mAssetMatrixInv);
- LLVector4a offset_v;
- offset_v.load3(offset.mV);
- agent_to_node.affineTransform(offset_v, offset_v);
- LLVector4a origin = LLVector4a::getZero();
- agent_to_node.affineTransform(origin, origin);
- offset_v.sub(origin);
- offset_v.getF32ptr()[3] = 1.f;
- LLMatrix4a trans;
- trans.setIdentity();
- trans.mMatrix[3] = offset_v;
- node.mMatrix.matMul(trans, node.mMatrix);
- // *TODO: only update transforms for this node and its children (or use a
- // dirty flag).
- mGLTFAsset->updateTransforms();
- }
- const LLQuaternion LLViewerObject::getRenderRotation() const
- {
- bool has_drawable = mDrawable.notNull();
- if (has_drawable && mDrawable->isState(LLDrawable::RIGGED) &&
- !isAnimatedObject())
- {
- return LLQuaternion();
- }
- if (!has_drawable || mDrawable->isStatic())
- {
- return getRotationEdit();
- }
- if (!mDrawable->isRoot())
- {
- return getRotation() *
- LLQuaternion(mDrawable->getParent()->getWorldMatrix());
- }
- return LLQuaternion(mDrawable->getWorldMatrix());
- }
- const LLMatrix4& LLViewerObject::getRenderMatrix() const
- {
- return mDrawable->getWorldMatrix();
- }
- const LLQuaternion LLViewerObject::getRotationRegion() const
- {
- if (((LLXform*)this)->isRoot())
- {
- return getRotation();
- }
- return getRotation() * getParent()->getRotation();
- }
- const LLQuaternion LLViewerObject::getRotationEdit() const
- {
- if (((LLXform*)this)->isRootEdit())
- {
- return getRotation();
- }
- return getRotation() * getParent()->getRotation();
- }
- void LLViewerObject::setPositionAbsoluteGlobal(const LLVector3d& pos_global)
- {
- if (isAttachment())
- {
- LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global);
- if (isRootEdit())
- {
- new_pos -= mDrawable->mXform.getParent()->getWorldPosition();
- LLQuaternion world_rotation =
- mDrawable->mXform.getParent()->getWorldRotation();
- new_pos = new_pos * ~world_rotation;
- }
- else
- {
- LLViewerObject* parentp = (LLViewerObject*)getParent();
- new_pos -= parentp->getPositionAgent();
- new_pos = new_pos * ~parentp->getRotationRegion();
- }
- setPositionLocal(new_pos);
- if (mParent && mParent->isAvatar())
- {
- // We have changed the position of an attachment, so we need to
- // clamp it
- ((LLVOAvatar*)mParent)->clampAttachmentPositions();
- }
- }
- else if (isRoot())
- {
- setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
- }
- else
- {
- // The relative position with the parent is not constant
- LLViewerObject* parent = (LLViewerObject*)getParent();
- // RN: this assumes we are only calling this function from the edit
- // tools
- gPipeline.updateMoveNormalAsync(parent->mDrawable);
- LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) -
- parent->getPositionRegion();
- pos_local = pos_local * ~parent->getRotationRegion();
- setPositionLocal(pos_local);
- }
- // RN: assumes we always want to snap the object when calling this function
- gPipeline.updateMoveNormalAsync(mDrawable);
- }
- void LLViewerObject::setPositionLocal(const LLVector3& pos, bool damped)
- {
- if (getPosition() != pos)
- {
- setChanged(TRANSLATED | SILHOUETTE);
- }
- setPosition(pos);
- updateDrawable(damped);
- if (isRoot())
- {
- // Position caches need to be up to date on root objects
- updatePositionCaches();
- }
- }
- void LLViewerObject::setPositionGlobal(const LLVector3d& pos_global,
- bool damped)
- {
- if (isAttachment())
- {
- LLVector3 new_pos;
- if (isRootEdit())
- {
- new_pos = mRegionp->getPosRegionFromGlobal(pos_global);
- new_pos = new_pos - mDrawable->mXform.getParent()->getWorldPosition();
- LLQuaternion inv_world_rot =
- mDrawable->mXform.getParent()->getWorldRotation();
- inv_world_rot.transpose();
- new_pos = new_pos * inv_world_rot;
- setPositionLocal(new_pos);
- }
- else
- {
- // Assumes parent is root editable (root of attachment)
- new_pos = mRegionp->getPosRegionFromGlobal(pos_global);
- new_pos = new_pos - mDrawable->mXform.getParent()->getWorldPosition();
- LLVector3 delta_pos = new_pos - getPosition();
- LLQuaternion invRotation = mDrawable->getRotation();
- invRotation.transpose();
- delta_pos = delta_pos * invRotation;
- // *FIXME: is this right ? Should not we be calling the
- // LLViewerObject version of setPosition ?
- LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition();
- mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos);
- setChanged(TRANSLATED | SILHOUETTE);
- }
- if (mParent && mParent->isAvatar())
- {
- // We have changed the position of an attachment, so we need to
- // clamp it
- ((LLVOAvatar*)mParent)->clampAttachmentPositions();
- }
- }
- else if (isRoot())
- {
- setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
- }
- else
- {
- // The relative position with the parent is constant, but the parent's
- // position needs to be changed
- LLVector3d position_offset;
- position_offset.set(getPosition()*getParent()->getRotation());
- LLVector3d new_pos_global = pos_global - position_offset;
- ((LLViewerObject*)getParent())->setPositionGlobal(new_pos_global);
- }
- updateDrawable(damped);
- }
- void LLViewerObject::setPositionParent(const LLVector3& pos_parent,
- bool damped)
- {
- // Set position relative to parent, if no parent, relative to region
- if (!isRoot())
- {
- setPositionLocal(pos_parent, damped);
- #if 0
- updateDrawable(damped);
- #endif
- }
- else
- {
- setPositionRegion(pos_parent);
- }
- }
- void LLViewerObject::setPositionRegion(const LLVector3& pos_region)
- {
- if (isRootEdit())
- {
- setPositionLocal(pos_region);
- mPositionRegion = pos_region;
- if (mRegionp)
- {
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- }
- else
- {
- LLViewerObject* parent = (LLViewerObject*)getParent();
- setPositionLocal(pos_region - parent->getPositionRegion() *
- ~parent->getRotationRegion());
- }
- }
- void LLViewerObject::setPositionAgent(const LLVector3& pos_agent)
- {
- if (mRegionp)
- {
- setPositionRegion(mRegionp->getPosRegionFromAgent(pos_agent));
- }
- }
- // Identical to setPositionRegion() except it checks for child-joints and does
- // not also move the joint-parent. *TODO: implement similar intelligence for
- // joint-parents toward their joint-children
- void LLViewerObject::setPositionEdit(const LLVector3& pos_edit, bool damped)
- {
- if (isRootEdit())
- {
- if (!mRegionp)
- {
- llwarns << "Region not set; position unchanged for object Id: "
- << mID << llendl;
- return;
- }
- setPositionLocal(pos_edit, damped);
- mPositionRegion = pos_edit;
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- else
- {
- // The relative position with the parent is constant, but the parent's
- // position needs to be changed
- LLVector3 position_offset = getPosition() * getParent()->getRotation();
- ((LLViewerObject*)getParent())->setPositionEdit(pos_edit -
- position_offset);
- updateDrawable(damped);
- }
- }
- LLViewerObject* LLViewerObject::getRootEdit() const
- {
- const LLViewerObject* root = this;
- while (root->mParent && !root->mParent->isAvatar())
- {
- root = (LLViewerObject*)root->mParent;
- }
- return (LLViewerObject*)root;
- }
- bool LLViewerObject::lineSegmentIntersect(const LLVector4a& start,
- const LLVector4a& end,
- S32 face,
- bool pick_transparent,
- bool pick_rigged,
- S32* face_hit,
- LLVector4a* intersection,
- LLVector2* tex_coord,
- LLVector4a* normal,
- LLVector4a* tangent)
- {
- return false;
- }
- bool LLViewerObject::lineSegmentBoundingBox(const LLVector4a& start,
- const LLVector4a& end)
- {
- if (mDrawable.isNull() || mDrawable->isDead())
- {
- return false;
- }
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- // VECTORIZE THIS
- LLVector4a center;
- center.setAdd(ext[1], ext[0]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(ext[1], ext[0]);
- size.mul(0.5f);
- return LLLineSegmentBoxIntersect(start, end, center, size);
- }
- void LLViewerObject::setMediaType(U8 media_type)
- {
- // *TODO: what if we do not have a media pointer ?
- if (mMedia && mMedia->mMediaType != media_type)
- {
- mMedia->mMediaType = media_type;
- // *TODO: update materials with new image
- }
- }
- void LLViewerObject::setMediaURL(const std::string& media_url)
- {
- if (!mMedia)
- {
- mMedia = new LLViewerObjectMedia;
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = false;
- // *TODO: update materials with new image
- }
- else if (mMedia->mMediaURL != media_url)
- {
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = false;
- // *TODO: update materials with new image
- }
- }
- bool LLViewerObject::setMaterial(U8 material)
- {
- bool res = LLPrimitive::setMaterial(material);
- if (res)
- {
- setChanged(TEXTURE);
- }
- return res;
- }
- void LLViewerObject::setNumTEs(U8 num_tes)
- {
- U8 old_num_tes = getNumTEs();
- if (num_tes == old_num_tes)
- {
- return;
- }
- if (num_tes)
- {
- // Duplicate last TE into new ones, when increasing the number of TEs:
- // this happens whenever you slice an object, or hollow it while
- // editing it, for example.
- if (old_num_tes && num_tes > old_num_tes)
- {
- mTEImages.reserve(num_tes);
- mTENormalMaps.reserve(num_tes);
- mTESpecularMaps.reserve(num_tes);
- U8 last = old_num_tes - 1;
- LLViewerTexture* diffusep = mTEImages[last].get();
- LLViewerTexture* normalp = mTENormalMaps[last].get();
- LLViewerTexture* specularp = mTESpecularMaps[last].get();
- for (U8 i = old_num_tes; i < num_tes; ++i)
- {
- mTEImages.emplace_back(diffusep);
- mTENormalMaps.emplace_back(normalp);
- mTESpecularMaps.emplace_back(specularp);
- }
- }
- else
- {
- mTEImages.resize(num_tes);
- mTENormalMaps.resize(num_tes);
- mTESpecularMaps.resize(num_tes);
- }
- }
- else if (!mTEImages.empty())
- {
- mTEImages.clear();
- mTENormalMaps.clear();
- mTESpecularMaps.clear();
- }
- LLPrimitive::setNumTEs(num_tes);
- setChanged(TEXTURE);
- // Duplicate any GLTF material in the same way.
- if (old_num_tes > 0 && old_num_tes < num_tes)
- {
- LLTextureEntry* srcp = getTE(old_num_tes - 1);
- if (srcp)
- {
- LLGLTFMaterial* matp = srcp->getGLTFMaterial();
- LLGLTFMaterial* omatp = srcp->getGLTFMaterialOverride();
- if (matp && omatp)
- {
- const LLUUID& mat_id = getRenderMaterialID(old_num_tes - 1);
- for (U8 i = old_num_tes; i < num_tes; ++i)
- {
- setRenderMaterialID(i, mat_id, false);
- LLTextureEntry* tep = getTE(i);
- if (!tep)
- {
- continue;
- }
- tep->setGLTFMaterialOverride(new LLGLTFMaterial(*omatp));
- LLGLTFMaterial* rmatp = new LLFetchedGLTFMaterial();
- *rmatp = *matp;
- rmatp->applyOverride(*omatp);
- tep->setGLTFRenderMaterial(rmatp);
- }
- }
- }
- }
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- void LLViewerObject::sendMaterialUpdate() const
- {
- LLViewerRegion* regionp = getRegion();
- if (!regionp) return;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_ObjectMaterial);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- msg->addU8Fast(_PREHASH_Material, getMaterial());
- msg->sendReliable(regionp->getHost());
- }
- // formerly send_object_shape(LLViewerObject *object)
- void LLViewerObject::sendShapeUpdate()
- {
- LLViewerRegion* regionp = getRegion();
- if (!regionp) return;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_ObjectShape);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), msg);
- msg->sendReliable(regionp->getHost());
- }
- void LLViewerObject::sendTEUpdate() const
- {
- LLViewerRegion* regionp = getRegion();
- if (!regionp) return;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_ObjectImage);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- if (mMedia)
- {
- msg->addString(_PREHASH_MediaURL, mMedia->mMediaURL);
- }
- else
- {
- msg->addString(_PREHASH_MediaURL, NULL);
- }
- // *TODO: send media type
- packTEMessage(msg);
- msg->sendReliable(regionp->getHost());
- }
- LLViewerTexture* LLViewerObject::getBakedTextureForMagicId(const LLUUID& id)
- {
- if (!LLAvatarAppearanceDictionary::isBakedImageId(id))
- {
- return NULL;
- }
- LLViewerObject* root = getRootEdit();
- bool is_animesh = root && root->isAnimatedObject();
- LLVOAvatar* avatarp = is_animesh ? root->getAvatarAncestor() : getAvatar();
- if (avatarp)
- {
- EBakedTextureIndex tex_idx =
- LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(id);
- LLViewerTexture* baked_tex = avatarp->getBakedTexture(tex_idx);
- if (baked_tex && !baked_tex->isMissingAsset())
- {
- return baked_tex;
- }
- return LLViewerFetchedTexture::sDefaultImagep;
- }
- return LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true,
- LLGLTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE);
- }
- void LLViewerObject::updateAvatarMeshVisibility(const LLUUID& id,
- const LLUUID& old_id)
- {
- LLVOAvatar* avatarp = getAvatar();
- if (id != old_id && avatarp &&
- (LLAvatarAppearanceDictionary::isBakedImageId(old_id) ||
- LLAvatarAppearanceDictionary::isBakedImageId(id)))
- {
- avatarp->updateMeshVisibility();
- }
- }
- void LLViewerObject::setTE(U8 te, const LLTextureEntry& texture_entry)
- {
- LLUUID old_image_id;
- LLTextureEntry* tep = getTE(te);
- if (tep)
- {
- old_image_id = tep->getID();
- }
- LLPrimitive::setTE(te, texture_entry);
- tep = getTE(te);
- if (!tep)
- {
- return;
- }
- const LLUUID& image_id = tep->getID();
- LLViewerTexture* baked_tex = getBakedTextureForMagicId(image_id);
- if (baked_tex)
- {
- mTEImages[te] = baked_tex;
- }
- else
- {
- mTEImages[te] =
- LLViewerTextureManager::getFetchedTexture(image_id,
- FTT_DEFAULT, true,
- LLGLTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE);
- }
- updateAvatarMeshVisibility(image_id, old_image_id);
- updateTEMaterialTextures(te);
- }
- LLViewerFetchedTexture* LLViewerObject::getFetchedTexForMat(const LLUUID& id,
- F32 vsize, U32 prio)
- {
- if (id.isNull())
- {
- return NULL;
- }
- LLViewerFetchedTexture* texp = NULL;
- if (LLAvatarAppearanceDictionary::isBakedImageId(id))
- {
- LLViewerTexture* btexp = getBakedTextureForMagicId(id);
- if (btexp)
- {
- texp = btexp->asFetched();
- }
- }
- else
- {
- texp = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true,
- (LLGLTexture::EBoostLevel)prio,
- LLViewerTexture::LOD_TEXTURE);
- }
- if (texp)
- {
- texp->addTextureStats(vsize);
- }
- return texp;
- }
- void LLViewerObject::updateTEMaterialTextures(U8 te)
- {
- LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- return;
- }
- if (tep->getMaterialParams().notNull())
- {
- const LLUUID& norm_id = tep->getMaterialParams()->getNormalID();
- mTENormalMaps[te] =
- LLViewerTextureManager::getFetchedTexture(norm_id,
- FTT_DEFAULT, true,
- LLGLTexture::BOOST_ALM,
- LLViewerTexture::LOD_TEXTURE);
- const LLUUID& spec_id = tep->getMaterialParams()->getSpecularID();
- mTESpecularMaps[te] =
- LLViewerTextureManager::getFetchedTexture(spec_id,
- FTT_DEFAULT, true,
- LLGLTexture::BOOST_ALM,
- LLViewerTexture::LOD_TEXTURE);
- }
- const LLUUID& mat_id = getRenderMaterialID(te);
- LLFetchedGLTFMaterial* matp =
- (LLFetchedGLTFMaterial*)tep->getGLTFRenderMaterial();
- if (matp)
- {
- if (mat_id.isNull())
- {
- tep->setGLTFMaterial(NULL);
- return;
- }
- }
- else if (mat_id.notNull())
- {
- matp = gGLTFMaterialList.getMaterial(mat_id);
- if (!matp) return; // Maybe paranoia ?... Better safe than sorry. HB
- if (matp->isFetching())
- {
- // Material is not loaded yet, rebuild draw info when the object
- // finishes loading.
- matp->onMaterialComplete([id = mID]
- {
- LLViewerObject* objp =
- gObjectList.findObject(id);
- if (!objp) return;
- LLViewerRegion* regionp =
- objp->getRegion();
- if (regionp)
- {
- regionp->loadCacheMiscExtras(objp);
- }
- objp->markForUpdate(false);
- });
- }
- tep->setGLTFMaterial(matp);
- }
- if (!matp)
- {
- return; // Nothing else to do.
- }
- // When enough memory, fetch at a good resolution, else use the discard
- // bias to reduce the initial resolution of the textures. HB
- constexpr F32 MAX_VSIZE = 512.f * 512.f;
- constexpr F32 BIAS_SCALER = 3.f / 5.f; // Bias 0 to 5 -> 0 to 3
- // Factor will be between 1 and 1/4, depending on discard bias
- F32 factor = 1.f / (1.f +
- BIAS_SCALER * LLViewerTexture::sDesiredDiscardBias);
- F32 vsize = MAX_VSIZE * factor * factor;
- matp->mBaseColorTexture =
- getFetchedTexForMat(matp->mTextureId[BASECOLIDX], vsize);
- matp->mNormalTexture = getFetchedTexForMat(matp->mTextureId[NORMALIDX],
- vsize, LLGLTexture::BOOST_ALM);
- matp->mMetallicRoughnessTexture =
- getFetchedTexForMat(matp->mTextureId[MROUGHIDX], vsize);
- matp->mEmissiveTexture =
- getFetchedTexForMat(matp->mTextureId[EMISSIVEIDX], vsize,
- LLGLTexture::BOOST_ALM);
- }
- void LLViewerObject::refreshBakeTexture()
- {
- LL_DEBUGS("AttachmentBakes") << "Refreshing attachment bake textures for object "
- << mID << LL_ENDL;
- bool changed = false;
- for (U8 te = 0, count = getNumTEs(); te < count; ++te)
- {
- LLTextureEntry* tep = getTE(te);
- if (!tep) continue;
- const LLUUID& image_id = tep->getID();
- if (LLAvatarAppearanceDictionary::isBakedImageId(image_id))
- {
- LLViewerTexture* baked_tex = getBakedTextureForMagicId(image_id);
- if (baked_tex)
- {
- LL_DEBUGS("AttachmentBakes") << "Face index: " << (S32)te
- << " - Bake Id: " << image_id
- << " - Baked texture Id: "
- << baked_tex->getID() << LL_ENDL;
- changeTEImage(te, baked_tex);
- changed = true;
- }
- }
- }
- // *HACK: strangely, we need force a LLVOVolume rebuild to see the texture
- // actually changing on the prim. It is probably a result of how textures
- // are batched in the Cool VL Viewer.
- if (changed && mDrawable.notNull())
- {
- LLVOVolume* volp = mDrawable->getVOVolume();
- if (volp)
- {
- volp->tempSetLOD(0);
- volp->faceMappingChanged();
- }
- }
- }
- bool LLViewerObject::hasRenderMaterialParams() const
- {
- return getParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL);
- }
- void LLViewerObject::setHasRenderMaterialParams(bool has_materials)
- {
- if (hasRenderMaterialParams() != has_materials)
- {
- setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL,
- has_materials, true);
- }
- }
- const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const
- {
- LLRenderMaterialParams* paramsp = getMaterialRenderParams();
- return paramsp ? paramsp->getMaterial(te) : LLUUID::null;
- }
- static void set_te_overide_mat(const LLUUID& obj_id, U8 te)
- {
- LLViewerObject* objp = gObjectList.findObject(obj_id);
- if (!objp)
- {
- return;
- }
- LLTextureEntry* tep = objp->getTE(te);
- if (!tep)
- {
- return;
- }
- const LLGLTFMaterial* matp = tep->getGLTFMaterial();
- if (!matp)
- {
- return;
- }
- const LLGLTFMaterial* omatp = tep->getGLTFMaterialOverride();
- if (omatp)
- {
- if (objp->getDebugUpdateMsg())
- {
- llinfos << "Setting material overrides for object: " << obj_id
- << llendl;
- }
- LLGLTFMaterial* rmatp = new LLFetchedGLTFMaterial();
- *rmatp = *matp;
- rmatp->applyOverride(*omatp);
- tep->setGLTFRenderMaterial(rmatp);
- }
- }
- // Implementation is delicate: if update is bound for server, it should always
- // null out GLTFRenderMaterial and clear GLTFMaterialOverride even if Ids have
- // not changed (the case where Ids have not changed indicates the user has
- // reapplied the original material, in which case overrides should be dropped),
- // otherwise it should only null out the render material where Ids or overrides
- // have changed (the case where Ids have changed but overrides are still
- // present is from unsynchronized updates from the simulator, or synchronized
- // updates with solely transform overrides).
- void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id,
- bool update_server, bool local_origin)
- {
- S32 end_idx = getNumTEs();
- if (te_in >= end_idx)
- {
- llwarns << "Out of bound te: " << te_in << ". Aborted." << llendl;
- return;
- }
- S32 start_idx;
- if (te_in < 0)
- {
- start_idx = 0;
- }
- else
- {
- start_idx = te_in;
- end_idx = llmin(start_idx + 1, end_idx);
- }
- // If needed, enable the "GLTF" debug tag for this method call with this
- // debugged LLViewerObject instance. HB
- bool set_debug_tag = mDebugUpdateMsg &&
- !HBFloaterDebugTags::debugTagActive("GLTF");
- if (set_debug_tag)
- {
- HBFloaterDebugTags::setTag("GLTF", true);
- }
- LL_DEBUGS("GLTF") << "Called for object " << mID << " to set PBR material "
- << id << " on face(s) " << start_idx;
- if (end_idx > start_idx + 1)
- {
- LL_CONT << " to " << end_idx - 1;
- }
- LL_CONT << ". update_server = " << (update_server ? "true" : "false")
- << LL_ENDL;
- constexpr U16 PRMAT = LLNetworkData::PARAMS_RENDER_MATERIAL;
- LLRenderMaterialParams* paramsp =
- (LLRenderMaterialParams*)getExtraParameterEntry(PRMAT);
- LL_DEBUGS("GLTF") << "PBR material parameter entry "
- << (paramsp ? "found." : "not found.") << LL_ENDL;
- if (!paramsp && id.notNull())
- {
- paramsp = (LLRenderMaterialParams*)createNewParameterEntry(PRMAT);
- if (!paramsp)
- {
- llwarns << "Could not create an extra parameter entry for: "
- << te_in << ". Aborted." << llendl;
- return;
- }
- }
- LLFetchedGLTFMaterial* matp = NULL;
- if (id.notNull())
- {
- matp = gGLTFMaterialList.getMaterial(id);
- LL_DEBUGS("GLTF") << "PBR material " << (matp ? "found" : "not found")
- << " in the materials list." << LL_ENDL;
- }
- // Update local state
- for (U8 te = start_idx; te < end_idx; ++te)
- {
- LLTextureEntry* tep = getTE(te);
- if (!tep) continue; // Paranoia. HB
- // If local_origin=false (i.e. it is from the server), we know the
- // material has updated or been created, because extra params are
- // checked for equality on unpacking. In that case, checking the
- // material Id for inequality would not work, because the material Id
- // has already been set.
- bool material_changed = !local_origin || !paramsp ||
- paramsp->getMaterial(te) != id;
- if (update_server)
- {
- // Clear most overrides so the render material better matches the
- // material Id (preserve transforms). If overrides become
- // passthrough, set the overrides to NULL.
- if (tep->setBaseMaterial())
- {
- material_changed = true;
- LL_DEBUGS("GLTF") << "Material reset to base material on face: "
- << U32(te) << LL_ENDL;
- }
- }
- if (update_server || material_changed)
- {
- tep->setGLTFRenderMaterial(NULL);
- LL_DEBUGS("GLTF") << "Render material NULLed out on face: "
- << U32(te) << LL_ENDL;
- }
- if (matp != tep->getGLTFMaterial())
- {
- tep->setGLTFMaterial(matp, !update_server);
- LL_DEBUGS("GLTF") << "New material set on face: " << U32(te)
- << LL_ENDL;
- }
- if (material_changed && matp && tep->getGLTFMaterialOverride())
- {
- LL_DEBUGS("GLTF") << "Registering set override callback for face: "
- << U32(te) << LL_ENDL;
- // Sometimes, the material may change out from underneath the
- // overrides. This is usually due to the server sending a new
- // material Id, but the overrides have not changed due to being
- // only texture transforms. Re-apply the overrides to the render
- // material here, if present.
- matp->onMaterialComplete([obj_id = mID, te]()
- {
- set_te_overide_mat(obj_id, te);
- });
- }
- }
- static LLCachedControl<U32> use_basecolor(gSavedSettings,
- "RenderUseBasecolorAsDiffuse");
- if (gUsePBRShaders || use_basecolor)
- {
- // Signal to render pipeline that render batches must be rebuilt for
- // this object
- if (matp)
- {
- LL_DEBUGS("GLTF") << "Registering rebuild material callback for object: "
- << mID << LL_ENDL;
- matp->onMaterialComplete([obj_id = mID]()
- {
- LLViewerObject* objp =
- gObjectList.findObject(obj_id);
- if (objp)
- {
- objp->rebuildMaterial();
- }
- });
- }
- else
- {
- LL_DEBUGS("GLTF") << "Asking for materials rebuild on object: "
- << mID << LL_ENDL;
- rebuildMaterial();
- }
- }
- // Predictively update LLRenderMaterialParams (do not wait for server)
- if (paramsp)
- {
- LL_DEBUGS("GLTF") << "Setting render materials on object: " << mID
- << LL_ENDL;
- // Update existing parameter block
- for (U8 te = start_idx; te < end_idx; ++te)
- {
- paramsp->setMaterial(te, id);
- }
- }
- if (update_server)
- {
- // Update via ModifyMaterialParams cap (server will echo back changes)
- for (U8 te = start_idx; te < end_idx; ++te)
- {
- // This sends a cleared version of this object's current material
- // override, but the override should already be cleared due to
- // calling setBaseMaterial() above.
- LLGLTFMaterialList::queueApply(this, te, id);
- }
- }
- else
- {
- // Land impact may have changed
- setObjectCostStale();
- }
- if (set_debug_tag)
- {
- HBFloaterDebugTags::setTag("GLTF", false);
- }
- }
- void LLViewerObject::setRenderMaterialIDs(const LLRenderMaterialParams* paramsp,
- bool local_origin)
- {
- if (local_origin)
- {
- return; // Nothing to do
- }
- if (paramsp)
- {
- for (U8 te = 0, count = getNumTEs(); te < count; ++te)
- {
- // We know material_params has updated or been created, because
- // extra params are checked for equality on unpacking.
- setRenderMaterialID(te, paramsp->getMaterial(te), false, false);
- }
- }
- else
- {
- for (U8 te = 0, count = getNumTEs(); te < count; ++te)
- {
- setRenderMaterialID(te, LLUUID::null, false, false);
- }
- }
- }
- void LLViewerObject::rebuildMaterial()
- {
- faceMappingChanged();
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- void LLViewerObject::shrinkWrap()
- {
- if (!mShouldShrinkWrap)
- {
- mShouldShrinkWrap = true;
- if (mDrawable)
- {
- // We were not shrink-wrapped before but we are now, so update the
- // spatial partition.
- gPipeline.markPartitionMove(mDrawable);
- }
- }
- }
- void LLViewerObject::setTEImage(U8 te, LLViewerTexture* texp)
- {
- if (te != 255 && te < getNumTEs() && texp && mTEImages[te] != texp)
- {
- LLUUID old_image_id;
- LLTextureEntry* tep = getTE(te);
- if (tep)
- {
- old_image_id = tep->getID();
- }
- const LLUUID& image_id = texp->getID();
- LLPrimitive::setTETexture(te, image_id);
- LLViewerTexture* baked_texp = getBakedTextureForMagicId(image_id);
- mTEImages[te] = baked_texp ? baked_texp : texp;
- updateAvatarMeshVisibility(image_id, old_image_id);
- setChanged(TEXTURE);
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- }
- S32 LLViewerObject::setTETextureCore(U8 te, LLViewerTexture* texp)
- {
- const LLTextureEntry* tep = getTE(te);
- if (!tep || !texp) return 0;
- const LLUUID& tex_id = texp->getID();
- LLUUID old_tex_id = tep->getID();
- if (tex_id.notNull() && old_tex_id == tex_id)
- {
- return 0;
- }
- S32 retval = LLPrimitive::setTETexture(te, tex_id);
- LLViewerTexture* baked_texp = getBakedTextureForMagicId(tex_id);
- mTEImages[te] = baked_texp ? baked_texp : texp;
- updateAvatarMeshVisibility(tex_id, old_tex_id);
- setChanged(TEXTURE);
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- return retval;
- }
- S32 LLViewerObject::setTENormalMapCore(U8 te, LLViewerTexture* texp)
- {
- const LLTextureEntry* tep = getTE(te);
- if (!tep) return 0;
- const LLUUID& tex_id = texp ? texp->getID() : LLUUID::null;
- if (tep->getID() != tex_id || tex_id.isNull())
- {
- LLMaterial* matp = tep->getMaterialParams();
- if (matp)
- {
- LL_DEBUGS("Materials") << "te = "<< (S32)te
- << ", setting normal map id = " << tex_id
- << LL_ENDL;
- matp->setNormalID(tex_id);
- }
- }
- changeTENormalMap(te, texp);
- return TEM_CHANGE_TEXTURE;
- }
- S32 LLViewerObject::setTESpecularMapCore(U8 te, LLViewerTexture* texp)
- {
- const LLTextureEntry* tep = getTE(te);
- if (!tep) return 0;
- const LLUUID& tex_id = texp ? texp->getID() : LLUUID::null;
- if (tep->getID() != tex_id || tex_id.isNull())
- {
- LLMaterial* matp = tep->getMaterialParams();
- if (matp)
- {
- LL_DEBUGS("Materials") << "te = "<< (S32)te
- << ", setting specular map id = " << tex_id
- << LL_ENDL;
- matp->setSpecularID(tex_id);
- }
- }
- changeTESpecularMap(te, texp);
- return TEM_CHANGE_TEXTURE;
- }
- //virtual
- void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* texp)
- {
- if (index >= 0 && index < getNumTEs())
- {
- mTEImages[index] = texp;
- }
- if (mDebugUpdateMsg)
- {
- llinfos << "Changed texture for face " << index << " to texture "
- << (texp ? texp->getID() : LLUUID::null)
- << " on debugged object: " << mID << llendl;
- }
- }
- //virtual
- void LLViewerObject::changeTENormalMap(S32 index, LLViewerTexture* texp)
- {
- if (index >= 0 && index < getNumTEs())
- {
- mTENormalMaps[index] = texp;
- refreshMaterials();
- }
- }
- //virtual
- void LLViewerObject::changeTESpecularMap(S32 index, LLViewerTexture* texp)
- {
- if (index >= 0 && index < getNumTEs())
- {
- mTESpecularMaps[index] = texp;
- refreshMaterials();
- }
- }
- //virtual
- S32 LLViewerObject::setTETexture(U8 te, const LLUUID& tex_id)
- {
- // Invalid host == get from the agent's sim
- LLViewerFetchedTexture* texp =
- LLViewerTextureManager::getFetchedTexture(tex_id, FTT_DEFAULT, true,
- LLGLTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE);
- return setTETextureCore(te, texp);
- }
- //virtual
- S32 LLViewerObject::setTENormalMap(U8 te, const LLUUID& tex_id)
- {
- LLViewerFetchedTexture* texp = NULL;
- if (tex_id.notNull())
- {
- texp =
- LLViewerTextureManager::getFetchedTexture(tex_id, FTT_DEFAULT,
- true,
- LLGLTexture::BOOST_ALM,
- LLViewerTexture::LOD_TEXTURE);
- }
- return setTENormalMapCore(te, texp);
- }
- //virtual
- S32 LLViewerObject::setTESpecularMap(U8 te, const LLUUID& tex_id)
- {
- LLViewerFetchedTexture* texp = NULL;
- if (tex_id.notNull())
- {
- texp =
- LLViewerTextureManager::getFetchedTexture(tex_id, FTT_DEFAULT,
- true,
- LLGLTexture::BOOST_ALM,
- LLViewerTexture::LOD_TEXTURE);
- }
- return setTESpecularMapCore(te, texp);
- }
- //virtual
- S32 LLViewerObject::setTEColor(U8 te, const LLColor3& color)
- {
- return setTEColor(te, LLColor4(color));
- }
- //virtual
- S32 LLViewerObject::setTEColor(U8 te, const LLColor4& color)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (color != tep->getColor())
- {
- retval = LLPrimitive::setTEColor(te, color);
- if (mDrawable.notNull() && retval)
- {
- // These should only happen on updates which are not the initial
- // update.
- dirtyMesh();
- }
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEBumpmap(U8 te, U8 bump)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (bump != tep->getBumpmap())
- {
- retval = LLPrimitive::setTEBumpmap(te, bump);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY);
- }
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTETexGen(U8 te, U8 texgen)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (texgen != tep->getTexGen())
- {
- retval = LLPrimitive::setTETexGen(te, texgen);
- setChanged(TEXTURE);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEMediaTexGen(U8 te, U8 media)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (media != tep->getMediaTexGen())
- {
- retval = LLPrimitive::setTEMediaTexGen(te, media);
- setChanged(TEXTURE);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEShiny(U8 te, U8 shiny)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (shiny != tep->getShiny())
- {
- retval = LLPrimitive::setTEShiny(te, shiny);
- setChanged(TEXTURE);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEFullbright(U8 te, U8 fullbright)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (fullbright != tep->getFullbright())
- {
- retval = LLPrimitive::setTEFullbright(te, fullbright);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEMediaFlags(U8 te, U8 media_flags)
- {
- // this might need work for media type
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (media_flags != tep->getMediaFlags())
- {
- retval = LLPrimitive::setTEMediaFlags(te, media_flags);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- gPipeline.markTextured(mDrawable);
- // JC - probably only need this if changes texture coords
- //gPipeline.markRebuild(mDrawable);
- }
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEGlow(U8 te, F32 glow)
- {
- S32 retval = 0;
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- }
- else if (glow != tep->getGlow())
- {
- retval = LLPrimitive::setTEGlow(te, glow);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEMaterialID(U8 te, const LLMaterialID& matidp)
- {
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << ", material " << matidp << llendl;
- return 0;
- }
- S32 retval = LLPrimitive::setTEMaterialID(te, matidp);
- refreshMaterials();
- LL_DEBUGS("Materials") << "Changed texture entry for te " << (S32)te
- << " - object: " << mID << " - material: " << matidp
- << " - retval = " << retval << LL_ENDL;
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEMaterialParams(U8 te, const LLMaterialPtr paramsp)
- {
- const LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID
- << llendl;
- return 0;
- }
- S32 retval = LLPrimitive::setTEMaterialParams(te, paramsp);
- setTENormalMap(te, paramsp ? paramsp->getNormalID() : LLUUID::null);
- setTESpecularMap(te, paramsp ? paramsp->getSpecularID() : LLUUID::null);
- refreshMaterials();
- LL_DEBUGS("Materials") << "Changed material params for te: " << (S32)te
- << " - object: " << mID << " - retval = " << retval
- << LL_ENDL;
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* matp)
- {
- LLTextureEntry* tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << " of object "
- << mID << llendl;
- return TEM_CHANGE_NONE;
- }
- LLFetchedGLTFMaterial* srcp =
- (LLFetchedGLTFMaterial*)tep->getGLTFMaterial();
- // If an override mat exists, we must also have a source mat; it could
- // however still be in flight (scrp == NULL) or being fetched.
- if (!srcp)
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Material missing (still in flight ?) for face "
- << (S32)te << " of object " << mID << llendl;
- }
- return TEM_CHANGE_NONE;
- }
- if (srcp->isFetching())
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Material still being fetched for face " << (S32)te
- << " of object " << mID << llendl;
- }
- else
- {
- LL_DEBUGS("GLTF") << "Material still being fetched for face "
- << (S32)te << " of object " << mID << LL_ENDL;
- }
- return TEM_CHANGE_NONE;
- }
- S32 retval = tep->setGLTFMaterialOverride(matp);
- if (retval)
- {
- if (matp)
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Setting render material on face " << (S32)te
- << " of object " << mID << llendl;
- }
- LLFetchedGLTFMaterial* rmatp = new LLFetchedGLTFMaterial(*srcp);
- rmatp->applyOverride(*matp);
- tep->setGLTFRenderMaterial(rmatp);
- if (matp->hasLocalTextures())
- {
- for (LLGLTFMaterial::local_tex_map_t::const_iterator
- it = matp->mTrackingIdToLocalTexture.begin(),
- end = matp->mTrackingIdToLocalTexture.end();
- it != end; ++it)
- {
- LLLocalBitmap::associateGLTFMaterial(it->first, matp);
- }
- }
- return TEM_CHANGE_TEXTURE;
- }
- if (tep->setGLTFRenderMaterial(NULL))
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Material reset on face " << (S32)te
- << " of object " << mID << llendl;
- }
- return TEM_CHANGE_TEXTURE;
- }
- }
- return retval;
- }
- void LLViewerObject::refreshMaterials()
- {
- setChanged(TEXTURE);
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- //virtual
- S32 LLViewerObject::setTEScale(U8 te, F32 s, F32 t)
- {
- S32 retval = LLPrimitive::setTEScale(te, s, t);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEScaleS(U8 te, F32 s)
- {
- S32 retval = LLPrimitive::setTEScaleS(te, s);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEScaleT(U8 te, F32 t)
- {
- S32 retval = LLPrimitive::setTEScaleT(te, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEOffset(U8 te, F32 s, F32 t)
- {
- S32 retval = LLPrimitive::setTEOffset(te, s, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEOffsetS(U8 te, F32 s)
- {
- S32 retval = LLPrimitive::setTEOffsetS(te, s);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTEOffsetT(U8 te, F32 t)
- {
- S32 retval = LLPrimitive::setTEOffsetT(te, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
- }
- //virtual
- S32 LLViewerObject::setTERotation(U8 te, F32 r)
- {
- S32 retval = LLPrimitive::setTERotation(te, r);
- if (retval && mDrawable.notNull())
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- shrinkWrap();
- }
- return retval;
- }
- LLViewerTexture* LLViewerObject::getTEImage(U8 face) const
- {
- if (face < getNumTEs())
- {
- LLViewerTexture* texp = mTEImages[face];
- if (texp)
- {
- return texp;
- }
- return LLViewerFetchedTexture::sDefaultImagep;
- }
- llwarns << "Requested image from invalid face: " << face << "/"
- << getNumTEs() << llendl;
- return NULL;
- }
- LLViewerTexture* LLViewerObject::getTENormalMap(U8 face) const
- {
- if (face < getNumTEs())
- {
- LLViewerTexture* texp = mTENormalMaps[face].get();
- if (texp)
- {
- return texp;
- }
- return LLViewerFetchedTexture::sDefaultImagep;
- }
- llwarns << "Requested image from invalid face: " << face << " / "
- << getNumTEs() << llendl;
- return NULL;
- }
- LLViewerTexture* LLViewerObject::getTESpecularMap(U8 face) const
- {
- if (face < getNumTEs())
- {
- LLViewerTexture* texp = mTESpecularMaps[face];
- if (texp)
- {
- return texp;
- }
- return LLViewerFetchedTexture::sDefaultImagep;
- }
- llwarns << "Requested image from invalid face: " << face << " / "
- << getNumTEs() << llendl;
- return NULL;
- }
- bool LLViewerObject::isImageAlphaBlended(U8 te) const
- {
- LLViewerTexture* texp = getTEImage(te);
- if (!texp)
- {
- return false;
- }
- GLenum format = texp->getPrimaryFormat();
- switch (format)
- {
- case GL_RGB:
- break;
- case GL_RGBA:
- case GL_ALPHA:
- return true;
- default:
- llwarns << "Unexpected tex format, returning no alpha." << llendl;
- }
- return false;
- }
- void LLViewerObject::fitFaceTexture(U8 face)
- {
- llwarns << "Not implemented !" << llendl;
- llassert(false);
- }
- LLBBox LLViewerObject::getBoundingBoxAgent() const
- {
- LLViewerObject* root_edit = (LLViewerObject*)getRootEdit();
- if (root_edit)
- {
- LLXform* root_parent = root_edit->getParent();
- if (!root_parent || !root_parent->isAvatar())
- {
- root_edit = NULL;
- }
- }
- LLVector3 position_agent;
- LLQuaternion rot;
- if (root_edit && root_edit->mDrawable.notNull() &&
- root_edit->mDrawable->getXform() &&
- root_edit->mDrawable->getXform()->getParent())
- {
- LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent();
- position_agent = (getPositionEdit() *
- parent_xform->getWorldRotation()) +
- parent_xform->getWorldPosition();
- rot = getRotationEdit() * parent_xform->getWorldRotation();
- }
- else
- {
- position_agent = getPositionAgent();
- rot = getRotationRegion();
- }
- return LLBBox(position_agent, rot, getScale() * -0.5f, getScale() * 0.5f);
- }
- U32 LLViewerObject::getNumVertices() const
- {
- U32 num_vertices = 0;
- if (mDrawable.notNull())
- {
- for (S32 i = 0, count = mDrawable->getNumFaces(); i < count; ++i)
- {
- LLFace* facep = mDrawable->getFace(i);
- if (facep)
- {
- num_vertices += facep->getGeomCount();
- }
- }
- }
- return num_vertices;
- }
- U32 LLViewerObject::getNumIndices() const
- {
- U32 num_indices = 0;
- if (mDrawable.notNull())
- {
- for (S32 i = 0, count = mDrawable->getNumFaces(); i < count; ++i)
- {
- LLFace* facep = mDrawable->getFace(i);
- if (facep)
- {
- num_indices += facep->getIndicesCount();
- }
- }
- }
- return num_indices;
- }
- // Find the number of instances of this object's inventory that are of the
- // given type
- S32 LLViewerObject::countInventoryContents(LLAssetType::EType type)
- {
- S32 count = 0;
- if (mInventory)
- {
- for (LLInventoryObject::object_list_t::const_iterator
- it = mInventory->begin(), end = mInventory->end();
- it != end; ++it)
- {
- LLInventoryObject* obj = *it;
- if (obj && obj->getType() == type)
- {
- ++count;
- }
- }
- }
- return count;
- }
- void LLViewerObject::setDebugText(const std::string& utf8text)
- {
- bool no_debug_text = utf8text.empty();
- if (no_debug_text && mHudTextString.empty())
- {
- if (mText)
- {
- mText->markDead();
- mText = NULL;
- }
- return;
- }
- if (!mText)
- {
- mText = (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1);
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
- mText->setColor(no_debug_text ? mHudTextColor : LLColor4::white);
- mText->setStringUTF8(no_debug_text ? mHudTextString : utf8text);
- mText->setZCompare(no_debug_text);
- mText->setDoFade(no_debug_text);
- updateText();
- }
- LLHUDIcon* LLViewerObject::setIcon(LLViewerTexture* texp, F32 scale)
- {
- if (!mIcon)
- {
- mIcon = (LLHUDIcon*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON);
- mIcon->setSourceObject(this);
- mIcon->setImage(texp);
- mIcon->setScale(scale);
- }
- else
- {
- mIcon->restartLifeTimer();
- }
- return mIcon;
- }
- LLViewerObject* LLViewerObject::getSubParent()
- {
- return (LLViewerObject*)getParent();
- }
- const LLViewerObject* LLViewerObject::getSubParent() const
- {
- return (const LLViewerObject*)getParent();
- }
- void LLViewerObject::updateText()
- {
- if (!isDead() && mText.notNull())
- {
- LLVOAvatar* avatar = getAvatar();
- if (avatar)
- {
- mText->setHidden(avatar->isVisuallyMuted());
- }
- LLVector3 up_offset(0, 0, 0);
- up_offset.mV[2] = getScale().mV[VZ] * 0.6f;
- if (mDrawable.notNull())
- {
- mText->setPositionAgent(getRenderPosition() + up_offset);
- }
- else
- {
- mText->setPositionAgent(getPositionAgent() + up_offset);
- }
- }
- }
- bool LLViewerObject::isParticleSource() const
- {
- return mPartSourcep.notNull() && !mPartSourcep->isDead();
- }
- void LLViewerObject::setParticleSource(const LLPartSysData& particle_params,
- const LLUUID& owner_id)
- {
- if (mPartSourcep)
- {
- deleteParticleSource();
- }
- LLPointer<LLViewerPartSourceScript> pss =
- LLViewerPartSourceScript::createPSS(this, particle_params);
- mPartSourcep = pss;
- if (mPartSourcep)
- {
- mPartSourcep->setOwnerUUID(owner_id);
- if (mPartSourcep->getImage()->getID() !=
- mPartSourcep->mPartSysData.mPartImageID)
- {
- const LLUUID& image_id = mPartSourcep->mPartSysData.mPartImageID;
- LLViewerTexture* image = gImgPixieSmall;
- if (image_id.notNull())
- {
- image = LLViewerTextureManager::getFetchedTexture(image_id);
- }
- mPartSourcep->setImage(image);
- }
- }
- gViewerPartSim.addPartSource(pss);
- }
- void LLViewerObject::unpackParticleSource(S32 block_num,
- const LLUUID& owner_id)
- {
- if (mPartSourcep.notNull() && mPartSourcep->isDead())
- {
- mPartSourcep = NULL;
- }
- if (mPartSourcep)
- {
- // If we have got one already, just update the existing source
- if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep,
- block_num))
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- return;
- }
- }
- else
- {
- LLPointer<LLViewerPartSourceScript> pss =
- LLViewerPartSourceScript::unpackPSS(this, NULL, block_num);
- if (!pss || LLMuteList::isMuted(owner_id, LLMute::flagParticles))
- {
- // Do not create the system
- return;
- }
- // We need to be able to deal with a particle source that has not
- // changed, but still got an update !
- LL_DEBUGS("Particles") << "Making particle system with owner "
- << owner_id << " for object " << mID << LL_ENDL;
- mPartSourcep = pss;
- gViewerPartSim.addPartSource(pss);
- }
- if (mPartSourcep)
- {
- mPartSourcep->setOwnerUUID(owner_id);
- const LLUUID& image_id = mPartSourcep->mPartSysData.mPartImageID;
- if (mPartSourcep->getImage()->getID() != image_id)
- {
- LLViewerTexture* image = gImgPixieSmall;
- if (image_id.notNull())
- {
- image = LLViewerTextureManager::getFetchedTexture(image_id);
- }
- mPartSourcep->setImage(image);
- }
- }
- }
- void LLViewerObject::unpackParticleSource(LLDataPacker& dp,
- const LLUUID& owner_id, bool legacy)
- {
- if (mPartSourcep.notNull() && mPartSourcep->isDead())
- {
- mPartSourcep = NULL;
- }
- if (mPartSourcep)
- {
- // If we have got one already, just update the existing source
- if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp,
- legacy))
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- return;
- }
- }
- else
- {
- LLPointer<LLViewerPartSourceScript> pss =
- LLViewerPartSourceScript::unpackPSS(this, NULL, dp, legacy);
- if (!pss || LLMuteList::isMuted(owner_id, LLMute::flagParticles))
- {
- // Do not create the system
- return;
- }
- // We need to be able to deal with a particle source that has not
- // changed, but still got an update !
- LL_DEBUGS("Particles") << "Making particle system with owner "
- << owner_id << " for object " << mID << LL_ENDL;
- pss->setOwnerUUID(owner_id);
- mPartSourcep = pss;
- gViewerPartSim.addPartSource(pss);
- }
- if (mPartSourcep && mPartSourcep->getImage())
- {
- const LLUUID& image_id = mPartSourcep->mPartSysData.mPartImageID;
- if (mPartSourcep->getImage()->getID() != image_id)
- {
- LLViewerTexture* image = gImgPixieSmall;
- if (image_id.notNull())
- {
- image = LLViewerTextureManager::getFetchedTexture(image_id);
- }
- mPartSourcep->setImage(image);
- }
- }
- }
- void LLViewerObject::deleteParticleSource()
- {
- if (mPartSourcep.notNull())
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- }
- // virtual
- void LLViewerObject::updateDrawable(bool force_damped)
- {
- if (LL_UNLIKELY(isChanged(MOVED)) && mDrawable.notNull() &&
- !mDrawable->isState(LLDrawable::ON_MOVE_LIST))
- {
- bool damped_motion =
- // Not shifted between regions this frame and...
- !isChanged(SHIFTED) &&
- // ...forced into damped motion by application logic or...
- (force_damped ||
- // ...not selected and...
- (!mUserSelected &&
- // ... is root or ...
- (mDrawable->isRoot() ||
- // ... parent is not selected and ...
- (getParent() &&
- !((LLViewerObject*)getParent())->mUserSelected)) &&
- // ...is a volume object and...
- getPCode() == LL_PCODE_VOLUME &&
- // ...is not moving physically and...
- getVelocity().isExactlyZero() &&
- // ...was not created this frame.
- mDrawable->getGeneration() != -1));
- gPipeline.markMoved(mDrawable, damped_motion);
- }
- clearChanged(SHIFTED);
- }
- // virtual, overridden by LLVOVolume
- F32 LLViewerObject::getVObjRadius() const
- {
- return mDrawable.notNull() ? mDrawable->getRadius() : 0.f;
- }
- void LLViewerObject::setAttachedSound(const LLUUID& audio_uuid,
- const LLUUID& owner_id, F32 gain,
- U8 flags)
- {
- if (!gAudiop)
- {
- return;
- }
- if (audio_uuid.isNull())
- {
- if (!mAudioSourcep)
- {
- return;
- }
- if (mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads())
- {
- // We do not clear the sound if it is a loop, it will go away on
- // its own. At least, this appears to be how the scripts work. The
- // attached sound ID is set to NULL to avoid it playing back when
- // the object rezzes in on non-looping sounds.
- LL_DEBUGS("AttachedSound") << "Clearing attached sound "
- << mAudioSourcep->getCurrentData()->getID()
- << LL_ENDL;
- gAudiop->cleanupAudioSource(mAudioSourcep);
- mAudioSourcep = NULL;
- }
- else if (flags & LL_SOUND_FLAG_STOP)
- {
- // Just shut off the sound
- mAudioSourcep->stop();
- }
- return;
- }
- if ((flags & LL_SOUND_FLAG_LOOP) &&
- mAudioSourcep && mAudioSourcep->isLoop() &&
- mAudioSourcep->getCurrentData() &&
- mAudioSourcep->getCurrentData()->getID() == audio_uuid)
- {
- LL_DEBUGS("AttachedSound") << "Already playing sound " << audio_uuid
- << " on a loop, ignoring." << LL_ENDL;
- return;
- }
- // Do not clean up before previous sound is done. Solves: SL-33486
- if (mAudioSourcep && mAudioSourcep->isDone())
- {
- gAudiop->cleanupAudioSource(mAudioSourcep);
- mAudioSourcep = NULL;
- }
- if (mAudioSourcep && mAudioSourcep->isMuted() &&
- mAudioSourcep->getCurrentData() &&
- mAudioSourcep->getCurrentData()->getID() == audio_uuid)
- {
- LL_DEBUGS("AttachedSound") << "Already having sound " << audio_uuid
- << " as muted sound, ignoring." << LL_ENDL;
- return;
- }
- getAudioSource(owner_id);
- if (mAudioSourcep)
- {
- bool queue = flags & LL_SOUND_FLAG_QUEUE;
- mAudioGain = gain;
- mAudioSourcep->setGain(gain);
- mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP);
- mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER);
- mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE);
- mAudioSourcep->setQueueSounds(queue);
- if (!queue)
- {
- // Stop any current sound first to avoid "farts of doom" (SL-1541)
- // -MG
- mAudioSourcep->stop();
- }
- // Play this sound if region maturity permits
- if (gAgent.canAccessMaturityAtGlobal(getPositionGlobal()))
- {
- LL_DEBUGS("AttachedSound") << "Playing attached sound: "
- << audio_uuid << LL_ENDL;
- // Check cutoff radius in case this update was an object-update
- // with a new value
- mAudioSourcep->checkCutOffRadius();
- mAudioSourcep->play(audio_uuid);
- }
- }
- }
- LLAudioSource* LLViewerObject::getAudioSource(const LLUUID& owner_id)
- {
- if (!mAudioSourcep)
- {
- // Arbitrary low gain for a sound that is not playing. This is used for
- // sound preloads, for example.
- mAudioSourcep = new LLAudioSourceVO(mID, owner_id, 0.01f, this);
- if (gAudiop)
- {
- gAudiop->addAudioSource(mAudioSourcep);
- }
- }
- return mAudioSourcep;
- }
- void LLViewerObject::adjustAudioGain(F32 gain)
- {
- if (gAudiop && mAudioSourcep)
- {
- mAudioGain = gain;
- mAudioSourcep->setGain(mAudioGain);
- }
- }
- bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker* dp)
- {
- if (mDebugUpdateMsg)
- {
- llinfos << "Unpacking extra parameter entry type " << param_type
- << " for object " << mID << llendl;
- }
- if (LLNetworkData::PARAMS_MESH == param_type)
- {
- param_type = LLNetworkData::PARAMS_SCULPT;
- }
- LLNetworkData* paramp = getExtraParameterEntryCreate(param_type);
- if (!paramp)
- {
- return false;
- }
- paramp->unpack(*dp);
- mExtraParameterInUse[LL_EPARAM_INDEX(param_type)] = true;
- parameterChanged(param_type, paramp, true, false);
- return true;
- }
- LLNetworkData* LLViewerObject::createNewParameterEntry(U16 param_type)
- {
- LLNetworkData* new_block = NULL;
- switch (param_type)
- {
- case LLNetworkData::PARAMS_FLEXIBLE:
- new_block = new LLFlexibleObjectData();
- break;
- case LLNetworkData::PARAMS_LIGHT:
- new_block = new LLLightParams();
- break;
- case LLNetworkData::PARAMS_SCULPT:
- new_block = new LLSculptParams();
- break;
- case LLNetworkData::PARAMS_LIGHT_IMAGE:
- new_block = new LLLightImageParams();
- break;
- case LLNetworkData::PARAMS_EXTENDED_MESH:
- new_block = new LLExtendedMeshParams();
- break;
- case LLNetworkData::PARAMS_RENDER_MATERIAL:
- new_block = new LLRenderMaterialParams();
- break;
- case LLNetworkData::PARAMS_REFLECTION_PROBE:
- new_block = new LLReflectionProbeParams();
- break;
- default:
- llinfos << "Unknown param type #" << param_type << llendl;
- }
- if (!new_block) return NULL;
- if (mDebugUpdateMsg)
- {
- llinfos << "Created extra parameter entry type " << param_type
- << " for object " << mID << llendl;
- }
- S32 i = LL_EPARAM_INDEX(param_type);
- mExtraParameters[i] = new_block;
- mExtraParameterInUse[i] = false; // Not yet in use
- return new_block;
- }
- LLNetworkData* LLViewerObject::getExtraParameterEntry(U16 param_type) const
- {
- S32 i = LL_EPARAM_INDEX(param_type);
- return i >= 0 && i < LL_EPARAMS_COUNT ? mExtraParameters[i] : NULL;
- }
- LLNetworkData* LLViewerObject::getExtraParameterEntryCreate(U16 param_type)
- {
- LLNetworkData* paramp = getExtraParameterEntry(param_type);
- if (!paramp)
- {
- paramp = createNewParameterEntry(param_type);
- }
- return paramp;
- }
- bool LLViewerObject::getParameterEntryInUse(U16 param_type) const
- {
- S32 i = LL_EPARAM_INDEX(param_type);
- return i >= 0 && i < LL_EPARAMS_COUNT && mExtraParameterInUse[i];
- }
- LLFlexibleObjectData* LLViewerObject::getFlexibleObjectData() const
- {
- constexpr S32 index = LL_EPARAM_INDEX(LLNetworkData::PARAMS_FLEXIBLE);
- if (mExtraParameterInUse[index])
- {
- return (LLFlexibleObjectData*)mExtraParameters[index];
- }
- return NULL;
- }
- LLLightParams* LLViewerObject::getLightParams() const
- {
- constexpr S32 index = LL_EPARAM_INDEX(LLNetworkData::PARAMS_LIGHT);
- if (mExtraParameterInUse[index])
- {
- return (LLLightParams*)mExtraParameters[index];
- }
- return NULL;
- }
- LLSculptParams* LLViewerObject::getSculptParams() const
- {
- constexpr S32 index = LL_EPARAM_INDEX(LLNetworkData::PARAMS_SCULPT);
- if (mExtraParameterInUse[index])
- {
- return (LLSculptParams*)mExtraParameters[index];
- }
- return NULL;
- }
- LLLightImageParams* LLViewerObject::getLightImageParams() const
- {
- constexpr S32 index = LL_EPARAM_INDEX(LLNetworkData::PARAMS_LIGHT_IMAGE);
- if (mExtraParameterInUse[index])
- {
- return (LLLightImageParams*)mExtraParameters[index];
- }
- return NULL;
- }
- LLExtendedMeshParams* LLViewerObject::getExtendedMeshParams() const
- {
- constexpr S32 index = LL_EPARAM_INDEX(LLNetworkData::PARAMS_EXTENDED_MESH);
- if (mExtraParameterInUse[index])
- {
- return (LLExtendedMeshParams*)mExtraParameters[index];
- }
- return NULL;
- }
- LLRenderMaterialParams* LLViewerObject::getMaterialRenderParams() const
- {
- constexpr S32 idx = LL_EPARAM_INDEX(LLNetworkData::PARAMS_RENDER_MATERIAL);
- if (mExtraParameterInUse[idx])
- {
- return (LLRenderMaterialParams*)mExtraParameters[idx];
- }
- return NULL;
- }
- LLReflectionProbeParams* LLViewerObject::getReflectionProbeParams() const
- {
- constexpr S32 idx = LL_EPARAM_INDEX(LLNetworkData::PARAMS_REFLECTION_PROBE);
- if (mExtraParameterInUse[idx])
- {
- return (LLReflectionProbeParams*)mExtraParameters[idx];
- }
- return NULL;
- }
- bool LLViewerObject::setParameterEntry(U16 param_type,
- const LLNetworkData& new_value,
- bool local_origin)
- {
- LLNetworkData* paramp = getExtraParameterEntryCreate(param_type);
- if (!paramp)
- {
- return false;
- }
- bool& in_use = mExtraParameterInUse[LL_EPARAM_INDEX(param_type)];
- if (in_use && new_value == *paramp)
- {
- return false;
- }
- in_use = true;
- paramp->copy(new_value);
- parameterChanged(param_type, paramp, true, local_origin);
- return true;
- }
- // Assumed to be called locally. If in_use is true, will create a new extra
- // parameter if none exists.
- bool LLViewerObject::setParameterEntryInUse(U16 param_type, bool in_use,
- bool local_origin)
- {
- LLNetworkData* paramp = getExtraParameterEntryCreate(param_type);
- if (!paramp)
- {
- return false;
- }
- bool& is_in_use = mExtraParameterInUse[LL_EPARAM_INDEX(param_type)];
- if (is_in_use != in_use)
- {
- is_in_use = in_use;
- parameterChanged(param_type, paramp, in_use, local_origin);
- return true;
- }
- return false;
- }
- //virtual
- void LLViewerObject::parameterChanged(U16 param_type, bool local_origin)
- {
- LLNetworkData* paramp = getExtraParameterEntry(param_type);
- if (paramp)
- {
- parameterChanged(param_type, paramp,
- mExtraParameterInUse[LL_EPARAM_INDEX(param_type)],
- local_origin);
- }
- }
- //virtual
- void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data,
- bool in_use, bool local_origin)
- {
- // Special treatment for render materials.
- if (param_type == LLNetworkData::PARAMS_RENDER_MATERIAL)
- {
- if (local_origin)
- {
- // Do not send the render material Id in this way as it will get
- // out-of-sync with other sent client data.
- // See LLViewerObject::setRenderMaterialID() and LLGLTFMaterialList
- llwarns << "Render materials shall not be updated on the server in this way."
- << llendl;
- }
- else
- {
- const LLRenderMaterialParams* params =
- in_use ? getMaterialRenderParams() : NULL;
- setRenderMaterialIDs(params, false);
- }
- return;
- }
- if (!local_origin)
- {
- return;
- }
- LLViewerRegion* regionp = getRegion();
- if (!regionp)
- {
- return;
- }
- // Change happened on the viewer. Send the change up
- U8 tmp[MAX_OBJECT_PARAMS_SIZE];
- LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE);
- if (data->pack(dpb))
- {
- U32 datasize = (U32)dpb.getCurrentSize();
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_ObjectExtraParams);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- msg->addU16Fast(_PREHASH_ParamType, param_type);
- msg->addBoolFast(_PREHASH_ParamInUse, in_use);
- msg->addU32Fast(_PREHASH_ParamSize, datasize);
- msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize);
- msg->sendReliable(regionp->getHost());
- }
- else
- {
- llwarns << "Failed to send object extra parameters: " << param_type
- << llendl;
- }
- }
- void LLViewerObject::setDrawableState(U32 state, bool recursive)
- {
- if (mDrawable)
- {
- mDrawable->setState(state);
- }
- if (recursive)
- {
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child) // Paranoia
- {
- child->setDrawableState(state, recursive);
- }
- }
- }
- }
- void LLViewerObject::clearDrawableState(U32 state, bool recursive)
- {
- if (mDrawable)
- {
- mDrawable->clearState(state);
- }
- if (recursive)
- {
- for (child_list_t::iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child) // Paranoia
- {
- child->clearDrawableState(state, recursive);
- }
- }
- }
- }
- bool LLViewerObject::isDrawableState(U32 state, bool recursive) const
- {
- bool matches = false;
- if (mDrawable)
- {
- matches = mDrawable->isState(state);
- }
- if (recursive)
- {
- for (child_list_t::const_iterator iter = mChildList.begin();
- (iter != mChildList.end()) && matches; ++iter)
- {
- LLViewerObject* child = *iter;
- if (child) // Paranoia
- {
- matches &= child->isDrawableState(state, recursive);
- }
- }
- }
- return matches;
- }
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- // RN: these functions assume a 2-level hierarchy
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- // Owned by anyone ?
- bool LLViewerObject::permAnyOwner() const
- {
- if (isRootEdit())
- {
- return flagObjectAnyOwner();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permAnyOwner();
- }
- }
- // Owned by this viewer ?
- bool LLViewerObject::permYouOwner() const
- {
- if (isRootEdit())
- {
- return flagObjectYouOwner();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permYouOwner();
- }
- }
- // Owned by a group ?
- bool LLViewerObject::permGroupOwner() const
- {
- if (isRootEdit())
- {
- return flagObjectGroupOwned();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permGroupOwner();
- }
- }
- // Can the owner edit ?
- bool LLViewerObject::permOwnerModify() const
- {
- if (isRootEdit())
- {
- return flagObjectOwnerModify();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permOwnerModify();
- }
- }
- // Can edit ?
- bool LLViewerObject::permModify() const
- {
- if (isRootEdit())
- {
- return flagObjectModify();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permModify();
- }
- }
- // Can copy ?
- bool LLViewerObject::permCopy() const
- {
- if (isRootEdit())
- {
- return flagObjectCopy();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permCopy();
- }
- }
- // Can move ?
- bool LLViewerObject::permMove() const
- {
- if (isRootEdit())
- {
- return flagObjectMove();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permMove();
- }
- }
- // Can be transferred ?
- bool LLViewerObject::permTransfer() const
- {
- if (isRootEdit())
- {
- return flagObjectTransfer();
- }
- else
- {
- return ((LLViewerObject*)getParent())->permTransfer();
- }
- }
- // Can only open objects that you own, or that someone has
- // given you modify rights to. JC
- bool LLViewerObject::allowOpen() const
- {
- return !flagInventoryEmpty() && (permYouOwner() || permModify());
- }
- LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo()
- {
- if (mListener)
- {
- mListener->clearVOInventoryListener(mObject);
- }
- }
- bool LLViewerObject::recursiveSetMaxLOD(bool lock)
- {
- LLViewerObject* rootp = getRootEdit();
- if (!rootp || rootp->mDead)
- {
- return false;
- }
- bool result = false;
- LLVOVolume* volp = rootp->asVolume();
- if (volp)
- {
- volp->setMaxLOD(lock);
- result = true;
- }
- for (child_list_t::iterator it = rootp->mChildList.begin(),
- end = rootp->mChildList.end();
- it != end; ++it)
- {
- LLViewerObject* childp = *it;
- if (childp)
- {
- LLVOVolume* volp = childp->asVolume();
- if (volp)
- {
- volp->setMaxLOD(lock);
- result = true;
- }
- }
- }
- return result;
- }
- bool LLViewerObject::isLockedAtMaxLOD()
- {
- LLViewerObject* rootp = getRootEdit();
- if (!rootp || rootp->mDead)
- {
- return false;
- }
- LLVOVolume* volp = rootp->asVolume();
- if (volp && volp->getMaxLOD())
- {
- return true;
- }
- for (child_list_t::iterator it = rootp->mChildList.begin(),
- end = rootp->mChildList.end();
- it != end; ++it)
- {
- LLViewerObject* childp = *it;
- if (childp)
- {
- LLVOVolume* volp = childp->asVolume();
- if (volp && volp->getMaxLOD())
- {
- return true;
- }
- }
- }
- return false;
- }
- void LLViewerObject::updateVolume(const LLVolumeParams& volume_params)
- {
- if (setVolume(volume_params, 1)) // *FIX: magic number, ack !
- {
- // Transmit the update to the simulator
- sendShapeUpdate();
- markForUpdate();
- }
- }
- void LLViewerObject::recursiveMarkForUpdate()
- {
- if (mDrawable.notNull())
- {
- for (child_list_t::iterator it = mChildList.begin(),
- end = mChildList.end();
- it != end; ++it)
- {
- LLViewerObject* child = *it;
- if (child) // Paranoia
- {
- child->markForUpdate();
- }
- }
- markForUpdate();
- }
- }
- //virtual
- void LLViewerObject::markForUpdate(bool rebuild_all)
- {
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- LLDrawable::EDrawableFlags flags = rebuild_all ?
- // *HACK: used to force-refresh the visibility of objects when they
- // are "missing" (this also should force an octree rebuild)... HB
- LLDrawable::REBUILD_ALL :
- LLDrawable::REBUILD_GEOMETRY;
- gPipeline.markRebuild(mDrawable, flags);
- }
- }
- bool LLViewerObject::isPermanentEnforced() const
- {
- return flagObjectPermanent() && mRegionp != gAgent.getRegion() &&
- !gAgent.isGodlike();
- }
- bool LLViewerObject::getIncludeInSearch() const
- {
- return flagIncludeInSearch();
- }
- void LLViewerObject::setIncludeInSearch(bool include_in_search)
- {
- setFlags(FLAGS_INCLUDE_IN_SEARCH, include_in_search);
- }
- void LLViewerObject::setRegion(LLViewerRegion* regionp)
- {
- if (!regionp)
- {
- llwarns << "viewer object set region to NULL" << llendl;
- }
- if (regionp != mRegionp)
- {
- if (mRegionp)
- {
- mRegionp->removeFromCreatedList(getLocalID());
- }
- if (regionp)
- {
- regionp->addToCreatedList(getLocalID());
- }
- }
- mLatestRecvPacketID = 0;
- mRegionp = regionp;
- for (child_list_t::iterator i = mChildList.begin(), end = mChildList.end();
- i != end; ++i)
- {
- LLViewerObject* child = *i;
- child->setRegion(regionp);
- }
- if (mPuppetAvatar)
- {
- mPuppetAvatar->setRegion(regionp);
- }
- setChanged(MOVED | SILHOUETTE);
- updateDrawable(false);
- }
- bool LLViewerObject::specialHoverCursor() const
- {
- return mClickAction != 0 || flagUsePhysics() || flagHandleTouch();
- }
- void LLViewerObject::updateFlags(bool physics_changed)
- {
- LLViewerRegion* regionp = getRegion();
- if (!regionp) return;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessage(_PREHASH_ObjectFlagUpdate);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addU32Fast(_PREHASH_ObjectLocalID, getLocalID());
- msg->addBoolFast(_PREHASH_UsePhysics, flagUsePhysics());
- msg->addBool(_PREHASH_IsTemporary, flagTemporaryOnRez());
- msg->addBool(_PREHASH_IsPhantom, flagPhantom());
- // Stinson 02/28/2012: this _PREHASH_CastsShadows bool is no longer used
- // in either the viewer or the simulator. The simulator code does not even
- // unpack this value when the message is received, but could be potentially
- // hijacked in the future for another use should the urgent need arise.
- msg->addBool(_PREHASH_CastsShadows, false);
- if (physics_changed)
- {
- msg->nextBlock(_PREHASH_ExtraPhysics);
- msg->addU8(_PREHASH_PhysicsShapeType, getPhysicsShapeType());
- msg->addF32(_PREHASH_Density, getPhysicsDensity());
- msg->addF32(_PREHASH_Friction, getPhysicsFriction());
- msg->addF32(_PREHASH_Restitution, getPhysicsRestitution());
- msg->addF32(_PREHASH_GravityMultiplier, getPhysicsGravity());
- }
- msg->sendReliable(regionp->getHost());
- if (physics_changed)
- {
- setObjectCostStale();
- }
- }
- bool LLViewerObject::setFlags(U32 flags, bool state)
- {
- bool setit = setFlagsWithoutUpdate(flags, state);
- #if 0 // BUG: Sometimes viewer physics and simulator physics get out of sync.
- // To fix this, always send update to simulator.
- if (setit)
- #endif
- {
- updateFlags();
- }
- return setit;
- }
- bool LLViewerObject::setFlagsWithoutUpdate(U32 flags, bool state)
- {
- bool setit = false;
- if (state)
- {
- if ((mFlags & flags) != flags)
- {
- mFlags |= flags;
- setit = true;
- }
- }
- else if ((mFlags & flags) != 0)
- {
- mFlags &= ~flags;
- setit = true;
- }
- return setit;
- }
- void LLViewerObject::setPhysicsShapeType(U8 type)
- {
- mPhysicsShapeUnknown = false;
- if (type != mPhysicsShapeType)
- {
- mPhysicsShapeType = type;
- setObjectCostStale();
- }
- }
- void LLViewerObject::setPhysicsGravity(F32 gravity)
- {
- mPhysicsGravity = gravity;
- }
- void LLViewerObject::setPhysicsFriction(F32 friction)
- {
- mPhysicsFriction = friction;
- }
- void LLViewerObject::setPhysicsDensity(F32 density)
- {
- mPhysicsDensity = density;
- }
- void LLViewerObject::setPhysicsRestitution(F32 restitution)
- {
- mPhysicsRestitution = restitution;
- }
- U8 LLViewerObject::getPhysicsShapeType() const
- {
- if (mPhysicsShapeUnknown)
- {
- mPhysicsShapeUnknown = false;
- gObjectList.updatePhysicsFlags(this);
- }
- return mPhysicsShapeType;
- }
- void LLViewerObject::applyAngularVelocity(F32 dt)
- {
- // Do target omega here
- mRotTime += dt;
- LLVector3 ang_vel = getAngularVelocity();
- F32 omega = ang_vel.lengthSquared();
- F32 angle = 0.f;
- LLQuaternion dQ;
- if (omega > 0.00001f)
- {
- omega = sqrtf(omega);
- angle = omega * dt;
- ang_vel /= omega;
- // Calculate the delta increment based on the object's angular velocity
- dQ.setAngleAxis(angle, ang_vel);
- if (sUseNewTargetOmegaCode)
- {
- // Accumulate the angular velocity rotations to re-apply in the
- // case of an object update
- mAngularVelocityRot *= dQ;
- }
- // Just apply the delta increment to the current rotation
- setRotation(getRotation() * dQ);
- setChanged(MOVED | SILHOUETTE);
- }
- }
- void LLViewerObject::resetRot()
- {
- mRotTime = 0.f;
- if (sUseNewTargetOmegaCode)
- {
- // Reset the accumulated angular velocity rotation
- mAngularVelocityRot.loadIdentity();
- }
- }
- bool LLViewerObject::isAnySelected() const
- {
- if (mUserSelected)
- {
- return true;
- }
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- const LLViewerObject* child = *iter;
- if (child && child->mUserSelected)
- {
- return true;
- }
- }
- return false;
- }
- //virtual
- void LLViewerObject::setSelected(bool sel)
- {
- mUserSelected = sel;
- if (sUseNewTargetOmegaCode)
- {
- resetRot();
- }
- else
- {
- mRotTime = 0.f;
- }
- if (!sel)
- {
- setAllTESelected(false);
- }
- }
- //virtual
- U32 LLViewerObject::getPartitionType() const
- {
- return LLViewerRegion::PARTITION_NONE;
- }
- void LLViewerObject::dirtySpatialGroup() const
- {
- if (mDrawable)
- {
- LLSpatialGroup* groupp = mDrawable->getSpatialGroup();
- if (groupp)
- {
- groupp->dirtyGeom();
- gPipeline.markRebuild(groupp);
- }
- }
- }
- //virtual
- void LLViewerObject::dirtyMesh()
- {
- if (mDrawable)
- {
- gPipeline.markRebuild(mDrawable);
- #if 0
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->dirtyMesh();
- }
- #endif
- }
- }
- // virtual
- void LLStaticViewerObject::updateDrawable(bool force_damped)
- {
- // Force an immediate rebuild on any update
- if (mDrawable.notNull())
- {
- mDrawable->updateXform(true);
- gPipeline.markRebuild(mDrawable);
- }
- clearChanged(SHIFTED);
- }
- void LLViewerObject::saveUnselectedChildrenPosition(std::vector<LLVector3>& positions)
- {
- if (mChildList.empty() || !positions.empty())
- {
- return;
- }
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* childp = *iter;
- if (childp && !childp->mUserSelected && childp->mDrawable.notNull())
- {
- positions.emplace_back(childp->getPositionEdit());
- }
- }
- }
- void LLViewerObject::saveUnselectedChildrenRotation(std::vector<LLQuaternion>& rotations)
- {
- if (mChildList.empty())
- {
- return;
- }
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* childp = *iter;
- if (childp && !childp->mUserSelected && childp->mDrawable.notNull())
- {
- rotations.emplace_back(childp->getRotationEdit());
- }
- }
- }
- // counter-rotation
- void LLViewerObject::resetChildrenRotationAndPosition(const std::vector<LLQuaternion>& rotations,
- const std::vector<LLVector3>& positions)
- {
- if (mChildList.empty())
- {
- return;
- }
- S32 index = 0;
- LLQuaternion inv_rotation = ~getRotationEdit();
- LLVector3 offset = getPositionEdit();
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* childp = *iter;
- if (childp && !childp->mUserSelected && childp->mDrawable.notNull())
- {
- if (childp->isAvatar())
- {
- LLVector3 reset_pos = (positions[index] - offset) *
- inv_rotation;
- LLQuaternion reset_rot = rotations[index] * inv_rotation;
- LLVOAvatar* av = (LLVOAvatar*)childp;
- av->mDrawable->mXform.setPosition(reset_pos);
- av->mDrawable->mXform.setRotation(reset_rot);
- av->mDrawable->getVObj()->setPositionLocal(reset_pos, true);
- av->mDrawable->getVObj()->setRotation(reset_rot, true);
- LLManip::rebuild(childp);
- }
- else // Not an avatar
- {
- childp->setRotation(rotations[index] * inv_rotation);
- childp->setPositionLocal((positions[index] - offset) *
- inv_rotation);
- LLManip::rebuild(childp);
- }
- ++index;
- }
- }
- }
- // counter-translation
- void LLViewerObject::resetChildrenPosition(const LLVector3& offset,
- bool simplified,
- bool skip_avatar_child)
- {
- if (mChildList.empty())
- {
- return;
- }
- LLVector3 child_offset;
- if (simplified) //translation only, rotation matrix does not change
- {
- child_offset = offset * ~getRotation();
- }
- else // Rotation matrix might change too.
- {
- if (isAttachment() && mDrawable.notNull())
- {
- LLXform* attachment_point_xform = mDrawable->getXform()->getParent();
- LLQuaternion parent_rotation = getRotation() * attachment_point_xform->getWorldRotation();
- child_offset = offset * ~parent_rotation;
- }
- else
- {
- child_offset = offset * ~getRenderRotation();
- }
- }
- for (child_list_t::const_iterator iter = mChildList.begin(),
- end = mChildList.end();
- iter != end; ++iter)
- {
- LLViewerObject* childp = *iter;
- if (childp && !childp->mUserSelected && childp->mDrawable.notNull())
- {
- if (!childp->isAvatar())
- {
- childp->setPositionLocal(childp->getPosition() + child_offset);
- LLManip::rebuild(childp);
- }
- else if (!skip_avatar_child)
- {
- LLVOAvatar* av = (LLVOAvatar*)childp;
- LLVector3 reset_pos = child_offset +
- av->mDrawable->mXform.getPosition();
- av->mDrawable->mXform.setPosition(reset_pos);
- av->mDrawable->getVObj()->setPositionLocal(reset_pos);
- LLManip::rebuild(childp);
- }
- }
- }
- }
- //static
- void LLViewerObject::setUpdateInterpolationTimes(F32 interpolate_time,
- F32 phase_out_time,
- F32 region_interp_time)
- {
- if (interpolate_time < 0.f || phase_out_time < 0.f ||
- phase_out_time > interpolate_time || region_interp_time < 0.5f ||
- region_interp_time > 5.f)
- {
- llwarns << "Invalid values for interpolation or phase out times, resetting to defaults"
- << llendl;
- interpolate_time = 3.f;
- phase_out_time = 1.f;
- region_interp_time = 1.f;
- }
- sMaxUpdateInterpolationTime = (F64)interpolate_time;
- sPhaseOutUpdateInterpolationTime = (F64)phase_out_time;
- sMaxRegionCrossingInterpolationTime = (F64)region_interp_time;
- }
- const LLUUID& LLViewerObject::extractAttachmentItemID()
- {
- LLUUID item_id;
- LLNameValue* item_id_nv = getNVPair("AttachItemID");
- if (item_id_nv)
- {
- const char* s = item_id_nv->getString();
- if (s)
- {
- item_id.set(s);
- }
- }
- setAttachmentItemID(item_id);
- return getAttachmentItemID();
- }
- const std::string& LLViewerObject::getAttachmentItemName()
- {
- if (isAttachment())
- {
- LLInventoryItem* item = gInventory.getItem(getAttachmentItemID());
- if (item)
- {
- return item->getName();
- }
- }
- return LLStringUtil::null;
- }
- //virtual
- LLVOAvatar* LLViewerObject::getAvatar() const
- {
- LLVOAvatar* avatarp = (LLVOAvatar*)getPuppetAvatar();
- if (!avatarp && isAttachment())
- {
- LLViewerObject* vobj = (LLViewerObject*)getParent();
- while (vobj && !vobj->asAvatar())
- {
- vobj = (LLViewerObject*)vobj->getParent();
- }
- avatarp = (LLVOAvatar*)vobj;
- }
- return avatarp;
- }
- // If this object is directly or indirectly parented by an avatar, return it.
- // Normally getAvatar() is the correct function to call and it will give the
- // avatar used for skinning. The exception is with animated objects that are
- // also attachments; in that case, getAvatar() will return the puppet avatar,
- // used for skinning, and getAvatarAncestor() will return the avatar to which
- // the object is attached.
- LLVOAvatar* LLViewerObject::getAvatarAncestor()
- {
- LLViewerObject* vobj = (LLViewerObject*)getParent();
- while (vobj)
- {
- LLVOAvatar* avatarp = vobj->asAvatar();
- if (avatarp)
- {
- return avatarp;
- }
- vobj = (LLViewerObject*)vobj->getParent();
- }
- return NULL;
- }
- bool LLViewerObject::isHiglightedOrBeacon() const
- {
- static LLCachedControl<bool> beacons_always_on(gSavedSettings,
- "BeaconAlwaysOn");
- if (!beacons_always_on && !LLPipeline::sRenderBeaconsFloaterOpen)
- {
- return false;
- }
- if (!LLPipeline::sRenderHighlight || !LLPipeline::highlightable(this))
- {
- return false;
- }
- bool is_scripted = flagScripted();
- return (is_scripted && LLPipeline::sRenderScriptedBeacons) ||
- (is_scripted && flagHandleTouch() &&
- LLPipeline::sRenderScriptedTouchBeacons) ||
- (isAudioSource() && LLPipeline::sRenderSoundBeacons) ||
- (getMediaType() != MEDIA_NONE && LLPipeline::sRenderMOAPBeacons) ||
- (isParticleSource() && LLPipeline::sRenderParticleBeacons) ||
- (flagUsePhysics() && LLPipeline::sRenderPhysicalBeacons);
- }
- class ObjectPhysicsProperties final : public LLHTTPNode
- {
- public:
- void post(LLHTTPNode::ResponsePtr responder, const LLSD& context,
- const LLSD& input) const override
- {
- LLSD object_data = input["body"]["ObjectData"];
- S32 num_entries = object_data.size();
- for (S32 i = 0; i < num_entries; ++i)
- {
- LLSD& curr_object_data = object_data[i];
- U32 local_id = curr_object_data["LocalID"].asInteger();
- // Iterate through nodes at end, since it can be on both the
- // regular AND hover list
- struct f : public LLSelectedNodeFunctor
- {
- LL_INLINE f(const U32& id)
- : mID(id)
- {
- }
- bool LL_INLINE apply(LLSelectNode* node) override
- {
- return node->getObject() &&
- node->getObject()->mLocalID == mID;
- }
- U32 mID;
- } fn(local_id);
- LLSelectNode* nodep = gSelectMgr.getSelection()->getFirstNode(&fn);
- if (!nodep)
- {
- continue;
- }
- LLViewerObject* objp = nodep->getObject();
- if (!objp || objp->isDead())
- {
- continue;
- }
- // The LLSD message builder does not know how to handle U8, so we
- // need to send as S8 and cast.
- U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger();
- F32 density = (F32)curr_object_data["Density"].asReal();
- F32 friction = (F32)curr_object_data["Friction"].asReal();
- F32 restitution = (F32)curr_object_data["Restitution"].asReal();
- F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal();
- objp->setPhysicsShapeType(type);
- objp->setPhysicsGravity(gravity);
- objp->setPhysicsFriction(friction);
- objp->setPhysicsDensity(density);
- objp->setPhysicsRestitution(restitution);
- }
- dialog_refresh_all();
- }
- };
- LLHTTPRegistration<ObjectPhysicsProperties>
- gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties");
|